Repository: D-Programming-GDC/GDC Branch: master Commit: e5a495a8490b Files: 3500 Total size: 26.8 MB Directory structure: gitextract_2b0kd2_b/ ├── .gitignore ├── CHANGELOG-old.md ├── README-MINGW.md ├── README.md ├── gcc/ │ ├── d/ │ │ ├── ChangeLog │ │ ├── ChangeLog-2006 │ │ ├── ChangeLog-2007 │ │ ├── ChangeLog-2008 │ │ ├── ChangeLog-2009 │ │ ├── ChangeLog-2010 │ │ ├── ChangeLog-2011 │ │ ├── ChangeLog-2012 │ │ ├── ChangeLog-2013 │ │ ├── ChangeLog-2014 │ │ ├── ChangeLog-2015 │ │ ├── ChangeLog-2016 │ │ ├── ChangeLog-2017 │ │ ├── Make-lang.in │ │ ├── config-lang.in │ │ ├── d-attribs.cc │ │ ├── d-builtins.cc │ │ ├── d-codegen.cc │ │ ├── d-convert.cc │ │ ├── d-diagnostic.cc │ │ ├── d-frontend.cc │ │ ├── d-incpath.cc │ │ ├── d-lang.cc │ │ ├── d-longdouble.cc │ │ ├── d-spec.cc │ │ ├── d-target-def.h │ │ ├── d-target.cc │ │ ├── d-target.def │ │ ├── d-target.h │ │ ├── d-tree.def │ │ ├── d-tree.h │ │ ├── decl.cc │ │ ├── dmd/ │ │ │ ├── MERGE │ │ │ ├── access.d │ │ │ ├── aggregate.d │ │ │ ├── aggregate.h │ │ │ ├── aliasthis.d │ │ │ ├── apply.d │ │ │ ├── argtypes.d │ │ │ ├── arrayop.d │ │ │ ├── arraytypes.d │ │ │ ├── arraytypes.h │ │ │ ├── astcodegen.d │ │ │ ├── attrib.d │ │ │ ├── attrib.h │ │ │ ├── blockexit.d │ │ │ ├── boostlicense.txt │ │ │ ├── builtin.d │ │ │ ├── canthrow.d │ │ │ ├── clone.d │ │ │ ├── compiler.d │ │ │ ├── compiler.h │ │ │ ├── complex.d │ │ │ ├── complex_t.h │ │ │ ├── cond.d │ │ │ ├── cond.h │ │ │ ├── constfold.d │ │ │ ├── cppmangle.d │ │ │ ├── ctfe.h │ │ │ ├── ctfeexpr.d │ │ │ ├── ctorflow.d │ │ │ ├── dcast.d │ │ │ ├── dclass.d │ │ │ ├── ddoc/ │ │ │ │ └── default_ddoc_theme.ddoc │ │ │ ├── declaration.d │ │ │ ├── declaration.h │ │ │ ├── delegatize.d │ │ │ ├── denum.d │ │ │ ├── dimport.d │ │ │ ├── dinterpret.d │ │ │ ├── dmacro.d │ │ │ ├── dmangle.d │ │ │ ├── dmodule.d │ │ │ ├── doc.d │ │ │ ├── doc.h │ │ │ ├── dscope.d │ │ │ ├── dstruct.d │ │ │ ├── dsymbol.d │ │ │ ├── dsymbol.h │ │ │ ├── dsymbolsem.d │ │ │ ├── dtemplate.d │ │ │ ├── dversion.d │ │ │ ├── entity.d │ │ │ ├── enum.h │ │ │ ├── errors.d │ │ │ ├── errors.h │ │ │ ├── escape.d │ │ │ ├── expression.d │ │ │ ├── expression.h │ │ │ ├── expressionsem.d │ │ │ ├── func.d │ │ │ ├── globals.d │ │ │ ├── globals.h │ │ │ ├── gluelayer.d │ │ │ ├── hdrgen.d │ │ │ ├── hdrgen.h │ │ │ ├── iasm.d │ │ │ ├── iasmgcc.d │ │ │ ├── id.d │ │ │ ├── id.h │ │ │ ├── identifier.d │ │ │ ├── identifier.h │ │ │ ├── impcnvtab.d │ │ │ ├── imphint.d │ │ │ ├── import.h │ │ │ ├── init.d │ │ │ ├── init.h │ │ │ ├── initsem.d │ │ │ ├── inline.d │ │ │ ├── intrange.d │ │ │ ├── json.d │ │ │ ├── json.h │ │ │ ├── lambdacomp.d │ │ │ ├── lexer.d │ │ │ ├── mangle.h │ │ │ ├── mars.h │ │ │ ├── module.h │ │ │ ├── mtype.d │ │ │ ├── mtype.h │ │ │ ├── nogc.d │ │ │ ├── nspace.d │ │ │ ├── nspace.h │ │ │ ├── objc.d │ │ │ ├── objc.h │ │ │ ├── opover.d │ │ │ ├── optimize.d │ │ │ ├── parse.d │ │ │ ├── parsetimevisitor.d │ │ │ ├── permissivevisitor.d │ │ │ ├── readme.txt │ │ │ ├── root/ │ │ │ │ ├── aav.d │ │ │ │ ├── array.d │ │ │ │ ├── array.h │ │ │ │ ├── ctfloat.d │ │ │ │ ├── ctfloat.h │ │ │ │ ├── dcompat.h │ │ │ │ ├── file.d │ │ │ │ ├── file.h │ │ │ │ ├── filename.d │ │ │ │ ├── filename.h │ │ │ │ ├── hash.d │ │ │ │ ├── longdouble.d │ │ │ │ ├── object.h │ │ │ │ ├── outbuffer.d │ │ │ │ ├── outbuffer.h │ │ │ │ ├── port.d │ │ │ │ ├── port.h │ │ │ │ ├── rmem.d │ │ │ │ ├── rmem.h │ │ │ │ ├── root.h │ │ │ │ ├── rootobject.d │ │ │ │ ├── speller.d │ │ │ │ └── stringtable.d │ │ │ ├── safe.d │ │ │ ├── sapply.d │ │ │ ├── scope.h │ │ │ ├── semantic2.d │ │ │ ├── semantic3.d │ │ │ ├── sideeffect.d │ │ │ ├── statement.d │ │ │ ├── statement.h │ │ │ ├── statement_rewrite_walker.d │ │ │ ├── statementsem.d │ │ │ ├── staticassert.d │ │ │ ├── staticcond.d │ │ │ ├── target.d │ │ │ ├── target.h │ │ │ ├── template.h │ │ │ ├── templateparamsem.d │ │ │ ├── tokens.d │ │ │ ├── tokens.h │ │ │ ├── traits.d │ │ │ ├── transitivevisitor.d │ │ │ ├── typesem.d │ │ │ ├── typinf.d │ │ │ ├── utf.d │ │ │ ├── utils.d │ │ │ ├── visitor.d │ │ │ └── visitor.h │ │ ├── expr.cc │ │ ├── gdc.texi │ │ ├── imports.cc │ │ ├── intrinsics.cc │ │ ├── intrinsics.def │ │ ├── lang-specs.h │ │ ├── lang.opt │ │ ├── longdouble.h │ │ ├── modules.cc │ │ ├── patches/ │ │ │ ├── patch-gcc-9.patch │ │ │ ├── patch-gcc-ddmd-9.patch │ │ │ ├── patch-targetdm-9.patch │ │ │ ├── patch-targetdm-untested-9.patch │ │ │ ├── patch-toplev-9.patch │ │ │ └── patch-toplev-ddmd-9.patch │ │ ├── runtime.cc │ │ ├── runtime.def │ │ ├── toir.cc │ │ ├── typeinfo.cc │ │ ├── types.cc │ │ └── verstr.h │ └── testsuite/ │ ├── gdc.dg/ │ │ ├── asan/ │ │ │ ├── asan.exp │ │ │ └── gdc272.d │ │ ├── compilable.d │ │ ├── dg.exp │ │ ├── gdc254.d │ │ ├── gdc260.d │ │ ├── gdc270a.d │ │ ├── gdc270b.d │ │ ├── gdc282.d │ │ ├── gdc283.d │ │ ├── imports/ │ │ │ ├── gdc170.d │ │ │ ├── gdc231.d │ │ │ ├── gdc239.d │ │ │ ├── gdc241a.d │ │ │ ├── gdc241b.d │ │ │ ├── gdc251a.d │ │ │ ├── gdc251b.d │ │ │ ├── gdc253.d │ │ │ ├── gdc254a.d │ │ │ ├── gdc256.d │ │ │ ├── gdc27.d │ │ │ ├── gdcpkg256/ │ │ │ │ └── package.d │ │ │ └── runnable.d │ │ ├── link.d │ │ ├── lto/ │ │ │ ├── lto.exp │ │ │ ├── ltotests_0.d │ │ │ └── ltotests_1.d │ │ ├── runnable.d │ │ └── simd.d │ ├── gdc.test/ │ │ ├── compilable/ │ │ │ ├── 99bottles.d │ │ │ ├── Test16206.d │ │ │ ├── a3682.d │ │ │ ├── aggr_alignment.d │ │ │ ├── aliasdecl.d │ │ │ ├── alignment.d │ │ │ ├── art4769.d │ │ │ ├── b11118.d │ │ │ ├── b1215.d │ │ │ ├── b15428.d │ │ │ ├── b16244.d │ │ │ ├── b16346.d │ │ │ ├── b16355.d │ │ │ ├── b16382.d │ │ │ ├── b16483.d │ │ │ ├── b16598.d │ │ │ ├── b16697.d │ │ │ ├── b16967.d │ │ │ ├── b17111.d │ │ │ ├── b18197.d │ │ │ ├── b18242.d │ │ │ ├── b18489.d │ │ │ ├── b33.d │ │ │ ├── b6227.d │ │ │ ├── b6395.d │ │ │ ├── betterCarray.d │ │ │ ├── betterCswitch.d │ │ │ ├── betterc.d │ │ │ ├── bug11735.d │ │ │ ├── bug6963.d │ │ │ ├── callconv.d │ │ │ ├── checkimports3.d │ │ │ ├── compile1.d │ │ │ ├── const.d │ │ │ ├── cppmangle.d │ │ │ ├── cppmangle2.d │ │ │ ├── cppmangle3.d │ │ │ ├── ctfe_math.d │ │ │ ├── ddoc1.d │ │ │ ├── ddoc10.d │ │ │ ├── ddoc10236.d │ │ │ ├── ddoc10236b.d │ │ │ ├── ddoc10325.d │ │ │ ├── ddoc10334.d │ │ │ ├── ddoc10366.d │ │ │ ├── ddoc10367.d │ │ │ ├── ddoc10869.d │ │ │ ├── ddoc10870.d │ │ │ ├── ddoc11.d │ │ │ ├── ddoc11479.d │ │ │ ├── ddoc11511.d │ │ │ ├── ddoc11823.d │ │ │ ├── ddoc12.d │ │ │ ├── ddoc12706.d │ │ │ ├── ddoc12745.d │ │ │ ├── ddoc13.d │ │ │ ├── ddoc13270.d │ │ │ ├── ddoc13502.d │ │ │ ├── ddoc13645.d │ │ │ ├── ddoc14.d │ │ │ ├── ddoc14383.d │ │ │ ├── ddoc14413.d │ │ │ ├── ddoc14633.d │ │ │ ├── ddoc14778.d │ │ │ ├── ddoc15475.d │ │ │ ├── ddoc17697.d │ │ │ ├── ddoc18361.d │ │ │ ├── ddoc198.d │ │ │ ├── ddoc2.d │ │ │ ├── ddoc2273.d │ │ │ ├── ddoc3.d │ │ │ ├── ddoc4.d │ │ │ ├── ddoc4162.d │ │ │ ├── ddoc4899.d │ │ │ ├── ddoc5.d │ │ │ ├── ddoc5446.d │ │ │ ├── ddoc5446a.d │ │ │ ├── ddoc5446b.d │ │ │ ├── ddoc6.d │ │ │ ├── ddoc648.d │ │ │ ├── ddoc6491.d │ │ │ ├── ddoc7.d │ │ │ ├── ddoc7555.d │ │ │ ├── ddoc7656.d │ │ │ ├── ddoc7715.d │ │ │ ├── ddoc7795.d │ │ │ ├── ddoc8.d │ │ │ ├── ddoc8271.d │ │ │ ├── ddoc8739.d │ │ │ ├── ddoc9.d │ │ │ ├── ddoc9037.d │ │ │ ├── ddoc9155.d │ │ │ ├── ddoc9305.d │ │ │ ├── ddoc9369.d │ │ │ ├── ddoc9475.d │ │ │ ├── ddoc9497a.d │ │ │ ├── ddoc9497b.d │ │ │ ├── ddoc9497c.d │ │ │ ├── ddoc9497d.d │ │ │ ├── ddoc9676a.d │ │ │ ├── ddoc9676b.d │ │ │ ├── ddoc9727.d │ │ │ ├── ddoc9789.d │ │ │ ├── ddoc9903.d │ │ │ ├── ddocYear.d │ │ │ ├── ddocbackticks.d │ │ │ ├── ddocunittest.d │ │ │ ├── debuginfo.d │ │ │ ├── defa.d │ │ │ ├── depmsg.d │ │ │ ├── deprecate12979a.d │ │ │ ├── deprecate14283.d │ │ │ ├── depsOutput9948.d │ │ │ ├── derivedarray.d │ │ │ ├── diag11066.d │ │ │ ├── diag3243.d │ │ │ ├── dip22.d │ │ │ ├── disable_new.d │ │ │ ├── empty_file.d │ │ │ ├── exception.d │ │ │ ├── extra-files/ │ │ │ │ ├── c6395.d │ │ │ │ ├── ddoc10367.ddoc │ │ │ │ ├── ddoc198.ddoc │ │ │ │ ├── ddoc3.ddoc │ │ │ │ ├── ddoc9369.ddoc │ │ │ │ ├── ddoc9497a.ddoc │ │ │ │ ├── ddoc9497b.ddoc │ │ │ │ ├── ddoc9497c.ddoc │ │ │ │ ├── ddoc9497d.ddoc │ │ │ │ ├── ddoc9676a.ddoc │ │ │ │ ├── ddoc9764.dd │ │ │ │ ├── depsOutput9948a.d │ │ │ │ ├── e6815.d │ │ │ │ ├── emptymain.d │ │ │ │ ├── example7190/ │ │ │ │ │ ├── controllers/ │ │ │ │ │ │ └── HomeController.d │ │ │ │ │ └── models/ │ │ │ │ │ └── HomeModel.d │ │ │ │ ├── header1.d │ │ │ │ ├── header18365.d │ │ │ │ ├── header2.d │ │ │ │ ├── header3.d │ │ │ │ ├── imp12624.d │ │ │ │ ├── imp9057.d │ │ │ │ ├── imp9057_2.d │ │ │ │ ├── minimal/ │ │ │ │ │ └── object.d │ │ │ │ ├── pkgDIP37/ │ │ │ │ │ ├── datetime/ │ │ │ │ │ │ ├── common.d │ │ │ │ │ │ └── package.d │ │ │ │ │ └── test17629/ │ │ │ │ │ ├── common.di │ │ │ │ │ └── package.di │ │ │ │ ├── pkgDIP37_10302/ │ │ │ │ │ ├── liba.d │ │ │ │ │ ├── libb.d │ │ │ │ │ └── package.d │ │ │ │ ├── pkgDIP37_10354/ │ │ │ │ │ ├── mbar.d │ │ │ │ │ ├── mfoo.d │ │ │ │ │ └── package.d │ │ │ │ ├── pkgDIP37_10421/ │ │ │ │ │ ├── algo/ │ │ │ │ │ │ ├── mod.d │ │ │ │ │ │ └── package.d │ │ │ │ │ └── except.d │ │ │ │ ├── serenity7190/ │ │ │ │ │ └── core/ │ │ │ │ │ ├── Controller.d │ │ │ │ │ └── Model.d │ │ │ │ ├── test14894a.d │ │ │ │ ├── test14894main.d │ │ │ │ ├── test16080b.d │ │ │ │ ├── test6461/ │ │ │ │ │ ├── a.d │ │ │ │ │ ├── b.d │ │ │ │ │ ├── main.d │ │ │ │ │ └── tmpl.d │ │ │ │ ├── test9680dllmain.d │ │ │ │ ├── test9680main.d │ │ │ │ └── test9680winmain.d │ │ │ ├── fail260.d │ │ │ ├── filefullpath_18911.d │ │ │ ├── fix17123.d │ │ │ ├── fix17335.d │ │ │ ├── fix17349.d │ │ │ ├── fix17686.d │ │ │ ├── forward1.d │ │ │ ├── future.d │ │ │ ├── futurexf.d │ │ │ ├── header18364.d │ │ │ ├── header18365.d │ │ │ ├── iasm_labeloperand.d │ │ │ ├── ice10040.d │ │ │ ├── ice10431a.d │ │ │ ├── ice10431b.d │ │ │ ├── ice10486.d │ │ │ ├── ice10598.d │ │ │ ├── ice11054.d │ │ │ ├── ice11300.d │ │ │ ├── ice11596.d │ │ │ ├── ice11610.d │ │ │ ├── ice11777.d │ │ │ ├── ice11906.d │ │ │ ├── ice11925.d │ │ │ ├── ice12002.d │ │ │ ├── ice12554.d │ │ │ ├── ice12956.d │ │ │ ├── ice13071.d │ │ │ ├── ice13088.d │ │ │ ├── ice13245.d │ │ │ ├── ice13323.d │ │ │ ├── ice13403.d │ │ │ ├── ice13792.d │ │ │ ├── ice13874.d │ │ │ ├── ice13886.d │ │ │ ├── ice13920.d │ │ │ ├── ice13968.d │ │ │ ├── ice14075.d │ │ │ ├── ice14739.d │ │ │ ├── ice1524.d │ │ │ ├── ice15333.d │ │ │ ├── ice15760.d │ │ │ ├── ice15789.d │ │ │ ├── ice15992.d │ │ │ ├── ice6538.d │ │ │ ├── ice8392.d │ │ │ ├── ice854.d │ │ │ ├── ice9663.d │ │ │ ├── imports/ │ │ │ │ ├── a12506.d │ │ │ │ ├── a12511.d │ │ │ │ ├── a12567.d │ │ │ │ ├── a13226.d │ │ │ │ ├── a14528.d │ │ │ │ ├── a15333.d │ │ │ │ ├── a15760.d │ │ │ │ ├── a15856.d │ │ │ │ ├── a18911.d │ │ │ │ ├── a313.d │ │ │ │ ├── a313templatemixin1.d │ │ │ │ ├── a313templatemixin2.d │ │ │ │ ├── a314.d │ │ │ │ ├── a8392.d │ │ │ │ ├── art4769a.d │ │ │ │ ├── art4769b.d │ │ │ │ ├── b313.d │ │ │ │ ├── b33a.d │ │ │ │ ├── b3682.d │ │ │ │ ├── bug8922.d │ │ │ │ ├── c314.d │ │ │ │ ├── checkimports3a.d │ │ │ │ ├── checkimports3b.d │ │ │ │ ├── checkimports3c.d │ │ │ │ ├── defaa.d │ │ │ │ ├── defab.d │ │ │ │ ├── defac.d │ │ │ │ ├── defad.d │ │ │ │ ├── dip22.d │ │ │ │ ├── f313.d │ │ │ │ ├── fwdref12201a.d │ │ │ │ ├── fwdref2_test17548.d │ │ │ │ ├── fwdref9514.d │ │ │ │ ├── g313.d │ │ │ │ ├── g313public.d │ │ │ │ ├── g313staticif.d │ │ │ │ ├── g313stringmixin.d │ │ │ │ ├── g313templatemixin.d │ │ │ │ ├── ice10598a.d │ │ │ │ ├── ice10598b.d │ │ │ │ ├── ice11054a.d │ │ │ │ ├── ice11300a.d │ │ │ │ ├── ice13403a.d │ │ │ │ ├── imp12242a.d │ │ │ │ ├── imp12242a1.d │ │ │ │ ├── imp12242a2.d │ │ │ │ ├── imp12242b.d │ │ │ │ ├── imp12242b1.d │ │ │ │ ├── imp12242b2.d │ │ │ │ ├── imp15490a.d │ │ │ │ ├── imp15490b.d │ │ │ │ ├── imp15907.d │ │ │ │ ├── imp15925.d │ │ │ │ ├── imp16080.d │ │ │ │ ├── imp16085.d │ │ │ │ ├── imp16085b.d │ │ │ │ ├── imp16088.d │ │ │ │ ├── imp16460.d │ │ │ │ ├── imp16798.d │ │ │ │ ├── jsonimport1.d │ │ │ │ ├── jsonimport2.d │ │ │ │ ├── jsonimport3.d │ │ │ │ ├── jsonimport4.d │ │ │ │ ├── pkg313/ │ │ │ │ │ └── c313.d │ │ │ │ ├── pkgmod313/ │ │ │ │ │ ├── mod.d │ │ │ │ │ └── package.d │ │ │ │ ├── protectionimp.d │ │ │ │ ├── stdio4003.d │ │ │ │ ├── test10375a.d │ │ │ │ ├── test10752.d │ │ │ │ ├── test11225b.d │ │ │ │ ├── test11225c.d │ │ │ │ ├── test11563core_bitop.d │ │ │ │ ├── test11563std_array.d │ │ │ │ ├── test11563std_range.d │ │ │ │ ├── test11563std_traits.d │ │ │ │ ├── test1238a.d │ │ │ │ ├── test1238b.d │ │ │ │ ├── test13242a.d │ │ │ │ ├── test13242b.d │ │ │ │ ├── test14666a.d │ │ │ │ ├── test14666b.d │ │ │ │ ├── test15117a.d │ │ │ │ ├── test15150a.d │ │ │ │ ├── test15150b.d │ │ │ │ ├── test15785.d │ │ │ │ ├── test15857a.d │ │ │ │ ├── test15857b.d │ │ │ │ ├── test15857c.d │ │ │ │ ├── test16348.d │ │ │ │ ├── test17541_2.d │ │ │ │ ├── test17541_3.d │ │ │ │ ├── test1754a.d │ │ │ │ ├── test1754b.d │ │ │ │ ├── test17991a/ │ │ │ │ │ ├── a.d │ │ │ │ │ └── package.d │ │ │ │ ├── test18771a.d │ │ │ │ ├── test18771b.d │ │ │ │ ├── test18771c.d │ │ │ │ ├── test18771d.d │ │ │ │ ├── test19107a.d │ │ │ │ ├── test19107b.d │ │ │ │ ├── test19187.d │ │ │ │ ├── test1imp.d │ │ │ │ ├── test25a.d │ │ │ │ ├── test25b.d │ │ │ │ ├── test2991.d │ │ │ │ ├── test4003a.d │ │ │ │ ├── test50a.d │ │ │ │ ├── test55a.d │ │ │ │ ├── test59a.d │ │ │ │ ├── test59b.d │ │ │ │ ├── test6013.d │ │ │ │ ├── test61a.d │ │ │ │ ├── test62a.d │ │ │ │ ├── test63a.d │ │ │ │ ├── test66a.d │ │ │ │ ├── test67a.d │ │ │ │ ├── test68a.d │ │ │ │ ├── test70.d │ │ │ │ ├── test71.d │ │ │ │ ├── test72a.d │ │ │ │ ├── test72b.d │ │ │ │ ├── test72c.d │ │ │ │ ├── test7491a.d │ │ │ │ ├── test7491b.d │ │ │ │ ├── test9276decl.d │ │ │ │ ├── test9276expr.d │ │ │ │ ├── test9276hash.d │ │ │ │ ├── test9276parser.d │ │ │ │ ├── test9276sem.d │ │ │ │ ├── test9276type.d │ │ │ │ ├── test9276util.d │ │ │ │ ├── test9276visitors.d │ │ │ │ ├── test9399a.d │ │ │ │ ├── test9436aggr.d │ │ │ │ ├── test9436interp.d │ │ │ │ ├── test9436node.d │ │ │ │ ├── test9436type.d │ │ │ │ ├── test9672a.d │ │ │ │ ├── test9692b.d │ │ │ │ ├── test9919a.d │ │ │ │ ├── test9919b.d │ │ │ │ ├── test9919c.d │ │ │ │ ├── testcontracts.d │ │ │ │ ├── testlambda1.d │ │ │ │ ├── testlambda2.d │ │ │ │ ├── typecons4003.d │ │ │ │ ├── udamodule1.d │ │ │ │ ├── udamodule2.d │ │ │ │ ├── udamodule2a.d │ │ │ │ └── wax16798.d │ │ │ ├── interpret3.d │ │ │ ├── isZeroInit.d │ │ │ ├── issue18097.d │ │ │ ├── json.d │ │ │ ├── line.d │ │ │ ├── minimal.d │ │ │ ├── minimal2.d │ │ │ ├── mixintempl.d │ │ │ ├── noderef.d │ │ │ ├── nogc.d │ │ │ ├── protattr.d │ │ │ ├── protection/ │ │ │ │ ├── aggregate/ │ │ │ │ │ └── mod14275.d │ │ │ │ ├── basic/ │ │ │ │ │ ├── mod1.d │ │ │ │ │ └── tests.d │ │ │ │ ├── bug/ │ │ │ │ │ └── bug14275.d │ │ │ │ ├── subpkg/ │ │ │ │ │ ├── explicit.d │ │ │ │ │ └── tests.d │ │ │ │ └── subpkg2/ │ │ │ │ └── tests.d │ │ │ ├── protection.d │ │ │ ├── pull6815.d │ │ │ ├── riia_ctor.d │ │ │ ├── scope.d │ │ │ ├── shared_destructor.d │ │ │ ├── staticforeach.d │ │ │ ├── sw_transition_complex.d │ │ │ ├── sw_transition_field.d │ │ │ ├── sw_transition_tls.d │ │ │ ├── test1.d │ │ │ ├── test10056.d │ │ │ ├── test10066.d │ │ │ ├── test10073.d │ │ │ ├── test10186.d │ │ │ ├── test10312.d │ │ │ ├── test10375.d │ │ │ ├── test10520.d │ │ │ ├── test10695.d │ │ │ ├── test10726.d │ │ │ ├── test10752.d │ │ │ ├── test10981.d │ │ │ ├── test10992.d │ │ │ ├── test10992b.d │ │ │ ├── test10993.d │ │ │ ├── test11169.d │ │ │ ├── test11225a.d │ │ │ ├── test11237.d │ │ │ ├── test11259.d │ │ │ ├── test11371.d │ │ │ ├── test11471.d │ │ │ ├── test11559upgradeoptlink.d │ │ │ ├── test11563.d │ │ │ ├── test11656.d │ │ │ ├── test11824.d │ │ │ ├── test11914.d │ │ │ ├── test11980.d │ │ │ ├── test12009.d │ │ │ ├── test1238.d │ │ │ ├── test12496.d │ │ │ ├── test12511.d │ │ │ ├── test12523.d │ │ │ ├── test12527.d │ │ │ ├── test12567a.d │ │ │ ├── test12567b.d │ │ │ ├── test12567c.d │ │ │ ├── test12567d.d │ │ │ ├── test12593.d │ │ │ ├── test12624.d │ │ │ ├── test12807.d │ │ │ ├── test12967.d │ │ │ ├── test12979a.d │ │ │ ├── test12979b.d │ │ │ ├── test13008.d │ │ │ ├── test13053.d │ │ │ ├── test13193.d │ │ │ ├── test13194.d │ │ │ ├── test13226.d │ │ │ ├── test13242.d │ │ │ ├── test13281.d │ │ │ ├── test13512.d │ │ │ ├── test1353.d │ │ │ ├── test13600.d │ │ │ ├── test13668.d │ │ │ ├── test13858.d │ │ │ ├── test13902.d │ │ │ ├── test14275.d │ │ │ ├── test14317.d │ │ │ ├── test14375.d │ │ │ ├── test14528.d │ │ │ ├── test14666.d │ │ │ ├── test14747.d │ │ │ ├── test14781.d │ │ │ ├── test14838.d │ │ │ ├── test14962.d │ │ │ ├── test14973.d │ │ │ ├── test15019.d │ │ │ ├── test15056.d │ │ │ ├── test15150.d │ │ │ ├── test15177.d │ │ │ ├── test15326.d │ │ │ ├── test1537.d │ │ │ ├── test15389_x.d │ │ │ ├── test15389_y.d │ │ │ ├── test15402.d │ │ │ ├── test15464.d │ │ │ ├── test15490.d │ │ │ ├── test15519_x.d │ │ │ ├── test15519_y.d │ │ │ ├── test15550.d │ │ │ ├── test15565.d │ │ │ ├── test15578.d │ │ │ ├── test15618.d │ │ │ ├── test15668.d │ │ │ ├── test15762.d │ │ │ ├── test15780.d │ │ │ ├── test15784.d │ │ │ ├── test15785.d │ │ │ ├── test15802.d │ │ │ ├── test15856.d │ │ │ ├── test15898.d │ │ │ ├── test15907.d │ │ │ ├── test15925.d │ │ │ ├── test16013a.d │ │ │ ├── test16013b.d │ │ │ ├── test16031.d │ │ │ ├── test16037.d │ │ │ ├── test16080.d │ │ │ ├── test16083.d │ │ │ ├── test16085.d │ │ │ ├── test16088.d │ │ │ ├── test16107.d │ │ │ ├── test16183.d │ │ │ ├── test16225.d │ │ │ ├── test16273.d │ │ │ ├── test16292.d │ │ │ ├── test16303.d │ │ │ ├── test16340.d │ │ │ ├── test16348.d │ │ │ ├── test16460.d │ │ │ ├── test16492.d │ │ │ ├── test16525.d │ │ │ ├── test16540.d │ │ │ ├── test16563.d │ │ │ ├── test16570.d │ │ │ ├── test16572.d │ │ │ ├── test16574.d │ │ │ ├── test16578a.d │ │ │ ├── test16578b.d │ │ │ ├── test16607.d │ │ │ ├── test16621.d │ │ │ ├── test16627.d │ │ │ ├── test16685.d │ │ │ ├── test1673.d │ │ │ ├── test16747.d │ │ │ ├── test16798.d │ │ │ ├── test17057.d │ │ │ ├── test17059.d │ │ │ ├── test17130.d │ │ │ ├── test17143.d │ │ │ ├── test17168.d │ │ │ ├── test17215.d │ │ │ ├── test17339.d │ │ │ ├── test17349.d │ │ │ ├── test17352.d │ │ │ ├── test17373.d │ │ │ ├── test17399.d │ │ │ ├── test17419.d │ │ │ ├── test17421.d │ │ │ ├── test17468.d │ │ │ ├── test17512.d │ │ │ ├── test1754.d │ │ │ ├── test17541.d │ │ │ ├── test17545.d │ │ │ ├── test17548.d │ │ │ ├── test17590.d │ │ │ ├── test17752.d │ │ │ ├── test17782.d │ │ │ ├── test17791.d │ │ │ ├── test17807.d │ │ │ ├── test17819.d │ │ │ ├── test17853.d │ │ │ ├── test17906.d │ │ │ ├── test17908.d │ │ │ ├── test17942.d │ │ │ ├── test17970.d │ │ │ ├── test17991.d │ │ │ ├── test18000.d │ │ │ ├── test18020.d │ │ │ ├── test18030.d │ │ │ ├── test18099.d │ │ │ ├── test18115.d │ │ │ ├── test18199.d │ │ │ ├── test18430.d │ │ │ ├── test18468.d │ │ │ ├── test18474.d │ │ │ ├── test18578.d │ │ │ ├── test18584.d │ │ │ ├── test18645.d │ │ │ ├── test18670.d │ │ │ ├── test18694.d │ │ │ ├── test18737.d │ │ │ ├── test18771.d │ │ │ ├── test18775.d │ │ │ ├── test1878a.d │ │ │ ├── test18821.d │ │ │ ├── test18871.d │ │ │ ├── test18905.d │ │ │ ├── test18936.d │ │ │ ├── test18951a.d │ │ │ ├── test18951b.d │ │ │ ├── test18976.d │ │ │ ├── test19066.d │ │ │ ├── test19081.d │ │ │ ├── test19107.d │ │ │ ├── test19108.d │ │ │ ├── test19187.d │ │ │ ├── test19201.d │ │ │ ├── test19203.d │ │ │ ├── test19292.d │ │ │ ├── test25.d │ │ │ ├── test2991.d │ │ │ ├── test313a.d │ │ │ ├── test313b.d │ │ │ ├── test313c.d │ │ │ ├── test313d.d │ │ │ ├── test313e.d │ │ │ ├── test313f.d │ │ │ ├── test313g.d │ │ │ ├── test314.d │ │ │ ├── test3673.d │ │ │ ├── test3775.d │ │ │ ├── test4003.d │ │ │ ├── test4090.d │ │ │ ├── test4364.d │ │ │ ├── test4375.d │ │ │ ├── test50.d │ │ │ ├── test5227.d │ │ │ ├── test55.d │ │ │ ├── test59.d │ │ │ ├── test5973.d │ │ │ ├── test6013.d │ │ │ ├── test602.d │ │ │ ├── test6056a.d │ │ │ ├── test6056b.d │ │ │ ├── test6056c.d │ │ │ ├── test6089.d │ │ │ ├── test61.d │ │ │ ├── test62.d │ │ │ ├── test63.d │ │ │ ├── test6319.d │ │ │ ├── test6395.d │ │ │ ├── test6534.d │ │ │ ├── test6552.d │ │ │ ├── test66.d │ │ │ ├── test67.d │ │ │ ├── test68.d │ │ │ ├── test69.d │ │ │ ├── test6999.d │ │ │ ├── test70.d │ │ │ ├── test7065.d │ │ │ ├── test71.d │ │ │ ├── test7172.d │ │ │ ├── test7190.d │ │ │ ├── test72.d │ │ │ ├── test7252.d │ │ │ ├── test7399.d │ │ │ ├── test7491.d │ │ │ ├── test7524.d │ │ │ ├── test7569.d │ │ │ ├── test7754.d │ │ │ ├── test7815.d │ │ │ ├── test7886.d │ │ │ ├── test8038.d │ │ │ ├── test8041.d │ │ │ ├── test8296.d │ │ │ ├── test8509.d │ │ │ ├── test8513.d │ │ │ ├── test8543.d │ │ │ ├── test8631.d │ │ │ ├── test8675.d │ │ │ ├── test8696.d │ │ │ ├── test8717.d │ │ │ ├── test8802.d │ │ │ ├── test8898.d │ │ │ ├── test8922a.d │ │ │ ├── test8922b.d │ │ │ ├── test8922c.d │ │ │ ├── test8922d.d │ │ │ ├── test8922e.d │ │ │ ├── test8922f.d │ │ │ ├── test8937.d │ │ │ ├── test8959.d │ │ │ ├── test9057.d │ │ │ ├── test9209.d │ │ │ ├── test9276.d │ │ │ ├── test9278a.d │ │ │ ├── test9278b.d │ │ │ ├── test9399.d │ │ │ ├── test9434.d │ │ │ ├── test9435.d │ │ │ ├── test9436.d │ │ │ ├── test9526.d │ │ │ ├── test9554.d │ │ │ ├── test9565.d │ │ │ ├── test9570.d │ │ │ ├── test9613.d │ │ │ ├── test9639.d │ │ │ ├── test9672.d │ │ │ ├── test9692.d │ │ │ ├── test9692a.d │ │ │ ├── test9701.d │ │ │ ├── test9766.d │ │ │ ├── test9818.d │ │ │ ├── test9919.d │ │ │ ├── testDIP37.d │ │ │ ├── testDIP37_10302.d │ │ │ ├── testDIP37_10354.d │ │ │ ├── testDIP37_10421.d │ │ │ ├── testDIP37a.d │ │ │ ├── testDIP42.d │ │ │ ├── testInference.d │ │ │ ├── testVRP.d │ │ │ ├── testcheckimports.d │ │ │ ├── testcontracts.d │ │ │ ├── testdip1008.d │ │ │ ├── testexpression.d │ │ │ ├── testfptr.d │ │ │ ├── testfwdref.d │ │ │ ├── testheader1.d │ │ │ ├── testheader12567a.d │ │ │ ├── testheader12567b.d │ │ │ ├── testheader1i.d │ │ │ ├── testheader2.d │ │ │ ├── testheader2i.d │ │ │ ├── testheader3.d │ │ │ ├── testheaderudamodule.d │ │ │ ├── testimport12242.d │ │ │ ├── testlambdacomp.d │ │ │ ├── testparse.d │ │ │ ├── testpostblit.d │ │ │ ├── testprofile.d │ │ │ ├── traits.d │ │ │ ├── uda.d │ │ │ ├── udamodule1.d │ │ │ ├── udamodule2.d │ │ │ ├── verrors_spec.d │ │ │ ├── version.d │ │ │ ├── vgc1.d │ │ │ ├── vgc2.d │ │ │ ├── vgc3.d │ │ │ └── warn3882.d │ │ ├── d_do_test.exp │ │ ├── fail_compilation/ │ │ │ ├── aacmp10381.d │ │ │ ├── b17918.d │ │ │ ├── b3841.d │ │ │ ├── b6227.d │ │ │ ├── betterc.d │ │ │ ├── bug15613.d │ │ │ ├── bug18743.d │ │ │ ├── bug4283.d │ │ │ ├── bug5.d │ │ │ ├── bug5b.d │ │ │ ├── bug8150a.d │ │ │ ├── bug8150b.d │ │ │ ├── bug8891.d │ │ │ ├── bug9631.d │ │ │ ├── ccast.d │ │ │ ├── cerrors.d │ │ │ ├── checkimports1a.d │ │ │ ├── checkimports1b.d │ │ │ ├── checkimports1c.d │ │ │ ├── checkimports2a.d │ │ │ ├── checkimports2b.d │ │ │ ├── checkimports2c.d │ │ │ ├── circ10280.d │ │ │ ├── class1.d │ │ │ ├── class2.d │ │ │ ├── commaexp.d │ │ │ ├── cppeh1.d │ │ │ ├── cppeh2.d │ │ │ ├── cppmangle.d │ │ │ ├── ctfe10989.d │ │ │ ├── ctfe10995.d │ │ │ ├── ctfe11467.d │ │ │ ├── ctfe13612.d │ │ │ ├── ctfe14207.d │ │ │ ├── ctfe14465.d │ │ │ ├── ctfe14731.d │ │ │ ├── ctypes.d │ │ │ ├── cwords.d │ │ │ ├── dephexstrings.d │ │ │ ├── depmsg.d │ │ │ ├── depmsg15814.d │ │ │ ├── depmsg15815.d │ │ │ ├── deprecate12979a.d │ │ │ ├── deprecate12979b.d │ │ │ ├── deprecate12979c.d │ │ │ ├── deprecate12979d.d │ │ │ ├── deprecate1553.d │ │ │ ├── deprecated6760.d │ │ │ ├── deprecateopdot.d │ │ │ ├── diag10089.d │ │ │ ├── diag10099.d │ │ │ ├── diag10141.d │ │ │ ├── diag10169.d │ │ │ ├── diag10221.d │ │ │ ├── diag10221a.d │ │ │ ├── diag10319.d │ │ │ ├── diag10327.d │ │ │ ├── diag10359.d │ │ │ ├── diag10405.d │ │ │ ├── diag10415.d │ │ │ ├── diag10688.d │ │ │ ├── diag10768.d │ │ │ ├── diag10783.d │ │ │ ├── diag10792.d │ │ │ ├── diag10805.d │ │ │ ├── diag10862.d │ │ │ ├── diag10926.d │ │ │ ├── diag10984.d │ │ │ ├── diag11078.d │ │ │ ├── diag11132.d │ │ │ ├── diag11198.d │ │ │ ├── diag11423.d │ │ │ ├── diag11425.d │ │ │ ├── diag11727.d │ │ │ ├── diag11756.d │ │ │ ├── diag11759.d │ │ │ ├── diag11769.d │ │ │ ├── diag11819a.d │ │ │ ├── diag11819b.d │ │ │ ├── diag11840.d │ │ │ ├── diag12063.d │ │ │ ├── diag12124.d │ │ │ ├── diag12280.d │ │ │ ├── diag12312.d │ │ │ ├── diag12380.d │ │ │ ├── diag12432.d │ │ │ ├── diag12480.d │ │ │ ├── diag12487.d │ │ │ ├── diag12598.d │ │ │ ├── diag12640.d │ │ │ ├── diag12678.d │ │ │ ├── diag12777.d │ │ │ ├── diag12829.d │ │ │ ├── diag13028.d │ │ │ ├── diag13082.d │ │ │ ├── diag13142.d │ │ │ ├── diag13281.d │ │ │ ├── diag13320.d │ │ │ ├── diag13333.d │ │ │ ├── diag13528.d │ │ │ ├── diag13609a.d │ │ │ ├── diag13609b.d │ │ │ ├── diag13787.d │ │ │ ├── diag13884.d │ │ │ ├── diag13942.d │ │ │ ├── diag14102.d │ │ │ ├── diag14163.d │ │ │ ├── diag14235.d │ │ │ ├── diag14818.d │ │ │ ├── diag14875.d │ │ │ ├── diag14876.d │ │ │ ├── diag15001.d │ │ │ ├── diag15186.d │ │ │ ├── diag15209.d │ │ │ ├── diag15340.d │ │ │ ├── diag15411.d │ │ │ ├── diag1566.d │ │ │ ├── diag15669.d │ │ │ ├── diag15713.d │ │ │ ├── diag15974.d │ │ │ ├── diag16499.d │ │ │ ├── diag16977.d │ │ │ ├── diag1730.d │ │ │ ├── diag18460.d │ │ │ ├── diag18574.d │ │ │ ├── diag19022.d │ │ │ ├── diag19196.d │ │ │ ├── diag19225.d │ │ │ ├── diag2452.d │ │ │ ├── diag3013.d │ │ │ ├── diag3438.d │ │ │ ├── diag3438b.d │ │ │ ├── diag3672.d │ │ │ ├── diag3672a.d │ │ │ ├── diag3673.d │ │ │ ├── diag3869.d │ │ │ ├── diag3913.d │ │ │ ├── diag4479.d │ │ │ ├── diag4528.d │ │ │ ├── diag4540.d │ │ │ ├── diag4596.d │ │ │ ├── diag5385.d │ │ │ ├── diag5450.d │ │ │ ├── diag6373.d │ │ │ ├── diag6539.d │ │ │ ├── diag6677.d │ │ │ ├── diag6699.d │ │ │ ├── diag6707.d │ │ │ ├── diag6717.d │ │ │ ├── diag6796.d │ │ │ ├── diag7050a.d │ │ │ ├── diag7050b.d │ │ │ ├── diag7050c.d │ │ │ ├── diag7420.d │ │ │ ├── diag7477.d │ │ │ ├── diag7747.d │ │ │ ├── diag7998.d │ │ │ ├── diag8101.d │ │ │ ├── diag8101b.d │ │ │ ├── diag8178.d │ │ │ ├── diag8318.d │ │ │ ├── diag8425.d │ │ │ ├── diag8510.d │ │ │ ├── diag8559.d │ │ │ ├── diag8648.d │ │ │ ├── diag8697.d │ │ │ ├── diag8714.d │ │ │ ├── diag8777.d │ │ │ ├── diag8787.d │ │ │ ├── diag8825.d │ │ │ ├── diag8892.d │ │ │ ├── diag8894.d │ │ │ ├── diag8928.d │ │ │ ├── diag9004.d │ │ │ ├── diag9148.d │ │ │ ├── diag9191.d │ │ │ ├── diag9210a.d │ │ │ ├── diag9247.d │ │ │ ├── diag9250.d │ │ │ ├── diag9312.d │ │ │ ├── diag9357.d │ │ │ ├── diag9358.d │ │ │ ├── diag9398.d │ │ │ ├── diag9420.d │ │ │ ├── diag9451.d │ │ │ ├── diag9479.d │ │ │ ├── diag9574.d │ │ │ ├── diag9620.d │ │ │ ├── diag9635.d │ │ │ ├── diag9679.d │ │ │ ├── diag9765.d │ │ │ ├── diag9831.d │ │ │ ├── diag9861.d │ │ │ ├── diag9880.d │ │ │ ├── diag9961.d │ │ │ ├── diag_cstyle.d │ │ │ ├── diag_err1.d │ │ │ ├── dip22a.d │ │ │ ├── dip22b.d │ │ │ ├── dip22d.d │ │ │ ├── dip22e.d │ │ │ ├── disable.d │ │ │ ├── disable_new.d │ │ │ ├── enum9921.d │ │ │ ├── extra-files/ │ │ │ │ ├── a14446.d │ │ │ │ ├── bar11453.d │ │ │ │ ├── foo11453.d │ │ │ │ ├── minimal/ │ │ │ │ │ └── object.d │ │ │ │ ├── no_Throwable/ │ │ │ │ │ └── object.d │ │ │ │ └── no_TypeInfo/ │ │ │ │ └── object.d │ │ │ ├── fail10.d │ │ │ ├── fail100.d │ │ │ ├── fail10082.d │ │ │ ├── fail101.d │ │ │ ├── fail10102.d │ │ │ ├── fail10115.d │ │ │ ├── fail10207.d │ │ │ ├── fail10254.d │ │ │ ├── fail10277.d │ │ │ ├── fail10285.d │ │ │ ├── fail10299.d │ │ │ ├── fail10346.d │ │ │ ├── fail104.d │ │ │ ├── fail10481.d │ │ │ ├── fail105.d │ │ │ ├── fail10528.d │ │ │ ├── fail10534.d │ │ │ ├── fail106.d │ │ │ ├── fail10630.d │ │ │ ├── fail10666.d │ │ │ ├── fail109.d │ │ │ ├── fail10905.d │ │ │ ├── fail10947.d │ │ │ ├── fail10964.d │ │ │ ├── fail10968.d │ │ │ ├── fail10980.d │ │ │ ├── fail11.d │ │ │ ├── fail110.d │ │ │ ├── fail11042.d │ │ │ ├── fail111.d │ │ │ ├── fail11125.d │ │ │ ├── fail11151.d │ │ │ ├── fail11163.d │ │ │ ├── fail113.d │ │ │ ├── fail11355.d │ │ │ ├── fail11375.d │ │ │ ├── fail114.d │ │ │ ├── fail11426.d │ │ │ ├── fail11445.d │ │ │ ├── fail11453a.d │ │ │ ├── fail11453b.d │ │ │ ├── fail115.d │ │ │ ├── fail11503a.d │ │ │ ├── fail11503b.d │ │ │ ├── fail11503c.d │ │ │ ├── fail11503d.d │ │ │ ├── fail11510.d │ │ │ ├── fail11532.d │ │ │ ├── fail11542.d │ │ │ ├── fail11545.d │ │ │ ├── fail11552.d │ │ │ ├── fail11562.d │ │ │ ├── fail11591b.d │ │ │ ├── fail116.d │ │ │ ├── fail11653.d │ │ │ ├── fail117.d │ │ │ ├── fail11714.d │ │ │ ├── fail11717.d │ │ │ ├── fail11720.d │ │ │ ├── fail11746.d │ │ │ ├── fail11748.d │ │ │ ├── fail11751.d │ │ │ ├── fail118.d │ │ │ ├── fail12.d │ │ │ ├── fail120.d │ │ │ ├── fail12047.d │ │ │ ├── fail121.d │ │ │ ├── fail122.d │ │ │ ├── fail12236.d │ │ │ ├── fail12255.d │ │ │ ├── fail123.d │ │ │ ├── fail12378.d │ │ │ ├── fail12390.d │ │ │ ├── fail124.d │ │ │ ├── fail12436.d │ │ │ ├── fail12485.d │ │ │ ├── fail125.d │ │ │ ├── fail12567.d │ │ │ ├── fail126.d │ │ │ ├── fail12604.d │ │ │ ├── fail12622.d │ │ │ ├── fail12636.d │ │ │ ├── fail127.d │ │ │ ├── fail12744.d │ │ │ ├── fail12749.d │ │ │ ├── fail12764.d │ │ │ ├── fail12809.d │ │ │ ├── fail129.d │ │ │ ├── fail12901.d │ │ │ ├── fail12908.d │ │ │ ├── fail12932.d │ │ │ ├── fail13064.d │ │ │ ├── fail131.d │ │ │ ├── fail13116.d │ │ │ ├── fail13120.d │ │ │ ├── fail13187.d │ │ │ ├── fail132.d │ │ │ ├── fail13203.d │ │ │ ├── fail133.d │ │ │ ├── fail13336a.d │ │ │ ├── fail13336b.d │ │ │ ├── fail134.d │ │ │ ├── fail13424.d │ │ │ ├── fail13434_m32.d │ │ │ ├── fail13434_m64.d │ │ │ ├── fail13435.d │ │ │ ├── fail13498.d │ │ │ ├── fail13574.d │ │ │ ├── fail136.d │ │ │ ├── fail13601.d │ │ │ ├── fail137.d │ │ │ ├── fail13701.d │ │ │ ├── fail13756.d │ │ │ ├── fail13775.d │ │ │ ├── fail139.d │ │ │ ├── fail13902.d │ │ │ ├── fail14.d │ │ │ ├── fail14009.d │ │ │ ├── fail14089.d │ │ │ ├── fail142.d │ │ │ ├── fail14249.d │ │ │ ├── fail143.d │ │ │ ├── fail14304.d │ │ │ ├── fail144.d │ │ │ ├── fail14406.d │ │ │ ├── fail14407.d │ │ │ ├── fail14416.d │ │ │ ├── fail14486.d │ │ │ ├── fail145.d │ │ │ ├── fail14554.d │ │ │ ├── fail14669.d │ │ │ ├── fail14965.d │ │ │ ├── fail14997.d │ │ │ ├── fail15.d │ │ │ ├── fail150.d │ │ │ ├── fail15044.d │ │ │ ├── fail15068.d │ │ │ ├── fail15089.d │ │ │ ├── fail152.d │ │ │ ├── fail15292.d │ │ │ ├── fail153.d │ │ │ ├── fail154.d │ │ │ ├── fail155.d │ │ │ ├── fail15535.d │ │ │ ├── fail15550.d │ │ │ ├── fail156.d │ │ │ ├── fail15616a.d │ │ │ ├── fail15616b.d │ │ │ ├── fail15626.d │ │ │ ├── fail15667.d │ │ │ ├── fail15691.d │ │ │ ├── fail15755.d │ │ │ ├── fail158.d │ │ │ ├── fail15896.d │ │ │ ├── fail159.d │ │ │ ├── fail16.d │ │ │ ├── fail160.d │ │ │ ├── fail161.d │ │ │ ├── fail162.d │ │ │ ├── fail16206a.d │ │ │ ├── fail16206b.d │ │ │ ├── fail163.d │ │ │ ├── fail16600.d │ │ │ ├── fail169.d │ │ │ ├── fail16997.d │ │ │ ├── fail17.d │ │ │ ├── fail170.d │ │ │ ├── fail172.d │ │ │ ├── fail17275.d │ │ │ ├── fail17354.d │ │ │ ├── fail17382.d │ │ │ ├── fail17419.d │ │ │ ├── fail17421.d │ │ │ ├── fail17491.d │ │ │ ├── fail17492.d │ │ │ ├── fail17502.d │ │ │ ├── fail17570.d │ │ │ ├── fail176.d │ │ │ ├── fail17602.d │ │ │ ├── fail17612.d │ │ │ ├── fail17625.d │ │ │ ├── fail17630.d │ │ │ ├── fail17646.d │ │ │ ├── fail17689.d │ │ │ ├── fail177.d │ │ │ ├── fail17722a.d │ │ │ ├── fail17722b.d │ │ │ ├── fail17842.d │ │ │ ├── fail179.d │ │ │ ├── fail17927.d │ │ │ ├── fail17955.d │ │ │ ├── fail17969.d │ │ │ ├── fail17976.d │ │ │ ├── fail18.d │ │ │ ├── fail180.d │ │ │ ├── fail18057.d │ │ │ ├── fail18093.d │ │ │ ├── fail18143.d │ │ │ ├── fail18219.d │ │ │ ├── fail18228.d │ │ │ ├── fail18236.d │ │ │ ├── fail18243.d │ │ │ ├── fail18266.d │ │ │ ├── fail183.d │ │ │ ├── fail184.d │ │ │ ├── fail18417.d │ │ │ ├── fail185.d │ │ │ ├── fail18620.d │ │ │ ├── fail187.d │ │ │ ├── fail18719.d │ │ │ ├── fail188.d │ │ │ ├── fail18892.d │ │ │ ├── fail189.d │ │ │ ├── fail18970.d │ │ │ ├── fail18985.d │ │ │ ├── fail18994.d │ │ │ ├── fail190.d │ │ │ ├── fail1900.d │ │ │ ├── fail19038.d │ │ │ ├── fail19076.d │ │ │ ├── fail19098.d │ │ │ ├── fail19181.d │ │ │ ├── fail19182.d │ │ │ ├── fail192.d │ │ │ ├── fail19209.d │ │ │ ├── fail193.d │ │ │ ├── fail19319a.d │ │ │ ├── fail19319b.d │ │ │ ├── fail194.d │ │ │ ├── fail195.d │ │ │ ├── fail196.d │ │ │ ├── fail198.d │ │ │ ├── fail199.d │ │ │ ├── fail20.d │ │ │ ├── fail200.d │ │ │ ├── fail201.d │ │ │ ├── fail202.d │ │ │ ├── fail203.d │ │ │ ├── fail204.d │ │ │ ├── fail205.d │ │ │ ├── fail206.d │ │ │ ├── fail207.d │ │ │ ├── fail208.d │ │ │ ├── fail209.d │ │ │ ├── fail212.d │ │ │ ├── fail213.d │ │ │ ├── fail215.d │ │ │ ├── fail216.d │ │ │ ├── fail217.d │ │ │ ├── fail218.d │ │ │ ├── fail22.d │ │ │ ├── fail220.d │ │ │ ├── fail221.d │ │ │ ├── fail222.d │ │ │ ├── fail223.d │ │ │ ├── fail224.d │ │ │ ├── fail225.d │ │ │ ├── fail228.d │ │ │ ├── fail229.d │ │ │ ├── fail23.d │ │ │ ├── fail231.d │ │ │ ├── fail232.d │ │ │ ├── fail233.d │ │ │ ├── fail235.d │ │ │ ├── fail236.d │ │ │ ├── fail2361.d │ │ │ ├── fail237.d │ │ │ ├── fail238_m32.d │ │ │ ├── fail238_m64.d │ │ │ ├── fail239.d │ │ │ ├── fail24.d │ │ │ ├── fail240.d │ │ │ ├── fail241.d │ │ │ ├── fail243.d │ │ │ ├── fail244.d │ │ │ ├── fail245.d │ │ │ ├── fail2456.d │ │ │ ├── fail246.d │ │ │ ├── fail247.d │ │ │ ├── fail248.d │ │ │ ├── fail249.d │ │ │ ├── fail25.d │ │ │ ├── fail250.d │ │ │ ├── fail251.d │ │ │ ├── fail252.d │ │ │ ├── fail253.d │ │ │ ├── fail254.d │ │ │ ├── fail256.d │ │ │ ├── fail257.d │ │ │ ├── fail258.d │ │ │ ├── fail259.d │ │ │ ├── fail261.d │ │ │ ├── fail262.d │ │ │ ├── fail263.d │ │ │ ├── fail264.d │ │ │ ├── fail265.d │ │ │ ├── fail2656.d │ │ │ ├── fail267.d │ │ │ ├── fail27.d │ │ │ ├── fail270.d │ │ │ ├── fail272.d │ │ │ ├── fail273.d │ │ │ ├── fail274.d │ │ │ ├── fail2740.d │ │ │ ├── fail275.d │ │ │ ├── fail276.d │ │ │ ├── fail278.d │ │ │ ├── fail2789.d │ │ │ ├── fail279.d │ │ │ ├── fail280.d │ │ │ ├── fail281.d │ │ │ ├── fail282.d │ │ │ ├── fail284.d │ │ │ ├── fail285.d │ │ │ ├── fail287.d │ │ │ ├── fail288.d │ │ │ ├── fail289.d │ │ │ ├── fail290.d │ │ │ ├── fail291.d │ │ │ ├── fail296.d │ │ │ ├── fail2962.d │ │ │ ├── fail297.d │ │ │ ├── fail298.d │ │ │ ├── fail299.d │ │ │ ├── fail3.d │ │ │ ├── fail301.d │ │ │ ├── fail302.d │ │ │ ├── fail303.d │ │ │ ├── fail304.d │ │ │ ├── fail305.d │ │ │ ├── fail306.d │ │ │ ├── fail307.d │ │ │ ├── fail308.d │ │ │ ├── fail309.d │ │ │ ├── fail310.d │ │ │ ├── fail311.d │ │ │ ├── fail312.d │ │ │ ├── fail313.d │ │ │ ├── fail314.d │ │ │ ├── fail3144.d │ │ │ ├── fail315.d │ │ │ ├── fail3150.d │ │ │ ├── fail316.d │ │ │ ├── fail317.d │ │ │ ├── fail318.d │ │ │ ├── fail319.d │ │ │ ├── fail320.d │ │ │ ├── fail322.d │ │ │ ├── fail324.d │ │ │ ├── fail325.d │ │ │ ├── fail327.d │ │ │ ├── fail328.d │ │ │ ├── fail329.d │ │ │ ├── fail3290.d │ │ │ ├── fail330.d │ │ │ ├── fail331.d │ │ │ ├── fail332.d │ │ │ ├── fail333.d │ │ │ ├── fail334.d │ │ │ ├── fail335.d │ │ │ ├── fail336.d │ │ │ ├── fail337.d │ │ │ ├── fail34.d │ │ │ ├── fail340.d │ │ │ ├── fail341.d │ │ │ ├── fail343.d │ │ │ ├── fail344.d │ │ │ ├── fail346.d │ │ │ ├── fail347.d │ │ │ ├── fail349.d │ │ │ ├── fail35.d │ │ │ ├── fail351.d │ │ │ ├── fail352.d │ │ │ ├── fail354.d │ │ │ ├── fail355.d │ │ │ ├── fail356a.d │ │ │ ├── fail356b.d │ │ │ ├── fail356c.d │ │ │ ├── fail3581a.d │ │ │ ├── fail3581b.d │ │ │ ├── fail359.d │ │ │ ├── fail36.d │ │ │ ├── fail3672.d │ │ │ ├── fail3673a.d │ │ │ ├── fail3673b.d │ │ │ ├── fail3703.d │ │ │ ├── fail3731.d │ │ │ ├── fail3753.d │ │ │ ├── fail37_m32.d │ │ │ ├── fail37_m64.d │ │ │ ├── fail38.d │ │ │ ├── fail3882.d │ │ │ ├── fail3895.d │ │ │ ├── fail39.d │ │ │ ├── fail3990.d │ │ │ ├── fail40.d │ │ │ ├── fail4082.d │ │ │ ├── fail41.d │ │ │ ├── fail42.d │ │ │ ├── fail4206.d │ │ │ ├── fail4269a.d │ │ │ ├── fail4269b.d │ │ │ ├── fail4269c.d │ │ │ ├── fail4269d.d │ │ │ ├── fail4269e.d │ │ │ ├── fail4269f.d │ │ │ ├── fail4269g.d │ │ │ ├── fail4374.d │ │ │ ├── fail4375a.d │ │ │ ├── fail4375b.d │ │ │ ├── fail4375c.d │ │ │ ├── fail4375d.d │ │ │ ├── fail4375e.d │ │ │ ├── fail4375f.d │ │ │ ├── fail4375g.d │ │ │ ├── fail4375h.d │ │ │ ├── fail4375i.d │ │ │ ├── fail4375j.d │ │ │ ├── fail4375k.d │ │ │ ├── fail4375l.d │ │ │ ├── fail4375m.d │ │ │ ├── fail4375o.d │ │ │ ├── fail4375p.d │ │ │ ├── fail4375q.d │ │ │ ├── fail4375r.d │ │ │ ├── fail4375s.d │ │ │ ├── fail4375t.d │ │ │ ├── fail4375u.d │ │ │ ├── fail4375v.d │ │ │ ├── fail4375w.d │ │ │ ├── fail4375x.d │ │ │ ├── fail4375y.d │ │ │ ├── fail44.d │ │ │ ├── fail4421.d │ │ │ ├── fail4448.d │ │ │ ├── fail45.d │ │ │ ├── fail4510.d │ │ │ ├── fail4511.d │ │ │ ├── fail4517.d │ │ │ ├── fail4559.d │ │ │ ├── fail46.d │ │ │ ├── fail4611.d │ │ │ ├── fail47.d │ │ │ ├── fail4958.d │ │ │ ├── fail50.d │ │ │ ├── fail51.d │ │ │ ├── fail5153.d │ │ │ ├── fail52.d │ │ │ ├── fail53.d │ │ │ ├── fail54.d │ │ │ ├── fail5435.d │ │ │ ├── fail55.d │ │ │ ├── fail56.d │ │ │ ├── fail5634.d │ │ │ ├── fail57.d │ │ │ ├── fail5733.d │ │ │ ├── fail58.d │ │ │ ├── fail5851.d │ │ │ ├── fail59.d │ │ │ ├── fail5953a1.d │ │ │ ├── fail5953a2.d │ │ │ ├── fail5953s1.d │ │ │ ├── fail5953s2.d │ │ │ ├── fail60.d │ │ │ ├── fail6029.d │ │ │ ├── fail61.d │ │ │ ├── fail6107.d │ │ │ ├── fail62.d │ │ │ ├── fail6242.d │ │ │ ├── fail63.d │ │ │ ├── fail6334.d │ │ │ ├── fail6451.d │ │ │ ├── fail6453.d │ │ │ ├── fail6458.d │ │ │ ├── fail6497.d │ │ │ ├── fail6561.d │ │ │ ├── fail66.d │ │ │ ├── fail6611.d │ │ │ ├── fail6652.d │ │ │ ├── fail6781.d │ │ │ ├── fail6795.d │ │ │ ├── fail6889.d │ │ │ ├── fail6968.d │ │ │ ├── fail7077.d │ │ │ ├── fail7173.d │ │ │ ├── fail7178.d │ │ │ ├── fail72.d │ │ │ ├── fail7234.d │ │ │ ├── fail73.d │ │ │ ├── fail7369.d │ │ │ ├── fail74.d │ │ │ ├── fail7424b.d │ │ │ ├── fail7424c.d │ │ │ ├── fail7424d.d │ │ │ ├── fail7424e.d │ │ │ ├── fail7424f.d │ │ │ ├── fail7424g.d │ │ │ ├── fail7424h.d │ │ │ ├── fail7424i.d │ │ │ ├── fail7443.d │ │ │ ├── fail75.d │ │ │ ├── fail7524a.d │ │ │ ├── fail7524b.d │ │ │ ├── fail76.d │ │ │ ├── fail7603a.d │ │ │ ├── fail7603b.d │ │ │ ├── fail7603c.d │ │ │ ├── fail77.d │ │ │ ├── fail7702.d │ │ │ ├── fail7751.d │ │ │ ├── fail78.d │ │ │ ├── fail7848.d │ │ │ ├── fail7851.d │ │ │ ├── fail7859.d │ │ │ ├── fail7861.d │ │ │ ├── fail7862.d │ │ │ ├── fail79.d │ │ │ ├── fail7903.d │ │ │ ├── fail8009.d │ │ │ ├── fail8032.d │ │ │ ├── fail80_m32.d │ │ │ ├── fail80_m64.d │ │ │ ├── fail8168.d │ │ │ ├── fail8179b.d │ │ │ ├── fail8217.d │ │ │ ├── fail8262.d │ │ │ ├── fail8313.d │ │ │ ├── fail8373.d │ │ │ ├── fail86.d │ │ │ ├── fail8631.d │ │ │ ├── fail8691.d │ │ │ ├── fail8724.d │ │ │ ├── fail9.d │ │ │ ├── fail9063.d │ │ │ ├── fail9081.d │ │ │ ├── fail91.d │ │ │ ├── fail9199.d │ │ │ ├── fail92.d │ │ │ ├── fail9279.d │ │ │ ├── fail9290.d │ │ │ ├── fail93.d │ │ │ ├── fail9301.d │ │ │ ├── fail9346.d │ │ │ ├── fail9368.d │ │ │ ├── fail94.d │ │ │ ├── fail9413.d │ │ │ ├── fail9414a.d │ │ │ ├── fail9414b.d │ │ │ ├── fail9414c.d │ │ │ ├── fail9414d.d │ │ │ ├── fail95.d │ │ │ ├── fail9537.d │ │ │ ├── fail9562.d │ │ │ ├── fail9572.d │ │ │ ├── fail96.d │ │ │ ├── fail9613.d │ │ │ ├── fail9665a.d │ │ │ ├── fail9665b.d │ │ │ ├── fail97.d │ │ │ ├── fail9710.d │ │ │ ├── fail9735.d │ │ │ ├── fail9766.d │ │ │ ├── fail9773.d │ │ │ ├── fail9790.d │ │ │ ├── fail98.d │ │ │ ├── fail9891.d │ │ │ ├── fail9892.d │ │ │ ├── fail99.d │ │ │ ├── fail9936.d │ │ │ ├── fail_arrayop1.d │ │ │ ├── fail_arrayop2.d │ │ │ ├── fail_arrayop3a.d │ │ │ ├── fail_arrayop3b.d │ │ │ ├── fail_arrayop3c.d │ │ │ ├── fail_casting.d │ │ │ ├── fail_casting1.d │ │ │ ├── fail_casting2.d │ │ │ ├── fail_circular.d │ │ │ ├── fail_circular2.d │ │ │ ├── fail_contracts1.d │ │ │ ├── fail_contracts2.d │ │ │ ├── fail_contracts3.d │ │ │ ├── fail_contracts4.d │ │ │ ├── fail_isZeroInit.d │ │ │ ├── fail_opover.d │ │ │ ├── fail_scope.d │ │ │ ├── failattr.d │ │ │ ├── failcontracts.d │ │ │ ├── faildeleteaa.d │ │ │ ├── faildottypeinfo.d │ │ │ ├── failescape.d │ │ │ ├── failinout1.d │ │ │ ├── failinout2.d │ │ │ ├── failinout3748a.d │ │ │ ├── failinout3748b.d │ │ │ ├── failmemalloc.d │ │ │ ├── failoffset.d │ │ │ ├── failsafea.d │ │ │ ├── failsafeb.d │ │ │ ├── failsafec.d │ │ │ ├── fix17635.d │ │ │ ├── fix17751.d │ │ │ ├── fix18575.d │ │ │ ├── fix19018.d │ │ │ ├── fix19059.d │ │ │ ├── fix350a.d │ │ │ ├── fix350b.d │ │ │ ├── fix5212.d │ │ │ ├── gag4269a.d │ │ │ ├── gag4269b.d │ │ │ ├── gag4269c.d │ │ │ ├── gag4269d.d │ │ │ ├── gag4269e.d │ │ │ ├── gag4269f.d │ │ │ ├── gag4269g.d │ │ │ ├── ice10016.d │ │ │ ├── ice10076.d │ │ │ ├── ice10212.d │ │ │ ├── ice10259.d │ │ │ ├── ice10273.d │ │ │ ├── ice10283.d │ │ │ ├── ice10341.d │ │ │ ├── ice10382.d │ │ │ ├── ice10419.d │ │ │ ├── ice10599.d │ │ │ ├── ice10600.d │ │ │ ├── ice10616.d │ │ │ ├── ice10624.d │ │ │ ├── ice10651.d │ │ │ ├── ice10713.d │ │ │ ├── ice10727a.d │ │ │ ├── ice10727b.d │ │ │ ├── ice10770.d │ │ │ ├── ice10922.d │ │ │ ├── ice10938.d │ │ │ ├── ice10949.d │ │ │ ├── ice11086.d │ │ │ ├── ice11136.d │ │ │ ├── ice11153.d │ │ │ ├── ice11404.d │ │ │ ├── ice1144.d │ │ │ ├── ice11472.d │ │ │ ├── ice11513a.d │ │ │ ├── ice11513b.d │ │ │ ├── ice11518.d │ │ │ ├── ice11552.d │ │ │ ├── ice11553.d │ │ │ ├── ice11626.d │ │ │ ├── ice11726.d │ │ │ ├── ice11790.d │ │ │ ├── ice11793.d │ │ │ ├── ice11822.d │ │ │ ├── ice11849b.d │ │ │ ├── ice11850.d │ │ │ ├── ice11919.d │ │ │ ├── ice11922.d │ │ │ ├── ice11926.d │ │ │ ├── ice11944.d │ │ │ ├── ice11963.d │ │ │ ├── ice11965.d │ │ │ ├── ice11967.d │ │ │ ├── ice11968.d │ │ │ ├── ice11969.d │ │ │ ├── ice11974.d │ │ │ ├── ice11982.d │ │ │ ├── ice12040.d │ │ │ ├── ice12158.d │ │ │ ├── ice12174.d │ │ │ ├── ice12235.d │ │ │ ├── ice12350.d │ │ │ ├── ice12362.d │ │ │ ├── ice12397.d │ │ │ ├── ice12501.d │ │ │ ├── ice12534.d │ │ │ ├── ice12539.d │ │ │ ├── ice12574.d │ │ │ ├── ice12581.d │ │ │ ├── ice12673.d │ │ │ ├── ice12727.d │ │ │ ├── ice12827.d │ │ │ ├── ice12836.d │ │ │ ├── ice12838.d │ │ │ ├── ice12841.d │ │ │ ├── ice12850.d │ │ │ ├── ice12902.d │ │ │ ├── ice12907.d │ │ │ ├── ice13024.d │ │ │ ├── ice13027.d │ │ │ ├── ice13081.d │ │ │ ├── ice13131.d │ │ │ ├── ice13220.d │ │ │ ├── ice13221.d │ │ │ ├── ice13225.d │ │ │ ├── ice13311.d │ │ │ ├── ice13356.d │ │ │ ├── ice13382.d │ │ │ ├── ice13385.d │ │ │ ├── ice13459.d │ │ │ ├── ice13465a.d │ │ │ ├── ice13465b.d │ │ │ ├── ice13563.d │ │ │ ├── ice1358.d │ │ │ ├── ice13644.d │ │ │ ├── ice13788.d │ │ │ ├── ice13816.d │ │ │ ├── ice13835.d │ │ │ ├── ice13921.d │ │ │ ├── ice13987.d │ │ │ ├── ice14055.d │ │ │ ├── ice14096.d │ │ │ ├── ice14116.d │ │ │ ├── ice14130.d │ │ │ ├── ice14146.d │ │ │ ├── ice14177.d │ │ │ ├── ice14185.d │ │ │ ├── ice14272.d │ │ │ ├── ice14424.d │ │ │ ├── ice14446.d │ │ │ ├── ice14621.d │ │ │ ├── ice14642.d │ │ │ ├── ice14844.d │ │ │ ├── ice14907.d │ │ │ ├── ice14923.d │ │ │ ├── ice14929.d │ │ │ ├── ice15002.d │ │ │ ├── ice15092.d │ │ │ ├── ice15127.d │ │ │ ├── ice15172.d │ │ │ ├── ice15239.d │ │ │ ├── ice15317.d │ │ │ ├── ice15332.d │ │ │ ├── ice15441.d │ │ │ ├── ice15688.d │ │ │ ├── ice15788.d │ │ │ ├── ice15816.d │ │ │ ├── ice15855.d │ │ │ ├── ice15922.d │ │ │ ├── ice16035.d │ │ │ ├── ice17074.d │ │ │ ├── ice17690.d │ │ │ ├── ice17831.d │ │ │ ├── ice18469.d │ │ │ ├── ice18753.d │ │ │ ├── ice18803a.d │ │ │ ├── ice18803b.d │ │ │ ├── ice2843.d │ │ │ ├── ice4094.d │ │ │ ├── ice4983.d │ │ │ ├── ice5996.d │ │ │ ├── ice6538.d │ │ │ ├── ice7645.d │ │ │ ├── ice7782.d │ │ │ ├── ice8100.d │ │ │ ├── ice8255.d │ │ │ ├── ice8309.d │ │ │ ├── ice8499.d │ │ │ ├── ice8511.d │ │ │ ├── ice8604.d │ │ │ ├── ice8630.d │ │ │ ├── ice8711.d │ │ │ ├── ice8742.d │ │ │ ├── ice8795.d │ │ │ ├── ice8795b.d │ │ │ ├── ice9013.d │ │ │ ├── ice9254a.d │ │ │ ├── ice9254b.d │ │ │ ├── ice9254c.d │ │ │ ├── ice9273a.d │ │ │ ├── ice9273b.d │ │ │ ├── ice9284.d │ │ │ ├── ice9291.d │ │ │ ├── ice9338.d │ │ │ ├── ice9406.d │ │ │ ├── ice9439.d │ │ │ ├── ice9494.d │ │ │ ├── ice9540.d │ │ │ ├── ice9545.d │ │ │ ├── ice9759.d │ │ │ ├── ice9806.d │ │ │ ├── ice9865.d │ │ │ ├── impconv.d │ │ │ ├── imphint.d │ │ │ ├── imports/ │ │ │ │ ├── a10169.d │ │ │ │ ├── a10528.d │ │ │ │ ├── a11850.d │ │ │ │ ├── a11919.d │ │ │ │ ├── a13131checkpoint.d │ │ │ │ ├── a13131elec.d │ │ │ │ ├── a13131parameters.d │ │ │ │ ├── a13311.d │ │ │ │ ├── a13465.d │ │ │ │ ├── a14116.d │ │ │ │ ├── a14235.d │ │ │ │ ├── a14407.d │ │ │ │ ├── a14424.d │ │ │ │ ├── a15667.d │ │ │ │ ├── a15816.d │ │ │ │ ├── a17625.d │ │ │ │ ├── a17630.d │ │ │ │ ├── a18219.d │ │ │ │ ├── a18243.d │ │ │ │ ├── a313.d │ │ │ │ ├── a314.d │ │ │ │ ├── b13465.d │ │ │ │ ├── b17625.d │ │ │ │ ├── b17630.d │ │ │ │ ├── b17918a.d │ │ │ │ ├── b18219.d │ │ │ │ ├── b313.d │ │ │ │ ├── b314.d │ │ │ │ ├── bar11136.d │ │ │ │ ├── c314.d │ │ │ │ ├── diag10089a.d │ │ │ │ ├── diag10089b.d │ │ │ │ ├── diag10141a.d │ │ │ │ ├── diag10141b.d │ │ │ │ ├── diag12598a.d │ │ │ │ ├── diag9210b.d │ │ │ │ ├── diag9210c.d │ │ │ │ ├── diag9210stdcomplex.d │ │ │ │ ├── diag9210stdtraits.d │ │ │ │ ├── dip22a.d │ │ │ │ ├── dip22b.d │ │ │ │ ├── dip22c.d │ │ │ │ ├── dip22d.d │ │ │ │ ├── dip22e.d │ │ │ │ ├── fail10277.d │ │ │ │ ├── fail17646.d │ │ │ │ ├── fail1900a.d │ │ │ │ ├── fail1900b.d │ │ │ │ ├── fail2962a.d │ │ │ │ ├── fail320a.d │ │ │ │ ├── fail320b.d │ │ │ │ ├── fail347a.d │ │ │ │ ├── fail355.d │ │ │ │ ├── fail356.d │ │ │ │ ├── fail4479.d │ │ │ │ ├── fail5385.d │ │ │ │ ├── foo10727a.d │ │ │ │ ├── foo10727b.d │ │ │ │ ├── ice10600a.d │ │ │ │ ├── ice10600b.d │ │ │ │ ├── ice11513x.d │ │ │ │ ├── ice11513y.d │ │ │ │ ├── ice7782algorithm.d │ │ │ │ ├── ice7782range.d │ │ │ │ ├── ice9865b.d │ │ │ │ ├── imp1.d │ │ │ │ ├── imp15896.d │ │ │ │ ├── imp17602.d │ │ │ │ ├── imp18554.d │ │ │ │ ├── imp2.d │ │ │ │ ├── pkg313/ │ │ │ │ │ └── package.d │ │ │ │ ├── range15788.d │ │ │ │ ├── spell9644a.d │ │ │ │ ├── spell9644b.d │ │ │ │ ├── stdtraits10727.d │ │ │ │ ├── test10327/ │ │ │ │ │ └── empty.d │ │ │ │ ├── test13152a.d │ │ │ │ ├── test13152b.d │ │ │ │ ├── test13152c.d │ │ │ │ ├── test13152d.d │ │ │ │ ├── test13152e.d │ │ │ │ ├── test13152f.d │ │ │ │ ├── test13152g.d │ │ │ │ ├── test13152h.d │ │ │ │ ├── test13152i.d │ │ │ │ ├── test13152j.d │ │ │ │ ├── test13152k.d │ │ │ │ ├── test13152l.d │ │ │ │ ├── test13152m.d │ │ │ │ ├── test13152n.d │ │ │ │ ├── test13152o.d │ │ │ │ ├── test13152p.d │ │ │ │ ├── test13152q.d │ │ │ │ ├── test13152r.d │ │ │ │ ├── test13152s.d │ │ │ │ ├── test13152t.d │ │ │ │ ├── test13152u.d │ │ │ │ ├── test13152v.d │ │ │ │ ├── test13152w.d │ │ │ │ ├── test13152x.d │ │ │ │ ├── test13152y.d │ │ │ │ ├── test13152z.d │ │ │ │ ├── test143.d │ │ │ │ ├── test15785.d │ │ │ │ ├── test15897.d │ │ │ │ ├── test18480b.d │ │ │ │ ├── test5412a.d │ │ │ │ ├── test5412b.d │ │ │ │ └── test64a.d │ │ │ ├── isreturnonstack.d │ │ │ ├── issue3827.d │ │ │ ├── lexer1.d │ │ │ ├── lexer2.d │ │ │ ├── lexer3.d │ │ │ ├── lexer4.d │ │ │ ├── lookup.d │ │ │ ├── mangle1.d │ │ │ ├── mangle2.d │ │ │ ├── moduleundefuda.d │ │ │ ├── no_Throwable.d │ │ │ ├── no_TypeInfo.d │ │ │ ├── nogc1.d │ │ │ ├── nogc2.d │ │ │ ├── nogc3.d │ │ │ ├── notype.d │ │ │ ├── objc_non_objc_base.d │ │ │ ├── parse12924.d │ │ │ ├── parse12967a.d │ │ │ ├── parse12967b.d │ │ │ ├── parse13361.d │ │ │ ├── parse14285.d │ │ │ ├── parse14745.d │ │ │ ├── parseStc.d │ │ │ ├── parseStc2.d │ │ │ ├── parseStc3.d │ │ │ ├── parseStc4.d │ │ │ ├── parseStc5.d │ │ │ ├── pragmainline.d │ │ │ ├── pragmas.d │ │ │ ├── protattr1.d │ │ │ ├── protattr2.d │ │ │ ├── protattr3.d │ │ │ ├── protection/ │ │ │ │ └── subpkg/ │ │ │ │ ├── test1.d │ │ │ │ ├── test2.d │ │ │ │ └── test3.d │ │ │ ├── reserved_version.d │ │ │ ├── reserved_version_switch.d │ │ │ ├── retref2.d │ │ │ ├── retscope.d │ │ │ ├── retscope2.d │ │ │ ├── retscope3.d │ │ │ ├── retscope4.d │ │ │ ├── retscope5.d │ │ │ ├── retscope6.d │ │ │ ├── scope_class.d │ │ │ ├── skip.d │ │ │ ├── spell9644.d │ │ │ ├── staticarrayoverflow.d │ │ │ ├── staticforeach1.d │ │ │ ├── staticforeach2.d │ │ │ ├── staticforeach3.d │ │ │ ├── switches.d │ │ │ ├── test1.d │ │ │ ├── test10.d │ │ │ ├── test11006.d │ │ │ ├── test11047.d │ │ │ ├── test11176.d │ │ │ ├── test12228.d │ │ │ ├── test12385.d │ │ │ ├── test12558.d │ │ │ ├── test12822.d │ │ │ ├── test12979.d │ │ │ ├── test13152.d │ │ │ ├── test13536.d │ │ │ ├── test13537.d │ │ │ ├── test13786.d │ │ │ ├── test13867.d │ │ │ ├── test14238.d │ │ │ ├── test143.d │ │ │ ├── test14496.d │ │ │ ├── test14538.d │ │ │ ├── test15191.d │ │ │ ├── test15306.d │ │ │ ├── test15373.d │ │ │ ├── test15399.d │ │ │ ├── test15544.d │ │ │ ├── test15660.d │ │ │ ├── test15672.d │ │ │ ├── test15703.d │ │ │ ├── test15704.d │ │ │ ├── test15785.d │ │ │ ├── test15785b.d │ │ │ ├── test15897.d │ │ │ ├── test15989.d │ │ │ ├── test16095.d │ │ │ ├── test16116.d │ │ │ ├── test16188.d │ │ │ ├── test16193.d │ │ │ ├── test16195.d │ │ │ ├── test16228.d │ │ │ ├── test16365.d │ │ │ ├── test16381.d │ │ │ ├── test16523.d │ │ │ ├── test16589.d │ │ │ ├── test16694.d │ │ │ ├── test17096.d │ │ │ ├── test17284.d │ │ │ ├── test17307.d │ │ │ ├── test17380.d │ │ │ ├── test17380spec.d │ │ │ ├── test17422.d │ │ │ ├── test17423.d │ │ │ ├── test17425.d │ │ │ ├── test17450.d │ │ │ ├── test17451.d │ │ │ ├── test17586.d │ │ │ ├── test17868.d │ │ │ ├── test17868b.d │ │ │ ├── test17892.d │ │ │ ├── test17908a.d │ │ │ ├── test17908b.d │ │ │ ├── test17959.d │ │ │ ├── test18130.d │ │ │ ├── test18282.d │ │ │ ├── test18312.d │ │ │ ├── test18484.d │ │ │ ├── test18554.d │ │ │ ├── test18597.d │ │ │ ├── test18607.d │ │ │ ├── test18644.d │ │ │ ├── test18708.d │ │ │ ├── test18736.d │ │ │ ├── test19112.d │ │ │ ├── test19176.d │ │ │ ├── test19193.d │ │ │ ├── test314.d │ │ │ ├── test4682.d │ │ │ ├── test4682a.d │ │ │ ├── test4838.d │ │ │ ├── test4946.d │ │ │ ├── test5412a.d │ │ │ ├── test5412b.d │ │ │ ├── test5412c.d │ │ │ ├── test64.d │ │ │ ├── test6883.d │ │ │ ├── test8509.d │ │ │ ├── test8556.d │ │ │ ├── test8751.d │ │ │ ├── test9150.d │ │ │ ├── test9176.d │ │ │ ├── test9701.d │ │ │ ├── test9701b.d │ │ │ ├── testCols.d │ │ │ ├── testInference.d │ │ │ ├── testpull1810.d │ │ │ ├── testscopestatic.d │ │ │ ├── traits.d │ │ │ ├── typeerrors.d │ │ │ ├── udaparams.d │ │ │ ├── verrors0.d │ │ │ ├── verrors5.d │ │ │ ├── warn12809.d │ │ │ ├── warn13679.d │ │ │ ├── warn7444.d │ │ │ └── widechars.d │ │ └── runnable/ │ │ ├── A16.d │ │ ├── Same.d │ │ ├── a17.d │ │ ├── a18.d │ │ ├── a19.d │ │ ├── a21.d │ │ ├── aliasthis.d │ │ ├── argufilem.d │ │ ├── arrayop.d │ │ ├── auto1.d │ │ ├── b16278.d │ │ ├── b17073.d │ │ ├── b18034.d │ │ ├── b26.d │ │ ├── b6400.d │ │ ├── bcraii.d │ │ ├── bcraii2.d │ │ ├── bench1.d │ │ ├── betterc.d │ │ ├── bitops.d │ │ ├── bug11155.d │ │ ├── bug12928.d │ │ ├── bug16146.d │ │ ├── bug5.d │ │ ├── bug7068.d │ │ ├── bug846.d │ │ ├── builtin.d │ │ ├── c22.d │ │ ├── cabi1.d │ │ ├── casting.d │ │ ├── circular.d │ │ ├── closure.d │ │ ├── complex.d │ │ ├── constfold.d │ │ ├── cpp_abi_tests.d │ │ ├── cpp_stdlib.d │ │ ├── cppa.d │ │ ├── ctorpowtests.d │ │ ├── debug_info.d │ │ ├── declaration.d │ │ ├── delegate.d │ │ ├── dhry.d │ │ ├── eh.d │ │ ├── eh2.d │ │ ├── entity1.d │ │ ├── evalorder.d │ │ ├── extern1.d │ │ ├── externmangle.d │ │ ├── externmangle2.d │ │ ├── extra-files/ │ │ │ ├── alice30.txt │ │ │ ├── cabi2.cpp │ │ │ ├── cpp_abi_tests.cpp │ │ │ ├── cpp_stdlib.cpp │ │ │ ├── cppb.cpp │ │ │ ├── cppb.h │ │ │ ├── depsprot.d │ │ │ ├── externmangle.cpp │ │ │ ├── externmangle2.cpp │ │ │ ├── foo37.txt │ │ │ ├── lib10386/ │ │ │ │ └── foo/ │ │ │ │ ├── bar.d │ │ │ │ └── package.d │ │ │ ├── lib13666.d │ │ │ ├── lib13742a.d │ │ │ ├── lib13742b.d │ │ │ ├── lib13774a.d │ │ │ ├── lib13774b.d │ │ │ ├── lib846.d │ │ │ ├── link14834a.d │ │ │ ├── link14834b.d │ │ │ ├── linkdebug.d │ │ │ ├── linkdebug_primitives.d │ │ │ ├── linkdebug_range.d │ │ │ ├── linkdebug_uni.d │ │ │ ├── main846.d │ │ │ ├── minimal/ │ │ │ │ └── object.d │ │ │ ├── mul9377a.d │ │ │ ├── mul9377b.d │ │ │ ├── multi9377.d │ │ │ ├── objc_self_test.m │ │ │ ├── std14198/ │ │ │ │ ├── array.d │ │ │ │ ├── conv.d │ │ │ │ ├── format.d │ │ │ │ └── uni.d │ │ │ ├── stdint.cpp │ │ │ ├── test10386.d │ │ │ ├── test10567.d │ │ │ ├── test10567a.d │ │ │ ├── test13666.d │ │ │ ├── test13742.d │ │ │ ├── test14198.d │ │ │ ├── test15.txt │ │ │ ├── test17968.d │ │ │ ├── test17968a.d │ │ │ ├── test18868_a.d │ │ │ ├── test18868_b.d │ │ │ ├── test2.d │ │ │ ├── test35.d │ │ │ ├── test39.d │ │ │ ├── test44.d │ │ │ ├── test_shared.d │ │ │ ├── teststdio.txt │ │ │ └── untag.html │ │ ├── fix17429.d │ │ ├── foreach.d │ │ ├── foreach2.d │ │ ├── foreach3.d │ │ ├── foreach4.d │ │ ├── foreach5.d │ │ ├── funclit.d │ │ ├── functype.d │ │ ├── future.d │ │ ├── hello.d │ │ ├── helloUTF8.d │ │ ├── hospital.d │ │ ├── ice10086a.d │ │ ├── ice10086b.d │ │ ├── ice10857.d │ │ ├── ice15030.d │ │ ├── ice15138.d │ │ ├── ice15176.d │ │ ├── ice15200.d │ │ ├── ice4481.d │ │ ├── ifti.d │ │ ├── implicit.d │ │ ├── imports/ │ │ │ ├── A16a.d │ │ │ ├── Other.d │ │ │ ├── a11447.d │ │ │ ├── a12010.d │ │ │ ├── a12037.d │ │ │ ├── a12874.d │ │ │ ├── a14267.d │ │ │ ├── a14992.d │ │ │ ├── a15030.d │ │ │ ├── a15079.d │ │ │ ├── a17a.d │ │ │ ├── a18a.d │ │ │ ├── a19a.d │ │ │ ├── a20a.d │ │ │ ├── a21a.d │ │ │ ├── a7595.d │ │ │ ├── a9546.d │ │ │ ├── a9741.d │ │ │ ├── another_module_with_tests.d │ │ │ ├── argufile.d │ │ │ ├── b11447.d │ │ │ ├── b15030.d │ │ │ ├── b26a.d │ │ │ ├── bar10378.d │ │ │ ├── bug10425.d │ │ │ ├── bug846.d │ │ │ ├── c11447.d │ │ │ ├── c22a.d │ │ │ ├── c22b.d │ │ │ ├── circularA.d │ │ │ ├── depsprot_default.d │ │ │ ├── depsprot_private.d │ │ │ ├── depsprot_public.d │ │ │ ├── extern1a.d │ │ │ ├── ice10086x.d │ │ │ ├── ice10086y.d │ │ │ ├── ice10857a.d │ │ │ ├── ice10857b.d │ │ │ ├── ice15138a.d │ │ │ ├── ice15176a.d │ │ │ ├── ice15176b.d │ │ │ ├── ice15200a.d │ │ │ ├── ice15200b.d │ │ │ ├── ice4481a.d │ │ │ ├── ice4481b.d │ │ │ ├── inc11239.d │ │ │ ├── inline2a.d │ │ │ ├── link10920a.d │ │ │ ├── link11069x.d │ │ │ ├── link11069y.d │ │ │ ├── link11069z.d │ │ │ ├── link11127a.d │ │ │ ├── link11395a.d │ │ │ ├── link12144a.d │ │ │ ├── link13043a.d │ │ │ ├── link13394a.d │ │ │ ├── link13400a.d │ │ │ ├── link13415a.d │ │ │ ├── link14074x.d │ │ │ ├── link14074y.d │ │ │ ├── link14074z.d │ │ │ ├── link14541traits.d │ │ │ ├── link14588a.d │ │ │ ├── link14814a.d │ │ │ ├── link15194b.d │ │ │ ├── link15194std.d │ │ │ ├── link2500a.d │ │ │ ├── link2500b.d │ │ │ ├── link2644a.d │ │ │ ├── link2644b.d │ │ │ ├── link2644c.d │ │ │ ├── link7745b.d │ │ │ ├── link8023b.d │ │ │ ├── link9571a.d │ │ │ ├── linktypeinfo_file.d │ │ │ ├── m1a.d │ │ │ ├── m8668a.d │ │ │ ├── m8668b.d │ │ │ ├── m8668c.d │ │ │ ├── mangle10077.d │ │ │ ├── mod2.d │ │ │ ├── module_with_tests.d │ │ │ ├── ovs1528a.d │ │ │ ├── ovs1528b.d │ │ │ ├── std11069array.d │ │ │ ├── std11069container.d │ │ │ ├── std11069range.d │ │ │ ├── std11069typecons.d │ │ │ ├── std11863bitmanip.d │ │ │ ├── std11863conv.d │ │ │ ├── std11863format.d │ │ │ ├── std12010container.d │ │ │ ├── std15017variant.d │ │ │ ├── std15021conv.d │ │ │ ├── std15021format.d │ │ │ ├── std15030algo.d │ │ │ ├── template13478a.d │ │ │ ├── template13478b.d │ │ │ ├── template2962a.d │ │ │ ├── template_ovs1.d │ │ │ ├── template_ovs2.d │ │ │ ├── template_ovs3.d │ │ │ ├── test10441b.d │ │ │ ├── test10441c.d │ │ │ ├── test10573a.d │ │ │ ├── test10736a.d │ │ │ ├── test10736b.d │ │ │ ├── test10736c.d │ │ │ ├── test10a.d │ │ │ ├── test11039b.d │ │ │ ├── test11745b.d │ │ │ ├── test11931a.d │ │ │ ├── test11931b.d │ │ │ ├── test11931c.d │ │ │ ├── test11931d.d │ │ │ ├── test13a.d │ │ │ ├── test14901a.d │ │ │ ├── test14901b.d │ │ │ ├── test14901c.d │ │ │ ├── test14901d.d │ │ │ ├── test15777a.d │ │ │ ├── test15777b.d │ │ │ ├── test18322import.d │ │ │ ├── test18868_fls.d │ │ │ ├── test21a.d │ │ │ ├── test24a.d │ │ │ ├── test24b.d │ │ │ ├── test27a.d │ │ │ ├── test29a.d │ │ │ ├── test29b.d │ │ │ ├── test31a.d │ │ │ ├── test32a.d │ │ │ ├── test35a.d │ │ │ ├── test38a.d │ │ │ ├── test39a.d │ │ │ ├── test3a.d │ │ │ ├── test3b.d │ │ │ ├── test40a.d │ │ │ ├── test41a.d │ │ │ ├── test44a.d │ │ │ ├── test45a.d │ │ │ ├── test45b.d │ │ │ ├── test46a.d │ │ │ ├── test46b.d │ │ │ ├── test46c.d │ │ │ ├── test48a.d │ │ │ ├── test49a.d │ │ │ ├── test57a.d │ │ │ ├── test57b.d │ │ │ ├── test58a.d │ │ │ ├── test61a.d │ │ │ ├── test7494a.d │ │ │ ├── test8997a.d │ │ │ ├── test9271a.d │ │ │ ├── testkwd_file.d │ │ │ ├── testmangle.d │ │ │ ├── testminitAA.d │ │ │ ├── testminitBB.d │ │ │ ├── testmod1a.d │ │ │ ├── testmod1b.d │ │ │ ├── testmod2a.d │ │ │ ├── tlsa.d │ │ │ ├── traits_getUnitTests_import.d │ │ │ ├── ufcs5a.d │ │ │ ├── ufcs5b.d │ │ │ ├── ufcs5c.d │ │ │ ├── ufcs5d.d │ │ │ └── ufcs5e.d │ │ ├── inline.d │ │ ├── inline14560.d │ │ ├── inline2.d │ │ ├── inner.d │ │ ├── integrate.d │ │ ├── interface.d │ │ ├── interface1.d │ │ ├── interface2.d │ │ ├── interface3.d │ │ ├── interpret.d │ │ ├── interpret2.d │ │ ├── issue16995.d │ │ ├── issue8671.d │ │ ├── lazy.d │ │ ├── ldc_github_1677.d │ │ ├── lexer.d │ │ ├── link10425.d │ │ ├── link10920.d │ │ ├── link11069a.d │ │ ├── link11069b.d │ │ ├── link11127.d │ │ ├── link11395.d │ │ ├── link11931.d │ │ ├── link12010.d │ │ ├── link12037.d │ │ ├── link12144.d │ │ ├── link13043.d │ │ ├── link13350.d │ │ ├── link13394.d │ │ ├── link13400.d │ │ ├── link13415.d │ │ ├── link13843.d │ │ ├── link14074a.d │ │ ├── link14074b.d │ │ ├── link14425.d │ │ ├── link14541.d │ │ ├── link14588.d │ │ ├── link14814.d │ │ ├── link14992.d │ │ ├── link15017.d │ │ ├── link15021.d │ │ ├── link15149.d │ │ ├── link2500.d │ │ ├── link2644.d │ │ ├── link6574.d │ │ ├── link7745.d │ │ ├── link7966.d │ │ ├── link8023.d │ │ ├── link9571.d │ │ ├── linktypeinfo.d │ │ ├── literal.d │ │ ├── loopunroll.d │ │ ├── m1.d │ │ ├── manboy.d │ │ ├── mangle.d │ │ ├── mars1.d │ │ ├── minimal.d │ │ ├── minimal2.d │ │ ├── mixin1.d │ │ ├── mixin2.d │ │ ├── mod1.d │ │ ├── nan.d │ │ ├── nested.d │ │ ├── newdel.d │ │ ├── nogc.d │ │ ├── nulltype.d │ │ ├── opdisp.d │ │ ├── opover.d │ │ ├── opover2.d │ │ ├── opover3.d │ │ ├── overload.d │ │ ├── pi.d │ │ ├── polysemous.d │ │ ├── printargs.d │ │ ├── property.d │ │ ├── property2.d │ │ ├── s2ir.d │ │ ├── sctor.d │ │ ├── sdtor.d │ │ ├── statictor.d │ │ ├── stdint.d │ │ ├── stress.d │ │ ├── structlit.d │ │ ├── template1.d │ │ ├── template13478.d │ │ ├── template2.d │ │ ├── template2962.d │ │ ├── template3.d │ │ ├── template4.d │ │ ├── template6.d │ │ ├── template8.d │ │ ├── template9.d │ │ ├── test10.d │ │ ├── test10378.d │ │ ├── test10441.d │ │ ├── test10573.d │ │ ├── test10736.d │ │ ├── test10942.d │ │ ├── test11.d │ │ ├── test11039.d │ │ ├── test11239.d │ │ ├── test11447a.d │ │ ├── test11447b.d │ │ ├── test11447c.d │ │ ├── test11745.d │ │ ├── test11863.d │ │ ├── test12.d │ │ ├── test12197.d │ │ ├── test12486.d │ │ ├── test12874.d │ │ ├── test13.d │ │ ├── test13504.d │ │ ├── test13613.d │ │ ├── test13944.d │ │ ├── test14613.d │ │ ├── test14874.d │ │ ├── test14901.d │ │ ├── test14903.d │ │ ├── test15.d │ │ ├── test15079.d │ │ ├── test15373.d │ │ ├── test15568.d │ │ ├── test15624.d │ │ ├── test15913.d │ │ ├── test16.d │ │ ├── test16115.d │ │ ├── test16555.d │ │ ├── test16640.d │ │ ├── test16980.d │ │ ├── test17.d │ │ ├── test17072.d │ │ ├── test17246.d │ │ ├── test17338.d │ │ ├── test17559.d │ │ ├── test17684.d │ │ ├── test17868.d │ │ ├── test17868b.d │ │ ├── test17878.d │ │ ├── test17899.d │ │ ├── test17940.d │ │ ├── test17943.d │ │ ├── test18296.d │ │ ├── test18322.d │ │ ├── test18534.d │ │ ├── test18746.d │ │ ├── test18868_2.d │ │ ├── test18868_3.d │ │ ├── test18880.d │ │ ├── test18916.d │ │ ├── test19.d │ │ ├── test19185.d │ │ ├── test19251.d │ │ ├── test20.d │ │ ├── test21.d │ │ ├── test22.d │ │ ├── test23.d │ │ ├── test24.d │ │ ├── test27.d │ │ ├── test28.d │ │ ├── test29.d │ │ ├── test3.d │ │ ├── test30.d │ │ ├── test31.d │ │ ├── test32.d │ │ ├── test34.d │ │ ├── test3449.d │ │ ├── test3574a.d │ │ ├── test3574b.d │ │ ├── test3574c.d │ │ ├── test3574d.d │ │ ├── test36.d │ │ ├── test37.d │ │ ├── test38.d │ │ ├── test4.d │ │ ├── test40.d │ │ ├── test41.d │ │ ├── test42.d │ │ ├── test42a.d │ │ ├── test435.d │ │ ├── test45.d │ │ ├── test46.d │ │ ├── test48.d │ │ ├── test49.d │ │ ├── test5.d │ │ ├── test52.d │ │ ├── test5305.d │ │ ├── test57.d │ │ ├── test58.d │ │ ├── test5943.d │ │ ├── test60.d │ │ ├── test61.d │ │ ├── test6423.d │ │ ├── test7.d │ │ ├── test7452.d │ │ ├── test7453.d │ │ ├── test7494.d │ │ ├── test7511.d │ │ ├── test7595.d │ │ ├── test7603.d │ │ ├── test7618.d │ │ ├── test7932.d │ │ ├── test8.d │ │ ├── test8182.d │ │ ├── test8544.d │ │ ├── test8997.d │ │ ├── test9259.d │ │ ├── test9271.d │ │ ├── test9309.d │ │ ├── test9495.d │ │ ├── testaa.d │ │ ├── testaa2.d │ │ ├── testaa3.d │ │ ├── testabi.d │ │ ├── testappend.d │ │ ├── testargtypes.d │ │ ├── testarray.d │ │ ├── testassign.d │ │ ├── testbitarray.d │ │ ├── testbounds.d │ │ ├── testbounds_off.d │ │ ├── testbounds_on.d │ │ ├── testbounds_safeonly.d │ │ ├── testclass.d │ │ ├── testconst.d │ │ ├── testconstsection.d │ │ ├── testcontracts.d │ │ ├── testdefault_after_variadic.d │ │ ├── testdstress.d │ │ ├── testdt.d │ │ ├── testenum.d │ │ ├── testfile.d │ │ ├── testformat.d │ │ ├── testgc2.d │ │ ├── testgc3.d │ │ ├── testinvariant.d │ │ ├── testkeyword.d │ │ ├── testline.d │ │ ├── testmain.d │ │ ├── testminit.d │ │ ├── testmmfile.d │ │ ├── testmod1.d │ │ ├── testmod2.d │ │ ├── testmodule.d │ │ ├── testpic.d │ │ ├── testptrref.d │ │ ├── testreturn.d │ │ ├── testrightthis.d │ │ ├── testsafe.d │ │ ├── testscope.d │ │ ├── testscope2.d │ │ ├── testsignals.d │ │ ├── testsocket.d │ │ ├── teststdio.d │ │ ├── testswitch.d │ │ ├── testthread.d │ │ ├── testthread2.d │ │ ├── testtypeid.d │ │ ├── testv.d │ │ ├── tls.d │ │ ├── tls_dup.d │ │ ├── traits.d │ │ ├── traits_getPointerBitmap.d │ │ ├── traits_getUnitTests.d │ │ ├── traits_getVirtualIndex.d │ │ ├── uda.d │ │ ├── ufcs.d │ │ ├── uniformctor.d │ │ ├── untag.d │ │ ├── variadic.d │ │ ├── version.d │ │ ├── warning1.d │ │ ├── wc.d │ │ ├── wc2.d │ │ ├── wc3.d │ │ ├── xdtor.d │ │ ├── xpostblit.d │ │ ├── xtest46.d │ │ ├── xtest55.d │ │ └── xtestenum.d │ └── lib/ │ ├── gdc-dg.exp │ └── gdc.exp ├── gcc.version ├── libphobos/ │ ├── Makefile.am │ ├── Makefile.in │ ├── acinclude.m4 │ ├── aclocal.m4 │ ├── config.h.in │ ├── configure │ ├── configure.ac │ ├── d_rules.am │ ├── libdruntime/ │ │ ├── LICENSE │ │ ├── MERGE │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── __entrypoint.di │ │ ├── __main.di │ │ ├── core/ │ │ │ ├── atomic.d │ │ │ ├── attribute.d │ │ │ ├── bitop.d │ │ │ ├── checkedint.d │ │ │ ├── cpuid.d │ │ │ ├── demangle.d │ │ │ ├── exception.d │ │ │ ├── internal/ │ │ │ │ ├── abort.d │ │ │ │ ├── arrayop.d │ │ │ │ ├── convert.d │ │ │ │ ├── hash.d │ │ │ │ ├── parseoptions.d │ │ │ │ ├── spinlock.d │ │ │ │ ├── string.d │ │ │ │ └── traits.d │ │ │ ├── math.d │ │ │ ├── memory.d │ │ │ ├── runtime.d │ │ │ ├── simd.d │ │ │ ├── stdc/ │ │ │ │ ├── assert_.d │ │ │ │ ├── complex.d │ │ │ │ ├── config.d │ │ │ │ ├── ctype.d │ │ │ │ ├── errno.d │ │ │ │ ├── errno_.c │ │ │ │ ├── fenv.d │ │ │ │ ├── float_.d │ │ │ │ ├── inttypes.d │ │ │ │ ├── limits.d │ │ │ │ ├── locale.d │ │ │ │ ├── math.d │ │ │ │ ├── signal.d │ │ │ │ ├── stdarg.d │ │ │ │ ├── stddef.d │ │ │ │ ├── stdint.d │ │ │ │ ├── stdio.d │ │ │ │ ├── stdlib.d │ │ │ │ ├── string.d │ │ │ │ ├── tgmath.d │ │ │ │ ├── time.d │ │ │ │ ├── wchar_.d │ │ │ │ └── wctype.d │ │ │ ├── stdcpp/ │ │ │ │ ├── exception.d │ │ │ │ └── typeinfo.d │ │ │ ├── sync/ │ │ │ │ ├── barrier.d │ │ │ │ ├── condition.d │ │ │ │ ├── config.d │ │ │ │ ├── exception.d │ │ │ │ ├── mutex.d │ │ │ │ ├── rwmutex.d │ │ │ │ └── semaphore.d │ │ │ ├── sys/ │ │ │ │ ├── bionic/ │ │ │ │ │ ├── fcntl.d │ │ │ │ │ └── unistd.d │ │ │ │ ├── darwin/ │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── mach/ │ │ │ │ │ │ ├── dyld.d │ │ │ │ │ │ ├── getsect.d │ │ │ │ │ │ ├── kern_return.d │ │ │ │ │ │ ├── loader.d │ │ │ │ │ │ ├── port.d │ │ │ │ │ │ ├── semaphore.d │ │ │ │ │ │ └── thread_act.d │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ └── in_.d │ │ │ │ │ ├── pthread.d │ │ │ │ │ └── sys/ │ │ │ │ │ ├── cdefs.d │ │ │ │ │ ├── event.d │ │ │ │ │ └── mman.d │ │ │ │ ├── dragonflybsd/ │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ └── in_.d │ │ │ │ │ ├── pthread_np.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── _bitset.d │ │ │ │ │ │ ├── _cpuset.d │ │ │ │ │ │ ├── cdefs.d │ │ │ │ │ │ ├── elf.d │ │ │ │ │ │ ├── elf32.d │ │ │ │ │ │ ├── elf64.d │ │ │ │ │ │ ├── elf_common.d │ │ │ │ │ │ ├── event.d │ │ │ │ │ │ ├── link_elf.d │ │ │ │ │ │ └── mman.d │ │ │ │ │ └── time.d │ │ │ │ ├── freebsd/ │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ └── in_.d │ │ │ │ │ ├── pthread_np.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── _bitset.d │ │ │ │ │ │ ├── _cpuset.d │ │ │ │ │ │ ├── cdefs.d │ │ │ │ │ │ ├── elf.d │ │ │ │ │ │ ├── elf32.d │ │ │ │ │ │ ├── elf64.d │ │ │ │ │ │ ├── elf_common.d │ │ │ │ │ │ ├── event.d │ │ │ │ │ │ ├── link_elf.d │ │ │ │ │ │ ├── mman.d │ │ │ │ │ │ └── mount.d │ │ │ │ │ ├── time.d │ │ │ │ │ └── unistd.d │ │ │ │ ├── linux/ │ │ │ │ │ ├── config.d │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── elf.d │ │ │ │ │ ├── epoll.d │ │ │ │ │ ├── errno.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── fcntl.d │ │ │ │ │ ├── ifaddrs.d │ │ │ │ │ ├── link.d │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ ├── in_.d │ │ │ │ │ │ └── tcp.d │ │ │ │ │ ├── sched.d │ │ │ │ │ ├── stdio.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── auxv.d │ │ │ │ │ │ ├── eventfd.d │ │ │ │ │ │ ├── file.d │ │ │ │ │ │ ├── inotify.d │ │ │ │ │ │ ├── mman.d │ │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ │ └── tcp.d │ │ │ │ │ │ ├── prctl.d │ │ │ │ │ │ ├── signalfd.d │ │ │ │ │ │ ├── socket.d │ │ │ │ │ │ ├── sysinfo.d │ │ │ │ │ │ ├── time.d │ │ │ │ │ │ └── xattr.d │ │ │ │ │ ├── termios.d │ │ │ │ │ ├── time.d │ │ │ │ │ ├── timerfd.d │ │ │ │ │ ├── tipc.d │ │ │ │ │ └── unistd.d │ │ │ │ ├── netbsd/ │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── elf.d │ │ │ │ │ │ ├── elf32.d │ │ │ │ │ │ ├── elf64.d │ │ │ │ │ │ ├── elf_common.d │ │ │ │ │ │ ├── event.d │ │ │ │ │ │ ├── link_elf.d │ │ │ │ │ │ └── mman.d │ │ │ │ │ └── time.d │ │ │ │ ├── openbsd/ │ │ │ │ │ └── dlfcn.d │ │ │ │ ├── osx/ │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── mach/ │ │ │ │ │ │ ├── dyld.d │ │ │ │ │ │ ├── getsect.d │ │ │ │ │ │ ├── kern_return.d │ │ │ │ │ │ ├── loader.d │ │ │ │ │ │ ├── port.d │ │ │ │ │ │ ├── semaphore.d │ │ │ │ │ │ └── thread_act.d │ │ │ │ │ ├── pthread.d │ │ │ │ │ └── sys/ │ │ │ │ │ ├── cdefs.d │ │ │ │ │ ├── event.d │ │ │ │ │ └── mman.d │ │ │ │ ├── posix/ │ │ │ │ │ ├── aio.d │ │ │ │ │ ├── arpa/ │ │ │ │ │ │ └── inet.d │ │ │ │ │ ├── config.d │ │ │ │ │ ├── dirent.d │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── fcntl.d │ │ │ │ │ ├── grp.d │ │ │ │ │ ├── iconv.d │ │ │ │ │ ├── inttypes.d │ │ │ │ │ ├── libgen.d │ │ │ │ │ ├── mqueue.d │ │ │ │ │ ├── net/ │ │ │ │ │ │ └── if_.d │ │ │ │ │ ├── netdb.d │ │ │ │ │ ├── netinet/ │ │ │ │ │ │ ├── in_.d │ │ │ │ │ │ └── tcp.d │ │ │ │ │ ├── poll.d │ │ │ │ │ ├── pthread.d │ │ │ │ │ ├── pwd.d │ │ │ │ │ ├── sched.d │ │ │ │ │ ├── semaphore.d │ │ │ │ │ ├── setjmp.d │ │ │ │ │ ├── signal.d │ │ │ │ │ ├── spawn.d │ │ │ │ │ ├── stdio.d │ │ │ │ │ ├── stdlib.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── filio.d │ │ │ │ │ │ ├── ioccom.d │ │ │ │ │ │ ├── ioctl.d │ │ │ │ │ │ ├── ipc.d │ │ │ │ │ │ ├── mman.d │ │ │ │ │ │ ├── msg.d │ │ │ │ │ │ ├── resource.d │ │ │ │ │ │ ├── select.d │ │ │ │ │ │ ├── shm.d │ │ │ │ │ │ ├── socket.d │ │ │ │ │ │ ├── stat.d │ │ │ │ │ │ ├── statvfs.d │ │ │ │ │ │ ├── time.d │ │ │ │ │ │ ├── ttycom.d │ │ │ │ │ │ ├── types.d │ │ │ │ │ │ ├── uio.d │ │ │ │ │ │ ├── un.d │ │ │ │ │ │ ├── utsname.d │ │ │ │ │ │ └── wait.d │ │ │ │ │ ├── syslog.d │ │ │ │ │ ├── termios.d │ │ │ │ │ ├── time.d │ │ │ │ │ ├── ucontext.d │ │ │ │ │ ├── unistd.d │ │ │ │ │ └── utime.d │ │ │ │ ├── solaris/ │ │ │ │ │ ├── dlfcn.d │ │ │ │ │ ├── elf.d │ │ │ │ │ ├── execinfo.d │ │ │ │ │ ├── libelf.d │ │ │ │ │ ├── link.d │ │ │ │ │ ├── sys/ │ │ │ │ │ │ ├── elf.d │ │ │ │ │ │ ├── elf_386.d │ │ │ │ │ │ ├── elf_SPARC.d │ │ │ │ │ │ ├── elf_amd64.d │ │ │ │ │ │ ├── elf_notes.d │ │ │ │ │ │ ├── elftypes.d │ │ │ │ │ │ ├── link.d │ │ │ │ │ │ ├── priocntl.d │ │ │ │ │ │ ├── procset.d │ │ │ │ │ │ └── types.d │ │ │ │ │ └── time.d │ │ │ │ └── windows/ │ │ │ │ ├── accctrl.d │ │ │ │ ├── aclapi.d │ │ │ │ ├── aclui.d │ │ │ │ ├── basetsd.d │ │ │ │ ├── basetyps.d │ │ │ │ ├── cderr.d │ │ │ │ ├── cguid.d │ │ │ │ ├── com.d │ │ │ │ ├── comcat.d │ │ │ │ ├── commctrl.d │ │ │ │ ├── commdlg.d │ │ │ │ ├── core.d │ │ │ │ ├── cpl.d │ │ │ │ ├── cplext.d │ │ │ │ ├── custcntl.d │ │ │ │ ├── dbghelp.d │ │ │ │ ├── dbghelp_types.d │ │ │ │ ├── dbt.d │ │ │ │ ├── dde.d │ │ │ │ ├── ddeml.d │ │ │ │ ├── dhcpcsdk.d │ │ │ │ ├── dlgs.d │ │ │ │ ├── dll.d │ │ │ │ ├── docobj.d │ │ │ │ ├── errorrep.d │ │ │ │ ├── exdisp.d │ │ │ │ ├── exdispid.d │ │ │ │ ├── httpext.d │ │ │ │ ├── idispids.d │ │ │ │ ├── imagehlp.d │ │ │ │ ├── imm.d │ │ │ │ ├── intshcut.d │ │ │ │ ├── ipexport.d │ │ │ │ ├── iphlpapi.d │ │ │ │ ├── ipifcons.d │ │ │ │ ├── iprtrmib.d │ │ │ │ ├── iptypes.d │ │ │ │ ├── isguids.d │ │ │ │ ├── lm.d │ │ │ │ ├── lmaccess.d │ │ │ │ ├── lmalert.d │ │ │ │ ├── lmapibuf.d │ │ │ │ ├── lmat.d │ │ │ │ ├── lmaudit.d │ │ │ │ ├── lmbrowsr.d │ │ │ │ ├── lmchdev.d │ │ │ │ ├── lmconfig.d │ │ │ │ ├── lmcons.d │ │ │ │ ├── lmerr.d │ │ │ │ ├── lmerrlog.d │ │ │ │ ├── lmmsg.d │ │ │ │ ├── lmremutl.d │ │ │ │ ├── lmrepl.d │ │ │ │ ├── lmserver.d │ │ │ │ ├── lmshare.d │ │ │ │ ├── lmsname.d │ │ │ │ ├── lmstats.d │ │ │ │ ├── lmsvc.d │ │ │ │ ├── lmuse.d │ │ │ │ ├── lmuseflg.d │ │ │ │ ├── lmwksta.d │ │ │ │ ├── lzexpand.d │ │ │ │ ├── mapi.d │ │ │ │ ├── mciavi.d │ │ │ │ ├── mcx.d │ │ │ │ ├── mgmtapi.d │ │ │ │ ├── mmsystem.d │ │ │ │ ├── msacm.d │ │ │ │ ├── mshtml.d │ │ │ │ ├── mswsock.d │ │ │ │ ├── nb30.d │ │ │ │ ├── nddeapi.d │ │ │ │ ├── nspapi.d │ │ │ │ ├── ntdef.d │ │ │ │ ├── ntdll.d │ │ │ │ ├── ntldap.d │ │ │ │ ├── ntsecapi.d │ │ │ │ ├── ntsecpkg.d │ │ │ │ ├── oaidl.d │ │ │ │ ├── objbase.d │ │ │ │ ├── objfwd.d │ │ │ │ ├── objidl.d │ │ │ │ ├── objsafe.d │ │ │ │ ├── ocidl.d │ │ │ │ ├── odbcinst.d │ │ │ │ ├── ole.d │ │ │ │ ├── ole2.d │ │ │ │ ├── ole2ver.d │ │ │ │ ├── oleacc.d │ │ │ │ ├── oleauto.d │ │ │ │ ├── olectl.d │ │ │ │ ├── olectlid.d │ │ │ │ ├── oledlg.d │ │ │ │ ├── oleidl.d │ │ │ │ ├── pbt.d │ │ │ │ ├── powrprof.d │ │ │ │ ├── prsht.d │ │ │ │ ├── psapi.d │ │ │ │ ├── rapi.d │ │ │ │ ├── ras.d │ │ │ │ ├── rasdlg.d │ │ │ │ ├── raserror.d │ │ │ │ ├── rassapi.d │ │ │ │ ├── reason.d │ │ │ │ ├── regstr.d │ │ │ │ ├── richedit.d │ │ │ │ ├── richole.d │ │ │ │ ├── rpc.d │ │ │ │ ├── rpcdce.d │ │ │ │ ├── rpcdce2.d │ │ │ │ ├── rpcdcep.d │ │ │ │ ├── rpcndr.d │ │ │ │ ├── rpcnsi.d │ │ │ │ ├── rpcnsip.d │ │ │ │ ├── rpcnterr.d │ │ │ │ ├── schannel.d │ │ │ │ ├── secext.d │ │ │ │ ├── security.d │ │ │ │ ├── servprov.d │ │ │ │ ├── setupapi.d │ │ │ │ ├── shellapi.d │ │ │ │ ├── shldisp.d │ │ │ │ ├── shlguid.d │ │ │ │ ├── shlobj.d │ │ │ │ ├── shlwapi.d │ │ │ │ ├── snmp.d │ │ │ │ ├── sql.d │ │ │ │ ├── sqlext.d │ │ │ │ ├── sqltypes.d │ │ │ │ ├── sqlucode.d │ │ │ │ ├── sspi.d │ │ │ │ ├── stacktrace.d │ │ │ │ ├── stat.d │ │ │ │ ├── subauth.d │ │ │ │ ├── threadaux.d │ │ │ │ ├── tlhelp32.d │ │ │ │ ├── tmschema.d │ │ │ │ ├── unknwn.d │ │ │ │ ├── uuid.d │ │ │ │ ├── vfw.d │ │ │ │ ├── w32api.d │ │ │ │ ├── winbase.d │ │ │ │ ├── winber.d │ │ │ │ ├── wincon.d │ │ │ │ ├── wincrypt.d │ │ │ │ ├── windef.d │ │ │ │ ├── windows.d │ │ │ │ ├── winerror.d │ │ │ │ ├── wingdi.d │ │ │ │ ├── winhttp.d │ │ │ │ ├── wininet.d │ │ │ │ ├── winioctl.d │ │ │ │ ├── winldap.d │ │ │ │ ├── winnetwk.d │ │ │ │ ├── winnls.d │ │ │ │ ├── winnt.d │ │ │ │ ├── winperf.d │ │ │ │ ├── winreg.d │ │ │ │ ├── winsock2.d │ │ │ │ ├── winspool.d │ │ │ │ ├── winsvc.d │ │ │ │ ├── winuser.d │ │ │ │ ├── winver.d │ │ │ │ ├── wtsapi32.d │ │ │ │ └── wtypes.d │ │ │ ├── thread.d │ │ │ ├── threadasm.S │ │ │ ├── time.d │ │ │ └── vararg.d │ │ ├── gc/ │ │ │ ├── bits.d │ │ │ ├── config.d │ │ │ ├── gcinterface.d │ │ │ ├── impl/ │ │ │ │ ├── conservative/ │ │ │ │ │ └── gc.d │ │ │ │ ├── manual/ │ │ │ │ │ └── gc.d │ │ │ │ └── proto/ │ │ │ │ └── gc.d │ │ │ ├── os.d │ │ │ ├── pooltable.d │ │ │ └── proxy.d │ │ ├── gcc/ │ │ │ ├── attribute.d │ │ │ ├── backtrace.d │ │ │ ├── builtins.d │ │ │ ├── config.d.in │ │ │ ├── deh.d │ │ │ ├── libbacktrace.d.in │ │ │ └── unwind/ │ │ │ ├── arm.d │ │ │ ├── arm_common.d │ │ │ ├── c6x.d │ │ │ ├── generic.d │ │ │ ├── package.d │ │ │ └── pe.d │ │ ├── object.d │ │ └── rt/ │ │ ├── aApply.d │ │ ├── aApplyR.d │ │ ├── aaA.d │ │ ├── adi.d │ │ ├── arrayassign.d │ │ ├── arraycast.d │ │ ├── arraycat.d │ │ ├── cast_.d │ │ ├── config.d │ │ ├── critical_.d │ │ ├── deh.d │ │ ├── dmain2.d │ │ ├── dylib_fixes.c │ │ ├── ehalloc.d │ │ ├── invariant.d │ │ ├── lifetime.d │ │ ├── memory.d │ │ ├── minfo.d │ │ ├── monitor_.d │ │ ├── obj.d │ │ ├── qsort.d │ │ ├── sections.d │ │ ├── sections_android.d │ │ ├── sections_elf_shared.d │ │ ├── sections_osx_x86.d │ │ ├── sections_osx_x86_64.d │ │ ├── sections_solaris.d │ │ ├── sections_win32.d │ │ ├── sections_win64.d │ │ ├── tlsgc.d │ │ ├── typeinfo/ │ │ │ ├── ti_Acdouble.d │ │ │ ├── ti_Acfloat.d │ │ │ ├── ti_Acreal.d │ │ │ ├── ti_Adouble.d │ │ │ ├── ti_Afloat.d │ │ │ ├── ti_Ag.d │ │ │ ├── ti_Aint.d │ │ │ ├── ti_Along.d │ │ │ ├── ti_Areal.d │ │ │ ├── ti_Ashort.d │ │ │ ├── ti_C.d │ │ │ ├── ti_byte.d │ │ │ ├── ti_cdouble.d │ │ │ ├── ti_cent.d │ │ │ ├── ti_cfloat.d │ │ │ ├── ti_char.d │ │ │ ├── ti_creal.d │ │ │ ├── ti_dchar.d │ │ │ ├── ti_delegate.d │ │ │ ├── ti_double.d │ │ │ ├── ti_float.d │ │ │ ├── ti_idouble.d │ │ │ ├── ti_ifloat.d │ │ │ ├── ti_int.d │ │ │ ├── ti_ireal.d │ │ │ ├── ti_long.d │ │ │ ├── ti_n.d │ │ │ ├── ti_ptr.d │ │ │ ├── ti_real.d │ │ │ ├── ti_short.d │ │ │ ├── ti_ubyte.d │ │ │ ├── ti_ucent.d │ │ │ ├── ti_uint.d │ │ │ ├── ti_ulong.d │ │ │ ├── ti_ushort.d │ │ │ ├── ti_void.d │ │ │ └── ti_wchar.d │ │ └── util/ │ │ ├── array.d │ │ ├── container/ │ │ │ ├── array.d │ │ │ ├── common.d │ │ │ ├── hashtab.d │ │ │ └── treap.d │ │ ├── random.d │ │ ├── typeinfo.d │ │ └── utf.d │ ├── m4/ │ │ ├── autoconf.m4 │ │ ├── druntime/ │ │ │ ├── cpu.m4 │ │ │ ├── libraries.m4 │ │ │ └── os.m4 │ │ ├── druntime.m4 │ │ ├── gcc_support.m4 │ │ ├── gdc.m4 │ │ └── libtool.m4 │ ├── src/ │ │ ├── LICENSE_1_0.txt │ │ ├── MERGE │ │ ├── Makefile.am │ │ ├── Makefile.in │ │ ├── etc/ │ │ │ └── c/ │ │ │ ├── curl.d │ │ │ ├── sqlite3.d │ │ │ └── zlib.d │ │ ├── index.d │ │ ├── libgphobos.spec.in │ │ └── std/ │ │ ├── algorithm/ │ │ │ ├── comparison.d │ │ │ ├── internal.d │ │ │ ├── iteration.d │ │ │ ├── mutation.d │ │ │ ├── package.d │ │ │ ├── searching.d │ │ │ ├── setops.d │ │ │ └── sorting.d │ │ ├── array.d │ │ ├── ascii.d │ │ ├── base64.d │ │ ├── bigint.d │ │ ├── bitmanip.d │ │ ├── compiler.d │ │ ├── complex.d │ │ ├── concurrency.d │ │ ├── container/ │ │ │ ├── array.d │ │ │ ├── binaryheap.d │ │ │ ├── dlist.d │ │ │ ├── package.d │ │ │ ├── rbtree.d │ │ │ ├── slist.d │ │ │ └── util.d │ │ ├── conv.d │ │ ├── csv.d │ │ ├── datetime/ │ │ │ ├── date.d │ │ │ ├── interval.d │ │ │ ├── package.d │ │ │ ├── stopwatch.d │ │ │ ├── systime.d │ │ │ └── timezone.d │ │ ├── demangle.d │ │ ├── digest/ │ │ │ ├── crc.d │ │ │ ├── digest.d │ │ │ ├── hmac.d │ │ │ ├── md.d │ │ │ ├── murmurhash.d │ │ │ ├── package.d │ │ │ ├── ripemd.d │ │ │ └── sha.d │ │ ├── encoding.d │ │ ├── exception.d │ │ ├── experimental/ │ │ │ ├── all.d │ │ │ ├── allocator/ │ │ │ │ ├── building_blocks/ │ │ │ │ │ ├── affix_allocator.d │ │ │ │ │ ├── aligned_block_list.d │ │ │ │ │ ├── allocator_list.d │ │ │ │ │ ├── ascending_page_allocator.d │ │ │ │ │ ├── bitmapped_block.d │ │ │ │ │ ├── bucketizer.d │ │ │ │ │ ├── fallback_allocator.d │ │ │ │ │ ├── free_list.d │ │ │ │ │ ├── free_tree.d │ │ │ │ │ ├── kernighan_ritchie.d │ │ │ │ │ ├── null_allocator.d │ │ │ │ │ ├── package.d │ │ │ │ │ ├── quantizer.d │ │ │ │ │ ├── region.d │ │ │ │ │ ├── scoped_allocator.d │ │ │ │ │ ├── segregator.d │ │ │ │ │ └── stats_collector.d │ │ │ │ ├── common.d │ │ │ │ ├── gc_allocator.d │ │ │ │ ├── mallocator.d │ │ │ │ ├── mmap_allocator.d │ │ │ │ ├── package.d │ │ │ │ ├── showcase.d │ │ │ │ └── typed.d │ │ │ ├── checkedint.d │ │ │ ├── logger/ │ │ │ │ ├── core.d │ │ │ │ ├── filelogger.d │ │ │ │ ├── multilogger.d │ │ │ │ ├── nulllogger.d │ │ │ │ └── package.d │ │ │ ├── note.md │ │ │ └── typecons.d │ │ ├── file.d │ │ ├── format.d │ │ ├── functional.d │ │ ├── getopt.d │ │ ├── internal/ │ │ │ ├── attributes.d │ │ │ ├── cstring.d │ │ │ ├── math/ │ │ │ │ ├── biguintcore.d │ │ │ │ ├── biguintnoasm.d │ │ │ │ ├── errorfunction.d │ │ │ │ └── gammafunction.d │ │ │ ├── scopebuffer.d │ │ │ ├── test/ │ │ │ │ ├── dummyrange.d │ │ │ │ ├── range.d │ │ │ │ └── uda.d │ │ │ ├── unicode_comp.d │ │ │ ├── unicode_decomp.d │ │ │ ├── unicode_grapheme.d │ │ │ ├── unicode_norm.d │ │ │ ├── unicode_tables.d │ │ │ └── windows/ │ │ │ └── advapi32.d │ │ ├── json.d │ │ ├── math.d │ │ ├── mathspecial.d │ │ ├── meta.d │ │ ├── mmfile.d │ │ ├── net/ │ │ │ ├── curl.d │ │ │ └── isemail.d │ │ ├── numeric.d │ │ ├── outbuffer.d │ │ ├── parallelism.d │ │ ├── path.d │ │ ├── process.d │ │ ├── random.d │ │ ├── range/ │ │ │ ├── interfaces.d │ │ │ ├── package.d │ │ │ └── primitives.d │ │ ├── regex/ │ │ │ ├── internal/ │ │ │ │ ├── backtracking.d │ │ │ │ ├── generator.d │ │ │ │ ├── ir.d │ │ │ │ ├── kickstart.d │ │ │ │ ├── parser.d │ │ │ │ ├── tests.d │ │ │ │ ├── tests2.d │ │ │ │ └── thompson.d │ │ │ └── package.d │ │ ├── signals.d │ │ ├── socket.d │ │ ├── stdint.d │ │ ├── stdio.d │ │ ├── string.d │ │ ├── system.d │ │ ├── traits.d │ │ ├── typecons.d │ │ ├── typetuple.d │ │ ├── uni.d │ │ ├── uri.d │ │ ├── utf.d │ │ ├── uuid.d │ │ ├── variant.d │ │ ├── windows/ │ │ │ ├── charset.d │ │ │ ├── registry.d │ │ │ └── syserror.d │ │ ├── xml.d │ │ ├── zip.d │ │ └── zlib.d │ └── testsuite/ │ ├── Makefile.am │ ├── Makefile.in │ ├── config/ │ │ └── default.exp │ ├── lib/ │ │ ├── libphobos-dg.exp │ │ └── libphobos.exp │ ├── libphobos.aa/ │ │ ├── aa.exp │ │ └── test_aa.d │ ├── libphobos.allocations/ │ │ ├── allocations.exp │ │ ├── overflow_from_existing.d │ │ └── overflow_from_zero.d │ ├── libphobos.cycles/ │ │ ├── cycles.exp │ │ ├── mod1.d │ │ ├── mod2.d │ │ └── mod3.d │ ├── libphobos.exceptions/ │ │ ├── chain.d │ │ ├── exceptions.exp │ │ ├── future_message.d │ │ ├── invalid_memory_operation.d │ │ ├── line_trace.d │ │ ├── rt_trap_exceptions.d │ │ ├── static_dtor.d │ │ ├── stderr_msg.d │ │ ├── unittest_assert.d │ │ └── unknown_gc.d │ ├── libphobos.hash/ │ │ ├── hash.exp │ │ └── test_hash.d │ ├── libphobos.imports/ │ │ ├── bug18193.d │ │ └── imports.exp │ ├── libphobos.init_fini/ │ │ ├── init_fini.exp │ │ ├── runtime_args.d │ │ ├── test18996.d │ │ └── thread_join.d │ ├── libphobos.shared/ │ │ ├── finalize.d │ │ ├── host.c │ │ ├── lib.d │ │ ├── lib_13414.d │ │ ├── liblinkdep.d │ │ ├── libloaddep.d │ │ ├── link.d │ │ ├── linkD.c │ │ ├── linkDR.c │ │ ├── link_linkdep.d │ │ ├── link_loaddep.d │ │ ├── load.d │ │ ├── loadDR.c │ │ ├── load_13414.d │ │ ├── load_linkdep.d │ │ ├── load_loaddep.d │ │ ├── plugin.d │ │ └── shared.exp │ ├── libphobos.testrunner/ │ │ └── testrunner.exp │ ├── libphobos.thread/ │ │ ├── external_threads.d │ │ ├── fiber_guard_page.d │ │ └── thread.exp │ ├── libphobos.typeinfo/ │ │ ├── comparison.d │ │ └── typeinfo.exp │ ├── libphobos.unittest/ │ │ ├── customhandler.d │ │ └── unittest.exp │ ├── test_runner.d │ └── testsuite_flags.in ├── semaphoreci.sh └── setup-gcc.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # gdc specific # ################### dev/ gcc/d/patches/series # libphobos specific # ###################### libphobos/autom4te.cache/ libphobos/config.guess libphobos/config.sub libphobos/install-sh libphobos/missing # from .hgignore # ################### .cproject .project .classpath Debug # OS generated files # ###################### .DS_Store* ehthumbs.db Icon? Thumbs.db ================================================ FILE: CHANGELOG-old.md ================================================ D Front End for GCC - Release 0.30 Last update: Saturday, 23 June, 2012 Authors: --------------------- The GNU D Compiler (GDC) project was originally started by David Friedman in 2004 until early 2007 when he disappeared from the D scene, and was no longer able to maintain GDC. Following a revival attempt in 2008, GDC is now under the lead of Iain Buclaw who has been steering the project since 2009 with the assistance of its contributors, without them the project would not have been nearly as successful as it has been. Contributors: --------------------- David Friedman for starting the GDC project. Vincenzo Ampolo for his reviving development efforts. Michael Parrott for adding initial support for the D2 frontend. Iain Buclaw for completing the port of GDC to GCC 4.2.x and later. Anders F Bjorklund for assistance in porting to OSX. Daniel Green for porting GDC to MinGW platform. Johannes Pfau for assistance in porting to Android and ARM. alexrp for standardising the platform identifiers in D. History: --------------------- Release Notes 0.30: * Support for GCC, 4.5.x and 4.6.x added * Removed support for GCC 3.4.x, 4.0.x, 4.1.x * Updated D1 to 1.069 * Updated D2 to 2.054 * Better D2 support for MinGW * Added 'optlink' calling convention for D * Added 64bit support for IASM (Work in Progress) * Moved correct implementation of delegates from GCC backend to GDC frontend glue code * Fixed Bugzilla 670, 4494, 4543, 5086, 5090, 5148, 5182, 5191, 5439, 5735, 5812 * Many other Bitbucket issues. 0.25: * Support for GCC, 4.2.x, 4.3.x, and 4.4.x added * Updated D1 to 1.063 * Updated D2 to 2.020 * Added druntime support * Fixed Bugzilla 1041, 1044, 1136, 1145, 1296, 1669, 1689, 1751, 1813, 1822, 1921, 1930, 2079, 2102, 2291, 2421 * Fixed Bitbucket issues too numerous to mention. :-) 0.24: * Removed support for GCC 3.3.x * Updated to DMD 1.020 * Fixed Bugzilla 1037, 1038 (gdc specific), 1043, 1045, 1046, 1031, 1032, 1034, 1065, 1109, 1191, 1137, 1152, 1208, 1325, 1329, 1898, 1400 * Fixed SourceForge issues 1689634, 1749622, 1721496, 1721435 0.23: * Added support for 64-bit targets * Added multilib support * Updated to DMD 1.007 * Fixed Bugzilla 984, 1013 0.22: * Added support for GCC 4.1.x * Support for GCC 3.3.x is deprecated * Updated to DMD 1.004 * Fixed Bugzilla 836, 837, 838, 839, 841, 843, 844, 889, 896 * Fixed problems with missing debug information * Added Rick Mann's -framework patch for gdmd 0.21: * Updated to DMD 1.00 * Fixed Bugzilla 695, 696, 737, 738, 739, 742, 743, 745 * Implemented GCC extended assembler * Implemented basic support for GCC attributes 0.20: * Updated to DMD 0.177 * Fixes for synchronized code generation * Better support for cross-hosted builds * Fixed Bugzilla 307, 375, 403, 575, 578 * Applied Anders Bjorklund's MacOS X build patches 0.19: * Fixed D Bugzilla bugs 141(gdc), 157, 162, 164, 171, 174, 175, 192, 229 * Applied Dave Fladebo's suggestion for -O3 in gdmd * Updated to DMD 0.162 * The version symbol for FreeBSD is now "freebsd" * Enabled std.loader for FreeBSD * Implement offsetof in assembler * Support building with Apple's GCC (4.0 only) * Fix parallel builds 0.18: * Fixes o ICE on assignment arithmetic o Problems mixing D and assembler floating point operations o Mac OS X 10.2 build problems o The gdc driver no longer compiles C source as C++ o Many others... * Improvements o Updated to DMD 0.157 o Support for PowerPC Linux o Partial support for SkyOS o Compiler can be relocated to another directory. 0.17: * Fixes o Mixed complex/float operations on GCC 4.0 (D.gnu/1485) o Applied Thomas Kuhne's HTML line number fix o Foreach/nested functions in templates (D.gnu/1514) o Use correct default initializer when allocating arrays of typedef'd types o Recursive calls to nested functions (D.gnu/1525) * Improvements o Updated to DMD 0.140 0.16: * Fixes o Concatenating a array and single element o "__arrayArg already defined" o ICE on nested foreach statements (D.gnu/1393) o Inline assembler * Functions returning floating point types * Spurious error on scaled register without a base register * Access to locals by var+ofs[EBP] now works with optimization. * Can now guess operand size from referenced variables. o Thunks errors with reimplemented interfaces (e.g., Mango) * Improvements o Support GCC 4.0.x o Updated to DMD 0.132 o Support DW_LANG_D for DWARF debugging o Support compiling multiple sources to a single object with GCC 3.4.x 0.15: * Updated to DMD 0.128 0.14: * Fixes o Classes nested in functions actually work now. o Fix for newest versions of the GNU assembler. * Improvements o Updated to DMD 0.127 0.13: * Fixes o Cygwin/MinGW assembler problem * Improvements o Updated to DMD 0.126. o Calling nested functions with delegates is faster. o The "check-target-libphobos" builds a separate library to enable runtime checks and unit tests. 0.12.1: * Fixes o Compilation errors and crashes with -fpic o Crashes with interfaces on Cygwin/MinGW o Support the -mno-cygwin option 0.12: * Fixes o Various problems building MinGW in MSYS o Mango "endless output" o Build problems with gcc 3.4.1 o Various problems revealed by dmdscript o Error message now go to standard error o DStress catch_01, catch_02, new_04, switch_19, throw_02, and others. * Improvements o Updated to DMD 0.125 o New target: AIX o GDC and DMD versions are reported with "gcc --version" o Take advantage of DMD template improvements on * Changes o std.c.unix is now std.c.unix.unix o The runtime library is now "libgphobos" to avoid conflicts with DMD. o The dmd wrapper script... + Is now named "gdmd". + Looks for gdc in its own directory instead of searching the path + Requires a comma after the "-q" option. 0.11: * Fixes o Reversed structure compare o Correct meaning of '-L' option in wrapper script o Static data GC bug on Linux * Improvements o Updated to DMD 0.121 o New target: MingGW o Included Anders F Bjorklund's man pages. o It is now possible to build a cross-compiler. Only MingGW is supported out-of-the-box, however. 0.11pre1: * Fixes o Incorrect/missing thunks o Problems when the C char type is unsigned o Side effects in void type return expressions o Calling a particular static ancestor method. o Install of /etc/c/zlib.d o Support for built-in function security patch. o More... * Improvements o Updated to DMD 0.113 o Phobos is now built as target library (i.e., no need for a separate build step) o Boehm-gc is no longer used and the Java package is no longer required. o Inline assembler for x86 (there are some limitations -- these need to be documented) o Included Anders Bjorklund's patches to enable the use of frameworks on Darwin. o On Darwin, D object code can be linked with the system gcc. Likewise, gdc can link C++ object code built by the system g++. o Improved support for alternate C main functions (see d/phobos/internal/{cmain.d,rundmain.d}) * Notes o The gdc driver no longer accepts D source files without the ".d" extension. The dmd wrapper script still supports this. 0.10: * Fixes o Complex number comparisons with NAN operands o Cleaned up Phobos installation. o Non-virtual method calls o Code generation with -mpowerpc64 o Break in labeled switch statement * Improvements o Updated to DMD 0.110 o Applied Thomas Kohne's and Anders Bjorklund's HTML patches. o Added Thomas Kohne's "dump source" code o Phobos Makefile now supports the DESTDIR variable 0.9: * Fixes o Detect use of non-static methods in a static context o Enumerated types are signed by default o Anders Bjorklund's patch for HTML infinite looping o va_start is now a template. o Delegate expressions for struct methods now work o bswap uses unsigned right shift o Fixed several problems with the dmd script o Fixed crash when compiling with debug information o Handle referenes to instance variables without "this" o Fixed ICE for interfaces with multiple inheritence o Fix id.h dependcy so concurrent make will work * Improvements o Updated to DMD 0.109 * Notes o The (undocumented) BitsPer{Pointer,Word} version identifiers are now prefixed with "GNU_" o Private declarations are now exported from object files 0.8: * Fixes o std.loader module is now enabled o Proper casting from complex and imaginary types o Diagnostics are now GCC-style o Exceptions don't leak memory anymore o The gdc command processes ".html" as D source files. o ICE for classes declared in a function o ICE on empty "if" statement o Test for existence of "execvpe", "fwide", and "fputwc" before using them o Corrected floating point "min_10_exp" properties o std.date.getLocalTZA returns a correct values o Using gdc to link with C++ should now just need "-lstdc++" * Improvements o Debugging information is vastly improved o DLLs can be built on Cygwin * Notes o "DigitalMars" is not longer defined as a version symbol Supported Systems: --------------------- * GCC 4.8.x * Linux (tested on Debian and Ubuntu x86, x86_64) * Mac OS X 10.3.9 and 10.4.x * FreeBSD 6.x, 7.x * Cygwin * MinGW * AIX (tested on 5.1) Similar versions of the above systems should work and other Unix platforms may work. Although the compiler will probably work on most architectures, the D runtime library will still need to be updated to support them. Requirements --------------------- * The base developer package for your system. Generally, this means binutils and a C runtime library. * The gdmd wrapper script requires Perl. Links --------------------- * This Project -- https://github.com/D-Programming-GDC/GDC/ * Previous home -- http://dgcc.sourceforge.net/ * The D Programming Language -- http://www.digitalmars.com/d/ * D Links Page -- http://digitalmars.com/d/dlinks.html * The D.gnu newsgroup -- news://news.digitalmars.com/D.gnu * For general D discussion, the digitalmars.D and digitalmars.D.bugs newsgroups * The GNU Compiler Collection -- http://gcc.gnu.org/ * Mac OS X binary distribution -- http://gdcmac.sourceforge.net/ Contact --------------------- Iain Buclaw e-mail: ibuclaw@gdcproject.org Status --------------------- Known Issues * See the DStress (http://svn.kuehne.cn/dstress/www/dstress.html) page for known failing cases. * Debugging information may have a few problems if you are using a version of gdb that is not 7.2 or later. To enable D name mangling in gdb, apply this patch. (http://dsource.org/projects/gdb-patches/) * Some targets do not support once-only linking which is needed for templates to work smoothly. A workaround is to manually control template emission. See the -femit-templates option below. For Darwin, Apple's GCC 3.x compiler supports one-only linking, but GDC does not build with those sources. There are no problems with the stock GCC 4.x on Darwin. * Complex floating point operations may not work the same as DMD. * Some math functions behave differently due to different implementations of the extended floating-point type. * Volatile statements may not always do the right thing. * Because of a problem on AIX, the linker will pull in more modules than needed. See: http://groups-beta.google.com/groups?hl=en&q=%22large+executables+on+AIX%22&qt_s=Search * Some C libraries (Cygwin, MinGW, AIX) don't handle floating-point formatting and parsing in a standard way. Known Differences from DMD * The type of _argptr in variadic functions is the target-specific va_list type. The only portable way to use _argptr is the std.stdarg.va_arg template. In particular, you cannot construct a va_list from a pointer to data and expect it to work. * The D Inline assembler is not supported by GDC. * Similarly, naked functions are not supported by GDC either. * Currently, GDC uses the C calling convention for all functions except those declared extern (Windows). * GDC allows catch statements in finally blocks. * pragma(lib) is not supported. * Some targets do not have a distinct extended floating-point type. On these targets, real and double are the same size. * On Win32 targets, GDC allocates 12 bytes for the real type, while DMD allocates 10 bytes. This also applies to the components of the creal type. License --------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . ================================================ FILE: README-MINGW.md ================================================ GDC should build for MINGW and MINGW64 targets, however not much testing has been done. ## Building ## The following patches are required for binutils / gcc to fix TLS support: * https://github.com/venix1/MinGW-GDC/blob/master/patches/mingw-tls-binutils-2.23.1.patch * https://github.com/venix1/MinGW-GDC/blob/master/patches/mingw-tls-gcc-4.8.patch This patch is required to fix a bug in GCC buildscripts: * https://github.com/venix1/MinGW-GDC/blob/master/patches/gcc/0001-Remove-fPIC-for-MinGW.patch ## SEH ## SEH should work for 64 bit windows targets. ================================================ FILE: README.md ================================================ [![Build Status](https://semaphoreci.com/api/v1/d-programming-gdc/gdc/branches/master/badge.svg)](https://semaphoreci.com/d-programming-gdc/gdc) ### What is GDC? GDC is a GPL implementation of the D compiler which integrates the open source D front end with GCC. The GNU D Compiler (GDC) project was originally started by David Friedman in 2004 until early 2007 when he disappeared from the D scene, and was no longer able to maintain GDC. Following a revival attempt in 2008, GDC is now under the lead of Iain Buclaw who has been steering the project since 2009 with the assistance of its contributors, without them the project would not have been nearly as successful as it has been. Documentation on GDC is available from [the wiki][wiki]. Any bugs or issues found with using GDC should be reported at [our bugzilla site][bugs]. For help with GDC, the [D.gnu][maillist] mailing list is the place to go with questions or problems. Work is currently under way to merge GDC into a future release of GCC. Assistance of any sort during this time would be invaluably appreciated. Feel free to contact via [email][email] or join in at #d.gdc on FreeNode. ### Building The master branch of this project closely follows [GCC development branch][gcc-devel], which if you intend to use GDC for production applications, is likely not the version of GCC you want to build against. For versions of GDC compatible with GCC releases, checkout one of the following branches: * [GCC 5.x](https://github.com/D-Programming-GDC/GDC/tree/gdc-5) * [GCC 6.x](https://github.com/D-Programming-GDC/GDC/tree/gdc-6) * [GCC 7.x](https://github.com/D-Programming-GDC/GDC/tree/gdc-7) * [GCC 8.x](https://github.com/D-Programming-GDC/GDC/tree/gdc-8) [home]: http://gdcproject.org [wiki]: http://wiki.dlang.org/GDC [bugs]: http://bugzilla.gdcproject.org [maillist]: http://forum.dlang.org/group/D.gnu [email]: mailto:ibuclaw@gdcproject.org [gcc-devel]: http://gcc.gnu.org/git/?p=gcc.git;a=shortlog ================================================ FILE: gcc/d/ChangeLog ================================================ 2018-10-26 Eugene Wissner * Make-lang.in (selftest-d): New. * d-diagnostic.cc (vwarning): Fix warning emitting. 2018-10-22 Iain Buclaw * d-spec.cc (lang_specific_driver): Always link against phobos if any input file is given. 2018-10-21 Iain Buclaw * d-lang.cc (d_get_alias_set): Always return zero. 2018-10-21 Iain Buclaw * intrinsics.cc (maybe_set_intrinsic): Don't set built-in flag on unsupported pow() overloads. 2018-10-20 Iain Buclaw * expr.cc (ExprVisitor::binop_assignment): Call stabilize_reference on LHS construct if it has side effects. 2018-10-20 Iain Buclaw * intrinsics.cc (clear_intrinsic_flag): Remove function. (maybe_expand_intrinsic): Remove clear_intrinsic_flag call. 2018-10-20 Iain Buclaw * intrinsics.cc (expand_intrinsic_copysign): Use mathfn_built_in to determine correct built-in to call. (expand_intrinsic_pow): Likewise. 2018-10-20 Iain Buclaw * intrinsics.cc (expand_intrinsic_sqrt): Remove implicit int to double conversion. (expand_intrinsic_pow): Likewise. 2018-10-20 Iain Buclaw * d-codegen.cc (get_frame_for_symbol): Use error_at. (build_frame_type): Likewise. (get_framedecl): Likewise. * d-frontend.cc (getTypeInfoType): Likewise. * d-lang.cc (d_parse_file): Likewise. * decl.cc (apply_pragma_crt): Likewise. (DeclVisitor::visit(PragmaDeclaration)): Likewise. (DeclVisitor::visit(StructDeclaration)): Likewise. (DeclVisitor::visit(StructDeclaration)): Likewise. (DeclVisitor::finish_vtable): Likewise. (DeclVisitor::visit(ClassDeclaration)): Likewise. (DeclVisitor::visit(InterfaceDeclaration)): Likewise. (DeclVisitor::visit(EnumDeclaration)): Likewise. (DeclVisitor::visit(VarDeclaration)): Likewise. * toir.cc (IRVisitor::check_goto): Likewise. (IRVisitor::check_previous_goto): Likewise. (IRVisitor::visit(ThrowStatement)): Likewise. * typeinfo.cc (build_typeinfo): Likewise. 2018-10-20 Iain Buclaw * d-codegen.cc (get_array_length): Use quoted format flag in message. (d_build_call): Likewise. * d-lang.cc (d_handle_option): Likewise. * decl.cc (apply_pragma_crt): Likewise. (DeclVisitor::finish_vtable): Likewise. * expr.cc (ExprVisitor::visit(CmpExp)): Likewise. (ExprVisitor::visit(ArrayLengthExp)): Likewise. (ExprVisitor::visit(DeleteExp)): Likewise. (ExprVisitor::visit(RemoveExp)): Likewise. (ExprVisitor::visit(RemoveExp)): Likewise. (ExprVisitor::visit(CallExp)): Likewise. (ExprVisitor::visit(DotVarExp)): Likewise. (ExprVisitor::visit(VarExp)): Likewise. (ExprVisitor::visit(ScopeExp)): Likewise. (ExprVisitor::visit(TypeExp)): Likewise. (build_expr): Likewise. * typeinfo.cc (build_typeinfo): Likewise. 2018-10-20 Iain Buclaw * d-diagnostic.cc (d_diagnostic_report_diagnostic): Skip translation by instead calling diagnostic_set_info_translated. 2018-10-20 Iain Buclaw * d-tree.h (bool_type_node): Rename to d_bool_type. (byte_type_node): Rename to d_byte_type. (ubyte_type_node): Rename to d_ubyte_type. (short_type_node): Rename to d_short_type. (ushort_type_node): Rename to d_ushort_type. (int_type_node): Rename to d_int_type. (uint_type_node): Rename to d_uint_type. (long_type_node): Rename to d_long_type. (ulong_type_node): Rename to d_ulong_type. (cent_type_node): Rename to d_cent_type. (ucent_type_node): Rename to d_ucent_type. 2018-10-20 Iain Buclaw * expr.cc (ExprVisitor::visit(PowExp)): Remove function. 2018-10-19 Iain Buclaw * d-attribs.c: Rename to d-attribs.cc. * d-spec.c: Rename to d-spec.cc. 2018-10-19 Iain Buclaw * d-lang.cc (d_gimplify_expr): Don't handle TREE_THIS_VOLATILE. 2018-10-19 Iain Buclaw * d-diagnostic.cc (vwarning): Update to use Diagnostic enum. (vdeprecation): Likewise. (vdeprecationSupplemental): Likewise. * d-lang.cc (d_init_options): Explicitly set warnings and deprecations as DIAGNOSTICoff. (d_handle_option): Update to use Diagnostic enum. (d_post_options): Likewise. 2018-10-18 Iain Buclaw * d-diagnostic.cc (expand_format): Rename to expand_d_format. Updated all callers. 2018-10-17 Iain Buclaw * d-codegen.cc (get_linemap): Rename function to make_location_t. Updated all callers. * d-tree.h (get_linemap): Rename declaration to make_location_t. 2018-10-17 Iain Buclaw * expr.cc (ExprVisitor::binary_op): Use POINTER_DIFF_EXPR. 2018-10-17 Iain Buclaw * intrinsics.cc (expand_intrinsic_bsf): Assert that built-in function code is not END_BUILTINS. (expand_intrinsic_bsr): Likewise. (expand_intrinsic_bswap): Likewise. (expand_intrinsic_popcnt): Likewise. 2018-10-17 Iain Buclaw * config-lang.in (gtfiles): Add modules.cc. * modules.cc: Include gt-d-modules.h. (module_info): Mark with GTY. (static_ctor_list): Likewise. (static_dtor_list): Likewise. 2018-10-17 Iain Buclaw * d-spec.c (lang_specific_driver): Use strrchr and strcmp to check input file suffix. 2018-10-17 Iain Buclaw * d-spec.c (phobos_action): New enum. (library): Rename to phobos_library. (lang_specific_driver): Update to use phobos_library. (lang_specific_pre_link): Likewise. 2018-10-16 Iain Buclaw * d-frontend.cc (Port::writelongLE): Remove function. (Port::writelongBE): Remove function. 2018-10-16 Iain Buclaw * d-convert.cc (convert): Remove goto maybe_fold. 2018-10-16 Iain Buclaw * d-codegen.cc (warn_for_null_address): New function. (build_boolop): Warn about comparing address of decl to null. * d-convert.cc (decl_with_nonnull_addr_p): New function. (d_truthvalue_conversion): Warn about evaluating address as boolean. * d-tree.h (decl_with_nonnull_addr_p): Add declaration. * lang.opt (Waddress): New option. 2018-10-16 Iain Buclaw * d-codegen.cc (d_array_length): Assert that argument type is a dynamic array. (d_array_ptr): Likewise. (d_array_value): Likewise. (delegate_method): Assert that argument type is a delegate. (delegate_object): Likewise. 2018-10-16 Iain Buclaw * d-attribs.c (handle_malloc_attribute): Use gcc_assert instead of gcc_unreachable. (handle_pure_attribute): Likewise. (handle_nothrow_attribute): Likewise. 2018-10-16 Iain Buclaw * Make-lang.in: Rename compiler proper to d21. * config-lang.in (compilers): Rename compiler to d21. * d-spec.c (lang_specific_driver): Update comments. * lang-specs.h: Rename compiler to d21. 2018-10-16 Iain Buclaw * lang.opt: Add missing periods to the ends of sentences. 2018-10-16 Iain Buclaw * d-lang.cc (d_handle_option): Remove handling of -fdeps. (d_parse_file): Don't generate module dependencies. * lang.opt (fdeps, fdeps=): Remove options. (fintfc, fintfc-dir=, fintfc-file=): Remove options. (ftransition=safe): Remove option. 2018-10-16 Iain Buclaw * d-lang.cc (d_init_ts): Remove handling of IASM_EXPR. (d_gimplify_expr): Likewise. * d-tree.def (IASM_EXPR): Remove tree code. 2018-10-15 Iain Buclaw * d-attrib.c (attr_noreturn_exclusions): Attribute not mutually exclusive with self. * typeinfo.cc (TypeInfoVisitor::layout_interfaces): Assert that base class vtable is found in interface. 2018-10-14 Iain Buclaw * d-target.cc (Target::getTargetInfo): Handle floatAbi, objectFormat, and cppRuntimeLibrary traits. * d-target.def (d_float_abi_type): New hook. (d_object_format): New hook. 2018-10-08 Iain Buclaw * Make-lang.in (d-warn): Use strict warnings. * d-frontend.cc (Compiler::onImport): New function. * decl.cc (DeclVisitor): Add using Visitor::visit. * expr.cc (ExprVisitor): Likewise. * imports.cc (ImportVisitor): Likewise. * toir.cc (IRVisitor): Likewise. * typeinfo.cc (TypeInfoVisitor): Likewise. (TypeInfoDeclVisitor): Likewise. (SpeculativeTypeVisitor): Likewise. * types.cc (TypeVisitor): Likewise. * verstr.h: Update to 2.082.1-beta.1 2018-10-01 Iain Buclaw * d-frontend.cc: Include compiler.h, errors.h, expression.h. (genCmain): Rename function to Compiler::genCmain. (Compiler::paintAsType): New function. (Compiler::loadModule): New function. (getTypeInfoType): Call error function directly. * d-lang.cc (deps_write): Use hash_set for dependency tracking. (d_init_options): Handle -ftransition=dtorfields option. (d_parse_file): Call Compiler::loadModule. * d-target.cc: Remove include identifier.h, module.h. (Target::paintAsType): Remove function. (Target::loadModule): Remove function. (Target::getTargetInfo): New function. * lang.opt (ftransition=dtorfields): New option. * typeinfo.cc (build_typeinfo): Call error function directly. 2018-10-01 Eugene Wissner * decl.cc (finish_thunk): Adjust call to cgraph_node::create_thunk. 2018-09-25 Eugene Wissner * d-codegen.cc (d_assert_call): Don't make STRING_CSTs larger than they are. * expr.cc (ExprVisitor::visit(StringExp)): Likewise. * typeinfo.cc (TypeInfoVisitor::layout_string): Likewise. 2018-09-24 Iain Buclaw * d-builtins.cc: Include expression.h, identifier.h. * d-codegen.cc: Include identifier.h. * d-convert.cc: Include declaration.h. * d-frontend.cc: Include identifier.h. * d-lang.cc: Include declaration.h, expression.h, identifier.h. (d_parse_file): Call moduleToBuffer to get string dump of contents. * d-target.cc: Include declaration.h, expression.h, identifier.h. * expr.cc: Include identifier.h. * imports.cc: Include identifier.h. * intrinsics.cc: Include identifier.h. * modules.cc: Include identifier.h. * toir.cc: Include expression.h, identifier.h. * typeinfo.cc: Include expression.h, identifier.h. * types.cc: Include expression.h, identifier.h. 2018-09-18 Iain Buclaw * d-lang.cc (deps_write): Use toChars accessor to get module path. * decl.cc (get_symbol_decl): Use get_identifier_with_length to get mangle override identifier node. 2018-09-10 Iain Buclaw * d-lang.cc (d_init_options): Set-up global.params.argv0 as D array. (d_parse_file): Use global.params.argv0 pointer field as format value. * intrinsics.cc (maybe_expand_intrinsic): Handle INTRINSIC_EXP. * intrinsics.def (EXP): Add CTFE intrinsic. 2018-09-07 Iain Buclaw * d-lang.cc: Include errors.h, mars.h. * decl.cc: Include errors.h. * typeinfo.cc: Include globals.h, errors.h. * verstr.h: Update to 2.082.0 2018-09-05 Eugene Wissner * d-frontend.cc (eval_builtin): Replace DECL_BUILT_IN with fndecl_built_in_p. 2018-09-04 Iain Buclaw * d-frontend.h: Remove file, and all sources that include it. * d-lang.cc: Include dmd/doc.h and dmd/mangle.h. * d-target.cc: Include dmd/mangle.h. * decl.cc: Include dmd/mangle.h. 2018-08-25 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Add iasm.o, iasmgcc.o (d.tags): Scan dmd/root/*.h * d-builtins.cc (build_frontend_type): Update callers for new front-end signatures. (d_init_versions): Add D_ModuleInfo, D_Exceptions, D_TypeInfo. * d-diagnostic.cc (vwarning): Increment gagged warnings error if gagging turned on. (vdeprecation): Likewise. * d-frontend.cc (asmSemantic): Remove function. * d-lang.cc (d_handle_option): Remove case for OPT_fproperty. * d-target.cc (Target::_init): Remove int64Mangle and uint64Mangle. * lang.opt (fproperty): Remove option. * toir.cc (IRVisitor::visit(ExtAsmStatement)): Rename override to GccAsmStatement. * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Use int for collecting ClassFlags. * (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Use int for collecting StructFlags. 2018-07-23 Eugene Wissner * d-lang.cc (d_handle_option): Change function argument to HOST_WIDE_INT. * lang.opt (Walloca-larger-than=, Wno-alloca-larger-than): New options. * opt.texi (Walloca-larger-than=, Wno-alloca-larger-than): Likewise. 2018-07-21 Iain Buclaw * decl.cc (get_symbol_decl): Set all generated static symbols as DECL_EXTERNAL. Move logic for determining TREE_STATIC ... (start_function): ... here. (reset_decl_tls_model): New function. (d_finish_decl): Call it on finished variables. 2018-07-14 Iain Buclaw * Make-lang.in (d.tags): Rename dfrontend to dmd. * d-attribs.c: Rename dfrontend includes to dmd. * d-builtins.cc: Likewise. * d-codegen.cc: Likewise. * d-convert.cc: Likewise. * d-diagnostic.cc: Likewise. * d-frontend.cc: Likewise. * d-incpath.cc: Likewise. * d-lang.cc: Likewise. * d-longdouble.cc: Likewise. * d-target.cc: Likewise. * decl.cc: Likewise. * expr.cc: Likewise. * imports.cc: Likewise. * intrinsics.cc: Likewise. * modules.cc: Likewise. * runtime.cc: Likewise. * toir.cc: Likewise. * typeinfo.cc: Likewise. * types.cc: Likewise. 2018-07-14 Iain Buclaw * types.cc (same_type_p): Check type codes match before checking equivalence. 2018-07-13 Iain Buclaw * expr.cc (ExprVisitor::visit(CmpExp)): Remove lowering of static and dynamic array comparisons. * runtime.def (ADCMP2): Remove define. (SWITCH_STRING): Likewise. (SWITCH_USTRING): Likewise. (SWITCH_DSTRING): Likewise. (SWITCH_ERROR): Likewise. * toir.cc (IRVisitor::visit(SwitchStatement)): Remove lowering of string switch statements. (IRVisitor::visit(SwitchErrorStatement)): Remove lowering of throwing SwitchErrors. 2018-07-12 Iain Buclaw * Make-lang.in (CHECKING_DFLAGS): New variable. (ALL_DFLAGS): Add -frelease when front-end tree checking is disabled. 2018-07-08 Iain Buclaw * verstr.h: Update to 2.081.1 2018-07-08 Iain Buclaw * d-lang.cc: Include id.h. 2018-07-06 Iain Buclaw * d-codegen.cc (lower_struct_comparison): Evaluate side effects of empty struct. (build_struct_comparison): Likewise. 2018-07-06 Iain Buclaw * typeinfo.cc (TypeInfoVisitor::layout_interfaces): Only generate an interface vtable for classes. (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Likewise. 2018-07-05 Iain Buclaw * d-lang.cc (deps_write): Ignore __main module. (d_handle_option): Handle -fmain option. (d_parse_file): Generate D main function if requested. * lang.opt (fmain): New option. 2018-07-04 Iain Buclaw * d-lang.cc (d_handle_option): Handle options -ftransition=dip1008 and -ftransition=intpromote. * lang.opt (ftransition=dip1008): New option. (ftransition=intpromote): New options. 2018-07-04 Iain Buclaw * d-builtins.cc (d_build_builtins_module): Export __builtin_clonglong and __builtin_culonglong to gcc builtins module. 2018-07-04 Iain Buclaw * d-builtins.cc (d_init_versions): Update condition for enabling version assert. * d-lang.cc (d_init_options): Remove setting of flags that are default initialized statically. (d_init_options_struct): Update condition for setting bounds check. (d_handle_option): Update condition for setting flags for enabling asserts and switch errors. (d_post_options): Likewise. * expr.cc (ExprVisitor::visit(AssertExp)): Update condition for generating assert code. 2018-07-04 Eugene Wissner * d-spec.c: Include opt-suggestions.h containing option_proposer used by gcc.h. 2018-07-01 Iain Buclaw * verstr.h: Update to 2.081.0-rc.1 2018-07-01 Iain Buclaw * decl.cc (walk_pragma_cdtor): New function. (DeclVisitor::visit(PragmaDeclaration)): Handle pragma crt_constructor and crt_destructor. 2018-07-01 Iain Buclaw * decl.cc (get_symbol_decl): Implicitly convert return type of 'void' main to 'int' for both C and D entry functions. * toir.cc (IRVisitor::visit(ReturnStatement)): Likewise. 2018-07-01 Iain Buclaw * d-target.cc (Target::_init): Set int64Mangle, uint64Mangle, twoDtorInVariable. * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Use tidtor symbol for destructor. (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Likewise. 2018-06-30 Iain Buclaw * expr.cc (ExprVisitor::visit(FuncExp)): Don't error about nested delegate literals. 2018-06-29 Iain Buclaw * d-frontend.cc (eval_builtin): Allow both gcc and frontend builtins. * intrinsics.cc (call_builtin_fn): Use convert. (expand_intrinsic_sqrt): Use fold_convert. (expand_intrinsic_copysign): New function. (expand_intrinsic_pow): New function. (maybe_expand_intrinsic): Handle many math intrinsics. * intrinsics.def (EXPM1, EXP2, LOG, LOG2, LOG10, ROUND, FLOORF), (FLOOR, FLOORL, CEILF, CEIL, CEILL, TRUNC, FMIN, FMAX, COPYSIGN), (POW, FMA): Add math intrinsics. 2018-06-29 Iain Buclaw * Make-lang.in (WARN_DFLAGS): New variable. (ALL_DFLAGS): Use coverage and warn flags. 2018-06-27 Iain Buclaw * d-builtins.cc (d_init_versions): Add version D_BetterC. * d-codegen.cc (find_aggregate_field): Move to decl.cc (build_class_instance): Move to decl.cc, make static. * d-frontend.cc (getTypeInfoType): Issue warning when -fno-rtti. * d-lang.cc (d_init): Check for global useExceptions. (d_handle_option): Handle OPT_fdruntime, OPT_fexceptions, OPT_frtti. (d_post_options): Set flags if -fno-druntime was given. * d-tree.h (build_class_instance): Remove declaration. (have_typeinfo_p): Add declaration. (build_typeinfo): Update signature. * decl.cc (DeclVisitor::finish_vtable): New function. (DeclVisitor::visit(StructDeclaration)): Generate typeinfo only if found in library. (DeclVisitor::visit(EnumDeclaration)): Likewise. (DeclVisitor::visit(InterfaceDeclaration)): Likewise. (DeclVisitor::visit(ClassDeclaration)): Likewise. Exit early if semantic error occurred during final semantic. * decl.cc: Update all callers of build_typeinfo. * lang.opt (fdruntime): New option. (fmoduleinfo): Add flag for option. (frtti): New option. * modules.cc (build_module_tree): Check for global useModuleInfo. * toir.cc (IRVisitor::visit(ThrowStatement)): Check for global useExceptions. * typeinfo.cc: Include options.h. (make_frontend_typeinfo): Set members and storage class fields on compiler-generated typeinfo. (have_typeinfo_p): New function. (TypeInfoVisitor::layout_base): Add reference to vtable only if typeinfo found in library. (TypeInfoVisitor::visit): Update all callers of build_typeinfo. (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Always set RTInfo field, even if null. (build_typeinfo): Add error if -fno-rtti passed on commandline. 2018-06-26 Iain Buclaw * types.cc (TypeVisitor::visit(TypeClass)): Handle get_symbol_decl returning an error_mark_node. 2018-06-24 Iain Buclaw * d-tree.h (lang_identifier): Add daggregate field. (IDENTIFIER_DAGGREGATE): New macro. (mangle_decl): Declare. * decl.cc (mangle_decl): Remove static linkage. * types.cc (TypeVisitor::visit(TypeStruct)): Handle duplicate declarations of type symbol. (TypeVisitor::visit(TypeClass)): Likewise. 2018-06-22 Iain Buclaw * verstr.h: Update to 2.081.0-beta.2 2018-06-22 Iain Buclaw * decl.cc (DeclVisitor::visit(FuncDeclaration)): Move function unnesting to... (get_symbol_decl): ... here. 2018-06-22 Iain Buclaw * d-lang.cc (d_post_options): Set global showColumns parameter. 2018-06-22 Iain Buclaw * d-builtins.cc (d_init_versions): Replace BOUNDSCHECK enum values with CHECKENABLE. * d-codegen.cc (array_bounds_check): Likewise. * d-frontend.cc (Global::init_): Don't set params initialized by the frontend. * d-lang.cc (d_init_options): Update initialization of global struct. (d_handle_option): Replace BOUNDSCHECK enum values with CHECKENABLE. Update handling of debug and version identifiers. (d_post_options): Replace BOUNDSCHECK enum values with CHECKENABLE. Handle debug and version identifiers given on the command line. (d_parse_file): Use global versionids to get full list of predefined identifiers. 2018-06-22 Iain Buclaw * d-frontend.cc (Global::startGagging): Remove function. (Global::endGagging): Remove function. (Global::increaseErrorCount): Remove function. (Loc::equals): Remove function. (retStyle): Remove function. (getTypeInfoType): Update signature. * d-target.cc (Target::isVectorOpSupported): Don't handle unordered expressions. (Target::prefixName): Remove function. (Target::cppParameterType): New function. (Target::isReturnOnStack): New function. 2018-06-22 Iain Buclaw * decl.cc (DeclVisitor::visit(ClassDeclaration)): Use ClassDeclaration::vtblSymbol to access vtable symbol. (get_vtable_decl): Likewise. 2018-06-22 Iain Buclaw * d-diagnostic.cc (expand_format): Handle whitespace format specifier. (d_diagnostic_report_diagnostic): Change signature, updated all callers. Handle writing messages verbatim. (vmessage): New function. * d-lang.cc (d_parse_file): Use message to emit verbose diagnostics. * decl.cc (DeclVisitor::visit(FuncDeclaration)): Likewise. (get_symbol_decl): Likewise. 2018-06-22 Iain Buclaw * d-builtins.cc (build_frontend_type): Update call to TypeVector::create. Use Type::merge2 to complete type. (maybe_set_builtin_1): Update call to AttribDeclaration::include. * d-codegen.cc (declaration_type): Use Type::merge2 to complete type. (type_passed_as): Likewise. * d-convert.cc (convert_expr): Use ClassDeclaration::isCPPclass. * d-frontend.cc (genCmain): Use new semantic entrypoints. * d-lang.cc (d_parse_file): Likewise. (d_build_eh_runtime_type): Use ClassDeclaration::isCPPclass. * decl.cc (DeclVisitor::visit(AttribDeclaration)): Update call to AttribDeclaration::include. (get_symbol_decl): Replace PROT enum values with Prot. * expr.cc (ExprVisitor::visit): Merge AndAndExp and OrOrExp into LogicalExp visitor method. * modules.cc (get_internal_fn): Replace PROT enum value with Prot. * toir.cc (IRVisitor::visit): Use ClassDecalration::isCPPclass. * typeinfo.cc (make_frontend_typeinfo): Use new semantic entrypoints. (TypeInfoVisitor::visit): Use Type::merge2 to complete type. * types.cc (layout_aggregate_members): Update call to AttribDeclaration::include. (layout_aggregate_type): Use ClassDeclaration::isCPPclass. 2018-06-22 Iain Buclaw * Makefile.in (d.mostlyclean): Remove cleanup of verstr.h. 2018-06-20 Iain Buclaw * Makefile.in (D_FRONTEND_OBJS): Add compiler.o, ctorflow.o, dsymbolsem.o, lambdacomp.o, longdouble.o, parsetimevisitor.o, permissivevisitor.o, port.o, semantic2.o, semantic3.o, templateparamsem.o, transitivevisitor.o (D_INCLUDES): Rename ddmd to dmd. (d/%.o): Likewise. 2018-06-16 Iain Buclaw * Makefile.in (DMD_WARN_CXXFLAGS, DMD_COMPILE) (DMDGEN_COMPILE): Remove variables. (ALL_DFLAGS, DCOMPILE.base, DCOMPILE, DPOSTCOMPILE, DLINKER) (DLLINKER): New variables. (D_FRONTEND_OBJS): Add new frontend objects. (D_GENERATED_SRCS, D_GENERATED_OBJS): Remove variables. (D_ALL_OBJS): Remove D_GENERATED_OBJS. (cc1d): Use DLLINKER command to produce compiler. (d.mostlyclean): Remove generated sources. (CFLAGS-d/id.o, CFLAGS-d/impcnvtab.o): Remove recipes. (d/%.o): Use DCOMPILE and DPOSTCOMPILE to build frontend. (d/idgen, d/impcvgen, d/id.c, d/id.h, d/impcnvtab.c) (d/verstr.h): Remove recipes. * config-lang.in (boot_language): New variable. * d-frontend.cc (inlineCopy): Remove function. (global): Remove variable. * d-diagnostics.cc (error, errorSupplemental): Remove functions. (warning, warningSupplemental): Likewise. (deprecation, deprecationSupplemental): Likewise. * d-lang.cc (d_init_options): Initialize D runtime. * d-longdouble.cc (CTFloat::zero, CTFloat::one, CTFloat::minusone) (CTFloat::half): Remove variables. * d-target.cc (Target::ptrsize, Target::c_longsize, Target::realsize) (Target::realpad, Target::realalignsize, Target::reverseCppOverloads) (Target::cppExceptions, Target::classinfosize) (Target::maxStaticDataSize): Remove variables. * verstr.h: New file. 2018-05-28 Iain Buclaw * expr.cc (ExprVisitor::visit(StringExp)): Copy string literal from the frontend to a null terminated string. 2018-05-21 Iain Buclaw * expr.cc (ExprVisitor::binary_op): Don't do complex conversions if already handling excess precision. 2018-04-02 Iain Buclaw * d-lang.cc (doing_semantic_analysis_p): New variable. (d_parse_file): Set when in semantic pass. * d-tree.h (doing_semantic_analysis_p): Add declaration. * intrinsics.cc (maybe_expand_intrinsic): Test for doing_semantic_analysis_p. 2018-03-18 Iain Buclaw * d-codegen.cc (stabilize_expr): Move modify expression rewrite... * expr.cc (ExprVisitor::binop_assignment): ... here. 2018-03-11 Iain Buclaw * expr.cc (ExprVisitor::visit(StringExp)): Include null terminator in length when calling build_String. Generate static array string literals as array constructors. 2018-03-04 Iain Buclaw * d-lang.cc (d_handle_option): Rename OPT_fintfc cases to OPT_H. * gdc.texi (Code Generation): Rename -fintfc options to -H. * lang-specs.h: Add H, Hd, and Hf options. * lang.opt (H, Hd, Hf): New options. (fintfc, fintfc-dir=, fintfc-file=): Deprecate and alias new options. 2018-03-04 Iain Buclaw * lang.opt (fdeps, fdeps=): Deprecate options. * gdc.texi (Code Generation): Remove deprecated fdeps options. 2018-02-25 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Remove inline.o and inlinecost.o. 2018-02-24 Iain Buclaw * d-frontend.cc (CTFloat::fabs): Assign result to real_t directly. (CTFloat::ldexp): Likewise. * d-longdouble.cc (longdouble::from_int): Remove function. (longdouble::from_uint): Likewise. (longdouble::to_int): Update Signature. (longdouble::to_uint): Likewise. (longdouble::operator): Likewise. (longdouble::add): New function, move operator overload headers. (longdouble::sub, longdouble::mul, longdouble::div): Likewise. (longdouble::mod, longdouble::neg): Likewise. (longdouble::cmp, longdouble::equals): Likewise. * d-target.cc (Target::_init): Construct assignment into real_t directly. 2018-02-19 Iain Buclaw * Make-lang.in (DMD_WARN_CXXFLAGS): Only filter out -Wmissing-format-attribute from WARN_CXXFLAGS. 2018-02-18 Iain Buclaw * d-builtins.cc (build_frontend_type): Set alignment of structs in frontend. 2018-02-17 Iain Buclaw * d-incpath.cc (add_environment_paths): Remove function. * gdc.texi (Environment Variables): Remove section. 2018-02-10 Iain Buclaw * expr.cc (ExprVisitor::AssertExp): Use builtin expect to mark assert condition as being likely true. 2018-02-11 Iain Buclaw * lang.opt (fd-vgc, fd-verbose, fd-vtls): Remove options. (femit-moduleinfo, femit-templates): Likewise. (fmake-deps, fmake-mdeps): Likewise. (fin, fout, fXf): Likewise. 2018-01-28 Iain Buclaw * gdc.texi (Runtime Options): Remove deprecated -fproperty option. 2018-01-27 Iain Buclaw * d-lang.cc (d_gimplify_expr): Gimplify all CALL_EXPR_ARGS_ORDERED call arguments, not just non-constant. 2018-01-27 Iain Buclaw * decl.cc (DeclVisitor::visit(VarDeclaration)): Don't reuse existing temporary for TARGET_EXPR. (declare_local_var): Push all variables to current binding level. 2018-01-27 Iain Buclaw * toir.cc (build_function_body): Set input_location. 2018-01-23 Iain Buclaw * d-codegen.cc (build_frame_type): Don't add chain field for functions without context pointer. (build_closure): Don't set chain field for functions without context pointer. 2018-01-21 Iain Buclaw * decl.cc (DeclVisitor::visit(StructDeclaration)): Mark compiler generated symbols as DECL_ONE_ONLY instead of DECL_COMDAT. (DeclVisitor::visit(ClassDeclaration)): Likewise. (DeclVisitor::visit(InterfaceDeclaration)): Likewise. (DeclVisitor::visit(EnumDeclaration)): Likewise. (get_symbol_decl): Mark template instantiations as DECL_ONE_ONLY instead of DECL_COMDAT. Don't call mark_needed. (declare_extern_var): Don't call mark_needed. (d_finish_decl): Remove zero initializer for common symbols. (finish_thunk): Don't call d_comdat_linkage on generic thunk. (d_comdat_linkage): Don't set DECL_DECLARED_INLINE on functions. * typeinfo.cc (TypeInfoDeclVisitor::visit(TypeInfoDeclaration)): Mark built-in typeinfo symbols as DECL_ONE_ONLY instead of DECL_COMDAT. 2018-01-21 Iain Buclaw * d-lang.cc (d_init): Disable flag_weak if not supported. * decl.cc (d_comdat_linkage): Use flag_weak to guard setting DECL_ONE_ONLY on decls. (d_linkonce_linkage): New function. * gdc.texi (Runtime Options): Document -fweak. * lang.opt (fweak): Declare. 2018-01-21 Iain Buclaw * decls.cc (get_symbol_decl): Use attribute to mark naked functions. 2018-01-08 Eugene Wissner * d-builtins.cc (d_eval_constant_expression): Handle polynomial VECTOR_CST_NELTS. (build_frontend_type): Handle polynomial TYPE_VECTOR_SUBPARTS. 2018-01-08 Iain Buclaw Update copyright years. Copyright (C) 2018 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2006 ================================================ 2006-12-27 DF * phobos/internal/fpmath.d: Support x86_64 * phobos/configure.in: x86_64 can use fpmath.d * phobos/configure: update * target-ver-syms.sh: Add some CPU architectures 2006-12-26 DF * phobos/configure.in: actually use value of --enable-phobos-config-dir 2006-12-26 David Friedman Rest of 0.178 changes: * phobos/std/bitarray.d: revert previous changes * d-decls.cc (toSymbolX): update * d-glue.cc (TypeFunction::retStyle): implement * phobos/std/format.d: update for Mangle.Tenum ------------- Initial merge of 0.178: * dmd/class.c, dmd/declaration.c, dmd/declaration.h, dmd/doc.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/init.c, dmd/lexer.c, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/mtype.c, dmd/optimize.c, dmd/parse.c, dmd/statement.c, dmd/statement.h, dmd/template.c, dmd/tocsym.c, dmd/toobj.c: Merge 0.178 * phobos/internal/gc/win32.d, phobos/internal/object.d, phobos/std/c/linux/linux.d, phobos/std/date.d, phobos/std/dateparse.d, phobos/std/format.d, phobos/std/gc.d, phobos/std/regexp.d, phobos/std/socket.d, phobos/std.ddoc: Merge 0.178 --------------- * dmd/constfold.c (CastExp::constFold): Fix Bugzilla 738. * dmd/todt.c (StructDeclaration::toDt): Fix Bugzilla 736. * d-decls.cc (VarDeclaration::toSymbol): Fix Bugzilla 737. * d-glue.cc (make_assign_math_op): Fix Bugzilla 739. * d-codegen.cc, d-decls.cc, d-glue.cc, symbol.cc, symbol.h: Use toParent2. Handle nested template instance functions. (Bugzilla 742, 743) 2006-12-25 David Friedman * dmd/mtype.c: Don't use '@' in mangled names * d-glue.cc (TypeFunction::toCtype): Handle recursive type reference (Bugzilla 745) * d-codegen.cc, d-codegen.h, d-glue.cc, d-objfile.cc, d-objfile.h, dmd/aggregate.h, dmd/attrib.c, dmd/class.c, dmd/declaration.c, dmd/declaration.h, dmd/enum.c, dmd/enum.h, dmd/func.c, dmd/idgen.c, dmd/scope.c, dmd/scope.h, dmd/struct.c: Implement GCC attributes. * dmd/mtype.c (TypeDelegate::dotExp): Fix regression caused by last fix. 2006-12-24 David Friedman * dmd/parse.h, dmd/parse.c(parseStatement, parseExtAsm), dmd/statement.h, asmstmt.cc: Implement GCC extended assembler. 2006-12-20 David Friedman * dmd/mars.h: format issues are due to newlib, not Cygwin * setup-gcc.sh: Fix sed patterns and options. * dmd/mtype.c (TypeDelegate::dotExp): Handle .ptr so that it can be an lvalue. (Bugzilla 696) * d-irstate.cc (getLoopForLabel): Handle labels pointing to ScopeStatements. (Bugzilla 695) 2006-12-16 David Friedman Release GDC 0.20 * setup-gcc.sh: account for modified version strings * dmd/mtype.c (TypeTuple::toDecoBuffer): workaround newlib bug * dmd/mars.h: fix printf formats for Cygwin * d-builtins.c (d_init_builtins): Handle va_list type when it is an array. * gcc-mars.cc, gdc-version: update * d-decls.cc: warnings cleanup * dmd/expression.c (realToMangleBuffer): filter out 'x' 2006-12-13 David Friedman * package/simple.sh: use MAKE environment variable 2006-12-11 David Friedman * patch-build_gcc-4.0: don't disable Objective C 2006-12-09 David Friedman * phobos/std/bitarray.d (unittest): workaround 0.177 breakage * phobos/std/format.d, * phobos/std/string.d, * phobos/std/loader.d: update * phobos/std/file.d: fix merge. update. * dmd/root.[ch] (writestring): make arg const * dmd/expression.c (toMangleBuffer): update Initial 0.177 merges * dmd/constfold.c, dmd/declaration.c, dmd/expression.[ch], dmd/func.c, dmd/idgen.c, dmd/manlge.c, dmd/mars.c, dmd/mtype.[ch], dmd/opover.c, dmd/tocsym.c, dmd/toobj.c, dmd/typinf.c: Merge 0.177 * etc/c/zlib.d, phobos/internal/aaA.d, phobos/internal/adi.d, phobos/internal/arraycat.d, phobos/internal/gc/gc.d, phobos/internal/gc/testgc.d, phobos/internal/object.d, phobos/internal/qsort.d, phobos/internal/switch.d, phobos/internal/trace.d, phobos/object.d, phobos/std/array.d, phobos/std/boxer.d, phobos/std/conv.d, phobos/std/cover.d, phobos/std/cpuid.d, phobos/std/date.d, phobos/std/file.d, phobos/std/format.d, phobos/std/loader.d, phobos/std/math2.d, phobos/std/md5.d, phobos/std/mmfile.d, phobos/std/outbuffer.d, phobos/std/path.d, phobos/std/regexp.d, phobos/std/socket.d, phobos/std/stream.d, phobos/std/string.d, phobos/std/switcherr.d, phobos/std/syserror.d, phobos/std/typeinfo/ti_Acdouble.d, phobos/std/typeinfo/ti_Acfloat.d, phobos/std/typeinfo/ti_Acreal.d, phobos/std/typeinfo/ti_Adchar.d, phobos/std/typeinfo/ti_Adouble.d, phobos/std/typeinfo/ti_Afloat.d, phobos/std/typeinfo/ti_Ag.d, phobos/std/typeinfo/ti_Aint.d, phobos/std/typeinfo/ti_Along.d, phobos/std/typeinfo/ti_Areal.d, phobos/std/typeinfo/ti_Ashort.d, phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_Auint.d, phobos/std/typeinfo/ti_Aulong.d, phobos/std/typeinfo/ti_Aushort.d, phobos/std/typeinfo/ti_Awchar.d, phobos/std/uri.d, phobos/std/utf.d, phobos/std/windows/charset.d, phobos/std/windows/registry.d, phobos/std/zlib.d: Merge 0.177 -------------- * patch-apple-gcc-4.0.x, patch-build_gcc-4.0: Support building the Apple way on PowerPC machines. 2006-12-06 David Friedman * d-codegen.cc (call): Fix for calling delegate literal. * setup-gcc.sh: fail if patching build_gcc fails * d-glue.cc (NewExp::toElem): expand stack vars for GCC 3.x * phobos/std/cpuid.d: fix for cpuid kludge 2006-12-05 David Friedman * dmd/mars.h: Handle msvcrt C99 printf incompatibility. * dmd/template.c, dmd/declaration.c, dmd/expression.c, dmd/func.c, dmd/init.c, dmd/lexer.c, dmd/mangle.c, dmd/mtype.c, dmd/optimize.c, dmd/root.c: ditto * phobos/config/unix-mid: fix compile error 2006-12-04 David Friedman More 0.176 merges * phobos/config/unix-mid: add reentrant funcs * d-glue.cc (DeleteExp::toElem): handle on-stack vars * d-glue.cc (FuncDeclaration::toObjFile): emit _arguments * dmd/declaration.h, dmd/func.c: save _arguments local var for backend 2006-12-03 David Friedman * d-glue.cc: New _arguments ABI. * gcc-mars.cc: Update for verror. * d-decls.cc, d-objfile.cc, * d-glue.cc (Module::genobjfile, d_gcc_aggregate_dtors): Update for new toSymbolX. * d-glue.cc (TypeAArray::toCtype): Implement new AA ABI. * d-codegen.cc (convertTo): Don't allow conversion of dynamic array to associated array and vice versa. * d-codegen.cc (getLibCallDecl, rawArray, convertForCondition), d-glue.cc (NullExp::toElem): change AA type * gcc-mars.cc : printf corrections * phobos/Makefile.in (MAIN_OBJS): add bind.o Initial merge of DMD 0.176 * attrib.c, dmd/cast.c, dmd/class.c, dmd/cond.c, dmd/constfold.c, dmd/declaration.c, dmd/doc.c, dmd/dsymbol.h, dmd/dump.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/init.c, dmd/init.h, dmd/lexer.c, dmd/link.c, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/optimize.c, dmd/parse.c, dmd/root.c, dmd/statement.c, dmd/template.c, dmd/tocsym.c, dmd/todt.c, dmd/toobj.c: Merge 0.176 * internal/aaA.d, phobos/internal/cmath2.d, phobos/internal/deh.c, phobos/internal/object.d, phobos/linux.mak, phobos/std/c/linux/linux.d, phobos/std/c/linux/socket.d, phobos/std/compiler.d, phobos/std/math.d, phobos/std/socket.d, phobos/std/string.d, phobos/std/traits.d, phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_ubyte.d, phobos/std.ddoc, phobos/win32.mak: Merge 0.176 * phobos/std/bind.d: New file in 0.176 * dmd/toir.[ch]: New files (from DMD 0.175) * phobos/phobos.d: New file (from DMD 0.160) -------------- * phobos/std/boxer.d (unbox(T : void*).unbox): fix * d-glue.cc (NewExp::toElem): Support allocation on stack Initial merge of DMD 0.175 * cast.c, dmd/class.c, dmd/dchar.c, dmd/dchar.h, dmd/declaration.c, dmd/declaration.h, dmd/delegatize.c, dmd/dsymbol.c, dmd/dump.c, dmd/enum.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/identifier.c, dmd/identifier.h, dmd/inifile.c, dmd/init.c, dmd/lexer.c, dmd/lstring.h, dmd/mangle.c, dmd/mars.c, dmd/mtype.c, dmd/mtype.h, dmd/optimize.c, dmd/parse.c, dmd/root.c, dmd/root.h, dmd/scope.c, dmd/scope.h, dmd/statement.c, dmd/statement.h, dmd/stringtable.c, dmd/todt.c, dmd/typinf.c: Merge 0.175 dmd/html.c: not merged * phobos/internal/object.d, phobos/std/demangle.d, phobos/std/format.d, phobos/std/socket.d, phobos/std/stdio.d, phobos/std/traits.d, phobos/std/uni.d, phobos/std.ddoc: Merge 0.175 ------------ * config/darwin8, config/mingw: update config fragments 2006-11-26 David Friedman * d-codegen.cc, d-glue.cc: Fix missing continue label expansion for GCC < 4.0 * d-glue.cc (make_math_op): Convert non-complex to complex in all version of GCC. (Buzilla 575) * d-codegen.cc: for tree code class for GCC < 4.0 * phobos/Makefile.in: make test programs dependendent on libgphobos.a as gdc will still try to find it * phobos/configure.in: conditionally build std/boxer.o * phobos/Makefile.in (MAIN_OBJS): remove std/boxer.o * phobos/internal/arraycat.d (_d_array_literal): disable * phobos/std/format.d: fix for PowerPC Linux 2006-11-25 David Friedman * d-gcc-real.h: cleanup for warnings 2006-11-24 David Friedman * d-glue.cc (DotVarExp::toElem): Handle const members. * d-codegen.cc (needs_temp): Return false for constants. (isFreeOfSideEffects): New function. * d-glue.cc (do_array_set): Evaluate the rvalue only once (Bugzilla 578). 2006-11-18 David Friedman Rest of DMD 0.174 merge: * dmd/mtype.c (TypeDelegate::dotExp): Use cast-to-pointer for .ptr property * d-decls.cc (VarDeclaration::toSymbol): Build CONST_DECLs * d-codegen.cc (IRState::emitLocalVar): Do nothing if CONST_DECL * d-codegen.cc (ArrayScope::setArrayExp): Handle tuple/constant lengths. * dmd/toobj.c (Dsymbol::toObjFile): emit local variables for tuples * svn: move traits.d and typetuple.d to the correct directory * gcc-mars.cc (error): add va_list form * dmd/mars.h (error): use va_list for 'error' * dmd/expression.c, dmd/lexer.c: fix compile errors * phobos/Makefile.in (MAIN_OBJS): add traits.o and typetuple.o * dmd-script: add -v1 option * dmd/root.c (FileName::ensurePathExists): fix conditions for non-win32, non-linux. * dmd-script (printUsage): add missing options documentation * d-codegen.{h, cc}: use size_t * phobos/internal/dgccmain2.d: update Initial merge of DMD 0.174: * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/declaration.c, dmd/declaration.h, dmd/doc.c, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/hdrgen.c, dmd/idgen.c, dmd/inline.c, dmd/lexer.c, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/parse.c, dmd/statement.c, dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/todt.c, dmd/toobj.c, dmd/typinf.c, dmd/utf.c, dmd/utf.h: Merge 0.174 * phobos/internal/aApplyR.d, phobos/internal/dmain2.d, phobos/internal/object.d, phobos/linux.mak, phobos/object.d, phobos/std/date.d, phobos/std/openrj.d, phobos/std/signals.d, phobos/win32.mak: Merge 0.174 * phobos/std/traits.d, phobos/std/typetuple.d: New files in 0.174 2006-11-17 David Friedman * package/simple.sh: enhancements * dmd/attrib.c: fix message 2006-11-16 David Friedman * d-codegen.cc (continueHere): fix error * d-glue.cc (d_gcc_aggregate_dtors): " 2006-11-14 David Friedman * d-builtins2.cc, d-codegen.{cc, h}, d-decls.cc, d-glue.cc, d-lang.h: remove D_TYPE_IS_NESTED. Do not pull original TypeFunction from FUNCTION_TYPE. * d-codegen.cc: cleanup * d-codegen.cc, gdc-alloca.h, phobos/config/gen_unix.c: fixes for older MacOS X builds 2006-11-13 David Friedman * phobos/std/cpuid.d: fixes for PIC * d-asm-i386.h: Fix for referencing funcs (Bugzilla 307). Correct clobbers for cpuid, but left out EBX as a kludge for std.cpuid. * phobos/std/c/linux/linux.d: make imports public (Bugzilla 403) * d-decls.cc (uniqueName): Fixed logic error (Bugzilla 375). Then just removed most of the code and comments because the workaround is no longer needed. 2006-11-12 David Friedman * dmd/root.c (Object::hashCode): cast to pointer acceptable int type Rest of DMD 0.173 merge: * d-glue.cc (UnrolledLoopStatement::toIR): implement * d-codegen.h (setContinueLabel): add interface for multiple continues * d-irstate.h (Flow), d-irstate.cc: add overrideContinueLabel for GCC < 4.0 * d-builtins2.cc, d-glue.cc, d-codegen.cc: update for TypeFunction::arguments -> parameters and tuples * dmd/func.c: update * d-gcc-complex_t.h: update * phobos/Makefile.in (MAIN_OBJS): add signals.o and cpuid.o Initial merge of DMD 0.173: * dmd/arraytypes.h, dmd/cast.c, dmd/class.c, dmd/complex_t.h, dmd/constfold.c, dmd/declaration.c, declaration.h, dmd/delegatize.c, dmd/doc.c, dmd/dsymbol.c, dmd/dsymbol.h, expression.c, dmd/expression.h, dmd/func.c, dmd/html.c, dmd/html.h, dmd/inline.c, lexer.c, dmd/lexer.h, dmd/mars.c, dmd/mars.h, dmd/mem.h, dmd/mtype.c, dmd/mtype.h, opover.c, dmd/optimize.c, dmd/parse.c, dmd/parse.h, dmd/statement.c, dmd/statement.h, struct.c, dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/toobj.c, dmd/typinf.c: Merge 0.173 * phobos/internal/object.d, phobos/linux.mak, phobos/std/stream.d, phobos/std/string.d, phobos/std/system.d, phobos/std.ddoc, phobos/unittest.d, phobos/win32.mak: Merge 0.173 * phobos/std/c/locale.d, phobos/std/cpuid.d, phobos/std/signals.d: New files in 0.173 ---- * dmd/class.c, dmd/mars.c, dmd/opover.c, dmd/statement.c: Merge DMD 0.172 Merge DMD 0.171: * dmd/func.c, dmd/optimize.c: Update comments * dmd/aggregate.h, dmd/class.c, dmd/func.c, dmd/mars.c: Merge 0.171 * phobos/internal/aApplyR.d, phobos/internal/gc/gc/.d: Merge 0.171 ---- Rest of DMD 0.170 merge: * d-glue.cc (ArrayLiteralExp::toElem): Handle the case in which the type of the expression is a pointer. * dmd/optimize.c (PtrExp::optimize): Don't change type of expression without cast * phobos/internal/aApplyR.d: turn off debug(apply) 2006-11-11 David Friedman * d-glue.cc (ForeachStatement::toIR): support foreach_reverse * dmd/lexer.c: size_t -> unsigned * d-lang.cc (d_handle_option): update * phobos/Makefile.in: add aApplyR.o * phobos/internal/monitor.c: merged Initial merge of DMD 0.170: * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/delegatize.c, dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/identifier.c, dmd/idgen.c, dmd/import.c, dmd/lexer.c, dmd/lexer.h, dmd/mangle.c, dmd/mars.c, dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/parse.c, dmd/statement.c, dmd/statement.h, dmd/template.h, dmd/utf.h: Merge 0.170 * phobos/internal/aApply, phobos/internal/cast.d, phobos/internal/gc/gc.d, phobos/internal/mars.h, phobos/internal/object.d, phobos/linux.mak, phobos/object.d, phobos/std/gc.d, phobos/std/math.d, phobos/std/outofmemory.d, phobos/std/path.d, phobos/std/zlib.d, phobos/std.ddoc, phobos/unittest.d, phobos/win32.mak: Merge 0.170 * internal/monitor.c: not changed; merge deferred for now * phobos/internal/aApplyR.d: new file in 0.170 ---- Rest of 0.169 merge: * phobos/internal/object.d: fix merge error * d-asm-i386.h: update for DMD changes * dmd/mtype.c, phobos/internal/adi.d (_adSortChar, _adSortWchar): fix for calling conventions * d-gcc-complex_t.h: updated Initial merge of DMD 0.169: * dmd/aggregate.h, dmd/arraytypes.h, dmd/attrib.h, dmd/class.c, dmd/complex_t.h, dmd/cond.h, dmd/declaration.h, dmd/declaration.c, dmd/doc.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/enum.h, dmd/expression.c, dmd/expression.h, dmd/hdrgen.h, dmd/html.h, dmd/identifier.h, dmd/idgen.c, dmd/import.c, dmd/import.h, dmd/init.c, dmd/init.h, dmd/lexer.h, dmd/macro.h, dmd/macro.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/optimize.c, dmd/parse.h, dmd/root.c, dmd/scope.c, dmd/scope.h, dmd/statement.c, dmd/statement.h, dmd/staticassert.h, dmd/struct.c, dmd/template.c, dmd/template.h, dmd/total.h, dmd/typinf.c, dmd/utf.h, dmd/version.h: Merge 0.169 * phobos/internal/adi.d, phbobos/internal/critical.c, phbobos/internal/mars.h, phbobos/internal/monitor.c, phbobos/internal/object.d, phbobos/object.d, phbobos/std/regexp.d: Merge 0.169 ---- * dmd-script: Create directories for output files Rest of 0.168 changes: * d-dmd-gcc.h, d-glue.cc (d_gcc_aggregate_dtors): new function * dmd/toobj.c (ClassDeclaration::toObjFile): use d_gcc_aggregate_dtors * d-codegen.cc (convertTo): handle delegate .ptr property * lang-specs.h, dmd-script: handle .xhtml extension Initial merge of DMD 0.168 * dmd/aggregate.h, dmd/arraytypes.h, dmd/cast.c, dmd/class.c, dmd/declaration.c, dmd/expression.h, dmd/func.c, dmd/html.[ch], dmd/idgen.c, dmd/init.c, dmd/lexer.c, dmd/lexer.h, dmd/link.c, dmd/mangle.c, dmd/mars.c, dmd/module.c, dmd/mtype.[ch], dmd/statement.c, dmd/toobj.c, dmd/typeinf.c: Merge 0.168 * phobos/etc/gamma.d, phobos/internal/object.d, phobos/std/c/linux/linux.d.orig-dmd, phobos/std/date.d, phobos/std/math.d, phobos/std/socket.d, phobos/std/socketstream.d, phobos/std/stream.d, phobos/std/uni.d, phobos/win32.mak: Merge 0.168 2006-11-10 David Friedman * Make-lang.in (d.install-common): cross install fix for gdmd * d-glue.cc (NewExp::toElem): uint -> unsigned * package/simple.sh: Don't depend on rsync * patch-toplev-3.4.x, patch-toplev-4.0.x: Modify top-level Makefile.in, configure.in, and configure to work with a Canadian cross build. * d-glue.cc (SynchronizedStatement::toIR): Remove uneeded startBindings call. Add missing _d_criticalenter call. 2006-10-12 David Friedman * phobos/config/unix-mid: add sysconf 2006-10-11 David Friedman * phobos/std/format.d (doFormat): support Mangle.Tstruct for p_args * phobos/config/unix-head: import tm from gcc.config * phobos/config/gen_unix.c (c_time): Moved out struct tm. * phobos/config/gen_config1.c: Support clock_t. Move struct tm here. * d-glue.cc (AssignExp::toElem): use _d_arraysetlength3p (FuncDeclaration::toObjFile): Fixed assert of class member if synchronized. * d-codegen.{h, cc}: replace libcall _d_arraysetlength2p with _d_arraysetlength3p * phobos/internal/gc/gc.d (_d_arraysetlength3p): pointer version of _d_arraysetlength3. GCC asm jump fix. 2006-10-09 David Friedman * d-codegen.{h, cc}: new libcalls: _dnewmp, _d_newarraymip * phobos/internal/gc/gc.d (_dnewmp, _d_newarraymip): pointer version of _dnewm, _d_newarraymi * phobos/config/unix-mid: add utime * phobos/std/file.d: changes for GDC * phobos/config/gen_unix.c: support utimbuf 2006-09-23 David Friedman Initial merge of 0.167: * dmd/array.c, dmd/cast.c, dmd/declaration.c, dmd/delegatize.c, dmd/expression.[ch], dmd/func.c, dmd/idgen.c, dmd/import.c, dmd/init.c, dmd/inline.c, dmd/lexer.[ch], dmd/mars.c, dmd/mtype.[ch], dmd/optimize.c, dmd/parse.c, dmd/statement.c, dmd/template.c, dmd/typinf.c: Merge 0.167 * phobos/internal/arraycat.d, phobos/internal/gc/gc.d, phobos/internal/gc/testgc.d, phobos/internal/object.d, phobos/linux.mak, phobos/object.d, phobos/std/asserterror.d, phobos/std/c/linux/linux.d.orig-dmd, phobos/std/c/time.d, phobos/std/file.d, phobos/std/format.d, phobos/std/math.d, phobos/std/string.d, phobos/std/thread.d, phobos/unittest.d, phobos/win32.mak: Merge 0.167 * phobos/std/c/windows/stat.d: New 0.167 2006-09-06 David Friedman * d-glue.cc (FuncDelaration::toObjFile): Assert isMember for synchronized functions. (NewExp::toElem): Correct some cases for nested classes 2006-09-04 David Friedman * gdc-version, gcc-mars.cc: update * d-codegen.cc (trueDeclarationType): support lazy arguments (trueArgumentType): ditto * d-codegen.{h, cc}: comment out convertForInitialization * Make-lang.in (D_DMD_OBJS): add delegatize * dmd/delegatize.c: new, DMD 0.166 * dmd/cast.c, dmd/declaration.[ch], dmd/expression.[ch], dmd/func.c, dmd/inline.c, dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/parse.c, dmd/statement.c, dmd/struct.c, dmd/template.c, dmd/tocsym.c, dmd/typinf.c: Merge DMD 0.166 * phobos/etc/c/zlib/...: Merge 0.166 * phobos/internal/aApply.d, phobos/internal/gc/linux.mak, phobos/linux.mak, phobos/std/cover.d, phobos/std/utf.d, phobos/win32.mak: Merge 0.166 * phobos/etc/zlib/infblock.[ch], phobos/etc/zlib/infcodes.[ch], phobos/etc/zlib/infutil.[ch], phobos/etc/zlib/maketree.c, phobos/etc/zlib/zlib.html: remove, DMD 0.166 * gdc-version: update * d-glue.cc (FuncDeclaration::toObjFile): update * dmd/cast.c, dmd/declaration.[ch], dmd/enum.c, dmd/expression.[ch], dmd/func.c, dmd/init.c, dmd/inline.c, dmd/mars.c, dmd/mtype.c, dmd/statement.c, dmd/template.c, dmd/typeinf.c: Merge DMD 0.165 * phobos/internal/gc/gcx.d, phobos/std.ddoc: Merge DMD 0.165 * gdc-version: updated * dmd/aggregate.h, dmd/declaration.[ch], dmd/doc.c, dmd/dsymbol.c, dmd/expression.c, dmd/import.c, dmd/inifile.c, dmd/mars.c, dmd/module.[ch], dmd/mtype.c, dmd/parse.c, dmd/statement.c, dmd/template.c: Merge DMD 0.164 * phobos/std/socket.d: Merge DMD 0.164 * phobos/std/thread.d: no change 2006-07-22 David Friedman * phobos/internal/gc/testgc.d: add import * phobos/std/thread.d (Thread.thread_init, Thread.getESP): make public * phobos/std/c/unix/unix.d: use public import * dmd/access.c, dmd/aggregate.h, dmd/attrib.c, dmd/class.c, dmd/declaration.[ch], dmd/enum.c, dmd/expression.c, dmd/func.c, dmd/import.[ch], dmd/mars.c, dmd/module.c, dmd/mtype.[ch], dmd/parse.[ch], dmd/scope.[ch], dmd/struct.c, dmd/template.[ch], dmd/todt.c: Merge DMD 0.163 * phobos/internal/object.d, phobos/std/c/linux/linux.d.orig-dmd, phobos/std/regexp.d, phobos/std/stdio.d, phobos/std/stream.d: Merge DMD 0.163 2006-07-12 David Friedman Release GDC 0.19 * dmd/template.c: don't use ehfilter * gdc-version: update 2006-07-11 David Friedman Support for Apple GCC and other fixes * setup-gcc.sh: patch build_gcc * patch-build_gcc-4.0: new * dmd-script: Support -arch option and apple driver naming. Use absolute path to execute program with -run. 2006-07-10 David Friedman * phobos/config/darwin8/{frag-gen,frag-math,frag-unix}: new * phobos/configure.in: support Darwin cross compiling * phobos/configure.in: updated * phobos/config/gen_unix.c (c_fcntl): added *_OK enums * phobos/config/skyos/frag-unix: updated 2006-07-03 David Friedman * ../../gcc/tree.h, ../../gcc/tree-dump.c: machine readable dump Merge DMD 0.162 * d-glue.cc (AssignExp::toElem): use _d_arraysetlength2p * phobos/internal/gc/gc.d: chanage _d_arraysetlength2 to _d_arraysetlength2p 2006-07-02 David Friedman * d-codegen.{h, cc}: support _d_arraysetlength2 * dmd/cast.c, dmd/declaration.c, dmd/doc.c, dmd/expression.c, dmd/func.c, dmd/mars.c, dmd/mtype.c, dmd/parse.c, dmd/struct.c, dmd/template.[ch], dmd/toobj.c: merged * phobos/internal/gc/gc.d, phobos/object.d, phobos/std/asserterror.d, phobos/std/moduleinit.d: merged --- * phobos/std/regexp.d (RegExp.Range.setbitmax): fix for big endian 2006-06-28 DF * d-glue.cc (TypeStruct::toCtype, TypeEnum::toCtype): Move initTypeDecl call to after size calculation. 2006-06-24 David Friedman * phobos/Makefile.in: fix and clean up config.d dependencies * d-gcc-real.cc (real_t): fix assumptions about HOST_WIDE_INT 2006-06-23 David Friedman * Make-lang.in, asmstmt.cc, d-convert.cc, d-gcc-includes.h, d-lang.cc, setup-gcc.sh: update to support building with Apple GCC * d-apple-gcc.cc, patch-apple-gcc-4.0.x: new Misc fixes * Make-lang.in: Add dependencies for DMD header files. * phobos/config/gen_unix.c (c_time): fix array bounds bug 2006-06-22 David Friedman * Make-lang.in: use BUILD_LDFLAGS for generator progs 2006-06-21 David Friedman * d-asm-i386.h: implement offset/offsetof 2006-06-20 David Friedman Merge DMD 0.161 * gcc-mars.cc, gdc-version: updated * dmd/cast.c, dmd/class.c, dmd/declaration.[ch], dmd/dsymbol.c, dmd/expression.[ch], dmd/func.c, dmd/idegen.c, dmd/import.h, dmd/inline.c, dmd/lexer.[ch], dmd/mars.[ch], dmd/module.c, dmd/mtype.c, dmd/opover.c, dmd/parse.c, dmd/root.[ch], dmd/statement.c, dmd/struct.c, dmd/template.[ch], dmd/toobj.c: Merge DMD 0.161 * phobos/internal/adi.d, phobos/internal/cast.d, phobos/internal/trace.d, phobos/linux.mak, phobos/std/asserterror.d, phobos/std/base64.d, phobos/std/bitarray.d, phobos/std/boxer.d, phobos/std/c/linux/socket.d, phobos/std/c/windows/windows.d, phobos/std/c/windows/winsock.d, phobos/std/conv.d, phobos/std/cstream.d, phobos/std/date.d, phobos/std/dateparse.d, phobos/std/demangle.d, phobos/std/file.d, phobos/std/format.d, phobos/std/math.d, phobos/std/math2.d, phobos/std/mmfile.d, phobos/std/random.d, phobos/std/regexp.d, phobos/std/socket.d, phobos/std/socketstream.d, phobos/std/stream.d, phobos/std/string.d, phobos/std/stream.d, phobos/std/thread.d, phobos/std/typeinfo/ti_Along.d, phobos/std/typeinfo/ti_Aulong.d, phobos/std/tyeinfo/ti_void.d, phobos/std/uni.d, phobos/std/uri.d, phobos/std/utf.d, phobos/std/windows/registry.d, phobos/std/zip.d, phobos/std/zlib.d, phobos/std.ddoc, phobos/unittest.d, phobos/win32.mak: Merge DMD 0.161 * Make-lang.in, d-lang.cc: Possible workaround for MingGW path issues. Create d-confdefs.h to contain the values of D_PHOBOS_DIR and D_PHOBOS_TARGET_DIR. 2006-06-10 David Friedman * History: new file * package/install.sif: ditto * package/simple.sh: * phobos/std/zip.d (putUshort): fix for BigEndian case * phobos/internal/gc/gcgccextern.d: update for version(freebsd) * target-ver-syms.sh: Use "freebsd" for FreeBSD. * phobos/configure.in: Enable std.loader for FreeBSD. * phobos/std/loader.d: ditto * phobos/configure: updated * Make-lang.in: Support package building. Cleanup. 2006-06-08 David Friedman * patch-gcc-4.0.x: updated with... * .../gcc/tree-nested.c: check if static chain is a PARM_DECL (Bugzilla 175) 2006-06-07 David Friedman * Make-lang.in: use CXX_FOR_BUILD * phobos/std/format.d (unittest): Some C libraries do not support the %A format. 2006-06-06 David Friedman * phobos/config/skyos/frag-unix: update for SkyOS beta 10 2006-06-05 David Friedman Merge DMD 0.160 * d-codegen.cc (arrayType): handle zero-length arrays for local variables. * gdc-version, gcc-mars.cc: update * d-glue.cc (NewExp::toElem): support 'exp. new ...' * d-codegen.{h, cc}: support _d_assert_msg * dmd/attrib.c, dmd/enum.c, dmd/expression.[ch], dmd/idgen.c, dmd/inifile.c, dmd/inline.c, dmd/mars.c, dmd/module.c, dmd/mtype.c, dmd/opover.c, dmd/parse.[ch], dmd/statement.[ch], dmd/staticassert.[ch], dmd/struct.c: Merge DMD 0.160 * phobos/std/asserterror.d, phobos/std/regexp.d, phobos/std/zlib.d, phobos/std.ddoc, phobos/win32.mak: Merge DMD 0.160 2006-06-04 David Friedman Various fixes * d-codegen.cc (twoFieldType): cleanup * phobos/internal/gc/gc_dyld.c: correct callback signature * phobos/std/format.d (unittest): Undo test change. (putreal): Handle the case where real is equivalent to double. * d-glue.cc (TypeClass::toCtype): use prepareTypeDecl instead of setting an initial TYPE_NAME (Bugzilla 174) (TypeStruct::toCtype): ditto (TypeEnum::toCtype): ditto * d-objfile.{h, cc} (prepareTypeDecl): New: Create type declarations, but do not declare them to back end. Merge DMD 0.159 and more * d-asm-i386.h (parsePrimaryExp): handle floating point const decls specially (Bugzilla 141) 2006-06-03 David Friedman * d-glue.cc (AssertExp::toElem): handle interfaces * phobos/std/math.d (poly): fix for darwin x86 * phobos/std/format.d (unittest): handle some variation in %a formats * gdc-version: updated * gcc-mars.cc: updated * dmd/attrib.c, dmd/attrib.h, dmd/class.c, dmd/declaration.c, dmd/doc.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/link.c, dmd/mars.c, dmd/module.c, dmd/module.h, dmd/parse.c, dmd/parse.h, dmd/statement.c, dmd/staticassert.c, dmd/struct.c, dmd/template.c, dmd/toobj.c: Merge DMD 0.159 * phobos/std/c/linux/linux.d.orig-dmd, phobos/std/c/linux/linuxextern.d, phobos/std/c/windows/windows.d, phobos/std/regexp.d, phobos/std/string.d, phobos/std/uni.d, phobos/std.ddoc: Merge DMD 0.159 * dmd-script: use -O3 for GCC if -O is passed Fix bugs 157, 162, 164, 171 * d-asm-i386.h: 'invlpg' instruction takes an operand (Bug 171) * patch-gcc-4.0.x: updated with... * .../gcc/tree-nested.c: use a VAR_DECL for custom static chain (Bug 162, Bug 164) * gdc-version: updated * d-glue.cc (FuncExp::toElem): Handle Tpointer case. (Bug 157) 2006-06-01 David Friedman * Start of SourceForge repository Copyright (C) 2006 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2007 ================================================ 2007-12-15 David Friedman * phobos*/Makefile.{am,in}, phobos*/aclocal.m4: Automake changes * setup-gcc.sh: Support Apple GCC build 5465 * patch-apple-gcc-5465, patch-build_gcc-5465, patch-toplev-5465: new files 2007-12-01 David Friedman * phobos/config/unix.x3, phobos/config/x3.c, phobos/config/x3.h phobos/config/x3, phobos/config/x3main.c: better diagnostics and behavior 2007-11-24 David Friedman * setup-gcc.sh: Ignore .svn directories when making symlink trees. * d-bi-attrs-34.h, d-bi-attrs-341.h, d-bi-attrs-40,h, d-bi-attrs-41.h: Support attributes on declarations in other modules. * d-codegen.cc (IRState::attributes): Support constant declarations as string arguments. 2007-11-08 David Friedman * d-cppmngl.cc: Use base-36 in substitutions. Other fixes. 2007-10-17 David Friedman * d-cppmngl.cc: More C++ mangling fixes and cleanups. 2007-10-16 David Friedman * d-glue.cc (EqualExp::toElem): Convert result to libcall to expression type. (Bugzilla 1573) 2007-10-15 David Friedman * d-cppmngl.cc: Improve C++ mangling. 2007-10-14 David Friedman Merge DMD 1.022, 2.005 * dmd/..., dmd2/..., phobos/..., phobos2/...: Merge. * Make-lang.in: Add builtin.dmd.o and d-cppmngl.o for V2. * d-cppmngl.cc: New file * phobos/std/c/dirent.d, phobos/std/c/linux/linux.d: Update * phobs2/...: same * symbol.h, d-decls.cc: Remove references to Classym ---- * d-glue.cc (CatExp::toElem): Null check. (Bugzilla 1581) Remove carriage returns from files 2007-10-13 David Friedman * d-glue.cc (CatExp::toElem): Flatten multiple CatExps into a single library call. (Bugzilla 1556) * phobos/std/boxer.d (box, boxArray), phobos2/...: Fix for promoted types. (Bugzilla 1543) * d-codegen.cc (call): Catch a case in which a member function can be called without 'this'. (Bugzilla 1568) * dmd/mtype.c (TypeArray::dotExp): Correct return type of sort and reverse functions. (SF 1809220 / Bugzilla 1554) * dmd2/mtype.c: Ditto. * patch-gcc-4.1.x: Add patch for ARM exception handling int nested functions. * d-objfile.cc: Make DT data TREE_CONSTANT * dmd2/optimize.c: Fix for infinite recursion on initializer when an error has already occurred. ----- Add support for ARM EABI. Fix some missing items from cross-compilation changes. * d-lang.cc: Add "Arm" and "Thumb" version identifiers * phobos/unwind.d: Move pointer encoding to deh_pe.d. Move generic unwinder interface to unwind_generic.d. Import either generic or ARM interfaces based on config value. * phobos/unwind_generic.d, phobos/unwind_pe.d: New file; old code. * phobos/unwind_arm.d: New file. * phobos/deh.d: Support ARM exception handling ABI. * phobos/configure.in, frag-ac.in: Add config for ARM unwinder * phobos/configure.in, phobos/internal.c, phobos/monitor.c: Support "no system" targets. * phobos/cbridge_math.c: Correct identifier names for earlier changes. * phobos/Makefile.am, phobos/Makefile.in, phobos/config.h.in, phobos/configure : Update. * phobos2/...: Duplicate phobos/ changes 2007-10-07 David Friedman Merge cross-compilation changes to phobos2 * phobos2/....: Merge --- Enhance cross-compilation support: * phobos/Makefile.am, phobos/Makefile.in, phobos/acinclude.m4, phobos/aclocal.m4, phobos/configure.in, phobos/configure, phobos/config.h.in: Replace "fragment generation" with "X3" system. Remove obsolete tests. * phobos/config/{config-head, config-mid, config-tail}: Removed * phobos/config/{makestruct.h, unix-head, unix-mid}: Removed * phobos/{darwin8, mingw, skyos}: Removed * phobos/config/{errno.x3, fpcls.x3, libc.x3, unix.x3}, phobos/config{x3, x3.c, x3.h, x3main.c}: New files * phobos/frag-ac.in: Now only contains boolean constants. * phobos/frag-math.in: New file. Contains old configured math functions. * phobos/gcc/configext.d: Removed * phobos/gcc/support.d: Move fallback strtold definition here. * phobos/Makefile.am: Do not compile std/c/stdio.o * phobos/std/c/stdio.c: Change function definitions to external declarations. * phobos/gcc/deh.d, phobos/gcc/fpcls.d, phobos/gcc/fpmath.d, phobos/gcc/support.d, phobos/gcc/threadsem.d, phobos/internal/dgccmain2.d, phobos/internal/fpmath.d, phobos/internal/gc/gcgcc.d, phobos/phobos-ver-syms.in, phobos/std/c/dirent.d, phobos/std/c/math.d, phobos/std/c/stddef.d, phobos/std/c/stdio.d, phobos/std/c/stdlib.d, phobos/std/c/time.d, phobos/std/c/unix/unix.d, phobos/std/date.d, phobos/std/math.d, phobos/std/math2.d, phobos/std/mmfile.d, phobos/std/random.d, phobos/std/stdio.d, phobos/std/stream.d, phobos/std/system.d, phobos/std/thread.d: Update. Add some support for targets withouth an operation system. 2007-09-24 David Friedman * d-glue.cc (IndeExp::toElem), d-codegen.cc (arrayElemRef): Put the BIND_EXPR "inside the brackets". (Bugzilla 1155) (StructLiteralExp::toElem): Handle NULL elements (for anonymous unions.) 2007-09-23 David Friedman * d-codegen.{h,cc}, d-glue.cc: Add type to error_mark_node for code that assumes the type of certain expressions. (Bugzilla 1051) * d-glue.cc (FuncDeclaration::toObjFile): Set DECL_IGNORED_P on the frame paramter. (Bugzilla 1033) * d-glue.cc, d-codegen.cc, d-objfile.cc: Set DECL_IGNORED_P in most cases where DECL_ARTIFICIAL is set. * d-builtins2.cc (d_gcc_magic_builtins_module): Handle type declarations after converting functions. * d-glue.cc (make_assign_math_op): Special case for division when lhs is imaginary. (Bugzilla 739) * dmd-script: Apply Ander's patch for implicit -H and -D behavior. (Bugzilla 1502) Use of -of argument does not depend on header generation. (Bugzilla 1501) * d-builtins2.cc, dmd*/module.c: If the target va_list is a struct, add the struct declaration to the object module. (Bugzilla 1507) * dmd2/parse.c: fix line endings ---- Update for D 2.0: * Make-lang.in: Support both DMD front end version 1 and 2. Replace gcc-mars.cc with d/mars.c. * gcc-mars.cc: Remove file. * d-codegen.h, d-codegen.cc: Update for DMD 2.x. Add _d_hidden_func libcall. * d-decls.cc, d-glue.cc: Update for DMD 2.x. * d-dmd-gcc.h: Add rtlsym, etc. * d-lange.cc: Include mars.h. Implement rtlsym. * d-objfile.cc (ObjectFile::hasModule): Add checks to allow this function to be called earlier. * dmd*/mars.c: Make changes for GDC. * dmd*/attrib.c: Use WANTinterpret for pragma(GNU_asm) * dmd2/parse.c (parseDeclarator): Fix aliasing bug. * rdmd.d: Update for D 2.0 * gdc-version: now only contains the GDC version * setup-gcc.sh: Support building D version 1 or 2. Take DMD version from dmd*/mars.c. * dmd2/, phobos2/: New directories * phobos2/Makefile.am (MAIN_OBJS): add std.c.stdio module for std{in,out,err} vars * phobos*/std/c/stdio.d: Make functions with definitions extern(D). * phobos2/std/loader.d: Update for D 2.0. * phobos2/std/hiddenfunc.d: Use C calling conventions for GDC. 2007-09-14 David Friedman * d-codegen.cc (convertTo, call): Prevent multiple re-evaluation of delgate. (Bugzilla 1492) 2007-09-13 David Friedman * d-glue.cc, d-codegen.h, d-codegen.cc: Make it an error to reference a nested function without a body. (SF 1793594) 2007-09-12 David Friedman * phobos/config/ldfuncs-ppclinux: Declare sqrt. * target-ver-syms.sh, phobos/acinclude.m4, phobos/configure.in: Support kfreebsd. * d-codegen.{h, cc}, d-glue.cc: Change rawArray to toDArray. Do not cast result to void[]. (Bugzilla 1490) 2007-09-07 David Friedman * phobos/std/c/stdio.d: Define fpos_t correctly for Drawin (Bugzilla 1469) 2007-09-05 David Friedman Merge DMD 1.021 * dmd-script, d-spec.c (lang_specific_driver): Support -debuglib= and -defaultlib= options. * dmd/cast.c, dmd/constfold.c, dmd/declaration.c, dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/identifier.c, dmd/idgen.c, dmd/init.c, dmd/init.h, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h, dmd/link.c, dmd/mars.c, dmd/mars.h, dmd/parse.c, dmd/statement.c, dmd/staticassert.c, dmd/template.c: Merge * internal/object.d, phobos/internal/trace.d, phobos/object.d, phobos/std/c/windows/windows.d, phobos/std/date.d, phobos/std/regexp.d, phobos/std/windows/registry.d: Merge --- * phobos/std/stdio.d (readln): Use the result of getdelim correctly. (SF 1788195) * d-glue.cc (FuncDeclaration::toObjFile): Do not gimplify if there were errors (Bugzilla 1415) 2007-08-31 David Friedman * d-objfile.cc (outdata): Do not set TREE_CONSTANT on initializers (Bugzilla 1453) 2007-08-29 David Friedman * d-decls.cc (uniqueName): Allow multiple static declaration with the same name if in a function. (SF 1783085) 2007-08-28 David Friedman * d-codegen.cc (call): Use CommaExp correctly. (Bugzilla 1443) * dmd/todt.c (createTsarrayDt): Don't take quadratic time to build the initializer. (Bugzilla 1440) 2007-08-22 David Friedman Release GDC 0.24 --- * rdmd.d: Fix for Windows 2007-08-21 David Friedman * GDC.html, History, README, gcc-mars.cc, gdc-version: Update for 0.24 * rdmd.d, rdmd.1: New files. (Bugzilla 1152) * patch-build_gcc-4.0: Build universal rdmd. (Bugzilla 1152) * package/simple.sh: Install rdmd. (Bugzilla 1152) Install man pages for MacOS build. * dmd-script: Apply Ander's patch to make -op apply to interface files. (Bugzilla 1137) * d-lang.cc (d_parse_file): In -fall-sources mode, only generate an interface file for the -fonly module. * phobos/internal/adi.d (_adReverseChar, _adReverseWchar): Make sure stride difference is signed. 2007-08-20 David Friedman * patch-gcc-4.1.x, patch-gcc-4.0.x: Fix botched patches. 2007-08-05 David Friedman * d-codegen.cc (convertForArgument): Recognize pointer arithmetic expression as reference. (Bugzilla 1400) * d-glue.cc (DotVarExp::toElem): Do not NOP_EXPR the result. (Bugzilla 1398) 2007-07-27 David Friedman * phobos/std/stdio: Fix breakage from last commit. (SF 1761989) 2007-07-26 David Friedman * phobos/std/c/stdio.d: Change import for gcc.config * d-lang.cc: add flag_iso for target macros * patch-gcc-4.0.x: (gcc/tree-sra.c): Do not use SRA on structs with aliased fields created for anonymous unions. (Followup to Bugzilla 1034) 2007-07-25 David Friedman * d-lang.cc: implement d_gcc_is_target_win32 * dmd/parse.c (parseLinkage): use d_gcc_is_target_win32 * d-dmd-gcc.h (d_gcc_is_target_win32): added 2007-07-24 David Friedman Merge DMD 1.019 - 1.020 * dmd/attrib.c, dmd/cast.c, dmd/constfold.c, dmd/declaration.h, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/inline.c, dmd/interpret.c, dmd/mars.c, dmd/mars.h, dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/parse.c, dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/toir.c: Merge * phobos/internal/gc/gc.d, phobos/linux.mak, phobos/std/demangle.d, phobos/std/format.d, phobos/std/loader.d, phobos/std/socket.d, phobos/std/uni.d: Merge 2007-07-22 David Friedman Merge DMD 1.015 - 1.018: * dmd/lexer.c (escapeSequence): Change vendor string. * dmd-script: Update documentation link * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/declaration.c, dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/hdrgen.h, dmd/idgen.c, dmd/init.c, dmd/init.h, dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/optimize.c, dmd/parse.c, dmd/scope.c, dmd/scope.h, dmd/statement.c, dmd/statement.h, dmd/staticassert.c, dmd/template.c: Merge * phobos/internal/dmain2.d, phobos/internal/gc/gcx.d, phobos/internal/object.d, phobos/object.d, phobos/std/bind.d, phobos/std/compiler.d, phobos/std/date.d, phobos/std/dateparse.d, phobos/std/format.d, phobos/std/intrinsic.d, phobos/std/loader.d, phobos/std/math2.d, phobos/std/metastrings.d, phobos/std/mmfile.d, phobos/std/outbuffer.d, phobos/std/string.d, phobos/std/windows/registry.d, phobos/win32.mak: Merge ---- * gdc_alloca.h: Support OpenBSD. (Bugzilla 1065) * patch-gcc-4.1.x (gcc/tree-sra.c): Do not use SRA on structs with aliased fields created for anonymous unions. (Bugzilla 1034) 2007-07-19 David Friedman * patch-gcc-4.1.x (gcc/predict.c): Add null-pointer check. (Bugzilla 1035) --- * phobos/std/format.d (doFormatPtr): Fix accidental reversion from DMD merge. * d-codegen.cc (maybeSetUpBuiltin): Add some missing instrinsics. * phobos/Makefile.am (MAIN_OBJS): Add gcc.builtins module to get built-instruct initializers. * phobos/Makefile.in: Regenerated * d-lang.cc (d_parse_file): Call d_gcc_magic_module for each module on the command line. * d-builtins2.cc (d_gcc_magic_builtins_module): output declaration other than funcs 2007-07-16 David Friedman * dmd/todt.c (StructLiteralExp::toDt): Use target_size_t as in StructInitializer::toDt. Bugzilla 1032: * dmd/todt.c: Use DT_container for arrays, array elements, and structs * dt.h, d-objfile.cc: Add DT_container / dtcontainer 2007-07-14 David Friedman * d-codegen.cc (ArrayScope::setArrayExp, finish): Handle constant lengths. (Bugzilla 1031) 2007-07-13 David Friedman * d-codegen.cc (toElemLvalue): Use toElemLvalue recursively. (Bugzilla 1191) * d-codegen.cc (twoFieldCtor): Only set TREE_READONLY if TREE_CONSTANT * d-glue.cc (array_set_expr, AssocArrayLiteralExp::toElem, (StructLiteralExp::toElem, NullExp::toElem): Do not set TREE_READONLY. * d-glue.cc (NewExp::toElem): Do not set TREE_READONLY on new array dimensions. * d-codegen.cc (darrayVal): Do not set TREE_READONLY. (Bugzilla 1329) (delegateVal): ditto * d-codegen.cc (FieldVisitor::visit): Handle classes that are forward references. (Bugzilla 1325) * dmd-script: Pass -J option correctly. (SF 1721435) * d-glue.cc (DeleteExp::toElem): Handle interfaces. (SF 1721496) * d-decls.cc (VarDeclaration::toSymbol): Handle void initializer. (SF 1749622) * d-glue.cc (AndAndExp, OrOrExp): Handle void second expression. (SF 1689634) * phobos/gcc/cbridge_time.c (_d_gnu_cbridge_tza): Remove daylight saving time offset from tm_gmtoff (Bugzilla 1208) * phobos/std/format.d (doFormat): Use original signature. Actual work is done by new doFormatPtr. (Bugzilla 1109) * phobos/std/boxer.d: Use doFormatPtr 2007-07-11 David Friedman * d-convert.cc (default_conversion): make public (SF 1711324 and 1709602) * d-apple-gcc.c (build_function_call): re-enable some code 2007-05-08 David Friedman * d-apple-gcc.c: Remove a variable that is now defined in d-lang.c * d-lang.cc: Fix for other GCC versions. * d-c-stubs.c: New file. * Make-lang.in (D_BORROWED_C_OBJS): Always use C_TARGET_OBJS. Add stubs for C compiler to allow linking target-specific preprocessor defines. 2007-05-05 David Friedman * d-codegen.cc (hwi2toli, getTargetSizeConst): Fix 2x wide int to long int conversion. * dmd/cast.c (implicitConvTo): Use GCC floating point routines instead of native. * d-gcc-real.cc (toInt): Correctly convert to long integer * Make-lang.in (D_DMD_H): Add d-gcc-real.h * phobos/internal/dgccmain2.d: Print newline after error message 2007-04-29 David Friedman Merge DMD 1.014: * dmd/aggregate.h, dmd/constfold.c, dmd/delegatize.c, dmd/enum.c, dmd/enum.h, dmd/expression.c, dmd/expression.h, dmd/idgen.c, dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/mtype.c, dmd/optimize.c, dmd/struct.c, dmd/template.c, dmd/tocsym.c, dmd/todt.c, dmd/toobj.c, dmd/typinf.c: Merge. * phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d, phobos/std/format.d, phobos/std.ddoc: Merge. * d-glue.d (StructLiteralExp::toElem): implement * d-decls.d (EnumDeclaration::toInitializer): copy from tocsym.c ------------ Merge DMD 1.013: * dmd/cast.c, dmd/constfold.c, dmd/declaration.c, dmd/expression.c, dmd/expression.h, dmd/interpret.c, dmd/link.c, dmd/mars.c, dmd/mtype.c, dmd/opover.c, dmd/optimize.c, dmd/parse.c, dmd/port.h, dmd/statement.c: Merge. * phobos/internal/aaA.d, phobos/internal/switch.d, phobos/std/date.d, phobos/std/file.d, phobos/std/format: Merge. * d-codegen.h, d-codegen.cc: add _d_assocarrayliteralTp * d-glue.cc (AssocArrayLiteralExp::toElem): Implement. * phobos/internal/aaA.d (_d_assocarrayliteralT): modified to use pointers to keys, values. -------------- Merge DMD 1.012: * arraytypes.h, dmd/declaration.c, dmd/delegatize.c, dmd/expression.c, dmd/expression.h, dmd/init.c, dmd/init.h, dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h, dmd/mangle.c, dmd/mars.c, dmd/optimize.c, dmd/template.c, dmd/template.h: Merge * phobos/internal/object.d: Merge * dmd/template.c (TemplateInstance::mangle): printf portability * d-glue.cc (AssocArrayLiteralExp::toElem): non-working implementation 2007-04-28 David Friedman Merge DMD 1.011: * dmd/access.c, dmd/aggregate.h, dmd/arraytypes.h, dmd/attrib.c, dmd/attrib.h, dmd/bit.c, dmd/cast.c, dmd/class.c, dmd/complex_t.h, dmd/cond.c, dmd/cond.h, dmd/constfold.c, dmd/declaration.c, dmd/declaration.h, dmd/delegatize.c, dmd/doc.c, dmd/doc.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/dump.c, dmd/entity.c, dmd/enum.c, dmd/enum.h, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/hdrgen.c, dmd/hdrgen.h, dmd/html.c, dmd/html.h, dmd/identifier.c, dmd/identifier.h, dmd/idgen.c, dmd/impcnvgen.c, dmd/import.c, dmd/import.h, dmd/inifile.c, dmd/init.c, dmd/init.h, dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h, dmd/link.c, dmd/macro.c, dmd/macro.h, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/optimize.c, dmd/parse.c, dmd/parse.h, dmd/scope.c, dmd/scope.h, dmd/statement.c, dmd/statement.h, dmd/staticassert.c, dmd/staticassert.h, dmd/struct.c, dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/todt.c, dmd/toir.c, dmd/toir.h, dmd/toobj.c, dmd/total.h, dmd/typinf.c, dmd/unialpha.c, dmd/utf.c, dmd/utf.h, dmd/version.c, dmd/version.h: Merge * phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d, phobos/internal/object.d, phobos/std/c/locale.d, phobos/std/stdio.d, phobos/std/windows/registry.d: Merge * dmd/expression.c: Comment out some logging code. * d-builtins2.cc: Update and fix handling of built-in structs. * d-codegen.cc, d-glue.cc: Update ---------------- Merge DMD 1.010: * dmd/aggregate.h, dmd/class.c, dmd/declaration.c, dmd/doc.c, dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/interpret.c, dmd/mars.c, dmd/scope.c, dmd/statement.c, dmd/template.c, dmd/template.h, dmd/todt.c: Merge. * phobos/internal/dmain2.d, phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d, phobos/internal/gc/testgc.d, phobos/internal/object.d, phobos/object.d, phobos/std/c/linux/linux.d, phobos/std/c/stdio.d, phobos/std/file.d, phobos/std/gc.d, phobos/std/moduleinit.d, phobos/std/regexp.d, phobos/std/stdio.d, phobos/std/string.d, phobos/std.ddoc, phobos/win32.mak: Merge * dmd/mtype.c, phobos/internal/dgccmain2.d: Update. * d-glue.cc (gcc_d_backend_init): Update. * phobos/config/unix-mid, phobos/std/c/unix/unix.d: Moved dirent and stdio definitions out of configunix to std.c.unix.unix because of compilation problems. * phobos/internal/gc/gcx.d (GC.realloc, GC.extend, GC.free): Clear gcx.p_cache * phobos/std/stdio.d, phobos/frag-ac.in, phobos/configure.in: Account for various configurations. * phobos/phobos-ver-syms.in: Remove GNU_Have_fwide * phobos/configure: Regenerate 2007-04-22 David Friedman * d-gcc-includes.h, d-lang.cc: Add target-specific preprocessor symbols to the list of D version symbols. * d-glue.cc (NewExp::toElem): Use NewExp::newtype (Bugzilla 1038) 2007-04-16 David Friedman Merge DMD 1.009 (from 1.007): * d-decls.c: Merge changes from dmd/tocsym.c * dmd/constfold.c, dmd/declaration.c, dmd/declaration.h, dmd/expression.c, dmd/expression.h, dmd/init.c, dmd/interpret.c, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/mtype.c, dmd/optimize.c, dmd/statement.c, dmd/staticassert.c, dmd/tocsym.c, dmd/todt.c: Merge changes. * phobos/std/path.d, phobos/std/string.d: Merge changes. ---- * d-builtins.c, d-builtins2.cc, d-lang.h: Reworked code to only convert built-in functions when the gcc.builtins module is imported. RECORD_TYPE is now converted to a TypeStruct. Fixed problem that caused some functions to not be available. Support targets builtins. 2007-03-11 David Friedman * d-decls.cc (ClassDeclaration::toSymbol): Do not set TREE_READONLY. (Bugzilla 1037) 2007-03-10 David Friedman * d-codegen.cc (call): Handle CommaExp form of a delegate call (Bugzilla 1043) * d-decls.cc (VarDeclaration::toSymbol): Partial fix for Bugzilla 1044 * dt.h, d-objfile.cc, dmd/typeinf.c: Only pad 32-bit words in RTTI if needed. (Bugzilla 1045, 1046) * dmd/toobj.c: update * d-glue.cc, d-objfile.cc: Additional GCC 3.3.x cleanup ---- * ChangeLog, History, Make-lang.in, asmstmt.cc, d-builtins.c, d-codegen.cc, d-convert.cc, d-decls.cc, d-gcc-includes.h, d-gcc-real.cc, d-glue.cc, d-gt.c, d-irstate.cc, d-lang.cc, d-lang.h, d-misc.c, d-objfile.cc, d-spec.c, phobos/configure.in, setup-gcc.sh: Remove support for GCC 3.3.x * phobos/configure: Regenerated * gcc-3.3.5-framework-headers.patch, gcc-3.3.5-framework-linker.patch, patch-gcc-3.3.x, patch-gcc-darwin-eh-3.3.x, patch-toplev-3.3.x, phobos/config/ldfuncs33, phobos/config/noldfuncs33, d-bi-attrs-33.h: Removed. 2007-03-05 David Friedman Release GDC 0.23 * phobos/Makefile.am: Add all-local target to build libgphobos.a * phobos/Makefile.in: Regenrated PowerPC 64 fixes: * d-glue.cc (TypeStruct:toCtype): Add words at the end of a struct. * phobos/config/darwin8/frag-unix: More accurate struct definitions. * phobos/internal/gc/gc_dyld.c: Support Mach-O 64. * phobos/internal/gc/gcgcc.d: Correct stack for 64-bit Darwin. * phobos/std/thread.d (getESP): Align result. 2007-03-04 David Friedman Rest of DMD 1.007 Merge: * package/simple.sh: Install GDC.html * Make-lang.in (D_DMD_OBJS): add interpret.dmd.o * gdc-version: update * GDC.html, d-lang.cc, dmd-script, lang-specs.h, lang.opt, patch-gcc-4.0.x, patch-gcc-4.1.x, patch-apple-gcc-4.0.x, patch-gcc-3.4.x, patch-gcc-3.3.x: Add -J option. * dmd/constfold.d, dmd/declaration.h, dmd/func.c: update * d-glue.c: update Initial merge of DMD 1.007 (from DMD 1.005): * dmd/arraytypes.h, dmd/attrib.c, dmd/cond.c, dmd/constfold.c, dmd/declaration.c, dmd/declaration.h, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/init.c, dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/opover.c, dmd/optimize.c, dmd/parse.c, dmd/parse.h, dmd/statement.c, dmd/statement.h, dmd/template.c, dmd/typinf.c: Merge * phobos/internal/aApply.d, phobos/internal/aApplyR.d, phobos/internal/adi.d, phobos/internal/dmain2.d, phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d, phobos/internal/gc/win32.d, phobos/internal/object.d, phobos/std/base64.d, phobos/std/c/string.d, phobos/std/c/time.d, phobos/std/c/windows/com.d, phobos/std/c/windows/windows.d, phobos/std/dateparse.d, phobos/std/demangle.d, phobos/std/file.d, phobos/std/format.d, phobos/std/regexp.d, phobos/std/stdio.d, phobos/std/stream.d, phobos/std/string.d, phobos/std/thread.d, phobos/std/utf.d: Merge * dmd/interpret.c: New file 2007-03-03 David Friedman * phobos/std/c/darwin/darwin.d: Remove. (Bugzilla 984) * phobos/std/date.d: Cleanup * d-lang.cc: Evaluate BYTES_BIG_ENDIAN at runtime. * d-codegen.cc: Cleanup. * d-glue.cc: Initialize foreach key with zero, not default init. * patch-gcc-4.0.x, patch-gcc-4.1.x, patch-apple-gcc-4.0.x: Prevent emission of prologue and epilogue code for naked functions. (Bugzilla 1013) 2007-03-02 David Friedman * d-lang.cc: Test BYTES_BIG_ENDIAN at runtime. * d-glue.cc (ForeachStatement::toIR): Initialize key to zero, not defaultInit. * patch-build_gcc-4.0, phobos/acinclude.m4, phobos/configure.in, phobos/Makefile.am: Remove references to libgphobos.spec * phobos/Makefile.in, phobos/configure: Regenerate * patch-gcc-3.4.x, patch-gcc-3.3.x, patch-gcc-4.0.x, patch-gcc-4.1.x, patch-apple-gcc-4.0.x: Support enabling -pthread option by default without 'unrecognized option' error message. * d-spec.c (lang_specific_driver): Enable -pthread option * phobos/libgphobos.spec.in: Remove 2007-02-28 David Friedman * phobos/std/loader.d: Fix error 2007-02-27 David Friedman * setup-gcc.sh: Create directory of links instead of a single link. No longer need to copy support files. * target-ver-syms.sh: Support targets with both 32-bit and 64-bit modes. Output preprocessor definitions instead of command line otions. * Make-lang.in: Put target-ver-syms.sh output in d-confdefs.h. * package/simple.sh: Handle multilib. * phobos/configure.in: Use Automake, multilib. * phobos/Makefile.am: New file. * phobos/acinclude.m4: Fix quoting. * phobos/Makefile.in, phobos/configure: regenerated * patch-gcc-3.3.x, patch-gcc-3.4.x, patch-gcc-4.0.x, patch-gcc-4.1.x, lang-specs.h: Add %N spec code. * patch-build_gcc-4.0: Grab 64-bit libgphobos.a * dt.h, d-objfile.cc (dt_size): Change return type to target_size_t. Use target_size_t. (dtnzeros, dtdword, dtxoff): Change count to target_size_t (dtabytes, dtnbytes, dtawords, dtnwords, dtnbits): Change count to size_t (dti32): added * d-todt.cc: Cleanup. * d-objfile.cc: (dt2node): use Type::tsize_t for DT_word and DT_xoff * d-glue.cc: (PtrExp::toElem): Use target_size_t for offset (gcc_d_backend_init): Set CLASSINFO_SIZE and Tindex. (AssignExp::toElem): Use tsize_t for _d_arraycopy arg (CaseStatement::toIR): (not really a 64-bit change) Use int32 for case value to match libcall (CatAssignExp::toElem): cleanup (not 64-bit) (ForeachStatement::toIR): fix bug in key increment expression * d-codegen.{cc,h} (AggLayout::addField): use target_size_t for offset * d-codegen.cc: (...): LIBCALL_ARRAYCAST: Use size_t args (libcall already uses size_t) LIBCALL_ARRAYCOPY: ditto (convertTo): Use Type::tsize_t for _d_arraycat arguments * d-decls.cc (ClassDeclaration::toVtblSymbol): Use Type::tindex for array size. (FuncDeclaration::toThunkSymbol): Use target_ptrdiff_t * lang.opt: add -fmultilib-dir * d-lang.cc: Use -fmultilib-dir (d_init): Set global.params.isX86_64 if TARGET_64BIT. Set CPU version symbol according to TARGET_64BIT. Remove BitsPerPointer and BitsPerWord version symbols. * d-builtins2.cc (d_gcc_magic_builtins_module): Change "abi" integer types to "C". Add "pointer" integer types. (gcc_type_to_d_type): Use Type::tindex for array types. Use whole back-end size. * symbol.h (Thunk): Use target_ptrdiff_t for offset. * dmd/mars.h: Define target_size_t and target_ptrdiff_t to allow use of 32-bit size-tracking variables when generating 32-bit code. * dmd/aggregate.h: (CLASSINFO_SIZE) change to 'extern int' %%.... * dmd/cast.d: Use target_ptrdiff_t with isBaseOf. * dmd/class.c: (ClassDeclaration::semantic): use PTRSIZE (InterfaceDeclaration::semantic): Use sc->offset = PTRSIZE * 2 instead of 8 -- not sure what this is for... * dmd/dsymbol.[ch] (Dsymbol::size): Change to target_size_t * dmd/init.h: ArrayInitializer::dim <- chg to target_size_t * dmd/aggregate.h: Use target_ptrdiff_t and target_size_t * dmd/typinf.c (TypeInfoStructDeclaration::toDt): Use dti32 for flags. * dmd/toobj.c (Module::genmoduleinfo, ClassDeclaration::toObjFile, InterfaceDeclaration::toObjFile): ditto * dmd/func.c: Use target_ptrdiff_t with isBaseOf. (NewDeclaration::semantic): Allow Type::tuns64 if 64-bit. * dmd/mtype.c (Type::init): set CLASSINFO_SIZE (Type::dotExp): use Type::tsize_t for .offsetof property (TypeArray::dotExp): use Type::tsize_t for _adReverse args (TypeAArray::dotExp): use PTRSIZE to align keysize (TypeStruct::dotExp): use Type::tsize_t for offset (TypeStruct::alignsize): use target_size_t * dmd/mtype.h: Add Tindex global variable. (Type): Change tindex to baseic[Tindex]. (Type::isBaseOf): use target_ptrdiff_t * dmd/expression.[ch]: (SymOffExp): offset changed to target_size_t (NewExp::semantic): use size_t as argument (ArrayLiteralExp::toMangleBuffer, SymOffExp::toCBuffer): fix printf * dmd/declaration.c (VarDeclaration::semantic): use sinteger_t for dim * dmd/declaration.h: (Declaration::size): Use target_size_t (VarDeclaration): Use target_size_t for offset * dmd/schope.h: (Scope::offset) Use target_size_t. * dmd/statement.c: (ForeachStatement::semantic): Change return value of _a*Apply* to Type::tint32. Fix logic for allowed index variable types. Use PTRSIZE to align keysize. * dmd/struct.c (AggregateDeclaration::addField): use target_size_t * dmd/todt.c (StructInitializer::toDt): Use target_size_t for offsets (ClassDeclaration::toDt2): Use PTRSIZE * phobos/object.d, phobos/internal/object.d: (Interface): Use ptrdiff_t for offset. (*.toHash): cast pointer to size_t * phobos/internal/object.d: Use integer type definitions from phobos/object.d. Split %.*s args. * phobos/internal/adi.d: (_adReverse): Use size_t for szelem. * phobos/configure.in: fix multilib dir * phobos/configure: updated * phobos/config/cb_unix.c: Removed. * phobos/config/gen_config1.c: Add ssize_t. * phobos/config/config-head: Use __builtin_Clong and __builtin_Culong. * phobos/config/config-mid: Support X86_64 and other 64-bit CPUs. * phobos/config/unix-mid: Some size_t and ssize_t arg/return type fixes. * phobos/config/darwin8/frag-gen, phobos/config/darwin8/frag-unix: Support 32- and 64-bit. * phobos/config/mingw/frag-unix, phobos/config/skyos/frag-unix: Add ssize_t. * phobos/gcc/builtins.d: Update documentation * phobos/gcc/unwind.d: Use different builtin integer types. * phobos/internal/arraycat.d (_d_arraycopy): use size_t arg * phobos/std/c/fenv.d: Add field for 64-bit Linux. * phobos/std/c/linuxextern.d: Use C long for timezone. * phobos/std/c/stdio.d, phobos/std/c/stdlib.d, phobos/std/c/math.d, phobos/std/c/time.d: use C long types * phobos/std/stdint.d: Add C long types. Use ptrdiff_t and size_t for *intptr_t types. * phobos/std/format.d: Formatting structs on X86_64 looses * phobos/internal/cast.d (_d_isbaseof2): change offset to size_t * phobos/internal/fpmath.d: Support 64-bit CPUs. * phobos/std/file.d: Type of stat.st_size may vary; use auto. (Unix read): Make sure file's size is within range. * phobos/crc32.d, phobos/gcstats.d, phobos/internal/qsortg.d: phobos/internal/gc/gc.d (_d_arraycatnT), phobos/internal/gc/gcold.d (_d_arraycatn), phobos/internal/gc/gcx.d, phobos/internal/mars.h, phobos/std/base64.d, phobos/std/bitarray.d, phobos/std/math.d, phobos/std/math2.d, phobos/std/md5sum.d, phobos/std/outbuffer.d, phobos/std/path.d, phobos/std/string.d, phobos/std/uri.d phobos/std/typeinfo/ti_AC.d, use size_t, ptrdiff_t/ssize_t * phobos/std/loader.d: Add definitions for 64-bit Mach-O objects. * phobos/std/openrj.d, phobos/std/loader.d, phobos/std/moduleinit.d, phobos/std/socket.d, phobos/std/regexp.d, phobos/std/uri. d, phobos/std/zip.d: split '%.*s' args * phobos/std/typeinfo/ti_A*.d, phobos/std/typeinfo/ti_ptr.d: fix compare methods * phobos/internal/gc/gc_dyld.c: use uintptr_t * phobos/std/c/stdio.d, phobos/internal/gc/gcgcc.d: Don't use old version symbols. * phobos/std/c/mach/mach.d (natural_t): always a uint * phobos/etc/c/zlib.d: use Culog_t 2007-02-13 David Friedman * setup-gcc.sh: Copy the removed files from the top-level directory. 2007-02-10 David Friedman * phobos/config.guess, phobos/config.sub, phobos/install-sh: Remove files. * phobos/std/format.d (putAArray): account for alignment of the value * phobos/Makefile.in: fix metastrings.o 2007-02-09 David Friedman * phobos/std/format.d (doFormat): use aligntsize Rest of DMD 1.005 merge: * phobos/Makefile.in (MAIN_OBJS): add metastrings.o 2007-02-08 David Friedman * d-lang.cc, lang.opt: support -v1 option * lang.opt (d_init_options): set global.params.Dversion * dmd-script: -v1 -> -fd-version=1 * phobos/std/format.d (doFormat): Fix for var args differences Initial merge of DMD 1.005: dmd/attrib.c, dmd/attrib.h, dmd/cast.c, dmd/cond.c, dmd/constfold.c, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/inline.c, dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/optimize.c, dmd/parse.c, dmd/parse.h, dmd/scope.c, dmd/statement.c, dmd/statement.h, dmd/template.c, dmd/template.h, dmd/toobj.c, dmd/typinf.c: Merge. phobos/internal/aaA.d, phobos/internal/gc/gc.d, phobos/internal/object.d, phobos/linux.mak, phobos/std/c/stdlib.d, phobos/std/conv.d, phobos/std/ctype.d, phobos/std/format.d, phobos/std/regexp.d, phobos/std/zlib.d, phobos/std.ddoc, phobos/win32.mak: Merge. phobos/std/metastrings.d: New file 2007-02-05 David Friedman Release GDC 0.22 * d-codegen.cc (twoFieldType): Fix back end -> front end type mapping. * Make-lang.in: Enable ELFOBJ to put some RTTI in the read-only data section. * GDC.html: Update 2007-02-04 David Friedman * phobos/gcc/cbridge_time.c (_d_gnu_cbridge_tza), phobos/std/date.d: Fix timezone adjust sign 2007-02-03 David Friedman * phobos/config/unix-mid: Correctly initialize sockaddr* (Bugzilla 818) * dmd-script: Fix -H* options (Bugzilla 896). Support -framework. Fix error message. * d-lang.cc (d_write_global_declarations), patch-gcc-4.1.x: Fixes for dwarf2out ICEs * d-objfile.cc (check_static_sym): Fix setting TREE_CONSTANT. Rest of DMD 1.004 merge: * gcc-mars.cc, gdc-version: Update * phobos/std/regexp.d: update * phobos/internal/gc/gcold.d (_d_newarrayip): * phobos/internal/gc/gc.d: Fix argument and result types. * phobos/config/unix-head, phobos/config/unix-mid: Update * phobos/Makefile.in: Update for files removed in DMD 1.004 * d-decls.cc (TypedefDeclaration::toInitializer): Copy from dmd/tocsym.c. Create the Sdt here. * dmd/toobj.c (TypedefDeclaration::toObjFile): Update for toInitializer change * dmd/mtype.c (TypeArray::dotExp): Fix library call decls * d-lang.cc: Update * d-codegen.[ch], d-glue.cc: Update memory allocation library calls. * d-lang.cc (d_write_global_declarations): call emit_debug_global_declarations only for GCC 4.0 * dmd/mtype.c (TypeArray::dotExp): update * phobos/config/unix-head, phobos/config/unix-mid: update * phobos/internal/gc/gcold.d: Use old GDC modifications. 2007-02-02 David Friedman Initial merge DMD 1.004: * dmd/aggregate.h, dmd/attrib.c, dmd/attrib.h, dmd/declaration.c, dmd/declaration.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c, dmd/import.c, dmd/import.h, dmd/inline.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/mtype.h, dmd/struct.c, dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/todt.c, dmd/toobj.c, dmd/typinf.c: Merge DMD 1.004 * phobos/internal/aaA.d, phobos/internal/adi.d, phobos/internal/arraycast.d, phobos/internal/arraycat.d, phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d, phobos/internal/gc/linux.mak, phobos/internal/gc/win32.mak, phobos/internal/object.d, phobos/linux.mak, phobos/object.d, phobos/std/c/linux/linux.d, phobos/std/compiler.d, phobos/std/file.d, phobos/std/gc.d, phobos/std/outbuffer.d, phobos/std/random.d, phobos/std/regexp.d, phobos/std/typeinfo/ti_AC.d, phobos/std/typeinfo/ti_Acdouble.d, phobos/std/typeinfo/ti_Acfloat.d, phobos/std/typeinfo/ti_Acreal.d, phobos/std/typeinfo/ti_Adouble.d, phobos/std/typeinfo/ti_Afloat.d, phobos/std/typeinfo/ti_Ag.d, phobos/std/typeinfo/ti_Aint.d, phobos/std/typeinfo/ti_Along.d, phobos/std/typeinfo/ti_Areal.d, phobos/std/typeinfo/ti_Ashort.d, phobos/std/typeinfo/ti_C.d, phobos/std/typeinfo/ti_cdouble.d, phobos/std/typeinfo/ti_cfloat.d, phobos/std/typeinfo/ti_char.d, phobos/std/typeinfo/ti_creal.d, phobos/std/typeinfo/ti_dchar.d, phobos/std/typeinfo/ti_delegate.d, phobos/std/typeinfo/ti_double.d, phobos/std/typeinfo/ti_float.d, phobos/std/typeinfo/ti_ptr.d, phobos/std/typeinfo/ti_real.d, phobos/std/typeinfo/ti_void.d, phobos/std/typeinfo/ti_wchar.d, phobos/win32.mak: Merge DMD 1.004 * phobos/std/typeinfo/ti_Aa.d, phobos/std/typeinfo/ti_Adchar.d, phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_Auint.d, phobos/std/typeinfo/ti_Aulong.d, phobos/std/typeinfo/ti_Aushort.d, phobos/std/typeinfo/ti_Awchar.d: Removed in DMD 1.004 * phobos/internal/gc/gcold.d: New in DMD 1.004 2007-02-01 David Friedman * d-lang.cc (d_write_global_declarations): Emit debug info. * d-codegen.cc (twoFieldType): Fix debugging information. * d-objfile.cc (initTypeDecl): Ditto. * d-glue.cc (PtrExp::toElem): Don't wrap the result in a NOP_EXPR. * Make-lang.in: Add d-tree.def to dependencies 2007-01-30 David Friedman GCC 4.1.x changes: * GDC.html, INSTALL, INSTALL.html, README: update * dmd/idgen.c, dmd/impcnvgen.c, dmd/mtype.h: Change to allow compilation as C. * patch-gcc-4.1.x, patch-toplev-4.1.x: New files * Make-lang.in: Use $(version) instead of $(gcc_version). Add d-bi-attrs-41.h. Use C for generator programs instead of C++. * d-bi-attrs-41.h: New file. * d-builtins.c: update * d-builtins2.cc: Do not associate d_gcc_builtin_va_list_d_type with va_list_type_node. Do this for GCC 4.0 and 4.1. * d-codegen.cc: Use CtorEltMaker. (maybeExpandSpecialCall): Cast d_gcc_builtin_va_list_d_type to va_list_type_node. (hostToTargetString): Update. * d-codegen.h: Add CtorEltMaker class for before/after 4.1.x compatibility. * d-convert.cc: Add special case for pointer/int comparison * d-decls.cc: Do not use SET_DECL_ASSEMBLER_NAME for CONST_DECLs * d-gcc-includes.h: Include vec.h * d-glue.cc: Use CtorEltMaker. (gcc_d_backend_init): Call default_init_unwind_resume_libfunc * d-lang.cc: Add d_types_compatible_p hook for va_list conversion * d-lang.h: Update * d-objfile.cc: CtorEltMaker. * phobos/std/conv.d: Do not assume signed integer wraparound. 2007-01-28 David Friedman * d-asm-i386.h, d-codegen.cc, d-gcc-real.cc, d-decls.cc, d-glue.cc, d-lanc.cc: various fixes * d-codegen.cc, d-codegen.h, d-glue.cc, d-lang.h: Remove bit array code 2007-01-27 David Friedman * d-asm-i386.h: fix fistp, lmsw, lldt, mov[sz]x, setCC, smsw, and sldt instructions (Bugzilla 836, 837, 838, 839, 841, 843, 844). Also r[co][lr]. * d-glue.cc (StringExp::toElem): Correct termination of wchar and dchar (Bugzilla 889) 2007-01-11 David Friedman * INSTALL.html: fix corruption 2007-01-03 David Friedman Release GDC 0.21 * GDC.html: New file. * README: Update, refer to GDC.html Rest of DMD 1.00 merge: * d-codegen.cc: Patch from Anders Bjrklund for GCC 3.3 * d-glue.cc (FuncDeclaration::toObjFile): Fix shouldDefer/outputStage logic. * dmd/attrib.c (PragmaDeclaration::semantic): uint -> unsigned * dmd/module.c (load): output to stdmsg * dmd/mtype.c: revert '@' mangling changes * gdc-version, gcc-mars.cc: update * phobos/config/unix-mid: Support more functions * phobos/acinclude.m4, phobos/config/gen_unix.c (c_pthread): Support more types * phobos/configure, phobos/config.h.in: update * phobos/config/darwin8/frag-unix: update Initial merge of DMD 1.00: * dmd/cond.c, dmd/constfold.c, dmd/delegatize.c, dmd/dsymbol.c, dmd/enum.c, dmd/expression.c, dmd/expression.h, dmd/init.c, dmd/inline.c, dmd/mars.c, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/parse.c, dmd/statement.c, dmd/struct.c, dmd/template.c, dmd/todt.c: Merge 1.00 * internal/gc/gc.d, phobos/linux.mak, phobos/std/c/linux/linux.d.orig-dmd, phobos/std/c/stdlib.d, phobos/std/conv.d, phobos/win32.mak: Merge 1.00 * phobos/std/c/linux/pthread.d.orig-dmd: New file (originally pthread.d DMD) ------------------------ * dmd/init.c (ArrayInitializer::semantic), * dmd/root.c (OutBuffer::write4): 64-bit host cleanup * d-asm-i386.h: cleanup, saftey 2007-01-02 DF * d-codegen.cc (convertTo): Use 64-bit for Tarray, Tsarray conversion. * d-codegen.{h, cc} (darrayVal): use uinteger_t arg Copyright (C) 2007 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2008 ================================================ 2008-12-12 Arthur Loiret Bugzilla 929: * dmd/mtype.c: Provide isZeroInit() overload in TypeAArray that returns TRUE. * dmd/mtype.h: Add prototype for TypeAArray::isZeroInit(). * dmd2/mtype.c, dmd2/mtype.h: Ditto. 2008-07-21 David Friedman * dmd/root.c, dmd2/root.c: Fix earlier patching error. * phobos/config/x3.c, phobos2/config/x3.c: Fix problem when building under MSYS. * config-lang.in: Remove lang_requires. 2008-07-20 David Friedman * dmd/expression.c, dmd2/expression.c: Make integer conversion fix work for other hosts/targets. 2008-07-20 Arthur Loiret * dmd/expression.c: Fix integer conversion routines on x86_64. Patch from downs , thanks! * dmd2/expression.c: Likewise. * config-lang.in: Add lang_requires="c c++". 2008-07-19 David Friedman * patches/patch-gcc-4.0.x, patches/patch-gcc-4.1.x: Fix infinite loop bug in patch. * patches/patch-apple-gcc-4.0.x: Ditto. * d-lang.cc: Do not assume D_OS_VERSYM is defined. Handle TARGET_xxx_CPP_BUILTINS macros for more targets. 2008-07-17 David Friedman * dmd-script: Append an exe suffix to executables when the target is Windows. * phobos/gcc/deh.d, phobos2/gcc/deh.d: Fix for sjlj exceptions. 2008-06-16 David Friedman * d-decls.cc: Correct logic for output constanting vars for V1. 2008-06-01 David Friedman Merge DMD.1.30 and 2.014 * dmd-script: Implement -man, -lib and single-object features. * phobos2/Makefile.am: add bigint * phobos2/config/{ldfuncs,ldfuncs-darwin,ldfuncs-ppclinux,noldfuncs}, Merge nanl change from std/c/math.d * phobos2/gcc/support.d: Merge std/c/math.d changes. * d-objfile.cc (obj_append): Implement. * phobos2/std/c/unix/unix.d: Merge linux.d and socket.d changes * d-glue.cc, d-irstate.cc, d-lang.cc: Update * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge 2008-05-26 David Friedman * asmstmt.cc, d-decls.cc, d-glue.cc, d-misc.c, d-objfile.{cc, h}: Fix for -combine compilation. Remove fileContext global and clean up generation of unique symbol names. * phobos/internal/object.d: Correct merge error ---- * dmd-script, lang.opt, d-lang.cc, : support -ignore Merge DMD 1.029 and 2.013 * phobos2/std/perf.d: use std.c.unix.unix 2008-05-22 Arthur Loiret * target-ver-syms.sh: Add missing CPUs and fix d_cpu_versym/d_cpu_versym64 for each. * d-lang.cc: Fix build on non biarched 64-bit archs (alpha, ia64, ...) and fix 64-bit cpu detection. * Move patch-* to patches/ * setup-gcc.sh: Update. 2008-05-10 David Friedman * lang-specs.h: Support a "cc1d" spec. (Bugzilla 2068) Merge DMD 1.028 and 2.012 * d-codegen.{h,cc}: Add postblitting array libcalls. * phobos2/internal/arrayassign.d (_d_arraysetassign, _d_arraysetctor): Use size_t. * d-glue.cc (AssignExp::toElem): Postblit-aware code * phobos2/Makefile.am: Add arrayssign.d. Remove math2.d. * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge 2008-05-03 David Friedman * d-dmd-gcc.h, d-glue.cc, dmd*/toobj.c: Cleanup: Remove unused d_gcc_aggregate_dtors. 2008-05-02 David Friedman Merge DMD 1.027 and 2.011 * termios.d: Point to std.c.unix.unix. Leave original termios.d as termios.d.orig-dmd * asmstsmt.cc: Implement blockExit * phobos2/config/unix.x3: Add termios stuff * phobos2/std/c/unix/unix.d: Merge new funcs from std.c.linux.d * d-objfile.cc: Implement stub obj_startaddress * d-glue.cc (ForStatement::toIR): condition may be NULL (DeleteExp::toIR): Use libcalls for interfaces * dmd*/clone.c, dmd*/e2ir.c: New files. * Make-lang.in: Add new clone.c * d-codegen.{h, cc}, d-glue.cc: Use _d_callinterfacefinalizer. Also use _d_delinterface instead of casting. * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge 2008-04-27 David Friedman Merge DMD 1.026 and 2.010 * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge --- * d-lang.cc (d_write_global_declarations): Make earlier change regarding cgraph_optimize only apply to 4.0.x. --- * d-decls.cc (VarDeclartion::toSymbol): Change for V2 STCmanifest. Make more constant vars have static storage (instead of making CONST_DECLs) in both V1 and V2. * dmd2/constfold.c (Cmp): Compare wchar and dchar strings portably. * asmstmt.cc (ExtAsmStatement::semantic): Heuristic for evaluating operands: If an input operand, evaluate. * d-asm-i386.h: Make previous change apply to V1. * d-glue.cc (TypeEnum::toCtype): Update. Phobos changes (applies to V2 Phobos as well): * phobos/Makefile.am, phobos/configure.in: Deal with strerror_r portability. * phobos/Makefile.in, phobos/configure, phobos/config.h.in: Updated. * phobos/gcc/cbridge_strerror.c: New file. * phobos/std/c/string.d: Replace non-portable strerror_r with _d_gnu_cbridge_strerror. * phobos/std/file.d, phobos/std/loader.d, phobos/std/process.d, phobos/std/socket.d, phobos/std/stdio.d: Use _d_gnu_cbridge_strerror. Merge DMD 2.009: * dmd2/..., phobos2/...: Merge. Merge DMD 1.025: * dmd/..., phobos/...: Merge. 2008-04-25 David Friedman * asmstmt.cc, d-asm-i386.h: Handle some other cases for constant floating point operands. 2008-04-19 David Friedman * dmd/toobj.c, dmd2/toobj.c (EnumDeclaration::toObjFile): Output initializer correctly. * d-decls.cc (EnumDeclaration::toInitializer): Correctly set up initializer symbol. (Bugzilla 1746) 2008-04-17 David Friedman * dmd/toobj.c (InterfaceDeclaration::toObjFile): Fix error. (Bugzilla 1844) 2008-04-16 David Friedman * d-codegen.{h, cc}: Clean up nested function / nested class / closure code. * phobos/std/c/stdlib.d, phobos2/...: Remove comment that hides atof. (Bugzilla 1888) 2008-03-11 David Friedman * d-glue.cc: cleanup * dmd/expression.c (DotVarExp::semantic): Apply fix from dmd2/ * dmd2/expression.c (DotVarExp::semantic): Move fix to better location. 2008-03-09 David Friedman * dmd2/func.c (FuncDeclaration::needsClosure): Closures fix: Change test from isVirtual to isThis. * dmd2/expression.c (DotVarExp::semantic): Note change from DMD. ---- * patch-build_gcc-5465: Correctly build driver-driver * phobos*/Makefile.am (MAIN_OBJS): Add std/cover.o * phobos2/std/file.d: use 'mkdir -p' in unittest * d-builtins2.cc: Fixes for pointer-to-function types (for V2) * d-codegen.cc: Add _d_allocmemory libcall. (emitLocalVar): Rework. (var): New function to handle static-frame/closure variables (convertTo): Use typesSame instead of typesCompatible (assignValue): New function to handle Exp(v=value) vs. Exp(value) (getFrameForFunction, getFrameForNestedClass): New interface to get frames for nested functions. (functionNeedsChain): Return false for nested functions that take closures. * d-decls.cc: Changes for const/invariant/STCinit * d-glue.cc: Use new interface for nested functions. Use IRState::var instead of v->toSymbol()->Stree. Create closures. * d-lang.cc: Implement CONVERT_PARM_FOR_INLINING hook * d-objfile.cc: Add case for closure-using function when setting the link-once attribute. * package/simple.sh: install .../include/d2 * patch-build_gcc-4.0, patch-build_gcc-5465: Support D 2.0 includes and libraries. * phobos2/std/bitmanip.d: Apply previous bitarray.d changes. * phobos*/std/typeinfo/ti_ptr.d (getHash): Cast to hash_t. * d-decls.cc (VarDeclaration::toSymbol): For D 2.0, use isInvariant() and STCinit as criteria for making CONST_DECLs and setting TREE_READONLY. * phobos2/std/c/linux/linux.d: Do not import std.c.dirent. * phobos2/std/c/dirent.d: Deprecated std.c.dirent. * phobos2/std/c/unix/unix.d: Move dirent/DIR routines here. * phobos*/std/c/darwin/ldblcompat.d: declare constants as 'string' Merge DMD 2.008: * dmd2/..., phobos2/...: Merge. Merge DMD 1.024: * phobos*/config/unix.x3: ensure MSG_NOSIGNAL is defined * dmd/..., phobos/...: Merge. ------ * patch-apple-gcc-4.0.x, patch-apple-gcc-5465: Include patch for SRA pass like the other 4.x patches. * d-codegen.cc (convertTo): Ensure pointers are cast to an unsigned type. * d-objfile.cc (dt2tree_list_of_elems): Always generate a CONSTRUCTOR for struct data. (ObjectFile::ObjectFile): Use NULL_TREE for file context instead of TRANSLATION_UNIT_DECL. * d-lang.cc (d_write_global_declarations): Call debug_hooks->global_decl before cgraph_optimize so that nested class functions do not get passed to dwarf2out before the outer class functions. * Rename patch-build_gcc-4.0 to patch-build_gcc-4.0.x Copyright (C) 2008 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2009 ================================================ 2009-12-28 michaelp Merge with DMD 1.043 * phobos/configure.in: Changed part of phobos configure. * samples/README, samples/samples.sh: Uploading the start of the some small tests to help in the testing of GDC/D components. * Make-lang.in, d-lang.cc, dmd/machobj.c, phobos/config/unix.x3, phobos/std/file.d, phobos/std/moduleinit.d, phobos/std/socket.d: Fixed problem when building on Mac OS X. 2009-12-05 michaelp Merge with DMD 1.042 * Make-lang.in: Added async.dmd.o * d-asm-i386.h, d-codegen.h: Merge changes from dmd/constfold.c. * d-codegen.h, phobos2/aclocal.m4, phobos2/configure.in: Fixed problems with D2. 2009-11-22 michaelp Merge with DMD 1.041 * Make-lang.in: Update for files added in DMD 1.041. * d-backendfunctions.c: Added stubs for functions in the backend that cannot be included in the front end source. * dmd-script: Added Bitbucket page to display for gdmd wrapper script. 2009-11-07 Vincenzo Ampolo Changes to GCC-4.4.x branch: * tools/makewebstatistics.d: Added d tool to generate webstats about dstress in D2. 2009-10-25 michaelp Merge with DMD 1.040 * dmd/..., phobos/...: Now working for D1 (Not on GCC 4.3.4?) * asmstmt.cc: Merge from dmd/statement.c * phobos/acinclude.m4, phobos/configure.in, phobos/phobos-ver-syms.in: Posix is now defined. 2009-10-24 Vincenzo Ampolo * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/constfold.c, dmd/declaration.c, dmd/dsymbol.c, dmd/expression.c, dmd/toobj.c: Fixes some errors in the DMD v1 frontend. Trying to fix DMD 1.039, but still no fix. The problem may be in phobos then. Changes to GCC-4.4.x branch: * d-lang.cc, d-lang.h setup-gcc.sh, patches/patch-gcc-4.4.x, patches/patch-toplev-4.4.x: Applied Eldar patches for gcc 4.4.0 2009-10-07 Vincenzo Ampolo * dmd2/attrib.c, dmd2/class.c, dmd2/declaration.c, dmd2/doc.c, dmd2/dsymbol.h, dmd2/func.c, dmd2/parse.c, dmd2/statement.c, dmd2/template.c, dmd2/toir.c: 2.015 WORKING ;) * dmd2/parse.c: Fixed problem with static if. * dmd2/template.c: Fixed problem with tuples. * Makefile-lang.in: Update for files added in DMD 2.015. 2009-10-01 Vincenzo Ampolo Changes to 2.032 branch: * dmd2/..., phobos2/...: Force merge with 2.032 - NOT WORKING AT ALL. - Adding new files. 2009-10-04 michaelp Merge with DMD 1.039 * d-decls.cc: Merge changes from dmd/mtype.h. * phobos/internal/aaA.d, phobos/std/stdio.d: Small Phobos fix. 2009-09-30 Vincenzo Ampolo * phobos2/internal/aaA.d, phobos2/linux.mak, phobos2/std/algorithm.d, phobos2/std/functional.d, phobos2/std/math.d, phobos2/std/thread.d: DMD 2.015 Phobos changes. * Make-lang.in: Fixed a problem introduced by Michael modifying a common file between D1 and D2. 2009-09-29 michaelp Merge with DMD 1.036 2009-09-28 Vincenzo Ampolo Merge with DMD 2.015 * dmd2/mtype.h, dmd2/parse.c: Fixed parser in D2. * dmd2/template.c, dmd2/toobj.c: Other fixes. 2009-09-28 michaelp Merge with DMD 1.035 * d-objfile.cc: Merge changes from dmd/attrib.c. * phobos/Makefile.in, phobos/internal/arraydouble.d, phobos/internal/arrayfloat.d: Included arraydouble, arrayfloat, and arrayreal in libphobos Makefile. * asmstmt.cc, dmd/statement.c, dmd/statement.h, phobos/std/math.d: Fixed Phobos std.math bug. 2009-09-25 michaelp Merge with DMD 1.033 2009-09-17 Vincenzo Ampolo * dmd2.032/...: Initial import of version 2.032. * setup-gcc.sh, dmd/.svn/...: Removed .svn directory. 2009-09-13 michaelp * phobos/std/boxer.d phobos/std/dateparse.d: Fixed phobos build and possible implicit conversion errors in boxer.d. * d-objfile.cc: Removed assert(0) line 926. 2009-09-13 Vincenzo Ampolo * History gdc-version: Changed version. * phobos2/config/x3, setup-gcc.sh: Added support for DMD 2. * phobos2/std/c/string.d, phobos2/std/contracts.d: Fixed a std.string bug following these guidelines: http://www.digitalmars.com/d/archives/D/gnu/strerror_r_3403.html * phobos2/std/contracts.d, phobos2/std/date.d, phobos2/std/dateparse.d, phobos2/std/file.d, phobos2/std/md5.d, phobos2/std/path.d, phobos2/std/random.d, phobos2/std/stdio.d: Fix DMD 2 for GCC-4.3.4 2009-09-11 Vincenzo Ampolo Switching to Mercurial branch system. * d/...: Setting up default branch with GCC-4.3.x support. * branches/gcc-4.1/...: Starting gcc-4.1.x stable branch. * setup-gcc.sh, target-ver-syms.sh: Fixed permission problems in bash scripts. 2009-09-10 Vincenzo Ampolo * trunk/...: Import of gdc 0.24 stable into bitbucket. 2009-01-31 Arthur Loiret * d-glue.cc, d-objfile.cc, d-codegen.cc, d-lang.h, d-builtins2.cc, d-convert.cc, d-codegen.h: Replace calls to build macro by appropriate buildN function (build is removed in GCC > 4.1). Copyright (C) 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2010 ================================================ 2010-12-28 Iain Buclaw * d/d-lang.cc, d/patches/patch-apple-gcc-5465, d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: New function added to langhooks: d_dump_tree [8a2198026630] * d/d-lang.cc, d/patches/patch-apple-gcc-5465, d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/phobos2/Makefile.am, d/phobos2/Makefile.in: New function added to langhooks: d_gimplify_expr [0d43883dcc75] * d/d-builtins2.cc, d/druntime/core/stdc/complex.d, d/druntime/rt/complex.c, d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 - Use GCC builtins in core.stdc.complex [d13bd5912295] * d/d-codegen.cc, d/d-glue.cc: Issue #109 - segfault in memcpy() [80c61a61f254] 2010-12-23 Iain Buclaw * d/Make-lang.in, d/asmstmt.cc, d/d-bi-attrs-45.h, d/d-c-stubs.c, d/d-cppmngl.cc, d/d-gcc-includes.h, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated to 2.051. [9d12fbe44d3] * d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 - Move generated headers out of the way so as they don't interfere with build process. [c52428bb97b] * /druntime/rt/aaA.d, d/druntime/rt/adi.d, d/druntime/rt/lifetime.d, d/druntime/rt/memory.d, d/druntime/rt/qsort.d, d/druntime/rt/switch_.d, d/druntime/rt/util/string.d: Merge differences between GDC and DMD Druntime. Should fix Issue #129 [1d6e8e716ae3] * d/d-glue.cc, d/d-lang.cc, d/druntime/rt/dmain2.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/gcc/bitmanip.d: Fix codegen in ArrayLiteralExp; Split cmain from dmain2 in druntime; Update gcc.bitmanip for 2.051. [b1393d6cc45a] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc, d/dt.cc: Use build_constructor to make constructor nodes. [bd721e198eff] 2010-12-17 Iain Buclaw * d/d-codegen.h, d/d-glue.cc, d/dmd/expression.c, d/dmd2/expression.c: Fix handling of _argptr after commit 398. [95992bb703de] * d/d-lang.cc, d/patches/patch-gcc-4.4.x: Issue #104 revisited - easier to instead fix in GCC. [dedbc5dc14a9] * d/d-lang.cc: Issue #104 - ICE on inlining nested struct member functions [eb09c05188ea] * d/d-decls.cc: Issue #85 - template functions not inlined. [c9db2183900a] 2010-12-12 Iain Buclaw * d/d-builtins2.cc, d/d-lang.cc, d/dmd2/toobj.c: D2 - tighten up purity set on builtins. [677ff59c566] * d/GDC.html, d/dmd/attrib.c, d/dmd/idgen.c, d/dmd2/attrib.c, d/dmd2/idgen.c, d/phobos/gcc/unwind_arm.d, d/phobos2/gcc/unwind_arm.d: GNU_attribute and GNU_set_attribute deprecated for promoting attribute and set_attribute. [99b197365502] * d/d-glue.cc, d/d-objfile.cc, d/dmd2/expression.c, d/dmd2/todt.c: cleanup todt; testsuite fixes. [3ee0b55b9fcc] 2010-12-10 Iain Buclaw * d/d-builtins2.cc, d/d-dmd-gcc.h, d/dmd2/builtin.c, d/dmd2/declaration.h, d/dmd2/expression.c, d/dmd2/interpret.c: Power operators ^^ now working in CTFE. [d804e40bb245] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #121 - ICE in gimple_rhs_has_side_effects. [63a29e175dba] * d/d-codegen.cc, d/d-codegen.h, d/d-gcc-real.h, d/d-irstate.h, d/d-lang.h, d/d-objfile.h, d/dt.h: Glue Header code cleanups. [42d36e6321f5] * d/phobos2/std/math.d: Issue #113 - std.math: cos/sin forward declaration issue. [089fa0826192] * d/d-asm-i386.h, d/phobos2/std/math.d: Add special case for fdiv/fsub opcodes. [69b717b206e1] * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc: Glue code cleanups. [03e46b45acfc] * d/d-asm-i386.h, d/dmd2/expression.c, d/phobos2/std/math.d: off-by-one Inline asm fix. [9f3bb8c3e1e4] * d/d-builtins2.cc, d/d-codegen.cc, d/dmd2/builtin.c, d/dmd2/declaration.h, d/dmd2/interpret.c, d/phobos2/Makefile.in, d/phobos2/configure: D2 - GCC builtins now CTFE'd. [46b8a2bb22f5] 2010-12-04 Iain Buclaw * d/d-lang.cc, d/druntime/gc/gcgccextern.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/std/math.d, d/setup-gcc.sh, d/target-ver-syms.sh: Updated FreeBSD and Solaris version identifiers. [a52396ea0fa4] 2010-12-03 Iain Buclaw * d/d-asm-i386.h, d/d-spec.c, d/dmd2/root.c, d/dmd2/speller.c, d/druntime/core/sys/posix/setjmp.d, d/phobos2/configure, d/phobos2/configure.in, d/phobos2/std/math.d: Applied patches from Issue #100, some work on Phobos/Druntime ARM port. [8dbea571bd08] * d/d-asm-i386.h, d/d-builtins.c, d/d-lang.cc: Issue #118 - Segfault on string compare. [e2092db74028] 2010-11-26 Iain Buclaw * d/d-decls.cc: Issue #110 - Pure Nothrow Functions Not Called. [46680c366e68] * d/dmd/entity.c, d/dmd2/entity.c: Fixes to html entities. [954a116bc175] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-irstate.h: D2 - support 'case var:' in switch statements. [af08a1a054c8] * d/d-glue.cc, d/d-objfile.cc, d/dmd/expression.c, d/dmd2/expression.c: Check lwr <= upr in pointer array slices, fixed AA bug using const types. [0a0c8ff325da] * d/druntime/core/sys/osx/mach/kern_return.d, d/druntime/core/sys/osx/mach/port.d, d/druntime/core/sys/osx/mach/semaphore.d, d/druntime/core/sys/osx/mach/thread_act.d: Add version(OSX) at top of source files. [106a741599c6] * d/d-glue.cc: Fix ICE compiling empty with{} or volatile{} statements. [e83350ff851b] * d/druntime/rt/aaA.d, d/phobos2/std/format.d, d/phobos2/std/string.d: Fix bug in aaA.d, remove workaround in std.format. [6549ec58cf1c] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/druntime/rt/lifetime.d: Issue #108 - crash when compiling declaration of a big array. [38209ac30752] * d/d-builtins2.cc, d/d-glue.cc, d/dmd2/expression.c, d/dmd2/expression.h, d/dmd2/optimize.c, d/druntime/core/atomic.d, d/dt.cc, d/dt.h: Refs #108 - Prevent crash when compiling declaration of a big array. [bece6cdf81f8] 2010-11-21 Iain Buclaw * d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc, d/d-cppmngl.cc, d/d-gcc-real.cc, d/d-glue.cc, d/druntime/core/stdc/stdarg.d, d/druntime/rt/lifetime.d, d/dt.cc, d/symbol.cc: Add _d_arrayliteralT as libcall. [1d3d564d0bfc] * d/d-glue.cc, d/dmd2/expression.c, d/druntime/core/stdc/stdarg.d, d/phobos2/std/algorithm.d: Issue #107 - compilation failed on associated array.clear() [75733609b163] * d/d-decls.cc, d/d-lang.cc, d/gdc.1, d/lang.opt, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Issue #106 - compilation failed on files importing std.xml. [3205e04db834] * d/d-objfile.cc, d/druntime/object.di, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Makefile now properly creates D interface files for installing. 2010-11-19 Iain Buclaw * d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.050. [93726e7f3043] * d/d-glue.cc, d/dmd2/*, d/phobos2/*: Issue #95 - 'Hello World' for 64bit not working. [f58b9a4c4827] * d/Make-lang.in, d/d-codegen.cc, d/d-decls.cc, d/d-irstate.cc, d/druntime/gc/gcgccextern.d, d/dt.h, d/phobos2/Makefile.am: No more segfaults from calling the moduleTlsDtor of a spawned thread. [7afee485d3ec] * d/druntime/core/atomic.d, d/druntime/rt/dmain2.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Fix makefile to generate & install .di headers for druntime. [8d8f3f8e346f] * d/d-codegen.cc, d/d-glue.cc, d/druntime/rt/memory.d: Passes the compilable/fail_compilation testsuite. Fix off-by-one static assert in rt.memory. [a05310b5bd39] * d/d-codegen.cc, d/druntime/core/atomic.d, d/druntime/rt/monitor.c: Don't make a libcall for _d_arraycast when converting void[] to array[]. Fix a hang in the generic atomicOps. [d9555265c627] * d/Make-lang.in, d/d-apple-gcc.c, d/d-codegen.cc, d/d-glue.cc: Remove redundant tree checking. Fold in apple-gcc patches. [a62de16def16] * d/patches/patch-apple-gcc-5664, d/patches/patch-build_gcc-5664: New patches for apple-gcc. [80db7b3f1bbc] * d/dmd/entity.c, d/dmd2/entity.c: Merge Walter's and Thomas' named entity lists. [8949157fe7b0] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #98 - cannot perform floating-point modulo division on creal. [53c34b538c56] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #102 - Fixed error using overloaded <>= operator. [61db8ca7622c] * d/d-glue.c: Issue #89 - Error initialising struct with static array. [24f69762e9c3] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #103 - destructor not called on array of structs. Postblit on struct now called when returned from a function. [cb7faae1f7b9] * d/druntime/object_.d: Merge workaround from Phobos1 library. [336c20f065e4] * d/phobos/std/math.d, d/phobos2/std/math.d: Add aliases for missing rndtol and rndtonl functions. [86eb7cecbe6a] * d/d-codegen.cc, d/d-glue.cc: Properly handle return (void)value. In slice expression [lwr .. upr], ensure lwr gets evaluated first. Tree checking fixes in NewExp and floatMod. [967482328f44] 2010-11-13 Iain Buclaw * d/d-c-stubs.c, d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.049. [6c13728646ec] * d/druntime/core/sys/posix/sys/select.d: Issue #90 - select.d fails to compile on 64 bits Linux. [9cd6979d9a7d] * d/druntime/core/sys/posix/sys/select.d, d/druntime/rt/lifetime.d, d/phobos2/gcc/bitmanip.d, d/phobos2/std/bitmanip.d, d/phobos2/std/regexp.d: Issue #91, #92, #93 - various issues building on 64bit Linux. [c3ef6baccc9d] 2010-11-12 Iain Buclaw * d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-convert.cc, d/d-cppmngl.cc, d/d-glue.cc, d/d-lang.cc, d/d-spec.c, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.048. [0d91f8245403] * d/druntime/core/sys/posix/sys/select.d: Fix some 64bit compat issues with druntime module. [05bb4c2b1f7d] 2010-11-08 Iain Buclaw * d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/d-lang.cc, d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.047. [4bd4615c8a7e] 2010-11-07 Iain Buclaw * d/Make-lang.in, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/dmd-script, d/dmd-script.1, d/gdc.1, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.046. Removed tabs, trailing spaces. [5be9e0023b23] 2010-11-05 Iain Buclaw * d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.040. [5beb7019c5e6] 2010-11-03 Iain Buclaw * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos/etc/c/zlib.d, d/phobos/std/zlib.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/etc/c/zlib.d, d/phobos2/std/zlib.d, d/zlib/*: Upgrade zlib support to zlib 1.2.5. [ea7e83019088] * d/d-gcc-real.cc: Issue #79 - Wrong decimal value in error message. [71d8713b0604] * d/phobos2/std/json.d, d/setup-gcc.sh: Added --update option for setup-gcc.sh to rebuild directory of libphobos links. * d/dmd/typinf.c, d/dmd2/typinf.c: Issue #83 - wrong TypeInfo_Struct name outputted. [f9ddff9d5ed9] * d/d-lang.cc: Bugzilla 1911 - Link error when creating array of typedefs with default initializer. [8667626321e7] 2010-11-01 michaelp * d/d-codegen.cc: Issue #76 - odd error message when casting between non-convertable types. [0c78536565d6] 2010-11-01 Iain Buclaw * d/asmstmt.cc, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.037. [e37f9fae0867] * d/druntime/compiler/gdc/object_.d, d/druntime/compiler/gdc/rt/aaA.d, d/druntime/import/object.di: Issue #82 - undefined references in object.d [0aff60753810] 2010-10-31 Iain Buclaw * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.036. [6bf237fb6ba6] * d/d-decls.cc, d/d-glue.cc: Issue #80 - Bad codegen for structs containing invariants. [2fe867d16c45] * d/d-codegen.cc, d/d-glue.cc: Issue #81 - Bad codegen and ICEs using enums. [3d028b2d1d30] * d/d-lang.cc: Issue #76 - Hide 'In file included from ' message in errors. [d590dd56696b] * d/phobos2/std/string.d, d/phobos2/std/zlib.d: Fix return result of cmp(). [582cd1b0bff4] * d/d-builtins2.cc, d/druntime/import/core/stdc/math.d: All GCC builtins now marked pure and optionally nothrow. core.stdc.math functions made builtin. [dc2b50a4c0f6] 2010-10-27 Iain Buclaw * d/Make-lang.in, d/d-glue.cc, d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Update D2 frontend to 2.035. [ef0d5e8ec06d] * d/d-glue.cc: Adjust Classinfo size for D2. [b8673983b46b] * d/patches/*, d/set-gcc.sh: Updated patches and setup-gcc.sh for Apple GCC. [b25313940945] * d/d-asm-i386.h, d/phobos/std/cpuid.d, d/phobos2/std/cpuid.d: Tell backend cpuid clobbers EBX; remove workaround in std.cpuid. [3cbf9b8108a2] 2010-10-24 michaelp * d/d-glue.cc, d/druntime/*, d/phobos2/*: Issue #77 - porting D2 Phobos to x86_64. [cf5f02e03fda] 2010-10-23 Iain Buclaw * d/phobos2/*: Issue #74 - New D2 Phobos source rebased from DMD. [98120f156997] * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos/config.h.in d/phobos/configure, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Fix building with --enable-multilib [67365c9f7b52] 2010-10-21 Iain Buclaw * d/d-asm-i386.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.032. [861e16b38529] * d/d-builtins2.cc, d/druntime/import/core/stdc/stdarg.d: D2 - Add core.stdc.stdarg as an stdarg module. Patched core.stdc.stdarg to work with GDC compiler. [8b0a0deb8e7d] * d/d-codegen.cc: Issue #72 - 'this' in nested structs cannot access frame of outer function. [3422c59c130a] * d/phobos/std/intrinsic.d: D1 - Fix bt function on 64bit archs. [7445723aaedd] * d/d-codegen.cc, d/d-glue.cc: Issue #73 - ICE declaring string enums. [0865e6286775] * d/druntime/compiler/gdc/aaA.d: D2 - Fixed segfault getting AA keys/values. [d049574ccd3f] * d/dmd/mars.h, d/dmd/mtype.c, d/phobos/acinclude.m4, d/phobos/configure, d/phobos/configure.in, d/phobos2/acinclude.m4, d/phobos2/configure, d/phobos2/configure.in, d/target-ver-syms.sh: Some updated to target OS detection. [7fecb2ef6432] 2010-10-12 opticron * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos2/Makefile.am d/phobos2/Makefile.in: D1/D2: Fix type sizes in gcc/config/* when building with multilib. [b9f7dd4e80a2] 2010-10-11 michaelp * d/patches/patch-gcc-4.4.x, d/patches/patch-toplev-4.4.x: Updated 4.4.x patches for 4.4.5 [dd2f05ac4246] 2010-10-08 Iain Buclaw * d/d-glue.cc, d/dmd2/*, d/druntime/*: Updated D2 frontend to 2.029. [082c04bad0c3] 2010-10-07 Iain Buclaw * d/Make-lang.in, d/d-asm-i386.h, d/d-codegen.h, d/d-decls.cc d/d-gcc-real.cc, d/d-gcc-real.h, d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Update D2 frontend to 2.028. [141118223a79] * d/dmd/cast.c d/dmd/constfold.c d/dmd/identifier.c d/dmd/lexer.c d/dmd/mars.h d/dmd/mtype.c d/dmd/opover.c d/dmd/optimize.c d/dmd/template.h d/dmd/todt.c d/dmd/toobj.c: Cleaned up D1 folder after D2 updates. [5c293d142e2d] * d/asmstmt.cc, d/d-asm-i386.h: Issue #70 - Inline Asm errors junk `(%ebp)+4' after expression. [21764cc50c3f] 2010-10-06 Iain Buclaw * d/Make-lang.in, dmd2/*, phobos2/*: Updated D2 frontend to 2.026. [7a1dfe79af05] * d/d-glue.cc: Issue #69 - ICE on typedef'd array concatenation. [fe66fbb9e08e] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: D2 - Fixed 'this.this' being null in a nested class. [d1dfd83df144] * d/d-decls.cc: Let backend know about functions marked as 'nothrow' and 'immutable'. [77df72e87dd0] * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc: D2 - Implemented nested structs. [8c901ab67b00] * d/d-codegen.cc d/d-codegen.h d/d-glue.cc: Move block of code initialising structs from emitLocalVar to AssignExp. [32165d66c011] * d/Make-lang.in, d/d-lang.cc, d/dmd2/array.c, d/dmd2/async.c d/dmd2/async.h, d/dmd2/root.c: D2 - Added AsyncRead sources. [3407bc0a9896] 2010-10-03 Iain Buclaw * d/phobos/std/regexp.d: Fix D1 phobos for 64bit systems. [2cc2741e0031] * d/d-decls.cc, d/d-lang.h: D2 - Let backend know about functions marked as 'pure'. [e9eb758ba073] * d/druntime/compiler/gdc/lifetime.d: Issue #69 - arraycatnT not working on 64bit. [1fb27285a969] 2010-09-30 Iain Buclaw * d/asmstmt.cc, d/d-codegen.cc, d/d-glue.cc, dmd2/*, druntime/* phobos2/*: Updated D2 frontend to 2.025. [4b8327c25e06] 2010-09-29 Iain Buclaw * d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.022 [747409fe2b40] * d/d-codegen.cc, d/d-glue.cc, d/phobos2/Makefile.in: Fix building with --enable-checking. [364d892342c5] * d/d-codegen.cc, d/druntime/gc/basic/gcx.d: Issue #68 - Cannot cast to structs of same type size. [8fd7216c74a7] * d/d-lang.cc, d/dmd-script, d/lang.opt: Added -safe switch. [a06f5919bd1c] * d/d-spec.c: Update D2 driver. [9e1b27a03458] 2010-09-28 Iain Buclaw * zlib/*: Moved zlib to it's own maintained directory. * d/phobos/etc/c/zlib, d/phobos2/etc/c/zlib: Removed. [46deecb698ea] * dmd/*, phobos/*: Updated D1 frontend to 1.064. [77f4acd15b72] * dmd2/*, druntime/*, phobos2/*: Updated D2 frontend to 2.021. [ed6460a378bc] * d/druntime/compiler/gdc/adi.d, d/druntime/compiler/gdc/alloca.d, d/druntime/compiler/gdc/cover.d, d/druntime/compiler/gdc/memset.d, d/druntime/compiler/gdc/qsort.d, d/druntime/compiler/gdc/qsort2.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 runtime segfault fixes. [7c9615da20cb] * d/d-builtins2.cc d/d-codegen.cc d/d-decls.cc d/d-glue.cc d/dmd2/mars.h d/druntime/compiler/gdc/util/console.d d/phobos2/std/bigint.d d/phobos2/std/bitmanip.d d/phobos2/std/boxer.d d/phobos2/std/date.d d/phobos2/std/dateparse.d d/phobos2/std/md5.d: D2 'this' parameter to struct member functions is now a reference type. [91fd4a667dc9] 2010-09-25 Iain Buclaw * d-glue.cc: D2 - rework return by ref. [ecd406de9575] * d-codegen.cc, d-glue.cc: Move check for ref function to better place. [9dc1edb1c332] * d-glue.cc: Issue #66 - Array setting causes OutOfMemoryException. [65f4cc943169] 2010-09-20 Iain Buclaw * d-builtins.c, d-codegen.cc, d-glue.cc: D2 updates - Return by reference now implemented (instead of ignored). [6e2ba321e290] * d-codegen.cc, d-convert.cc, d-decls.cc, d-glue.cc: Gain back some compiler speed in release builds. [c8bdb254e8fc] 2010-09-18 Iain Buclaw * phobos2/config.h.in, phobos2/configure: Regenerate D2 configure scripts. [eed0b915018b] * druntime/compiler/gdc/dmain2.d: Fix _d_hidden_func to work with GDC compiler [8c2f5a4e8805] * d-codegen.cc, d-convert.cc, d-glue.cc, d-lang.h: Issue #64 - enable-checking in configure fails on 4.4.x [7bfec5c437bb] * d-lang.h: Issue #28 - enable-checking in configure fails [3de9afb31bb7] * druntime/compiler/gdc/trace.d, phobos2/Makefile.am, phobos2/Makefile.in, phobos2/config.log: Remove trace.d from D2 [253e781b9254] 2010-09-15 Iain Buclaw * d-codegen.cc d-glue.cc: Fix obscure memory bug in D2. [af9fbe154ba6] * d-codegen.cc, d-codegen.h, d-glue.cc, d-irstate.cc, d-irstate.h, dmd/statement.c, dmd2/statement.c: Issue #56 - goto into a try block doesn't produce an error. [960b54da053d] * dmd2/inifile.c, druntime/compiler/gdc/cmath2.d, druntime/compiler/gdc/gccmemory.d, druntime/compiler/gdc/memory.d, phobos2/Makefile.am, phobos2/Makefile.in: Split off rt.memory, remove useless sources. [08fac74f4074] * druntime/common/core/thread.d, druntime/compiler/gdc/util/cpuid.d: Merge getESP code from D2 phobos to druntime. [5e6ee66625e4] * druntime/compiler/gdc/llmath.d: Remove llmath.d [6b7397510e33] 2010-09-09 Iain Buclaw * d-codegen.cc: Revert part of commit 210, and fix integer representations on gdc-4.4. [844b25646834] * d-bi-attrs-34.h, d-bi-attrs-341.h, d-builtins.c, d-c-stubs.c, Make-lang.in: Merge d-bi-attrs-341 with d-bi-attrs-34.h. [c2f92387a049] 2010-09-07 michaelp * gcc-mars.cc: Removed gcc-mars.cc from top level d/ folder. [e4b1e3753bf5] * Make-lang.in: Updated Make-lang.in for removal of gcc-mars.cc. [db7d6aae8ceb] * GDC.html, History, INSTALL, INSTALL.html, README, dmd-script, dmd-script.1, gdc.1: Documentation updates. [e651ed00a16e] 2010-09-03 Iain Buclaw * d-codegen.cc, d-glue.cc, d-objfile.cc: Issue #59 and #60: ICE when goto undefined label and ICE in foreach over member member array in static func [955dc7d43780] * d-codegen.cc, d-glue.cc, d-irstate.cc, d-lang.h, dmd/func.c, dmd/statement.c, dmd/statement.h: Issue #54: 1.063 changes in phobos versioning + dmd backend. [4c10fa4a539a] 2010-09-01 Iain Buclaw * dmd/cast.c, dmd/impcnvgen.c, dmd2/impcnvgen.c: Bugzilla 1822 - String slicing in 64-bit gdc causes spurious warnings [5efc9014eef8] * patches/patch-gcc-4.0.x, patches/patch-gcc-4.1.x, d/patches /patch-gcc-4.2.x, patches/patch-gcc-4.3.x, patches/patch- gcc-4.4.x: Issue #50 - thanks venix1: SjLj expections fail when thrown from catch block [d655a072bbb8] * d-builtins2.cc, d-lang.cc, d-spec.c: Removed va_list hack, small change to D2 lang driver. [7a67e4973ace] 2010-08-30 Iain Buclaw * d-codegen.cc: Issue #14: STATIC_CHAIN_EXPR not caught in estimate_num_insns_1() [63c14701ccde] 2010-08-29 Iain Buclaw * d-c-stubs.c, d-glue.cc, d-lang.cc: Add stubs for C_TARGET_OBJS on non-x86 archs. [b530fcd9baab] * d-glue.cc: Bugzilla 1669 - this.outer in nested classes gives a bogus pointer [ebce488abf89] * d-lang.cc, phobos2/Makefile.am, phobos2/acinclude.m4: Add D_Version2 version predicate. [9808b8987cce] 2010-08-28 Iain Buclaw * d-c-stubs.c, d-decls.cc, d-lang.cc, druntime/compiler/gdc/aaA.d, druntime/compiler/gdc/util/cpuid.d, druntime/gc/basic/gc_c.h, druntime/gc/basic/gc_dyld.c, druntime/gc/basic/gc_freebsd.c, druntime/gc/basic/gcgccextern.d, phobos/internal/gc/gcgccextern.d, phobos/std/loader.d, phobos2/Makefile.am, phobos2/acinclude.m4, phobos2/std/cpuid.d: D2 updates. [ebe4ca2bd83a] 2010-08-27 Iain Buclaw * d/Make-lang.in, d-spec.c, phobos2/Makefile.am: Add druntime to the GDC driver. [3dbc1c4cd214] * druntime/Makefile, druntime/compiler/gdc/dgccmain2.d, druntime/compiler/gdc/lifetime.d, phobos2/gcc/deh.d, phobos2/gcc/unwind_generic.d, phobos2/gcc/unwind_pe.d, phobos2/std/stream.d: Remove Makefile and fix module dependencies in Druntime [6fea2af61a0c] * phobos2/Makefile.am, phobos2/acinclude.m4, phobos2/aclocal.m4, phobos2/configure.in, d/setup-gcc.sh: Reorganise D2 Makefile for Druntime [f888b572d19a] * d/Make-lang.in: Use BACKENDLIBS rather than GMPLIBS for gdc-4.4 [bda0f5d37728] * d-glue.cc: Fix ICE in D2 ForeachRange statements [7d35bcb69e7e] 2010-08-26 Iain Buclaw * patches/patch-gcc-4.4.x: Regenerate gcc-4.4.x patch [4dfe5494460a] 2010-08-25 Iain Buclaw * d-codegen.h: Fix codegen for addressOf array types, resolves broken va_lists on gdc-4.4. [9463381e1daa] * druntime/compiler/gdc/fpmath.d, druntime/compiler/gdc/gcc/*, druntime/druntimelicense.txt, druntime/druntimereadme.txt, druntime/hello.d, druntime/license.txt, druntime/readme.txt: Re-add fpmath.d - previously from removed internal directory. [bf3e292d1a4c] * d-builtins2.cc: Slight alteration to va_list type generation on gdc-4.4 [e005caeafced] * d-codegen.cc, d-glue.cc, d-irstate.cc, d-lang.h: Use own language flag for labels marked 'used'. [d7963235235c] * d-lang.cc: Rework of previous commit for Issue #58. [025031c2e274] 2010-08-24 Iain Buclaw * d-lang.cc: Issue #58 - Fixed stack overflow in gdc-4.4 [c02f5ac787a8] 2010-08-23 Iain Buclaw * d-codegen.cc: Bugzilla 1813 - ICE on static function parametrized with alias. [2e06ca97b873] 2010-08-22 michaelp * patches/patch-gcc-3.4.x, patches/patch-gcc-4.0.x, d/patches /patch-gcc-4.1.x, patches/patch-gcc-4.2.x, patches/patch- gcc-4.3.x, patches/patch-toplev-3.4.x, patches/patch- toplev-4.0.x, patches/patch-toplev-4.1.x, patches/patch- toplev-4.2.x, patches/patch-toplev-4.3.x: Updated patches for D2/druntime [dc882e7537c0] 2010-08-22 Iain Buclaw * d/Make-lang.in, d-bi-attrs-44.h, d-builtins.c, d-builtins2.cc, d-codegen.cc, d-decls.cc, d-gcc-includes.h, d-lang.cc, d-objfile.cc, patches/patch-gcc-4.4.x, patches/patch- toplev-4.4.x, d/setup-gcc.sh: Building on GCC-4.4 now supported. [0616ebb4255b] * d-lang.cc: Issue #51: 1.062 outstanding issues [9663a271233b] 2010-08-20 michaelp * phobos2/*: Updated phobos2 to 2.020 (not working) [08d9a5b24ff4] 2010-08-20 Iain Buclaw * d-glue.cc: Fix ICE on shorthand if statements. [ef2959fa8184] 2010-08-20 michaelp * d-glue.cc: Fixed problem with continue statements in D2 [511f3176ec0d] 2010-08-20 Iain Buclaw * d-lang.cc, druntime/compiler/gdc/arraybyte.d, druntime/compiler/gdc/arraydouble.d, druntime/compiler/gdc/arrayfloat.d, druntime/compiler/gdc/arrayint.d, druntime/compiler/gdc/arrayshort.d, phobos/internal/arraybyte.d, phobos/internal/arraydouble.d, phobos/internal/arrayfloat.d, phobos/internal/arrayint.d, phobos/internal/arrayshort.d, phobos2/internal/arraybyte.d, phobos2/internal/arraydouble.d, phobos2/internal/arrayfloat.d, phobos2/internal/arrayint.d, phobos2/internal/arrayshort.d: Issue #30: D_InlineAsm updates [ce1833f9106a] 2010-08-19 michaelp * d-lang.cc: Fixed JSON option for D2 [2118f4d1de83] * d/setup-gcc.sh: Updated setup-gcc.sh for libdruntime building [6e7640bc2b3c] * patches/patch-toplev-4.1.x, patches/patch-toplev-4.2.x, patches/patch-toplev-4.3.x: Updated toplevel 4.1, 4.2, and 4.3 patches for libdruntime [1df5716f2b88] * patches/patch-toplev-3.4.x, patches/patch-toplev-4.0.x: Updated 3.4 + 4.0 toplevel patches to include libdruntime [a74ceca3c239] * dmd/func.c: Issue #57: C-style variadic functions broken [ae817bd07dbf] 2010-08-19 Iain Buclaw * phobos/*: Updated Phobos to 1.063 - expanded tabs. [bbe96bfd09dd] 2010-08-17 michaelp * d-glue.cc: One of Issue #56. Cannot goto into finally block [22792e6a6253] 2010-08-17 Iain Buclaw * d-codegen.cc, d-glue.cc, d-irstate.cc, d-irstate.h: Bugzilla 1041 - incorrect code gen for scope(exit) inside switch [d472abadf847] 2010-08-16 michaelp * d-glue.cc, dmd/func.c, dmd/statement.c, dmd/statement.h: Temporarily reverted 1.063 change [d89d1a46125d] 2010-08-16 Iain Buclaw * d/asmstmt.cc, d-apple-gcc.c, d-asm-i386.h, d-builtins.c, d-builtins2.cc, d-c-stubs.c, d-codegen.cc, d-codegen.h, d-convert.cc, d-cppmngl.cc, d-decls.cc, d-gcc-includes.h, d-gcc-real.h, d-glue.cc, d-irstate.cc, d-lang.cc, d-lang.h, d-objfile.cc, d-spec.c, d/dt.cc, d/dt.h, d/gdc_alloca.h, d/symbol.cc: Added GPL onto files missing it, attributed modifications. [4d41771eba7c] 2010-08-15 Iain Buclaw * d-codegen.cc: Some more type conversion updates in glue. [4567e417c0b3] 2010-08-14 Iain Buclaw * d-apple-gcc.c, d-codegen.cc, d-convert.cc, d-glue.cc, d-lang.cc: Remove default_conversion, tighten up signed/unsigned conversions. [c1ae96f4e1a6] * d-builtins2.cc, d-codegen.cc, d-glue.cc, d-lang.cc, d-lang.h: Removed references to TREE_UNSIGNED. [4a59c1bbc04c] * d-gcc-includes.h: Fixed previous glue commit. [9cac96f771a1] 2010-08-14 michaelp * phobos/std/thread.d: Updated thread_attach bug in Windows [de30c34ef79d] 2010-08-14 Iain Buclaw * d/asmstmt.cc, d-builtins2.cc, d-codegen.cc, d-gcc-includes.h, d-glue.cc, d-lang.cc, d-objfile.cc: Glue touch-ups, now uses D_USE_MAPPED_LOCATION [6122f6d23a71] 2010-08-13 michaelp * d-cppmngl.cc: Uploaded missing fix from 1.063 merge [fc7de0a268ab] * dmd/template.c: Fixed implicit conversion of template parameters [888e3cc8a31d] * d-glue.cc, dmd/async.c, dmd/declaration.c, dmd/declaration.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/enum.c, dmd/enum.h, dmd/expression.c, dmd/func.c, dmd/init.c, dmd/interpret.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/parse.c, dmd/parse.h, dmd/root.c, dmd/statement.c, dmd/statement.h, dmd/todt.c, phobos/internal/deh2.d, phobos/internal/object.d, phobos/std/math.d: Updated to 1.063 [f1e726cbcc98] 2010-08-11 Iain Buclaw * d/Make-lang.in, d-bi-attrs-34.h, d-bi-attrs-341.h, d-bi- attrs-40.h, d-bi-attrs-41.h, d-bi-attrs-42.h, d-bi-attrs-43.h, d-builtins.c: Cleanup d-bi-attrs. Make includes slightly smarter. [349f85192e52] * d-codegen.cc: Remove useless trial/error comments in function. [89b4363653f8] 2010-08-10 michaelp * d-codegen.cc: Issue 33 - Sefault with nested array allocation [be805cb4fb58] 2010-08-09 Iain Buclaw * d/Make-lang.in, patches/patch-gcc-4.2.x, patches/patch- toplev-4.2.x, d/setup-gcc.sh: Building on GCC-4.2 now supported. [c1b55292cd94] * d-codegen.cc, d-glue.cc, d-irstate.cc: Apply adaptation of feep's autovec patch (one big thanks!) [fbce9c0580d3] * d/asmstmt.cc, d-asm-i386.h: Replace tabs for space in ASM outbuffer. [659f6f38f6f4] 2010-08-09 michaelp * d/dmd-script: Whitespace fix to previous commit. [0fee937d84d4] * d-lang.cc, d/dmd-script, d/lang.opt: Added JSON support - Issue 52 + gdmd usage change [35f04cb2339c] * d/dmd-script: Added -defaultlib= and -debuglib= into gdmd usage [e34a68f9c427] * d/dmd-script: Updated -defaultlib and -debuglib switches for gdmd - Issue 46 [181e89b3d8d6] 2010-08-08 Iain Buclaw * d-builtins.c, d-c-stubs.c, d-codegen.cc, d-glue.cc, d-lang.h: Build with GCC-3.4 working again. [58e9b23e110c] * d/Make-lang.in, dmd2/array.c, dmd2/mars.c, dmd2/root.c, dmd2/total.h: Updates of previous commit [41657ecdc3fe] * d/Make-lang.in, d-decls.cc, dmd/expression.c, dmd2/arrayop.c, dmd2/bit.c, dmd2/complex_t.h, dmd2/e2ir.c, dmd2/lib.h, dmd2/libelf.c, dmd2/link.c, dmd2/man.c, dmd2/port.h, dmd2/template.c, dmd2/tocsym.c, dmd2/toir.c, dmd2/toir.h, dmd2/toobj.c, d/symbol.cc, d/symbol.h: Issue 29 - Remove unused D2 files [fdef7864146b] * d-decls.cc: Bugzilla 1296 - ICE when object.d is missing things [e9bfccc01834] 2010-08-06 michaelp * d/dmd-script: More updates to gdmd [d77ee89f6174] 2010-08-05 michaelp * d/dmd-script: Small changes to gdmd; some fixes for Issue 46 [9269acda0b86] 2010-08-05 Iain Buclaw * d-decls.cc, d-glue.cc: Fix logic on array ops. Fixup comments for previous commits. [5792cfbf3ae7] * d-glue.cc: Issue 43: >>> and >>>= generate wrong code [56caae262c41] 2010-08-02 Iain Buclaw * d-lang.cc: Regression in D1 when building with --enable-checking [6f2adfcabae6] * d-spec.c: Check missing argument for -defaultlib [8d59f275476b] * d-decls.cc: Issue 47: GDC improperly handles extern(System) and extern(Windows) on Windows [e5b50cb17c57] 2010-07-31 Iain Buclaw * d-codegen.cc, dmd/todt.c: Issue 51: 1.062 outstanding issues [f41ce1e8e5b2] * dmd/aav.c, dmd/aav.h, dmd/arrayop.c, dmd/attrib.c, dmd/cast.c, dmd/constfold.c, dmd/dsymbol.c, dmd/expression.c, dmd/imphint.c, dmd/interpret.c, dmd/lexer.c, dmd/mtype.c, dmd/parse.c, dmd/speller.h, dmd/statement.c, dmd/toobj.c, dmd/unittests.c, dmd/utf.c: Line endings, cleanups, and a missing ')' [84378e5ef655] * d-codegen.cc, d-glue.cc: Glue updates for previous merge. [a48e13277e67] 2010-07-31 michaelp * d-glue.cc, dmd/*, phobos/std/date.d: Updated to 1.062 [9f7927e5f551] 2010-07-30 Iain Buclaw * d-spec.c: Added -defaultlib and -debuglib to allow building with another library other than libphobos. [f7a52f778a09] * druntime/*: Initial import of druntime into project. [2f052aaedd25] * d-glue.cc: Fix generation of D array concatenation calls. [d70321dcd604] * phobos2/acinclude.m4, phobos2/configure, phobos2/configure.in, phobos2/internal/arrayassign.d, phobos2/phobos-ver-syms.in: D2 now defines Posix. [575ed6d347e0] * dmd/parse.c, dmd/speller.c: Include header needed for MinGW to build. [5260cab6c448] 2010-07-29 michaelp * phobos2/std/c/stdio.d: Fixed accidentally reapplied Windows patch [d4356fb371ee] * d/Make-lang.in, dmd/aav.c, dmd/aav.h, dmd/class.c, dmd/declaration.c, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c, dmd/func.c, dmd/imphint.c, dmd/mars.c, dmd/mars.h, dmd/optimize.c, dmd/scope.c, dmd/speller.c, dmd/struct.c, dmd/template.c, phobos2/std/c/stdio.d: Updated to 1.061 [9038432ea1ff] * phobos/std/c/stdio.d, phobos2/std/c/stdio.d: Remove stdio.d patches from Issue 21 patch [a53c51fad1bd] * d-decls.cc, phobos/std/c/stdio.d, phobos2/std/c/stdio.d: Issue 21 - _iob undefined reference under Windows [ea913c7eec42] * d-glue.cc: Fixed array ops bugs from 1.059 [92c39c74433f] * d/Make-lang.in, dmd/cast.c, dmd/class.c, dmd/declaration.c, dmd/declaration.h, dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/idgen.c, dmd/init.c, dmd/inline.c, dmd/interpret.c, dmd/json.c, dmd/mars.c, dmd/mtype.c, dmd/parse.c, dmd/speller.c, dmd/speller.h, dmd/statement.h, dmd/unittests.c: Updated to 1.060 [1c1cc97db718] 2010-07-28 Iain Buclaw * d/dmd-script, d/lang-specs.h: Issue 48: gdc/gdmd should be able to compile .di files [976a611f59f3] * d-lang.cc, dmd/*, phobos/*: Updated to 1.058 [9ac6a02138c2] * d/Make-lang.in, dmd/machobj.c: Remove machobj.c from D1 [67d109f8fe79] * d-lang.cc, d/dmd-script, d/symbol.cc: Issue 42: -Wall should not error out compiler [7593822be7c0] 2010-07-27 michaelp * d/Make-lang.in, d-lang.cc, d/dmd-script, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c, dmd/func.c, dmd/init.c, dmd/inline.c, dmd/interpret.c, dmd/machobj.c, dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/root.c, dmd/root.h, dmd/scope.c, dmd/scope.h, dmd/speller.c, dmd/speller.h, dmd/statement.c, dmd/template.c, d/lang.opt, phobos/internal/aaA.d: Updated to 1.057 [b4fb93e94c29] 2010-07-27 Iain Buclaw * d/Make-lang.in, dmd/array.c, dmd/bit.c, dmd/complex_t.h, dmd/constfold.c, dmd/e2ir.c, dmd/elfobj.c, dmd/expression.c, dmd/irstate.c, dmd/irstate.h, dmd/lib.h, dmd/libelf.c, dmd/libmach.c, dmd/link.c, dmd/man.c, dmd/mars.c, dmd/mem.c, dmd/mem.h, dmd/mtype.c, dmd/port.c, dmd/port.h, dmd/root.c, dmd/tocsym.c, dmd/toir.c, dmd/toir.h: Issue 29 - Remove unused D1 files [d74291c4230b] * dmd/template.c, dmd2/template.c: Issue 36: duplicate symbols created for negatively initialized template arugments [1bd9793d8fc6] * d-builtins.c: Partial fix for Issue 28 [7fb5519947d4] * d-lang.cc: Issue 44: strange code in d-asm-1386.h [73c379cc9714] 2010-07-26 Iain Buclaw * d-codegen.cc, d-glue.cc: D2 postblit on struct literals finished! [9ee37bd66bca] 2010-07-25 michaelp * d-lang.cc, d/dmd-script, dmd/*, phobos/internal/arrayfloat.d: Updated to 1.056 [4ff162deda23] 2010-07-24 Iain Buclaw * d-glue.cc: D2 postblit updates. [d53a8be7c0ed] 2010-07-23 michaelp * dmd/class.c, dmd/enum.c, dmd/enum.h, dmd/mars.c, dmd/struct.c: Updated to 1.055 [9c62fb9d0abf] * dmd/expression.c: Fixed spot with wrong patch in it [172855a888e9] * dmd/*, phobos/internal/gc/gcx.d: Updated to 1.054 [64df5a74b2c4] 2010-07-21 Iain Buclaw * d-lang.cc: Fixed warnings in d-lang.cc (thanks Trass3r) [7a3c1ae0b625] * d-asm-i386.h: Fix cast warnings in d-asm-i386.h [fa9b66399a13] * dmd/lexer.c, dmd2/lexer.c: Fix buffer overflow in certain error messages [b91574453f5e] * d-asm-i386.h: Correctly check align value in asm. [d5a0f3619810] 2010-07-20 Iain Buclaw * d-glue.cc, dmd/root.c, dmd/statement.c, dmd/template.c, dmd/template.h, phobos/std/c/stddef.d: Quick updates to D1 and postblit code. [214fbfbf5f3f] * d-builtins2.cc, d-codegen.cc, d-codegen.h, d-glue.cc, dmd/expression.c, dmd/func.c, dmd/machobj.c, dmd/mtype.c, dmd/parse.c, dmd/statement.c, dmd/statement.h, dmd/toobj.c, phobos/internal/gc/gc.d: Some whitespace corrections. [c9c54a275526] 2010-07-20 michaelp * d-builtins2.cc, d-codegen.cc, d-codegen.h, d-glue.cc, dmd/*, phobos/*: Updated to 1.053 [f02a96cfc1de] 2010-07-20 Iain Buclaw * d-glue.cc: Quick revision updates [c79811b4f1fc] 2010-07-19 Iain Buclaw * d-glue.cc, dmd2/attrib.c, dmd2/cast.c, dmd2/cond.c, dmd2/constfold.c, dmd2/declaration.c, dmd2/declaration.h, dmd2/e2ir.c, dmd2/expression.c, dmd2/func.c, dmd2/impcnvgen.c, dmd2/lexer.c, dmd2/lexer.h, dmd2/link.c, dmd2/mars.c, dmd2/mtype.c, dmd2/mtype.h, dmd2/parse.c, dmd2/parse.h, dmd2/statement.c, dmd2/toir.c: Updated to 2.020 - Frontend Only [676f0aa79458] 2010-07-17 Iain Buclaw * phobos2/Makefile.in: libgphobos2 Makefile fixes. [c4acdacfddd2] 2010-07-16 Iain Buclaw Merge with DMD 2.019 * d-decls.cc: Merge changes from dmd2/tocsym.c * phobos/Makefile.am, phobos/Makefile.in, phobos2/Makefile.am, phobos2/Makefile.in: Fix build for check-target-libphobos tests. * d-decls.cc, d-objfile: Fixed ICE in gdc-4.3 [39825b8156a3] 2010-07-14 Iain Buclaw Merge with DMD 2.018 * d-lang.cc: Added support for AsyncRead in D1. * dmd/constfold.c, dmd2/constfold.c: Fixed lost precision when casting from large floats to integral types. * dmd/todt.c, dmd2/todt.c: Fixed initialiased pointer array values being reset to null during compilation. * Make-lang.in, d-backendfunctions.c, dmd/template.c: Removed backendfunctions.c from Makefile. 2010-07-11 Iain Buclaw * d-asm-i386.h: AMD Opcodes Supported. * Make-lang.in, dmd/mtype.c, dmd/struct.c, target-ver-syms.sh: struct ABI fixes. * phobos/std/math.d, phobos2/std/math.d: Fix wrong return value in expi() function. 2010-07-07 michaelp * dmd/arrayop.c: Fix problem with float array operations. - Added linear search for the array op library functions. 2010-07-05 Iain Buclaw * dmd2/..., phobos2/...: Resolved issues for DMD 2.017. * phobos2/configure, phobos2/configure.in: Re-add GNU_Need_execvpe for D2 libphobos. * dmd/mtype.h, phobos2/internal/object.d, phobos2/std/cpuid.d: Quick updates to previous revisions. 2010-07-05 michaelp Merge DMD 2.017 2010-07-04 Iain Buclaw Merge DMD 1.052 * d-glue.cc: Fix ICE when using type tuple as function argument. * phobos/..., phobos2/...: libphobos cleanup and updates. * d-codegen.cc, d-decls.cc: Fix problem when building with --enable-checking. 2010-06-28 michaelp * setup-gcc.sh: D1 is default in setup-gcc.sh now. 2010-06-27 Iain Buclaw Merge with DMD 1.050 * Make-lang.in: Update for files added in DMD 1.050. * phobos/etc/c/zlib.d, phobos/std/zlib.d, phobos2/etc/c/zlib.d: Updated Zlib to 1.2.3. 2010-06-22 michaelp * phobos/configure, phobos/configure.in, phobos/std/process.d, phobos2/configure, phobos2/configure.in, phobos2/std/process.d: Fix problem when building with a version of GNU C that has execvpe() implemented (staring with glibc-2.11). * phobos/configure, phobos/configure.in, phobos/std/c/freebsd/freebsd.d: Fix problem when linking on FreeBSD targets. 2010-06-19 Iain Buclaw Merge with DMD 1.049 * d-lang.cc: Merge changes from dmd/mars.c. * d-codegen.cc, d-decls.cc: Fix ICEs in const array assignments. * d-lang.cc, dmd-script, lang.opt: Added -fdeps option to gdc and -deps to gdmd. * dmd/mem.c, dmd/mem.h, dmd/port.c, dmd/rmem.h, dt.cc, dt.h, phobos/internal/qsortg.d: Remove executable bit on source files. 2010-06-12 Iain Buclaw Merge with DMD 1.047 * d-codegen.cc: Look for reference initializations in foreach statement assignments. * dmd/..., dmd2/..., phobos/..., phobos2/...: Converted CR, CRLF line endings to LF (thanks to venix1). 2010-06-04 Vincenzo Ampolo * d-asm-i386.h: Apply patch to compile tango (thanks to venix1). 2010-04-05 michaelp Merge with DMD 1.046 * d-decls.cc: Fix problem with struct declarations in GCC-4.3.x. * dmd-script: Added -pipe option to gdmd * d-lang.cc, phobos/...: Fix FreeBSD and Windows version issues. * dmd/root.c: Fix Windows template instantiating error. * dmd/func.c: Fix segfault on wrong arg type. 2010-02-17 Vincenzo Ampolo * d-glue.cc: Make d1 classinfo like d2 ones. * dmd/expression.c, phobos/std/process.d: Apply feep (downs) patch. 2010-02-07 michaelp Merge with 1.045 * phobos/linux.mak, phobos/win32.mak: Removed Phobos .mak files for D 1.045 update. * samples/hello.d, samples/samples.sh: Added 1 file to samples directory. 2010-01-15 opticron * phobos/std/string.d: Fix a set of bugs in std.string.split which made delemiters of length > 1 segfault. Copyright (C) 2010 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2011 ================================================ 2011-12-31 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc: Revert some prior code additions. [a61a03e817c3] * d/d-decls.cc, d/d-glue.cc: Issue #301 - ref return funcs returning wrong reference [2350d3a27ac8] 2011-12-30 Iain Buclaw * d/d-irstate.cc, d/d-lang.cc: Implicitly convert all statements to void, warn if statement has no side effects. [d73ff02f1131] * d/d-decls.cc, d/d-glue.cc: mark RESULT_DECL as artificial. [a2de4187caa4] * d/d-codegen.cc, d/d-glue.cc: Remove check for isref out of ::call and into CallExp::toElem [1b827c7df15c] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Use INIT_EXPR instead of MODIFY_EXPR where applicable, added vinit. [27c401e61169] * d/d-codegen.cc, d/d-codegen.h: Move functions written in d-codegen header to source file. [605c79094f14] * d/d-codegen.cc: Issue #302 - lazy arg causing ICE in gimple_expand_cfg, at cfgexpand.c:4063 [786acc44a0ff] 2011-12-28 Daniel Green * d/phobos2/Makefile.am, d/phobos2/Makefile.in: Add std/internal/windows/advapi32.o to WINDOWS_OBJS. [e7639c523add] 2011-12-28 Iain Buclaw * d/d-gcc-includes.h, d/d-glue.cc: Emit pretty debug tree information on -fdump-tree-original [7631e902659e] * d/d-asm-i386.h, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc: Remove some dead code. [e8ae51578e54] * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc: Issue #258 - cannot access frame with contract inheritance [0b470bc59251] * d/d-lang.cc, d/gdc.1, d/lang.opt: Add switches to control in(), out() and invariant() code generation. [e9904da308eb] * d/asmstmt.cc, d/d-builtins2.cc, d/d-decls.cc, d/d-glue.cc, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x: Remove gdc patch to cgraph.c - fix codegen. [fc5e3bddbf94] * d/d-decls.cc: Issue #298 - Array Range Functions Don't Get Inlined [f9217ce815ea] 2011-12-25 Iain Buclaw * d/d-glue.cc, d/dmd2/expression.c, d/dmd2/expression.h, d/dmd2/optimize.c, d/phobos/configure, d/phobos2/configure: Fixup arrayliteral assignments. [d71656e55ad8] * d/phobos/configure, d/phobos2/configure: Rebuild configure for D1 [bedf43669633] * d/d-glue.cc: Issue #297 - GDC Acquires Locks Twice in Synchronized Member Methods. [7470a20b2900] * d/d-objfile.cc, d/d-objfile.h: First attack at fixing issue #246 [bd1f89846e93] 2011-12-23 Iain Buclaw * d/d-codegen.cc: Issue #287 - Casting between array types is broken. [63647d6f2b87] * d/phobos2/Makefile.in, d/phobos2/configure: Rebuild Makefile.in, configure for D2. [b3200b086277] * d/d-lang.cc: Issue #296 - -fproperty implies -frelease [4dfa4c11ccd7] * d/d-codegen.cc, d/d-codegen.h, d/d-lang.cc: Remove unused warnSignCompare. [60ea5d6b4173] * d/d-codegen.cc: Issue #289 - ICE: in extract_range_from_binary_expr, at tree-vrp.c:229 [9076a0f27fd9] * d/dmd-script, d/dmd-script.1, d/gdc.1: Update manpages for new GDC/GDMD options. [9caec4bea289] * d/d-objfile.cc: Issue #279 - ICE: in gimple_expand_cfg [6778c7a1f79e] * d/d-builtins2.cc: Add CTFE support for builtins atan2, rndtol, expm1, exp2. [afe30f1b9435] 2011-12-18 Iain Buclaw * d/d-codegen.cc: D2 - Handle nulltype to D array conversions. [d7fe9fa5bb6c] * d/d-glue.cc, d/d-lang.cc: Match GCC logic for emitting D_LP64 version identifier. [7475431fe1bd] * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc: Better implementation of bt, btc, bts, btr functions, allowing constant folding. [caf2c8d4f036] * d/d-builtins2.cc: Implement CTFE for bswap, bsr, bsf. [730c51fcdd3e] * d/druntime/core/thread.d: Issue #290 - errno conflict in std.file [ecd60be7f89c] * d/d-lang.cc: Define D_LP64 if is64bit. [633ea9c9e5bf] * d/dmd-script: Issue #282 - gdmd multithreaded -lib implementation. [f1bd82f9bb5b] * d/dmd-script: Issue #283 - gdmd: libraries not put into -od dir. [75a7b584473a] * d/d-objfile.cc, d/dmd/attrib.c, d/dmd2/attrib.c, d/lang.opt: Issue #286 - -fignore-unknown-pragmas doesn't seem to work [f342fde254e2] 2011-12-16 Iain Buclaw * d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-irstate.cc, d/d-irstate.h, d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.057 [36c28efc6c88] 2011-12-11 Iain Buclaw * d/dmd/*: Updated D1 Frontend to 1.072 [e83cac3b4109] * d/dmd/expression.c, d/dmd2/expression.c: Issue #279 - ICE: in gimple_expand_cfg [c501487a685a] 2011-12-08 Iain Buclaw * d/Make-lang.in, d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-dmd-gcc.h, d/d-glue.cc, d/d-irstate.cc, d/d-lang-45.h, d/d-lang-type-45.h, d/d-lang-type.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc, d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Fronted to 2.056 [fbe890ef4c1f] * d/d-codegen.cc, d/d-glue.cc: Relax conversion checking. Move getImpl to CastExp. [b0407ff2e57c] * d/dmd/optimize.c, d/dmd2/optimize.c: Remove old frontend ifdef'd code. [8e0291212f46] 2011-12-02 Iain Buclaw * d/d-lang.cc, d/lang-specs.h, d/lang.opt: remove preprocessor options from spec and use own switches. [5f71b69d1494] * d/d-objfile.cc: Issue #275 - ICE with wrong interface implementation [e32c8fbe7343] * d/d-lang.cc, d/dmd/mars.h, d/dmd2/mars.h, d/lang-specs.h, d/lang.opt: Issue #236 - -M, -MM, -MF options to generate dependencies like gcc [3763796b9cbf] * d/d-lang.cc, d/lang.opt: ASCII collate lang switches. [951ff44f1035] 2011-12-02 Iain Buclaw * d/d-objfile.cc: Issue #268 - ICE with -flto and -g [3da453291dc3] 2011-11-24 Iain Buclaw * d/Make-lang.in: Issue #266 - make install-strip fails to install gdmd. [d1005cb77a06] * d/d-glue.cc, d/d-lang.cc, d/dt.cc: Remove checks for type_structural_equality for now. [5265f1318114] * d/d-glue.cc: Issue #261 - ICE: tree check: expected record_type or union_type, have array_type in delegateVal [61ab289788a3] * d/d-glue.cc: Issue #264 - ICE: can't convert between bool and enum : bool [fcb2523b8ccd] * d/d-codegen.cc, d/d-glue.cc: Issue #263 - forward reference error with algorithm.find [75b7e1bca4d7] 2011-11-19 Iain Buclaw * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-decls.cc, d/d-glue.cc, d/d-irstate.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc: Add d_free, rename dkeep to d_keep. [a0e0fcfd913c] 2011-11-18 Iain Buclaw * d/d-builtins2.cc, d/d-codegen.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: Issue #262 - ICE: weird segfault when -o option is used [51d11a9bddf2] * d/d-lang.cc: Issue #255 - ICE: invalid conversion in gimple call [36ae9c015e86] * d/d-decls.cc: Issue #259 - ICE: constant not recomputed when ADDR_EXPR changed [72c16f7ab674] * d/d-builtins2.cc, d/d-dmd-gcc.h, d/dmd/attrib.c, d/dmd/declaration.c, d/dmd/declaration.h, d/dmd/mtype.c, d/dmd/struct.c, d/dmd2/attrib.c, d/dmd2/declaration.c, d/dmd2/declaration.h, d/dmd2/mtype.c, d/dmd2/struct.c: Issue #215 - Alignment of struct members wrong on ARM [2df7ca5fa4b6] * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc: Issue #242 - Another lambda segfault [467d7fa518fc] 2011-10-31 Iain Buclaw * d/d-lang.cc: Arm -> ARM and darwin -> Darwin in d-lang.cc. [51e67c38af0c] 2011-10-30 Iain Buclaw * d/target-ver-syms.sh: Make some system and CPU version identifiers consistent in casing. [5d11c2ded7b7] * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc: Use isMember2 when checking member functions. [d89c3b7d495a] * d/d-codegen.cc, d/d-decls.cc, d/d-lang-45.h, d/d-lang.h, d/d-objfile.cc: Issue #78 D1/D2 - in/out contract inheritance [736ae4b92f2] 2011-10-26 Iain Buclaw * d/asmstmt.cc, d/d-asm-i386.h, d/d-glue.cc, d/d-irstate.cc: Issue #252 - Error: suffix or operands invalid for `jc' [0d65aed46422] * d/lang-specs.h, d/patches/patch-apple-gcc-5465, d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x: Issue #251 - Remove all references to fmultilib-dir usage in gdc spec and patches. [c72727fc3f13] 2011-10-23 Iain Buclaw * d/druntime/core/stdc/stdio.d, d/druntime/core/stdc/stdlib.d, d/druntime/rt/critical_.d, d/druntime/rt/dmain2.d, d/druntime/rt/monitor_.d, d/phobos/config/libc.x3, d/phobos2/config/libc.x3, d/target-ver-syms.sh: Start on implementing platform agnostic druntime for GDC D2. [c46d1009bd78] * d/d-lang.cc, d/target-ver-syms.sh: Add VENDOR_VERSYM to D version identifiers if defined. [f7abc9009d0d] * d/d-lang.cc, d/d-objfile.cc: Issue #224 - Link time optimization [bf9d0ac53e9d] * d/d-decls.cc, d/d-glue.cc, d/d-irstate.cc, d/d-irstate.h, d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/lang.opt: Merge changes from gcc-4.7 branch. [5992dd0f2f7e] * d/d-codegen.cc: Use gcc atomics for bt, btc, btr, bts intrinsics. [2cc2e8c5a778] * d/d-glue.cc: build_assign_math_op: Stabilize LHS expression. [031b711ce09] 2011-10-21 Iain Buclaw * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/d-lang-45.h, d/d-lang.h, d/dmd/mtype.c, d/dmd2/mtype.c: Issue #247 - undefined reference to `.LDASM1' [19de20aec625] * d/asmstmt.cc, d/d-asm-i386.h: Fallback to 32bit instruct suffix when 64bit not available, add special case for fild. [8789c97f84ac] * d/asmstmt.cc, d/d-asm-i386.h: Issue #248 - Inline assembler generates wrong argument size for FILD instruction. [8bd2a4ca84c0] 2011-09-27 Iain Buclaw * d/dmd-script: Issue #241 - dmd.conf DFLAGS doesn't work with DMD-style args. [4bf307759462] * d/d-codegen.cc, d/d-glue.cc: Issue #239 - Filter + Closure = Segfault. [23b24ffe94f2] * d/dmd-script: Properly handle -X and -map switches in gdmd. [f7c13cf55264] * d/asmstmt.cc, d/d-asm-i386.h, d/d-irstate.cc, d/d-irstate.h: Fixup some build warnings. [891f65500765] * d/dmd-script: Issue #234 - add DFLAGS to the build command in gdmd. [3acdb17df213] 2011-09-25 Iain Buclaw * d/dmd-script: Issue #234 - dmd.conf equivalent [db9070d078a8] * d/druntime/core/thread.d, d/phobos2/std/path.d: Re-add fixes that got removed in last D library merge. [a998cdff6e0f] * d/dmd/todt.c, d/dmd2/todt.c, d/dt.cc: size_t'ify toDt. [c1306d366f94] * d/d-glue.cc: CallExp - only call convert on basic return types. [bc7ad8e2569] * d/d-gcc-real.cc: real_t::convert - check base type [71eb59683499] * d/dmd/attrib.c, d/dmd2/attrib.c: Optimise attribute pragma arguments. [dca4ddf21110] 2011-09-23 Iain Buclaw * d/d-glue.cc: Issue #235 - ICE in feep's tools library [17da3d28ba17] 2011-09-15 Daniel Green * d/d-glue.cc: Make PowAssignExp::toElem only compile with D2. [fa6a47ddbd9c] * d/dt.h: Issue #231. Use size_t for dt_size declaration in dt.h. [f9fee0fd57a2] 2011-09-14 Iain Buclaw * d/d-builtins2.cc, d/d-gcc-real.cc, d/d-gcc-real.h, d/d-glue.cc, d/dmd2/constfold.c, d/dmd2/declaration.h, d/dmd2/expression.c, d/dmd2/expression.h, d/dmd2/interpret.c, d/dmd2/optimize.c: Implement constant folding of ^^ expressions. [06f5e7c038fa] * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-incpath.cc, d/d-lang.cc, d/d-objfile.cc, d/dt.cc: Change unsigned for size_t in for loops. [814fc99ff732] * d/d-lang.cc, d/dmd/mars.c, d/dmd2/mars.c: Re-enforce -Werror flag in gdc. [eced11f7d5b5] * d/d-glue.cc: Issue #232 - sqrt(3) == 2.15118e-4930 [8994cef9271f] 2011-09-12 Daniel Green * d/d-lang.cc: Convert Array to Strings required by DMD 1.070/2.055 [fc0033715683] 2011-09-12 Iain Buclaw * d/druntime/rt/dmain2.d, d/druntime/rt/lifetime.d: Issue #214 - Segfault Allocating from Shared Static C'tor [41218d9f5f59] * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-cppmngl.cc, d/d-decls.cc, d/d-dmd-gcc.h, d/d-glue.cc, d/d-incpath.cc, d/d-irstate.cc, d/d-irstate.h, d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.055. [0ada920f6394] * d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.070. [fad5f4cad72b] 2011-09-10 Iain Buclaw * d/d-spec.c: Issue #230 - Error building Cross Compiler under MinGW [b0a9ef534877] * d/d-lang.cc, d/druntime/core/thread.d: Issue #226 - GC from spawned threads segfaults on 64-bit [3ea496446c7e] 2011-09-03 Daniel Green * d/asmstmt.cc: Use of V1 is more correct. [748ce286f58f] * d/dmd/root.c d/dmd2/root.c: Enables MinGW32 to use ANSI STDIO. [e69b142048f0] * d/asmstmt.cc: Allow inline assembly to set return values. Matches DMD functionality. [857c5645429c] 2011-08-29 Iain Buclaw * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc, d/symbol.cc: Emit pretty identifier to the debugger. [ac87eb9db360] 2011-08-23 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc: Don't warn about unused compiler generated vars. [0a71a122ca29] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-irstate.cc, d/d-irstate.h, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: New functions build_d_decl_lang_specific, d_mark_exp_read. Added support for -Wunused-variable, WIP -Wunused-but-set-variable. [d23bab68266c] 2011-08-19 Daniel Green * d/druntime/core/sys/windows/stacktrace.d: Issue #227. build error libphobos/core/sys/windows/stacktrace.d. [b1c34b7e7764] 2011-08-15 Iain Buclaw * d/d-decls.cc: Issue #225 - Array ops should be COMDAT. [dda1c10c8c7b] 2011-08-12 Iain Buclaw * d/d-glue.cc, d/d-irstate.cc: Re-add codegen which caused issue #205 in correct place. [e26b2b67bffa] * d/d-codegen.cc, d/d-gcc-includes.h: Issue #191 - SEGV(gimple.c:2624) getting array ref of incomplete type. [d0edf91c3fcf] 2011-08-07 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc: Issue #205 - ICE using phobos sort. [b3a5c764de90] * d/d-asm-i386.h, d/d-tree.def: Define tree code IASM_EXPR. [c7e7dc1c089b] * d/d-asm-i386.h: Handle zero and one operand forms of fcomi, fcomip. Fixed db, ds, di, dl to output constants and strings properly. [e394c90a88fa] * d/d-decls.cc, d/d-glue.cc, d/d-lang-type-45.h, d/d-lang-type.h, d/d-lang.cc, d/d-lang.h: Create TYPE_LANG_SPECIFIC type for arrays, functions, delegates. [1c25bfb71c05] * d/d-glue.cc, d/dt.cc: Use TYPE_STRUCTURAL_EQUALITY for conversions of records, should fix Issue #217. [04b8a399ddeb] * d/asmstmt.cc, d/d-asm-i386.h: Fix error using offsetoff for SymOffExp's in IASM. [933d2ca08770] * d/d-asm-i386.h: Added SSE4.1, SSE4.2 instructions [6a643f59ac86] * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc, d/dt.cc: More 4.6.x gimple checking issues. [148a5a16d432] 2011-07-30 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc, d/d-lang-45.h, d/d-lang.h, d/d-objfile.cc, d/dt.cc: Fix gimplication checking issues in 4.6.x [d3cc96b0546f] * d/d-codegen.cc: Issue #220 - Segfault on nested mixin functions. [c3720dd1e4f6] * d/patches/patch-gcc-4.6.x: Issue #218 - segmentation fault when compiling Hello World. [07bb061b2e4b] 2011-07-28 Daniel Green * d/d-glue.cc: Backout untested solution to issue #217. [fd532d8a5181] * d/d-glue.cc, d/setup-gcc.sh: Fixes issue #219 [949ab1610a42] * d/setup-gcc.sh: Updated -hg to reflect working directory revision and handle compiling outside a mercurial repository. [b3b60fdac583] 2011-07-24 Iain Buclaw * d/GDC.html, d/README, d/gdc-version: GDC version 0.30 [a4f3d0470b7a] * d/Make-lang.in, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x, d/symbol.cc d/symbol.h: Re-implemented D custom static chains into frontend - removed all belated backend patches. [488e8c0f482f] * d/Make-lang.in, d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.054 [ca958eccbde0] * d/Make-lang.in, d/asmstmt.cc, d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc, d/d-decls.cc, d/d-glue.cc, d/d-irstate.cc, d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.069 [c77c7af3dda0] 2011-07-11 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc, d/d-lang.h: Debug fixes: Give AAs a TYPE_NAME. Make closure vars visible to the debugger. [7cb42bd4eb94] 2011-07-09 Iain Buclaw * d/d-asm-i386.h: Issue #213 - ASM: Invalid absolute jmp/call address [e01697578501] * d/d-asm-i386.h, d/d-glue.cc, d/d-lang.cc: Asm 32/64bit generation fixes. [0a2261bde3e1] * d/d-codegen.h, d/d-decls.cc, d/d-lang.h, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x: Use TREE_NO_TRAMPOLINE macro - remove redundant patches. [b79169244c60] 2011-07-04 Iain Buclaw * d/Make-lang.in: Fixes executable relocation issues with MinGW. [c272d49246c9] * d/d-decls.cc: Always mark struct/class members for inlining. [61c81c98d80c] 2011-06-30 Daniel Green * d/d-asm-i386.h: Fixes issue #213. [71737ec293cb] 2011-06-20 Daniel Green * d/phobos/internal/gc/win32.d, d/phobos/std/stream.d: Win64 support for Phobos/D1. [b2b0dae5dec2] * d/Make-lang.in, d/dmd/root.c: Enables ANSI implemention of MinGW stdio. [fd0f112bfca8] * d/dmd-script: Added the ability to specify the name of output map file. Undocumented DMD feature. [d36a8b0e175] 2011-06-19 Iain Buclaw * d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc, d/dmd2/arrayop.c, d/druntime/core/stdc/math.d, d/phobos2/gcc/deh.d: Issue #212 - ICE With Map, dotProduct [f333a7e70d3d] 2011-06-08 Iain Buclaw * d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.053 [89eccdc0155e] * d/d-decls.cc, d/d-lang-45.h, d/d-lang.h, d/d-objfile.cc: gcc-4.6.x - Fix imported static const optimizer bug (D2 now passes testsuite). [9ccc077422a8] 2011-06-05 Iain Buclaw * d/Make-lang.in, d/d-codegen.cc, d/dmd-script: gcc-4.6.x - -combine removed, re-add d-gcc.o object, fix compilation on ARM. [dd43ade64753] * d/d-decls.cc, d/d-objfile.cc, d/patches/patch-gcc-4.6.x: gcc-4.6.x - Fix undefined references to thunks. [6b13c1f980f4] * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h: Remove d-bi-attrs.h for 4.0 and 4.1 [86169933de9c] 2011-06-02 Iain Buclaw * d/Make-lang.in, d/d-bi-attrs-45.h, d/d-lang.cc, d/d-spec.c, d/lang.opt, d/patches/patch-gcc-4.6.x, d/setup-gcc.sh: Fix missing gcc-4.6 driver options, add to setup scripts. [937e3e68e003] 2011-05-31 Iain Buclaw * d/Make-lang.in, d/config-lang.in, d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.h, d/d-gcc-real.cc, d/d-glue.cc, d/d-incpath.cc, d/d-lang-45.h, d/d-lang.cc, d/d-spec.c, d/lang.opt, d/patches/patch-gcc-4.6.x, d/patches/patch-toplev-4.6.x: Add gcc-4.6.x support [94fdbcd3ae33] * d/Make-lang.in, d/d-bi-attrs-45.h, d/d-builtins.c, d/d-codegen.cc, d/d-codegen.h, d/d-gcc-includes.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc, d/druntime/core/stdc/stdarg.d, d/druntime/core/vararg.d, d/patches/patch-gcc-4.0.x, d/patches/patch-gcc-4.1.x, d/patches/patch-toplev-4.0.x, d/patches/patch-toplev-4.1.x, d/phobos/std/c/stdarg.d, d/phobos/std/stdarg.d, d/symbol.h: Drop support for gcc-4.0.x; gcc-4.1.x [75f0bbfbdd5e] * d/d-asm-i386.h: Rename cmpxch8b to cmpxchg8b [21128c37d917] 2011-04-29 Iain Buclaw * d/d-glue.cc: Issue #203 - ArrayLiteralExp::toElem incorrectly sets TREE_STATIC [584a5f3a7dce] * d/druntime/core/stdc/wchar_.d: Use alias to make vswprintf and swprintf match ANSI signature. [344229e36805] * d/d-glue.cc: Issue #200 - Optimization breaks condition variables [b805b62dcdc8] * d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/dt.cc: Be less trusting with GCC builtins. [194016d49ca] 2011-04-23 Iain Buclaw * d/d-asm-i386.h: Make SSE3 iasm opcodes available for 32bit. [7861f5acdf6b] * d/dmd/todt.c, d/dmd2/todt.c: speed up emission of large static array initialisers. [9a840a37e508] * d-decls.cc, d/d-glue.cc, d/phobos/configure, d/phobos/configure.in, d/phobos2/Makefile.am, d/phobos2/configure: D1 regression with static array equality testing. [af07c3a2f08c] 2011-04-18 Daniel Green * d/phobos2/Makefile.in: Added std/c/wcharh.d to list of compiled Windows objects. Required by MinGW's stdio patch [3cf208768d86] 2011-04-17 Iain Buclaw * d/Make-lang.in, d/d-decls.cc, d/druntime/core/thread.d, d/phobos/configure, d/phobos/configure.in, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/configure, d/phobos2/configure.in: Edit configure scripts so cross compilers install imports in gcc version specific runtime directory [8fe76a59ba1e] * d/d-builtins2.cc: Issue #192 - ARM Compilation Fails When Including gcc.intrinsics [bf186179001b] * d/druntime/core/stdc/stdio.d: Change ctor in cstdio to 'shared static' - should fix Mingw IO in std.stdio [efb1b1ed90d8] * d/d-objfile.cc, d/druntime/core/stdc/stdio.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/std/stdio.d: Merge Daniel's MinGW work, put special case static ctor in core.stdio [71f10f204790] 2011-04-15 Iain Buclaw * d/dmd/func.c, d/dmd2/func.c: Remove __va_argsave definition from 64bit GDC [997a9ec407fe] * testsuite/*: Upload D2 testsuite for GDC. [6e40c9c42f6e] * d/d-asm-i386.h, d/d-irstate.cc, d/d-objfile.cc, d/druntime/core/thread.d: 64bit IASM fix, move tls definitions to d-objfile, add _tls_index stub for MinGW. [ff35bec78100] * d/d-objfile.cc: Issue #187 - Multiple definition of TypeInfo with MinGW. [d52ae1bf8343] * d/d-lang.cc, d/dmd-script, d/druntime/rt/monitor_.d: Uncomment implementations in rt.monitor_ (for MinGW), code cleanups. [1cf36f68d061] * d/d-codegen.cc: Issue #189 - sqrt(integer) causes ICE in maybeExpandSpecialCall [d46da356ca46] * d/d-incpath.cc: Issue #188 - -J option ignored. [875395c71f37] * d/Make-lang.in, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/dt.cc: 64bit testsuite fixes - passes all tests 32bit linux passes. [62c8038af25a] * d/Make-lang.in, d/d-builtins.c, d/d-decls.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-misc.c, d/d-objfile.cc, d/phobos/configure, d/phobos/configure.in, d/phobos2/configure, d/phobos2/configure.in: Remove d-misc.c, fixed code that depended on it. [066ecfe85f1] * d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h: Issue #185 - Intrinsics cause ICE on MinGW [c17a1cdfb868] 2011-04-11 Daniel Green * d/Make-lang.in, d/d-incpath.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: Added d-incpath.c for handling import paths. [5a55df337408] * d/setup-gcc.sh: Added option '-hg' for replacing 'gdc-version' with repository revision. [32ed0cf6d419] 2011-04-09 Iain Buclaw * d/d-codegen.cc, d/d-codegen.h: Implement math intrinsics into the compiler. [431f375abaf1] * d/d-asm-i386.h, d/druntime/core/atomic.d: More 64bit IASM fixes, favour ASM implementations in core.atomic. [8f5627ca0ba5] * d/phobos2/gcc/bitmanip.d: Really remove gcc.bitmanip. [c61617158bd8] * d/druntime/core/atomic.d, d/phobos/configure, d/phobos/configure.in, d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/configure, d/phobos2/configure.in, d/phobos2/gcc/atomics.d: First stab at gcc.atomics; Remove unused gcc.bitmanip; Add -inline as DFLAG for Phobos [1a74f184e2d8] 2011-04-08 Iain Buclaw * d/d-asm-i386.h, d/d-codegen.cc, d/d-glue.cc, d/d-lang.cc, d/d-spec.c: Issue #164 - ICE:fold-const.c:2792. [c42297cf76c3] * d/d-asm-i386.h, d/druntime/core/thread.d: 64bit IASM fixes. [406daaa254ad] * d/d-builtins2.cc, d/d-glue.cc: Issue #164 - (ICE:fold-const.c:2792) using std.range.zip [437b1cc2f607] * d/d-lang.cc, d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Phobos: Issue #179 - explicitly include zlib directory when building. [37ba91ed454c] * d/d-convert.cc: Issue 143: non-determistic FPE in runtime code. [4ea171da4900] * d/d-codegen.cc: Issue #178 - ICE in hwi2toli. [9133d6873087] * d/Make-lang.in, d/d-codegen.cc: Tidy up Make-lang.in, remove old bits. [1d8b36b4bfb7] * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/d-objfile.cc: Remove old-old workarounds for GCC < 4.0.x [b2ffdbb41245] * d/d-gcc-real.cc, d/d-gcc-real.h, d/dmd/cast.c, d/dmd2/cast.c, d/dmd2/expression.c: D2: Fix precision bug in PowExp. [ab7782c68bb5] * d/d-codegen.cc, d/d-gcc-real.cc: Don't error when casting from static array -> struct of same type size. [90b0b0208d3f] 2011-03-30 Iain Buclaw * d/Make-lang.in, d/d-gcc-real.cc, d/d-gcc-real.h: Fix strict-aliasing warning. [79ed94287f94] 2011-03-30 Daniel Green * d/asmstmt.cc: An unitialized array was forcing GDC to mark all registers as clobbered. [007de89f7694] 2011-03-27 Iain Buclaw * d/d-lang.cc: Move cgraph finalize into d_write_global_decls. [b7da3f7426ac] * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.h, d/d-dmd-gcc.h, d/d-gcc-real.h, d/d-irstate.cc, d/d-irstate.h, d/d-objfile.cc, d/d-objfile.h, d/druntime/core/thread.d, d/patches/patch-gcc-4.5.x, d/symbol.h: _tlsstart/_tlsend compiler generated symbols. [d2dfed983fff] * d/Make-lang.in, d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: New d_global_trees array for gcc trees of commonly used D types/decls. [d553b62db8e6] 2011-03-24 Iain Buclaw * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc, d/d-objfile.h, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: More WIP DMD calling convention - evaluate arguments left to right, pass in reverse order [6949b05e21e4] * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc, d/d-codegen.h, d/d-irstate.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/lang.opt: More WIP - 64bit IASM. [a85a80c8732a] * d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x, d/patches/patch-toplev-4.1.x, d/patches/patch-toplev-4.2.x, d/patches/patch-toplev-4.3.x, d/patches/patch-toplev-4.4.x, d/patches/patch-toplev-4.5.x: Switch patches to unified diff. [1738b301128b] * d/d-builtins2.cc, d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc, d/d-tree.def, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: More WIP DMD calling convention - Add 'optlink' function attribute. [521dce459f71] 2011-03-19 Iain Buclaw * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: WIP: Merge make_bool_binop, make_math_op, make_assign_math_op into toElemBin. [886b0a5af18a] * d/asmstmt.cc, d/d-asm-i386.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-irstate.h, d/d-lang-45.h, d/d-objfile.cc, d/d-spec.c: Use gcc_unreachable instead of abort, cleanup line endings. [3d6a01bd6e93] 2011-03-18 Iain Buclaw * d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/symbol.cc, d/symbol.h: Issue #167 - Assembler error: Already defined. [36a609d5155b] * d/d-glue.cc: IndexExp: call aaGetp if AA is modifiable. [d69227218b07] * d/d-codegen.cc, d/d-objfile.cc: Issue #165: Link failure with templates. [2221d9fb1dd9] * d/Make-lang.in, d/d-builtins2.cc, d/d-codegen.cc: Add experimental void* _argptr implementation switch in Makefile. [9a8cbe47da29] * d/Make-lang.in, d/d-builtins2.cc, d/d-codegen.cc, d/d-convert.cc, d/d-gcc-real.cc, d/d-glue.cc, d/d-spec.c: Replace calls to fold(build()) with fold_build() [8eab661a9626] * d/d-convert.cc: Harden d_truthvalue_conversion, catches scalars passed for conversion by buggy frontend. [ff5142f57beb] * d/Make-lang.in, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc: Add experimental DMD calling convention switch in Makefile [c5153f67119a] * d/d-bi-attrs-44.h: Update d-bi-attrs-44.h for current 4.4.5 release. [e44747eee585] * d/d-glue.cc: Mark used parameters to prevent false warnings from -Wunused-parameter. [f0a6db429617] 2011-03-12 Iain Buclaw * d/d-glue.cc: Fix codegen bug in CatAssignExp. [15f72843d336] * d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc: IRState::addTypeModifiers - Add D2 type modifiers (const/shared) onto GCC types (const/volatile). [ef3c725214ec] 2011-03-06 Iain Buclaw * d/d-lang.cc, d/d-spec.c, d/gdc.1, d/lang-specs.h, d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: Remove lang_specific_spec_functions code. [da7dc4ae6277] * d/dmd-script: Issue #161 - noboundscheck doesn't work with GDMD. [9ad16376258f] 2011-02-28 Iain Buclaw * d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc, d/d-objfile.h, d/dmd/template.c, d/dmd2/template.c, d/symbol.h: Moved GCC code to prevent templates being emitted more than once to the backend. [585920b19963] * d/Make-lang.in, d/d-decls.cc, d/d-glue.cc, d/d-lang.h, d/d-objfile.cc: Cleaned up ObjFile::makeDeclOneOnly implementation. [cbad6b2b6b42] 2011-02-25 Iain Buclaw * d/d-apple-gcc.c, d/d-builtins2.cc, d/d-c-stubs.c, d/d-codegen.cc, d/d-gcc-includes.h, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc: Remove dependencies on CPP objects. [33967b4ff6e9] * d/d-gcc-includes.h, d/patches/patch-apple-gcc-5465, d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: Remove old redundant code. [7b72e8118c29] * d/d-spec.c: Handle -pthread option in d-spec.c [b6062a158fdd] * d/d-glue.cc, d/phobos2/std/stdio.d, d/target-ver-syms.sh: Issue #151 - MinGW-w64: recent GDC does not build w/ recent GCC [978bb5bc82cf] * d/druntime/core/sys/posix/sys/un.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in: Remove posix.sys.un from druntime. [bb92ab765845] 2011-02-20 Iain Buclaw * d/Make-lang.in, d/d-builtins2.cc, d/d-lang.cc, d/d-spec.c, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.052. [c4980ba67971] * d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.067. [343f35cc00c8] * d/d-objfile.cc: Put compiler-generated arrayops on comdat. [4d14649603c2] * d/d-gcc-includes.h, d/d-glue.cc: use totym to apply D type modifiers on GCC types. [d3b9d3188b68] * d/d-decls.cc: Issue #155 - ICE when using byte [7846c6471861] * d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h: Remove 'artificial' attribute from GDC. [4b8f90d1f6aa] * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc: Conversion fixes for types with GCC attributes applied. [5e733844f91f] * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc, d/druntime/object.di, d/druntime/object_.d, d/druntime/rt/aaA.d, d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos/gcc/support.d, d/phobos/internal/aaA.d, d/phobos/internal/gc/gc.d, d/phobos2/gcc/support.d: ABI update: New signatures for _d_assocarrayliteralTp, _d_arrayliteralTp and _d_arrayappendcTp [b66226b53e71] * d/d-glue.cc: Update make_assign_math_op implementation [8390d07b450e] * d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc, d/d-gcc-includes.h, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc: Fix cast-qual and unused parameter warnings in glue. [377c4f5505be] * d/Make-lang.in, d/d-c-stubs.c, d/d-lang.cc: Drop support for CPP Builtins. [6dc9468f6789] 2011-02-10 Iain Buclaw * d/d-builtins.c, d/d-builtins2.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: New function added to langhooks: d_register_builtin_type. [9674e391725f] * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h, d/d-bi-attrs-42.h, d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h: Only accept string argument in mode attribute handler. [99764267b71b] * d/asmstmt.cc, d/d-builtins2.cc, d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-dmd-gcc.h, d/d-glue.cc, d/d-irstate.cc, d/d-objfile.cc, d/d-todt.cc: Remove all references to total.h in glue. [30c8afda4902] * d/asmstmt.cc, d/d-apple-gcc.c, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-gcc-real.cc, d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc, d/d-objfile.cc, d/dt.cc: Remove all references to assert.h in glue. [1d176d15d1e8] 2011-02-02 Iain Buclaw * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h, d/d-bi-attrs-42.h, d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h, d/dmd/attrib.c, d/dmd2/attrib.c: Fix mode attribute handler to accept string argument. [4ab9f7b5de07] 2011-01-29 Iain Buclaw * d/druntime/core/stdc/config.d: D2 - import gcc.builtins in core.stdc.config [1e41fd67396c] * d/d-codegen.cc, d/d-glue.cc, d/druntime/core/stdc/config.d, d/druntime/core/stdc/stdint.d, d/druntime/core/thread.d, d/druntime/gc/gc.d, d/druntime/gc/gcbits.d, d/druntime/gc/gcx.d, d/druntime/gcstub/gc.d, d/druntime/rt/lifetime.d, d/phobos2/std/intrinsic.d: 64bit TLS/GC fixes. Closes #109, #115. [0c10de583cd3] 2011-01-28 Iain Buclaw * d/Make-lang.in, d/d-codegen.cc, d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.066 [06b390b6f86b] * d/d-codegen.cc, d/d-glue.cc, d/druntime/rt/mars.h, d/phobos/std/c/stdarg.d: Remove redundant checks for Tbit in D1, add __va_argsave_t alias in phobos. [5a4481f10bce] * d/Make-lang.in: use new variable (ALL_CXXFLAGS) [a3ec7496100e] * d/d-c-stubs.c, d/d-codegen.cc, d/d-codegen.h, d/dmd/root.h, d/dmd2/root.h: Implement frontend std.intrinsics into GDC. [330bd9e6077b] 2011-01-18 Iain Buclaw * d/asmstmt.cc, d/d-codegen.cc, d/dmd/statement.h, d/dmd2/statement.h: Implemented ExtAsmstatement::toCBuffer. [4163067c9831] * d/dmd/arrayop.c, d/dmd/root.c, d/dmd2/arrayop.c, d/dmd2/root.c: Add binary implementation, use it in arrayops. [78358cd41c04] * d/dmd2/func.c, d/phobos/std/math.d, d/phobos2/std/intrinsic.d, d/phobos2/std/math.d, d/phobos2/std/string.d: Fix log2 implementation for systems requiring supplement. [961f4dd29944] 2011-01-16 Iain Buclaw * d/d-glue.cc: Pass static chain by reference for functions nested in classes. [e37f417ab86f] * d/d-lang-45.h, d/dmd/todt.c, d/dmd2/todt.c: rework todt for GCC. [a15a367a189a] * d/druntime/core/sys/posix/config.d, d/druntime/core/sys/posix/sys/stat.d, d/druntime/core/sys/posix/sys/types.d, d/druntime/gc/gcx.d: rework sys.stat struct implementation. [dc8e70a01ccf] 2011-01-13 Iain Buclaw * d/d-glue.cc, d/d-lang.cc, d/d-lang.h: Improve type names of shared/const/immutable types in debugging. [95990b0754e6] * d/d-codegen.cc: Issue #147 - static arrays passed as parameter should be value type. [59c59a459398] * d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: Second fix for Issue #104. [1e4da57f4be4] 2011-01-09 Iain Buclaw * d/dmd/mtype.c, d/dmd2/mtype.c: Issue #134 - Fix 64bit double align. [ab3473b8ee56] * d/dmd-script, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: Remove -fomit-frame-pointer from gdmd, fixes Issue #141 [191fd75f1716] 2011-01-06 Iain Buclaw * d/d-codegen.h, d/d-glue.cc, d/d-objfile.cc, d/lang-specs.h: Compiler segfault when not Object class not defined. [44b6978e5f6c] * d/d-builtins2.ca,c d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/dmd/dchar.h, d/dmd/mars.c, d/dmd2/dchar.h: Fix some warnings in d-lang, ICE when object.d is empty. [48827ef72351] * d/d-asm-i386.h, d/d-codegen.h: Refs Issue #135 - turn ICE into a temp error. [8f4b7ddb676e] * d/d-glue.cc: Call rest_of_type_compilation in toDebug for Record/Union/Enums. [ca79068bcb60] * d/druntime/object.di, d/druntime/object_.d: Issue #133 - Segfault On AA Foreach [aba6c8857d64] * d/druntime/core/thread.d, d/druntime/gc/gcx.d: Refs #115 - addRoot for each call for malloc in the GC. [3721c1dc5aad] * d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 - emit templates only for building phobos. [c2b8a3f7c35b] * d/d-decls.cc, d/d-objfile.cc: Issue #132 - unresolved symbol with typedef initializers. [69ebdbbcd8c2] * d/druntime/core/sys/posix/config.d, d/druntime/core/sys/posix/signal.d, d/druntime/core/sys/posix/sys/stat.d, d/phobos2/std/file.d: Fix struct stat_t implementation for linux. [29c51189bf66] 2011-01-02 Iain Buclaw * d/d-spec.c: Fix warning messages in d-spec.c. [da4c33277396] * d/d-codegen.cc, d/d-glue.cc: Issue #105 - assertion failure comparing structs for equality. [9a212ed12cec] * d/d-codegen.cc: Fix some diagnostic messages. [1447423e541a] * d/d-convert.cc: Update d_convert_basic for gcc-4.5 [28166c71baad] * d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc: Declare d_build_decl as extern "C". Add function d_build_decl_loc. [29253025adb2] Copyright (C) 2011 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2012 ================================================ 2013-02-15 Iain Buclaw * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro. 2013-02-14 Iain Buclaw * d-lang.h (D_DECL_IS_CONTRACT): Remove macro. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. 2013-02-13 Iain Buclaw * d-lang.cc (d_gcc_is_target_win32): Remove. (d_add_builtin_version): New function to handle define_builtin callback from backend. * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic bt. * d-builtins.c: Merge with d-builtins2.cc. * d-builtins2.cc: Remove. 2013-02-07 Johannes Pfau * d-lang.cc (d_init): Use gcc's config system for predefined OS versions. * setup-gcc.sh: Likewise. * target-ver-syms.sh: Likewise. 2013-02-05 Iain Buclaw * d-builtins2.cc (gcc_type_to_d_type): Remove STRUCTTHISREF condition. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. * d-elem.cc (ThisExp::toElem): Likewise. * d-ctype.cc (TypeSArray::toCtype): Remove SARRAYVALUE condition. * d-codegen.cc (IRState::isDeclarationReferenceType): Likewise. (IRState::isArgumentReferenceType): Likewise. 2013-02-01 Johannes Pfau * d-lang.cc (d_init): Use gcc's config system for predefined CPU versions. (d_init): Fix definition of D_LP64 version. * setup-gcc.sh: Likewise. * target-ver-syms.sh: Likewise. 2012-12-16 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Don't optimise PUREconst calls. 2012-10-27 Iain Buclaw * d-codegen.cc (IRState::buildAssignOp): Handle case where LHS type is not compatible with expression type. 2012-10-26 Iain Buclaw * d-decls.cc (ClassDeclaration::toSymbol): Use empty RECORD_TYPE to build internal symbol. (Module::toSymbol): Likewise. * d-objfile.cc (outdata): Set type size from constructor if not COMPLETE_TYPE_P. Assert that DECL_INITIAL is never bigger than TYPE_SIZE. 2012-10-25 Iain Buclaw * d-codegen.cc (IRState::getFrameInfo): Use vthis to determine whether function is nested. 2012-10-21 Iain Buclaw * d-builtins2.cc (gcc_type_to_d_type): Remove special case for double/long double types. (d_gcc_magic_builtins_module): Cleanup generation of builtin types. Add __builtin_unwind_int and __builtin_unwind_uint. 2012-10-16 Iain Buclaw * d-objfile.cc (ObjectFile::outputThunk): Mark thunk as DECL_WEAK rather than using weakref attribute. 2012-10-14 Iain Buclaw * d-bi-attrs.h: Remove file. * d-builtins.c (d_attribute_table): Define table of machine independant attributes for gcc builtins. (d_format_attribute_table): Define table of format attributes for gcc builtins. (handle_noreturn_attribute, handle_leaf_attribute, handle_const_attribute, handle_malloc_attribute, handle_returns_twice_attribute, handle_pure_attribute, handle_novops_attribute, get_nonnull_operand, handle_nonnull_attribute, handle_nothrow_attribute, handle_sentinel_attribute, handle_type_generic_attribute, handle_fnspec_attribute, handle_transaction_pure_attribute, ignore_attribute): Moved common attribute handlers from d-bi-attrs.h. * d-lang.cc (LANG_HOOKS_ATTRIBUTE_TABLE): Use instead of LANG_HOOKS_COMMON_ATTRIBUTE_TABLE. (d_attribute_table): Renamed from d_common_attribute_table. (d_format_attribute_table): Renamed from d_common_format_attribute_table. (d_init_ts): Renamed from d_common_init_ts. * d-builtins2.cc (d_bi_init): Determine D frontend type for size_t. * d-objfile.cc (ObjectFile::hasModule): Remove old compatibility macros. 2012-10-08 Iain Buclaw * d-glue.cc (VectorExp::toElem): Handle non-constant array literals as vector expressions. 2012-10-04 Iain Buclaw * d-glue.cc (VectorExp::toElem): Handle both array literal as well as single element constructors for vector expressions. 2012-09-27 Iain Buclaw * d-convert.cc (convert): Remove assert. 2012-09-22 Iain Buclaw * d-codegen.cc (IRState::maybeCompound): Use IRState::compound. (IRState::maybeVoidCompound): Use IRState::voidCompound. (IRState::call): Check TREE_SIDE_EFFECTS to determine order of evaluation in function calls. Evaluate callee before arguments if has side effects. * d-decls.cc (FuncDeclaration::toSymbol): Don't set any pure/nothrow attributes if asserts are generated in code. * d-incpath (add_fileimp_path): Fix ICE using -J option. * d-objfile.cc (Obj::moduleinfo): Clean-up. 2012-09-18 Iain Buclaw * d-lang.cc (d_initialize_diagnostics): New function, disable unneeded diagnostic options. (d_handle_option): Remove OPT_fdebug_c. * d-spec.c (lang_specific_driver): Remove OPT_fod_, OPT_fop. * lang.opt: Remove -fdebug-c, -fod, and -fop compiler options. 2012-09-17 Iain Buclaw * d-codegen.h (CtorEltMaker::cons): Adjust call to VEC_safe_push. * d-objfile.cc (ObjectFile::stripVarDecl): Clean-up. 2012-09-16 Iain Buclaw * d-codegen.cc (IRState::isCallByAlias): New function. (IRState::call): Use IRState::isCallByAlias. * d-objfile.cc (ObjectFile::setupSymbolStorage): Mark force_static_public symbols as public. * d-spec.c (lang_specific_driver): Update for GCC-4.8. * lang.opt: Fix spelling of option -static-libphobos * d-codegen.cc (IRState::maybeExpandSpecialCall): Do not handle inp* and outp* port intrinsic functions. (IRState::maybeSetUpBuiltin): Likewise. (IRState::expandPortIntrinsic): Remove. 2012-09-10 Iain Buclaw * d-codegen.cc (AggLayout::doFields): Propagate volatile out of type. (AggLayout::addField): Likewise. * d-decls.cc (VarDeclaration::toSymbol): Likewise. 2012-09-06 Iain Buclaw * d-codegen.h (IRState::vconvert): Don't use VIEW_CONVERT_EXPR. * d-glue.cc (TypeEnum::toCtype): Mark TYPE_PACKED if flag_short_enums. (TypeClass::toCtype): Mark TREE_ADDRESSABLE to ensure class is always passed in memory. * d-tree.def (UNSIGNED_RSHIFT_EXPR): Define new tree expression. (FLOAT_MOD_EXPR): Define new tree expression. * d-lang.cc (d_common_init_ts): New function. (d_write_global_declarations): Call check_global_declarations after finalize_compilation_unit. (d_gimplify_expr): Handle UNSIGNED_RSHIFT_EXPR, IASM_EXPR. * d-codegen.cc (IRState::arrayOpNotImplemented): New function. (IRState::buildOp): New function. (IRState::buildAssignOp): New function. * d-glue.cc (build_bool_binop): Remove function, mostly move to CmpExp::toElem. (build_math_op): Remove function, mostly move to IRState::buildOp. (build_assign_math_op): Remove function, mostly move to IRState::buildAssignOp. (BinExp::toElemBin): Remove function. (IdentityExp::toElem, EqualExp::toElem, CmpExp::toElem) (AndAndExp::toElem, OrOrExp::toElem): Clean-up, use IRState::boolOp. (XorExp::toElem, OrExp::toElem, AndExp::toElem, UshrExp::toElem) (ShrExp::toElem, ShlExp::toElem, ModExp::toElem, DivExp::toElem) (MulExp::toElem, MinExp::toElem, AddExp::toElem):Use IRState::arrayOpNotImplemented, IRState::buildOp. (XorAssignExp::toElem, OrAssignExp::toElem, AndAssignExp::toElem) (UshrAssignExp::toElem, ShrAssignExp::toElem, ShlAssignExp::toElem) (ModAssignExp::toElem, DivAssignExp::toElem, MulAssignExp::toElem) (MinAssignExp::toElem, AddAssignExp::toElem): Use IRState::arrayOpNotImplemented, IRState::buildAssignOp. * d-codegen.cc (libcall_ids): Remove _adCmpChar. (IRState::getLibCallDecl): Remove LIBCALL_ADCMPCHAR. * d-glue.cc (CmpExp::toElem): Don't call LIBCALL_ADCMPCHAR. * lang.opt: Define Wcast-result. * d-codegen.cc (IRState::convertTo): Warn about null result, but only if -Wcast-result. (IRState::hwi2toli): Move to header. (IRState::realPart): Likewise. (IRState::imagPart): Likewise. (IRState::toElemLvalue): Clean-up tree args array. (IRState::doArraySet): New function. (IRState::arraySetExpr): New function. * d-glue.cc (EqualExp::toElem): Clean-up tree args array. (CatAssignExp::toElem): Likewise. (AssignExp::toElem): Likewise. (DeleteExp::toElem): Likewise. (NewExp::toElem): Use IRState::modify. (ArrayLiteralExp::toElem): Don't call ARRAYLITERALTX library function if assigning to static array. (StructLiteralExp::toElem): Use IRState::arraySetExpr. (do_array_set): Move to IRState::doArraySet. (array_set_expr): Move to IRState::arraySetExpr. * d-lang.h (D_TYPE_IMAGINARY_FLOAT): Define. (d_convert_basic): Remove. * d-builtins.c (d_init_builtins): Mark imaginary types as D_TYPE_IMAGINARY_FLOAT. * d-builtins2.cc (gcc_type_to_d_type): Use convert. * d-codegen.cc (IRState::emitLocalVar): Call pushdecl earlier so catches CONST_DECLs. (IRState::convertTo): Remove handling of conversions between imaginary/real, imaginary/complex, complex/imaginary types, use convert. (IRState::convertForArgument): Use convert. (IRState::arrayElemRef): Likewise. (IRState::call): Likewise. (IRState::libCall): Likewise. (IRState::maybeExpandSpecialCall): Likewise. * d-convert.cc (d_convert_basic): Mark static. (convert): Handle correct conversions between imaginary/real, imaginary/complex, complex/imaginary types. * d-glue.cc (InExp::toElem): Use convert. (BoolExp::toElem): Likewise. (FuncDeclaration::buildClosure): Likewise. * d-builtins.c (def_fn_type): Use build_varargs_function_type_array and build_function_type_array to create built-in functions. (d_init_builtins): Use lang_hooks.types.type_for_size. * d-builtins2.cc (d_gcc_magic_builtins_module): Use lang_hooks.types.type_for_mode. * d-codegen.cc (IRState::pointerIntSum): Use lang_hooks.types.type_for_size. (IRState::call): Use lang_hooks.types.type_promotes_to. (IRState::maybeExpandSpecialCall): Likewise. * d-glue.cc (build_math_op): Use lang_hooks.types.type_for_mode. * d-lang.cc (d_type_for_mode): Mark static. (d_type_for_size): Likewise. (d_type_promotes_to): Likewise. 2012-08-31 Iain Buclaw * d-glue.cc (FuncDeclaration::toObjFile): Flatten nested levels and loops in function, delay printing function name in verbose mode until we know the function is being compiled. * d-codegen.cc (IRState::buildFrameForFunction): New function. (IRState::buildChain): Use IRState::buildFrameForFunction to get the frame record type. (IRState::getFrameInfo): Likewise. * d-glue.cc (FuncDeclaration::buildClosure): Likewise. 2012-08-30 Iain Buclaw * asmstmt.cc (ExtAsmStatement::toCBuffer): Mark unused parameter as ATTRIBUTE_UNUSED. * d-codegen.cc (WrappedExp::toCBuffer): Likewise. * d-objfile.cc (ObjectFile::setupSymbolStorage): Revert to previous behaviour of setting symbol storage. * d-codegen.cc (IRState::expandDecl): Use IRState::vinit. (IRState::binding): Likewise. (IRState::var): Handle all declarations, not just vars. * d-glue.cc (PtrExp::toElem): Simplify use of IRState::var. (SymbolExp::toElem ): Likewise. (ThisExp::toElem): Likewise. * d-lang.cc (d_init): Remove 'Thumb' identifier for ARM as 16bit platforms aren't supported. (GNU_LongDouble128): Remove identifier as long double size is determined from type information. * d-decls.cc (TypeInfoDeclaration::toSymbol): Mark all typeinfo decls as 'used'. * d-glue.cc (one_elem_array): Remove. (CatExp::toElem): Inline use of one_elem_array, clean-up. * d-objfile.cc (ObjectFile::setupSymbolStorage): Update to better handle use of declarations marked with comdat, extern or static. (ObjectFile::doSimpleFunction): Mark function as 'used'. * dt.cc (dt2node): Clean-up indentation. * Make-lang.in: Fix issue with cross-compiler configuration. 2012-08-29 Iain Buclaw * lang-specs.h: Remove special case for handled D source files. * Make-lang.in: Remove special case for building gcc.o, use GCC_EXTRA_LIBS to link against, rather than specific gcc object files. (D_DRIVER_NAME): Remove use of variable. (D_DRIVER_OBJS): Likewise. (D_COMPILER_NAME): Likewise. 2012-08-23 Iain Buclaw * d-builtins2.cc (eval_builtin): Use builtin_decl_explicit. * d-codegen.cc (IRState::emitLocalVar): Use warning. (IRState::convertTo): Likewise. (IRState::addressOf): Use IRState::markAddressable. (IRState::markAddressable): New function. (IRState::markUsed): New function. (IRState::markRead): New function. (IRState::maybeExpandSpecialCall): Use builtin_decl_explicit. (IRState::floatMod): Likewise. (IRState::exceptionObject): Likewise. * d-glue.cc (IdentityExp::toElem): Likewise. (EqualExp::toElem): Likewise. (PowExp::toElem): Likewise. (AssignExp::toElem): Likewise. (HaltExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (FuncDeclaration::toObjFile): Likewise. * d-lang.cc (d_mark_addressable): Remove function. (d_mark_exp_read): Remove function. * d-lang.h (d_warning): Remove macro. (d_built_in_decls): Remove macro. * d-objfile.cc (Obj::includelib): Use warning. (Obj::startaddress): Likewise. 2012-08-22 Iain Buclaw * d-lang.cc (binary): Moved function from frontend. * d-codegen.cc (IRState::extractMethodCallExpr): Update for new C++ VEC template in GCC. * d-bi-attrs.h (parse_optimize_options): Likewise. * d-dmd-gcc.h: Remove ifdef __cplusplus, use GCC_SAFE_DMD. * d-gcc-includes.h: Remove ifdef __cplusplus. * d-lang.h: Likewise. * Make-lang.in: Remove CC and CFLAGS from Makefile, add build rule for new texi man pages. * gdc.texi: New documentation for GDC. 2012-08-18 Iain Buclaw * d-codegen.cc (IRState::convertTo): Fix to allow conversion between void* and associative arrays. (IRState::convertForArgument): Use d_convert_basic. (IRState::call): Don't use d_convert_basic, now handled by convertForArgument. * d-gcc-real.cc (real_t::real_t): Increase real type mode to be greater than integer type size to prevent overflow in conversions. * d-glue.cc (CastExp::toElem): Don't get implicit AA type. 2012-08-17 Iain Buclaw * dfrontend: Update to D frontend version 2.060 * d-codegen.cc (libcall_ids): New library functions. (IRState::getLibCallDecl): Implement new library function signatures. * d-codegen.h (LibCall::LIBCALL_NEWITEMT): New enum value. (LibCall::LIBCALL_NEWITEMIT): Likewise. * d-decls.cc (FuncDeclaration::toSymbol): Small readability cleanup. * d-glue.cc (NewExp::toElem): Use new library functions. (StructLiteralExp::toElem): Update for new frontend. (ReturnStatement::toIR): Likewise. * d-incpath.cc (add_import_path): New signature. (add_fileimp_path): Likewise. (add_import_paths): Pass split Strings to helper functions. * d-lang.cc (d_parse_file): Use Obj::init and Obj::term. * d-objfile.cc (objmod): New variable. (Obj::init): New function. (Obj::term): Likewise. (Obj::includelib): Likewise. (Obj::startaddress): Likewise. (Obj::allowZeroSize): Likewise. (Obj::moduleinfo): Likewise. (Obj::export_symbol): Likewise. * symbol.h (Obj): New struct to allow object oriented interface to glue code from frontend. * d-builtins2.cc (d_gcc_magic_stdarg_check): Add new va_arg magic function that stores the next value through a passed parameter. Remove workaround for inout signature as va_list is always passed by reference to intrinsic templates. (d_gcc_magic_module): Assign module directly to global IRState. * d-codegen.cc (IRState::builtinsModule): Remove static declaration. (IRState::intrinsicModule): Likewise. (IRState::intrinsicCoreModule): Likewise. (IRState::mathModule): Likewise. (IRState::mathCoreModule): Likewise. (IRState::cstdargTemplateDecl): Likewise. (IRState::cstdargStartTemplateDecl): Likewise. (IRState::varsInScope): Likewise. (IRState::call): Use flag_split_darrays. (IRState::maybeExpandSpecialCall): Clean-up va_start and va_arg implementations. (IRState::maybeSetUpBuiltin): Handle new va_arg function. * d-codegen.h (Intrinsic::INTRINSIC_VA_ARG): New enum definition. (IRState::setBuiltinsModule): Remove. (IRState::setIntrinsicModule): Likewise. (IRState::setMathModule): Likewise. (IRState::setCStdArg): Likewise. * d-glue.cc (CatExp::toElem): Use flag_split_darrays. * d-irstate.cc (IRBase::startFunction): Set varsInScope. * d-lang.cc (d_init_options): Set modules that require special handling. (d_handle_option): Don't handle OPT_fsplit_dynamic_arrays. * lang.opt: fsplit-dynamic-arrays mapped to variable flag_split_darrays. 2012-08-16 Iain Buclaw * d-glue.cc (IdentityExp::toElem): Re-order precendence of type checking. Treat static arrays as D arrays in identity comparisons. (EqualExp::toElem): Use adEq2 over built-in memcmp for equality comparisons for static and dynamic arrays. (TypeStruct::toCtype): Remove old platform specific workaround. * d-builtins2.cc (bi_lib_list): New decl to hold list of GCC library built-ins. (d_bi_init): Add decls to bi_list_list if recognising built-ins. (d_gcc_magic_builtins_module): Rename built-in type C long to __builtin_clong, built-in type C ulong to __builtin_culong. (d_gcc_magic_libbuiltins_check): New function to assign internal symbol for built-in library functions. (d_gcc_magic_libbuiltins_module): New function to scan modules that contain GCC library built-ins. (d_gcc_magic_module): Search all core.stdc modules for possible GCC library built-ins. * d-codegen.h (IRState::useBuiltins): Remove. * d-lang.cc (d_init_options): Don't set IRState::useBuiltins. (d_handle_option): Likewise. * lang.opt: Re-order D frontend compiler options. * d-codegen.cc (IRState::buildChain): Override chainLink and chainFunc for function if static chain is passed via hidden 'this' and no frame is created. (IRState::getFrameInfo): Pass static chain around nested functions in the same way as closures for better performance. * d-codegen.cc (libcall_ids): Re-order list in ascii collating order, add new library routines to lookup, rename all non-vararg functions to match DMD ABI implementation. (LibCall): Re-order enum and rename values to match libcall_ids. (IRState::toElemLvalue): Use new LibCall name. (IRState::getLibCallDecl): Update to match current library signatures, add implementation of new library routines. (IRState::maybeSetLibCallDecl): New function to set internal symbol for special D RT library functions. * d-decls.cc (FuncDeclaration::toSymbol): Use IRState::maybeSetLibCallDecl. * d-glue.cc (InExp::toElem): Use new LibCall name. (CatAssignExp::toElem): Likewise. (IndexExp::toElem): Likewise. (DeleteExp::toElem): Likewise. (RemoveExp::toElem): Likewise. (NewExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (AssocArrayLiteralExp::toElem): Likewise. (NullExp::toElem): Use IRState::convertTo. * d-codegen.cc (needs_temp): Remove. (IRState::makeTemp): New function. (IRState::maybeMakeTemp): Re-implement to use isFreeOfSideEffects. (IRState::isFreeOfSideEffects): Re-implement to allow better CSE. (IRState::call): Use IRState::makeTemp. * d-builtins2.cc (gcc_type_to_d_type): Use d_convert_basic. * d-codegen.cc (IRState::emitLocalVar): Use IRState::vinit. (IRState::convertTo): New function for tree conversions. (IRState::convertTo): Use IRState::convertTo. (IRState::convertForCondition): Likewise. (IRState::darrayVal): Likewise. (IRState::pointerIntSum): Likewise. (IRState::pointerOffsetOp): Likewise. (IRState::pvoidOkay): Likewise. (IRState::boundsCond): Likewise. * d-convert.cc (convert): New function to be called from C. (d_build_truthvalue_op): Use d_convert_basic. * d-glue.cc (convert): Remove. (build_bool_binop): Use IRState::convertTo. (build_math_op): Likewise. (CmpExp::toElem): Likewise. (PowExp::toElem): Likewise. (do_array_set): Likewise. (AssignExp::toElem): Likewise. (VectorExp::toElem): Likewise. (NotExp::toElem): Likewise. (CallExp::toElem): Likewise. (SymbolExp::toElem): Likewise. * dt.cc (dt2tree_list_of_elems): Use d_convert_basic. 2012-07-26 Iain Buclaw * d-gcc-real.cc (real_t::real_t): Use d_float64 for constructor. (real_t::isConst0): Remove. (real_t::isConst1): Likewise. (real_t::isConst2): Likewise. (real_t::isConstMinus1): Likewise. (real_t::isConstHalf): Likewise. * d-gcc-real.h (longdouble): New typedef for real_t. (ldouble): New template for ldouble conversions. (ld_sprint): New function for ldouble to string formatting. * d-codegen.cc (IRState::hwi2toli): Handle maximum 64bit value case. 2012-07-18 Iain Buclaw * d-codegen.cc (IRState::delegateVal): Remove ENABLE_CHECKING code. (IRState::objectInstanceMethod): Remove special case to avoid calling DotTypeExp::toElem. * d-glue.cc (CommaExp::toElem): Likewise. (DotTypeExp::toElem): Implement function. (StructLiteralExp::toElem): Assert instead that basetype is a struct. * d-gcc-reah.cc (real_t::real_t): New overload for 'double' type. (real_t::format): Change function type to int, return size of buffer from function. (real_t::formatHex): Likewise. * d-builtins2.cc (d_gcc_magic_stdarg_check): Update signature, remove check for is_c_std_arg. (d_gcc_magic_stdarg_module): Likewise. (d_gcc_magic_module): Remove check for core.vararg. * d-codegen.cc (INTRINSIC_STD_VA_ARG): Remove. (IRState::maybeSetUpBuiltin): Don't handle INTRINSIC_STD_VA_ARG. 2012-07-13 Iain Buclaw * d-decls.cc (Dsymbol::toSymbolX): Remove use of PRIuSIZE format macro. (FuncDeclaration::toThunkSymbol): Likewise. 2012-07-12 Iain Buclaw * d-lang.h (D_DECL_IS_CONTRACT): New macro. * d-decls.cc (FuncDeclaration::toSymbol): Mark in and out contracts as D_DECL_IS_CONTRACT. (FuncDeclaration::toThunkSymbol): D thunks no longer private by design. Alter mangling of thunk symbols to be unique across the entire compilation unit. * d-objfile.cc (ObjectFile::makeDeclOneOnly): Catch public contracts to mark them as one-only. (ObjectFile::outputThunk): Mark weakref thunks as private. 2012-07-10 Iain Buclaw * Make-lang.in: Remove unused borrowed objects. * d-builtins2.cc (d_bi_builtin_func): Don't add builtin if -fno-builtin was given. * d-codegen.cc (IRState::emitTemplates): Remove static declaration. (IRState::splitDynArrayVarArgs): Likewise. (IRState::useInlineAsm): Likewise. (IRState::useBuiltins): Likewise. (d_gcc_force_templates): Update to use global gen. * d-codegen.h (emitTemplates): Remove static attribute. (splitDynArrayVarArgs): Likewise. (useBuiltins): Likewise. (useInlineAsm): Remove member. (stdInc): Define new member. * d-incpath.cc (std_inc): Remove global. (add_import_paths): Update function signature. * d-lang.cc (d_init_options): Default splitDynArrayVarArgs to false. (d_init): Update call to add_import_paths. (d_handle_option): Remove OPT_fd_inline_asm, add OPT_fsplit_dynamic_arrays. * lang.opt: Likewise. 2012-07-08 Iain Buclaw * d-builtins2.cc (d_gcc_type_align): Update function signature. Use type align size to determine the known align size of a decl. * d-dmd-gcc.h (d_gcc_type_align): Update function signature. * symbol.h (Symbol): New member, Salignment. * symbol.cc (Symbol::Symbol): Initialise Salignment. * d-decls.cc (VarDeclaration::toSymbol): Set Salignment if there is an alignment in effect on the decl. (AggregateDeclaration::toInitializer): Likewise. * d-objfile.cc (ObjectFile::outputStaticSymbol): Set DECL_ALIGN if Salignment was given for static decl. 2012-07-07 Iain Buclaw * d-builtins2.cc (d_gcc_magic_builtins_module): Add check for DECL_ASSEMBLER_NAME_SET_P when testing for builtins that can be markable as pure in the D frontend. * d-codegen.cc (IRState::integerConstant): Hide use of HOST_BITS_PER_WIDE_INT macros. (IRState::hwi2toli): Likewise. (IRState::getTargetSizeConst): Likewise. * d-builtins.c (d_global_trees): Move declaration here. (lookup_C_type_name): Rename to lookup_ctype_name. (d_init_builtins): Move set-up of d_global_trees here. (gcc_d_backend_init): Move function from d-glue.cc and refactored. (gcc_d_backend_term): Likewise. * d-builtins2.cc (d_bi_init): Set-up D frontend sizes here. * d-glue.cc (gcc_d_backend_init): Removed. (gcc_d_backend_term): Likewise. * d-incpath.cc (add_phobos_versyms): New function to scan phobos-vers-syms file. (register_import_chains): Renamed to add_import_paths. * d-lang.cc (d_init): Call add_phobos_versyms and add_import_paths. (d_parse_int): Don't use strtol to get number from argument string. * d-incpath.cc (maybe_fixup_phobos_target): Remove. (register_import_chains): Remove use of maybe_fixup_phobos_target. * d-lang.cc (maybe_fixup_os_versym): Remove (d_init): Remove use of maybe_fixup_os_versym. * d-lang.cc (saved_reg_names): Remove. (d_init): Remove use of saved_reg_names. (d_post_options): Likewise. 2012-07-05 Iain Buclaw * d-glue.cc (StructLiteralExp::toElem): Stop after first assignment for constructors built for union types. 2012-07-01 Iain Buclaw * symbol.h (deferredNestedFuncs): Renamed from otherNestedFuncs, use as value type rather than pointer. (thunks): Use as value type rather than pointer. * d-decls.cc (FuncDeclaration::toSymbol): Remove check for deferredNestedFuncs being NULL. (FuncDeclaration::toThunkSymbol): Remove check for thunks being NULL. * d-glue.cc (DelegateExp::toElem): Remove check for deferredNestedFuncs being NULL. (FuncDeclaration::toObjFile): Likewise. * d-objfile.cc (ObjectFile::shouldEmit): Add nested functions to deferredNestedFuncs of their parent function incase parent is actually emitted later in during compilation. * d-builtins2.cc (d_gcc_type_align): Explicit alignment of variables takes precedence over default alignment. * d-gcc-includes.h: Re-order list of includes. 2012-06-26 Iain Buclaw * d-codegen.cc (IRState::twoFieldType): Use rest_of_decl_compilation. * d-gcc-includes.h: Remove last of poisoned backend headers. * d-glue.cc (FuncDeclaration::toObjFile): Use fprintf for diagnostic message. Use rest_of_decl_compilation directly. (SynchronizedStatement::toIR): Likewise. (TypeFunction::toCtype): Remove old version1 macro. * d-lang.cc (d_parse_file): Remove dependency on backend header. Use fprintf for diagnostic messages. (nametype): Use rest_of_decl_compilation directly. (d_handle_option): Remove version 1 option. * dmd-script: Likewise. * lang.opt: Likewise. * d-objfile.cc (ObjectFile::outputStaticSymbol): Use rest_of_decl_compilation directly. (ObjectFile::declareType): Likewise. (obj_moduleinfo): Likewise. (obj_tlssections): Likewise. (ObjectFile::outputThunk): Implement new method of thunk generation for external symbols using weakref. * d-objfile.h (rodc): Remove. 2012-06-25 Iain Buclaw * d-builtins.c (d_init_builtins): Use build_tree_list to initialise void_list_node. * d-glue.cc (ArrayLiteralExp::toElem): Always generate code for arrayliteralTp. (TypeFunction::toCtype): Chain on void_list_node to the end of the function type parameters. Fixes function signatures in debugging. 2012-06-23 Iain Buclaw * Make-lang.in (d_OBJS): Add so IN_GCC_FRONTEND is defined when building gdc sources. * d-builtins.c: Remove poisoned headers. * d-codegen.cc: Likewise. * d-gcc-includes.h: GCC system headers included first, removed internally defined macros and poisoned headers. * d-gcc-tree.h: Use GCC system headers instead of defining tree_node. * d-lang.cc: GCC system headers included first. (pushdecl_top_level): Removed. * d-objfile.cc: Remove poisoned headers. * gdc_alloca.h: Use liberty.h instead of handling include of alloca. * d-decls.cc (Dsymbol::toSymbolX): Use snprintf rather than sprintf. (FuncDeclaration::toSymbol): Likewise. * d-gcc-real.cc (real_t::init): Likewise. * symbol.cc (Symbol::Symbol): Use NULL_TREE to initialise tree. (symbol_calloc): Use xstrdup to copy string. * Make-lang.in: Remove D language version 1 from build (_GNU_SOURCE): Removed macro from build. (ELFOBJ): Likewise. (D_VA_LIST_TYPE_VOIDPTR): Likewise. * asmstmt.cc (ExtAsmStatement::semantic): Removed use of V2 macro. * d-builtins2.cc (d_gcc_builtin_va_list_d_type): Removed use of D_VA_LIST_TYPE_VOIDPTR macro. (gcc_type_to_d_type): Likewise. (d_gcc_magic_stdarg_check): Likewise. (d_gcc_magic_builtins_module): Removed use of V2 macro, and V1 encapsulated code. * d-codegen.cc (IRState::convertTo): Likewise. (IRState::toDArray): Likewise. (IRState::typesCompatible): Likewise. (IRState::arrayBoundsCheck): Likewise. (IRState::assertCall): Likewise. (libcall_ids): Likewise. (IRState::getLibCallDecl): Likewise. (IRState::getFrameForSymbol): Likewise. (IRState::isFuncNestedIn): Likewise. (IRState::buildChain): Likewise. (IRState::getFrameInfo): Likewise. (IRState::getFrameRef): Likewise. (IRState::functionNeedsChain): Likewise. (IRState::startCond): Likewise. (IRState::exitIfFalse): Likewise. (IRState::startCase): Likewise. (IRState::doCase): Likewise. (IRState::endCase): Likewise. * d-decls.cc (VarDeclaration::toSymbol): Likewise (FuncDeclaration::toSymbol): Likewise. * d-glue.cc (CondExp::toElem): Likewise. (build_bool_binop): Likewise. (EqualExp::toElem): Likewise. (CmpExp::toElem): Likewise. (AndAndExp::toElem): Likewise. (OrOrExp::toElem): Likewise. (AssignExp::toElem): Likewise. (CastExp::toElem): Likewise. (CallExp::toElem): Likewise. (AssertExp::toElem): Likewise. (AssocArrayLiteralExp::toElem): Likewise. (StructLiteralExp::toElem): Likewise. (FuncDeclaration::toObjFile): Likewise. (Module::genobjfile): Likewise. (TypeFunction::toCtype): Likewise. (ThrowStatement::toIR): Likewise. (TryCatchStatement::toIR): Likewise. (ReturnStatement::toIR): Likewise. (SwitchStatement::toIR): Likewise. (IfStatement::toIR): Likewise. (ForStatement::toIR): Likewise. (ExpStatement::toIR): Likewise. * d-irstate.cc (IRBase::startFunction): Likewise. * d-lang.cc (d_init_options_struct): Likewise. (d_handle_option): Likewise. (d_parse_file): Likewise. 2012-06-21 Iain Buclaw * Make-lang.in: Remove d-asm-i386.h * asmstmt.cc (d_build_asm_stmt): Update signature, use build5. (getFrameRelativeValue): Remove. (d_format_priv_asm_label): Likewise. (d_have_inline_asm): Likewise. (AsmProcessor): Likewise. (AsmStatement::toIR): Update sorry message. * d-codegen.cc (IRState::expandPortIntrinsic): Update call to d_build_asm_stmt. (IRState::doAsm): Likewise. * d-decls.cc (FuncDeclaration::toSymbol): Remove check for inline asm. * d-glue.cc (FuncDeclaration::toObjFile): Likewise. (LabelStatement::toIR): Likewise. * d-lang.cc (VersionCondition::addPredefinedGlobalIdent): Remove D Inline Asm version identifiers. * d-lang.h (d_build_asm_stmt): Update signature. 2012-06-19 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Mark in/out contracts as TREE_PUBLIC to allow calling cross-module. * d-lang.cc (d_parse_file): Update for 2.059. 2012-06-16 Iain Buclaw * dfrontend: Merged with DMD 2.059. * d-builtins2.cc (gcc_type_to_d_type): Use new frontend value. * d-codegen.cc (IRState::getLibCallDecl): Fix return type of _aaDelp. (IRState::getVThis): Use frontend provided member to determine if function has nested references. * d-decl.cc (FuncDeclaration::toSymbol): Weakly pure functions don't guarantee no vops. * d-gcc-real.cc (max_float_mode): Remove. (real_t::convert): Catch imaginary types in conversion. * d-glue.cc (EqualExp::toElem): Use memcmp for struct comparisons. (CatAssignExp::toElem): Rework order of logic to allow appending delegates to an array. (DelegateExp::toElem): Implement handling of lambda functions. (FuncExp::toElem): Ditto. (AssocArrayLiteralExp::toElem): Implement handling of AssociativeArray types sent to backend. * d-objfile.cc (lmtab): Remove. (cvtLocToloc_t): Update implementation. (outdata): Now assert that we don't receive error nodes. 2012-06-05 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Make better use of 'pure' and 'pure const' functions in GCC codegen. * d-bi-attrs.h: Added TM_ATTR* masks. (handle_tm_wrap_attribute, handle_tm_attribute, tm_attr_to_mask, find_tm_attribute): New. (struct d_common_attribute_table): Added transaction* attributes. 2012-06-04 Iain Buclaw * d-objfile.cc (ObjectFile::outputThunk): Output thunks moved back to the frontend, as backend does not emit them for DECL_EXTERNAL functions. 2012-05-29 Daniel Green * setup-gcc.sh: Add GCC 4.8 to list of supported GCC versions. Patch courtesy of Calrama https://bitbucket.org/goshawk/gdc/issue/345 2012-05-29 Iain Buclaw * d-codegen.cc (IRState::endCase): Remove parameter from function. Use condition type as the SWITCH_EXPR type, rather than use of void. * d-codegen.h (IRState::endCase): Update signature. * d-glue.cc (SwitchStatement::toIR): Update call to endCase. 2012-05-28 Daniel Green * d-builtins.c (DEF_ATTR_STRING): Define and undefine along with other macros. * d-lang.cc (d_write_global_declartions): Use finalize_compilation_unit. GCC 2012-04-30 * d-objfile.cc (ObjectFile::outputThunk): Use symtab_add_to_same_comdat_group. GCC 2012-04-30 * lang.opt: Match help strings for duplicated options. 2012-02-01 Iain Buclaw * setup-gcc.sh: Remove -hg option. * dfrontend/func.c (FuncDeclaration::semantic): Remove code adding method to flat list. (FuncDeclaration::semantic3): Re-add here. 2012-01-01 Iain Buclaw * d-builtins2.cc (IRState::buildChain): Don't do nrvo if the variable is put in a closure. * d-glue.cc (FuncDeclaration::buildClosure): Ditto. (ReturnStatement::toIR): Don't call postblit on nrvo returns. (DtorExpStatement::toIR): Don't call destructor if var is returned as the nrvo variable. Copyright (C) 2012 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2013 ================================================ 2013-12-27 Iain Buclaw * d-codegen.cc (build_two_field_type): Declare builtin types as toplevel declarations. * d-ctype.cc (EnumDeclaration::toDebug): Build type decl in debug code. * d-lang.cc (nametype): Rename to d_nametype. 2013-12-23 Iain Buclaw * d-decls.cc (EnumDeclaration::toDebug): Don't send array types to rest_of_type_compilation. 2013-12-16 Iain Buclaw * d-spec.cc (lang_specific_driver): Require linking in library for all files except D interface files. * d-lang.cc (d_write_global_declarations): Call d_finish_compilation. * d-objfile.cc (mark_needed): Mark static. (d_finish_symbol): Don't call mark_needed. (d_finish_function): Likewise. (d_finish_compilation): New function to wrapup all global declarations, mark templates/comdats as needed if required, and start the final compilation. 2013-12-10 Iain Buclaw * d-ctype.cc (TypeVector::toCtype): Treat void vectors as ubyte. * d-objfile.cc (VarDeclaration::toObjFile): Gag all errors compiling manifest constants. * d-todt.cc (TypeVector::toDt): New function to generate correct static data for vector initialisers. 2013-12-05 Iain Buclaw * d-lang.cc (d_init_options_struct): Don't define strict aliasing. (d_get_alias_set): New function to return language-specific alias set. * d-convert.cc (d_convert_basic): Always zero extend pointer to integer conversions. 2013-12-04 Iain Buclaw * d-codegen.cc (maybe_set_builtin_frontend): Assert that all runtime library functions have been set-up correctly. (libcall_ids): Remove unhandled library functions. (get_libcall): Likewise. * d-codegen.h (LibCall): Likewise. * d-objfile.cc (output_symbol_p): Remove. 2013-12-03 Iain Buclaw * d-lang.cc (d_init_options): Update for frontend changes. (d_handle_option): Set frontend allInst option if -femit-templates. * d-objfile.cc (output_template_p): Want to emit all instantiated templates if -femit-templates or -fdebug was passed to the compiler. * d-objfile.h (TemplateEmission): Define TEallinst. * d-todt.cc (StructDeclaration::toDt): Update for frontend changes. * d-spec.cc (THREAD_LIBRARY): Define default thread library to link if one is not already specified in the configuration process. (TIME_LIBRARY): Define default real time library to link if one is not already specified in the configuration process. (LIBSTDCXX): Define C++ library to link if compiling C++ and D sources. (lang_specific_driver): Update implementation to use new macros. 2013-12-02 Iain Buclaw * d-elem.cc (CatAssignExp::toElem): Don't call postblit after element append to array. (NewExp::toElem): Handle calling 'new' on opaque types. (ArrayLiteralExp::toElem): Ensure array literal elements have no side effects by making temporaries as necessary. * d-todt.cc (StructLiteralExp::toDt): Update for frontend changes. * d-codegen.cc (build_frame_type): Check for scoped variables if building a closure. * d-objfile.cc (d_finish_symbol): Relax toDt checking rule. 2013-12-01 Iain Buclaw * d-asmstmt.cc (ExtAsmStatement::ExtAsmStatement): Remove labels member from class. * d-codegen.cc (d_gcc_force_templates): Remove. (convert_expr): Update for frontend changes. (convert_for_assignment): Likewise. (maybe_set_builtin_frontend): Update for changes to libdruntime core.bitops signatures. * d-ctype.cc (TypeFunction::toCtype): Update for frontend changes. * d-decls.cc (Dsymbol::toSymbolX): Likewise. (VarDeclaration::toSymbol): Likewise. (FuncDeclaration::toSymbol): Don't defer nested functions here. * d-elem.cc (PowAssignExp::toElem): Update for frontend changes. (DeleteExp::toElem): Likewise. (AssertExp::toElem): Don't call invariant on an extern C++ class. * d-glue.cc (Global::init): Initialise new stdmsg member. * d-lang.cc (d_handle_option): Handle -fdeps switch. Remove TEprivate for -femit-templates switch. (genCmain): Update for frontend changes. (d_parse_file): Likewise. * d-longdouble.cc (longdouble::dump): Likewise. * d-objfile.cc (ClassDeclaration::toObjFile): Update for frontend changes. (InterfaceDeclaration::toObjFile): Likewise. (EnumDeclaration::toObjFile): Likewise. (Symbol::Symbol): Remove outputSymbol member. (output_symbol_p): Mark static. (output_declaration_p): Determine symbol codegen status from semanticRun. (output_template_p): New function to determine whether an instantiated template is to be written to object file. (FuncDeclaration::toObjFile): Use semanticRun to update codegen status of function. (FuncDeclaration::buildClosure): Error if putting a scoped variable in a closure. (Module::genobjfile): Update for frontend changes. (d_comdat_linkage): Don't determine linkage from TE setting. Mark all comdat symbols as DECL_COMDAT. (setup_symbol_storage): Use output_template_p to determine whether the symbol is being written to object file. (mark_needed): New function to mark decls that must be emitted. (d_finish_symbol): Mark finished symbols as needed. (d_finish_function): Mark finished functions as needed. (build_simple_function): Set semanticRun for glue changes. * d-objfile.h (OutputStage): Remove enum. * d-todt.cc (build_vptr_monitor): Update for frontend changes. (StructInitializer::toDt): Likewise. (StructDeclaration::toDt): Likewise. (TypeInfoEnumDeclaration::toDt): Likewise. (TypeInfoStructDeclaration::toDt): Likewise. (Type::getTypeInfo): Likewise. 2013-11-30 Iain Buclaw * d-lang.cc (genCmain): Implement code generation of __entrypoint module to provide the target C main function. (deps_write): Ignore the module __entrypoint when writing make deps. (d_parse_file): Handle writing __entrypoint module to object file. * d-objfile.cc (d_finish_symbol): Remove special handling of _tlsstart symbol, but ensure _tlsend gets written to the thread common section. (d_finish_function): Remove call to build_tlssections. (build_tlssections): Remove. 2013-11-29 Iain Buclaw * d-decls.cc (ClassDeclaration::toVtblSymbol): Use TypeSArray::makeType to generate frontend static array type. * d-glue.cc (Dsymbol::ungagSpeculative): Define. * d-lang.cc (genCmain): Define as empty. (d_parse_file): Update for frontend changes. * d-objfile.cc (StructDeclaration::toObjFile): Likewise. * d-typinf.cc (TypeBasic::builtinTypeInfo): Likewise. * d-longdouble.cc (longdouble::isIdenticalTo): Remove. * d-port.cc (Port::fequal): Define. 2013-11-28 Iain Buclaw * d-builtins.cc (gcc_type_to_d_type): Use TypeSArray::makeType to generate frontend static array types. * d-codegen.cc (build_attributes): Use optimize as don't want the ctfeInterpret of TypeExp expressions. (get_object_method): Update for frontend changes. (get_libcall): Update to use Type::dtypeinfo. * d-elem.cc (IndexExp::toElem): Don't generate bounds checking codegen if frontend explictly requests it. (ArrayLiteralExp::toElem): Use TypeSArray::makeType to generate frontend static array type. (StructLiteralExp::toElem): Update for frontend changes. * d-glue.cc (Global::increaseErrorCount): Define. * d-objfile.cc (Module::genmoduleinfo): Remove moduleinfo 'New' implementation for libdruntime changes. * d-todt.cc (StructLiteralExp::toDt): Literal initialisers override default initialisers. (TypeInfoDeclaration::toDt): Update to use Type::dtypeinfo. (TypeInfoStructDeclaration::toDt): Update for frontend changes. * d-typinf.c (Type::getInternalTypeInfo): Update to use Type::dtypeinfo. 2013-11-25 Iain Buclaw * d-asmstmt.cc (ExtAsmStatement::comeFromImpl): Define for frontend implementation changes. * d-codegen.cc (get_libcall): Update to use Type::typeinfoclass. * d-codegen.cc (WrappedExp): Define as class. * d-convert.cc (d_convert_basic): Fix format warnings. * d-decls.cc (ModuleInfoDeclaration::toSymbol): Remove. (FuncDeclaration::toSymbol): Use mangleExact to get decl mangle. * d-elem.cc (ClassReferenceExp::toElem): Return reference to class. * d-glue.cc (verror): Fix format warnings. (verrorSupplemental): Likewise. (vwarning): Likewise. (vdeprecation): Likewise. (escapePath): Define for frontend implementation changes. * d-irstate.cc (IRState::getLoopForLabel): Implement breaking on named scope labels in for/while loops. * d-lang.cc (d_handle_option): Add handler for new -fdeps and -fmake-deps options. (d_parse_file): Handle new -fdeps and fmake-deps options. * d-objfile.cc (Dsymbol::toObjFile): Update to use RootObject. (Type::typeinfoclass): Update to use Type::typeinfoclass. (InterfaceDeclaration::toObjFile): Likewise. * d-objfile.h (Symbol): Remove inheritance from Object. * d-todt.cc (TypeInfoStructDeclaration::toDt): Update to use Type::immutableOf. 2013-11-24 Iain Buclaw * d-builtins.c (gcc_type_to_d_type): Use TREE_INT_CST_LOW macro instead of tree_low_cst. (eval_builtin): Likewise. (gcc_cst_to_d_expr): Use tree_cst_hwi. * d-codegen.cc (tree_to_hwi): Remove call to deleted host_integerp. (maybe_expand_builtin): Use TREE_INT_CST_LOW macro. * d-lang.cc (d_parse_file): Update debug_hooks call for middle-end changes. * d-system.h: Update includes for middle-end changes. 2013-11-17 Iain Buclaw * d-objfile.cc (finish_thunk): Update for conversion of symtab types to a true class hierarchy. * d-ctype.cc (TypeClass::toCtype): Fix ABI to emit correct vtable and monitor field names. * d-ctype.cc (TypeClass:toCtype): Set TYPE_LANG_SPECIFIC on record as well as reference type. * d-lang.cc (d_classify_record): New langhook to return appropriate class/interface/struct type to the debugger. 2013-10-27 Iain Buclaw * d-elem.cc (ArrayLiteralExp::toElem): Build empty constructor for zero sized arrays. 2013-10-23 Iain Buclaw * d-elem.cc (AssignExp::toElem): Optimise assigning array literal to a static array. (ArrayLiteralExp::toElem): Do not allocate static or const array literals on the heap using the GC. 2013-10-16 Iain Buclaw * d-builtins.c (DEF_FUNCTION_TYPE_8): Define. 2013-10-10 Iain Buclaw * d-builtins.c (gcc_cst_to_d_expr): Add support for VECTOR_CST to Expression conversion. (d_gcc_paint_type): Add support for painting to/from array literals. 2013-10-01 Iain Buclaw * d-objfile.cc (cvtLocToloc_t): Rename to get_linemap. * d-glue.cc: New source to provide interface for defined globals and error handling called from the front-end. 2013-09-16 Iain Buclaw * d-codegen.cc (IRState::call): Rename to d_build_call. (IRState::emitLocalVar): Rename to build_local_var. (IRState::buildAssignOp): Move to BinExp::toElemBin. (IRState::IRState): Remove IRState class. * d-irstate.cc (IRBase::IRBase): Rename to IRState, remove inheritance from Object class. * d-decls.cc (VarDeclaration::toSymbol): Remove redundant CONST_DECL code as VarDeclaration::toObjFile does not emit manifest constants. * d-ctype.cc (TypeEnum::toCtype): Generate CONST_DECLs for enumeration members for correct debugging. * d-objfile.cc (build_type_decl): Use fully qualified type name in debugging code. (VarDeclaration::toObjFile): Emit manifest constant values in debug code generation. 2013-09-10 Iain Buclaw * d-elem.cc (SliceExp::toElem): Don't build D array for slices that return a static array. 2013-09-03 Iain Buclaw * d-codegen.cc (IRState::buildOp): Rename to build_binary_op. 2013-09-01 Iain Buclaw * d-decls.cc (binfo_for): Rename to build_class_binfo. (intfc_binfo_for): Rename to build_interface_binfo. (ClassDeclaration::toDebug): Move binfo generation into toCtype. * d-lang.cc (pushlevel): Rename to push_binding_level. (poplevel): Rename to pop_binding_level. (global_bindings_p): Rename to d_global_bindings_p, add langhook. (pushdecl): Rename to d_pushdecl, add langhook. (getdecls): Rename to d_getdecls, add langhook. (set_block): Remove function. (insert_block): Remove function. * d-irstate.cc (IRBase::startBindings): Inline set_block here. (IRBase::endBindings): Inline insert_block here. 2013-08-29 Iain Buclaw * d-spec.c (lang_specific_spec_functions): Remove. 2013-08-28 Iain Buclaw * d-codegen.cc (IRState::doArraySet): Rename to IRBase::doArraySet. (IRState::arraySetExpr): Remove function. (IRState::expandDecl): Rename to expand_decl. (IRState::typeinfoReference): Rename to build_typeinfo. (IRState::buildChain): Merge into FuncDeclaration::buildClosure. (IRState::getVThis): Rename to build_vthis. (IRState::maybeExpandSpecialCall): Rename to maybe_expand_builtin. (IRState::toDArray): Rename to d_array_convert. 2013-08-26 Iain Buclaw * d-codegen.cc (convert_expr): Check that the class type the codegen is casting from is a base class of the class type the codegen is casting to, not the other way round. 2013-08-14 Iain Buclaw * d-elem.cc (ArrayLiteralExp::toElem): Return null for zero length array literals. 2013-08-07 Iain Buclaw * d-objfile.cc (finish_thunk): Don't emit thunks to external symbols as weakref declarations. * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic yl2x and yl2xp1 builtins. (maybe_set_builtin_frontend): Likewise. 2013-07-09 Iain Buclaw * d-builtins.c (d_gcc_magic_builtins_module): Set builtins solely provided by the compiler as @safe, pure and nothrow. * d-codegen.cc (IRState::getVThis): Don't set outer 'this' of structs to be parent function chain if no frame has been created. 2013-07-08 Iain Buclaw * d-elem.cc (Expression::toElemDtor): Wrap temp variables destructor calls in a try/finally expression. 2013-07-05 Johannes Pfau * patch-versym-os-4.8.x: Set versions on powerpc and alpha. Remove SysV4 support and therefore fix macro redefinition warnings. * patch-versym-os-4.9.x: Likewise. 2013-07-03 Iain Buclaw * d-longdouble.cc (longdouble::set): Intepret set values at higher precision for min/max properties. * d-codegen.cc (maybe_set_builtin_frontend): Add yl2x and yl2xp1 math intrinsics. (IRState::maybeExpandSpecialCall): Likewise. 2013-07-02 Iain Buclaw * d-objfile.cc (Module::genobjfile): Don't free current_module_info. * d-codegen.cc (IRState::buildAssignOp): Don't create a SAVE_EXPR around comma expressions used as lvalues. * d-todt.cc (TypeSArray::toDtElem): Get underlying vector basetype when layouting out data in a static array. 2013-06-29 Iain Buclaw * complex_t.h: Move into dfrontend. * d-builtins.c (gcc_cst_to_d_expr): Explicitly create longdouble. * d-longdouble.cc (longdouble::parse): Remove function. (longdouble::longdouble): Remove constructors from longdouble. Replaced with operator= template and longdouble::set. (longdouble::rv): Update for new class layout. (longdouble::from_shwi): New function to create a longdouble value from a HOST_WIDE_INT. (longdouble::from_uhwi): Likewise, but from an unsigned HOST_WIDE_INT. (longdouble::to_shwi): New function to return a HOST_WIDE_INT value from a longdouble. (longdouble::to_uhwi): Likewise, but from an unsigedn HOST_WIDE_INT. (longdouble::set): New function to explicitly set longdouble value. (longdouble::toInt): Remove function. (longdouble::isZero): Remove function. (longdouble::isNegative): Remove function. * d-port.cc (Port::nan): Rename to Port::ldbl_nan. (Port::infinity): Rename to Port::ldbl_infinity. (Port::ldbl_max): New static field. (Port::init): Set ldbl_max to be maximimum value for long double type. (Port::strtof): New function to convert string to longdouble. (Port::strtod): Likewise. (Port::strtold): Likewise. 2013-06-24 Iain Buclaw * d-objfile.cc (make_alias_for_thunk): Do not set TREE_SYMBOL_REFERENCED. 2013-06-17 Iain Buclaw * d-codegen.cc (build_struct_memcmp): New function. * d-elem.cc (IdentityExp::toElem): Use build_struct_memcmp for field comparisons of small structs. 2013-06-13 Iain Buclaw * d-codegen.cc (make_temp): New function. * d-decls.cc (StructLiteralExp::toSymbol): Implement correctly to generate an anonymous symbol to reference to in the codegen. (ClassReferenceExp::toSymbol): Likewise, but also use an anonymous type as size is not determined until the data has been layed out. * d-elem.cc (EqualExp::toElem): Optimise comparisons of arrays of basic types, also ensure left-to-right evaluation. (SliceExp::toElem): Handle returing slice as a static array type. (AddrExp::toElem): Handle taking the address of StructLiteralExp and ClassReferenceExp symbols. (FuncExp::toElem): Relax type checking to allow returning function addresses as generic pointer types. (ArrayLiteralExp::toElem): Implicitly convert static arrays of void to static arrays of ubyte. (StructLiteralExp::toElem): Remove code generation of postblit calls, now taken care of in the front end. * d-objfile.cc (Module::genmoduleinfo): Emit module name as a null terminated static array. * d-ctype.cc (TypeAArray::toCtype): Pass AA types around like pointers. 2013-06-11 Iain Buclaw * dfrontend: Update to D front-end version 2.063. * d-builtins.c (gcc_type_to_d_type): Use Loc for unknown locations. (d_gcc_magic_builtins_module): Likewise. (gcc_cst_to_d_expr): Likewise. * d-codegen.cc (get_libcall): Use FuncDeclaration::genCfunc to build D runtime library functions. * d-decl.cc (SymbolDeclaration::SymbolDeclaration): Remove function. (StructLiteralExp::toSymbol): New function. (ClassReferenceExp::toSymbol): New function. * d-elem.cc (AssertExp::toElem): Call struct/class invariants only if compiler is generating invariant code. (TupleExp::toElem): Update for new front-end. (ClassReferenceExp::toElem): New function. * d-lang.cc (d_init_options): Set compiler.vendor front-end parameter. (d_init): Call Expression::init. * d-objfile.cc (InterfaceDeclaration::toObjFile): Correctly set the xgetRTInfo field in the record layout. * d-todt.cc (CastExp::toDt): New function. (AddrExp::toDt): New function. (ClassReferenceExp::toDt): New function. (ClassReferenceExp::toDtI): New function. (ClassReferenceExp::toInstanceDt): New function. (ClassReferenceExp::toDt2): New function. 2013-06-10 Iain Buclaw * d-objfile.cc (FuncDeclaration::toObjFile): Set 'this' parameter as implicitly read-only. * d-codegen.cc (declaration_type): Set 'this' declaration type as implicitly const. (build_frame_type): Set frame or closure type as implicitly const. 2013-06-09 Iain Buclaw * d-builtins.c (d_init_builtins): Make d_unknown_type_node a RECORD_TYPE. * d-lang.cc (d_build_eh_type_type): Cast the returned typeinfo decl to void pointer type. 2013-06-07 Iain Buclaw * d-codegen.cc (IRState::var): Rename to get_decl_tree. (IRState::convertForArgument): Rename to convert_for_argument. (IRState::floatMod): Rename to build_float_modulus. (IRState::findThis): Rename to find_this_tree. (IRState::emitLocalVar): Update signature. (IRState::arrayElemRef): Remove function. * d-elem.cc (IndexExp::toElem): Move implementation of IRState::arrayElemRef here. 2013-06-04 Iain Buclaw * d-codegen.cc (cmodule): Rename to current_module_decl. (object_file): Remove variable. * d-objfile.cc (ObjectFile::moduleInfo): Rename to current_module_info. (ObjectFile::modules): Rename to output_modules. (ObjectFile::staticCtorList): Rename to static_ctor_list. (ObjectFile::staticDtorList): Rename to static_dtor_list. (ObjectFile::emitTemplates): Rename to flag_emit_templates. (ObjectFile::beginModule): Remove function. (ObjectFile::endModule): Remove function. (ObjectFile::finish): Rename to d_finish_module. (ObjectFile::doLineNote): Remove function. (ObjectFile::setLoc): Rename to set_input_location. (ObjectFile::setDeclLoc): Rename to set_decl_location. (ObjectFile::setCfunEndLoc): Rename to set_function_end_locus. (ObjectFile::giveDeclUniqueName): Rename to get_unique_name. (ObjectFile::setupSymbolStorage): Rename to setup_symbol_storage. (ObjectFile::setupStaticStorage): Remove function. (ObjectFile::makeDeclOneOnly): Rename to d_comdat_linkage. (ObjectFile::outputStaticSymbol): Rename to d_finish_symbol. (ObjectFile::outputFunction): Rename to d_finish_function. (ObjectFile::addAggMethod): Remove function. (ObjectFile::initTypeDecl): Rename to build_type_decl. (ObjectFile::declareType): Remove function. (ObjectFile::shouldEmit): Rename to output_declaration_p. (ObjectFile::shouldEmit): Rename variant to output_symbol_p. (ObjectFile::doThunk): Rename to use_thunk. (ObjectFile::stripVarDecl): Remove function. (ObjectFile::doSimpleFunction): Rename to build_simple_function. (ObjectFile::doFunctionToCallFunctions): Rename to build_call_function. (ObjectFile::doCtorFunction): Rename to build_ctor_function. (ObjectFile::doDtorFunction): Rename to build_dtor_function. (ObjectFile::doUnittestFunction): Rename to build_unittest_function. (ObjectFile::hasModule): Rename to output_module_p. (ObjectFile::outputThunk): Rename to finish_thunk. (write_deferred_thunks): New function to emit deferred thunks. 2013-06-03 Iain Buclaw * d-decls.cc (VarDeclaration::toSymbol): Don't set default tls model. * d-objfile.cc (ObjectFile::setupSymbolStorage): Set default tls model for var decls before determining whether symbol is public. (build_tlssections): Likewise for TLS symbols. 2013-06-01 Johannes Pfau * d-codegen.cc (maybe_set_builtin_frontend): Check parameter and return types of intrinsics. 2013-06-01 Iain Buclaw * d-codegen.cc (IRState::var): Handle variables used for NRVO. * d-ir.cc (ReturnStatement::toIR): Return result decl directly if NRVO. * d-objfile.cc (Symbol::SnamedResult): New member to hold the named RESULT_DECL of the function. (FuncDeclaration::toObjFile): Set-up function for NRVO. (build_tlssections): Align _tlsstart and _tlsend symbols to target address size. * d-ctype.cc (TypeFunction::toSymbol): Mark functions returning non-POD structs as TREE_ADDRESSABLE to force return in memory. * d-decls.cc (FuncDeclaration::toSymbol): Propagate TREE_ADDRESSABLE from the original function type. 2013-05-29 Iain Buclaw * d-target.cc: New source file to handle Target structure. * d-builtins.c (d_bi_init): Remove function. (d_gcc_type_align): Move to Target::alignsize. (d_gcc_field_align): Move to Target::fieldalign. (d_init_builtins): Build va_list type for D frontend. * d-lang.cc (d_init): Use isLP64 to determine LP64 targets. (d_add_builtin_version): Set is64bit if target is X86_64. * d-codegen.cc (convert_for_assignment): Use memset to implement front end code (struct = 0) here, rather than build an empty constructor. * d-elem.cc (AssignExp::toElem): Remove handling of (struct = 0) and call convert_for_assignment. 2013-05-28 Iain Buclaw * d-gcc-complex_t.h: Rename to complex_t.h. * d-gcc-real.cc: Rename to d-longdouble.cc. * d-gcc-real.h: Rename to longdouble.h * d-port.cc: New source file to handle Port structure. * gdc_alloca.h: Remove source. * d-longdouble.cc (real_t): Rename to longdouble. (longdouble::getnan): Move to Port::nan. (longdouble::getsnan): Move to Port::snan. (longdouble::getinfinity): Move to Port::infinity. (longdouble::isInf): Move to Port::isInfinite. (longdouble::isNan): Move to Port::isNan. (longdouble::isSignallingNan): Move to Port::isSignallingNan. * d-builtins.c (gcc_d_backend_init): Rename to d_backend_init. (gcc_d_backend_term): Rename to d_backend_term. (gcc_type_to_d_type): Don't map 128bit integers to D front end. * d-elem.cc (AssignExp::toElem): Remove handling of fillHoles, use memset to implement (struct = 0). (StructLiteralExp::toElem): Handle fillHoles here, creating a temporary var that is zero init'd with memset and returned. 2013-05-27 Iain Buclaw * d-codegen.cc (IRState::localVar): Rename to build_local_var. (IRState::exprVar): Rename to create_temporary_var. (IRState::maybeExprvar): Rename to maybe_temporary_var. (IRState::pointerIntSum): Rename to build_array_index. * d-lang.cc (d_handle_target_attribute): New function to handle D target attributes. 2013-05-26 Iain Buclaw * d-incpath.cc (prefixed_path): Add cpp_GCC_INCLUDE_DIR back in as second method for relocation. * d-elem.cc (IndexExp::toElem): Fix call to _aaGetX as from IRState::toElemLvalue. * d-codegen.cc (IRState::toElemLvalue): Remove function. (IRState::convertForAssignment): Rename to convert_for_assignment. (IRState::convertForCondition): Rename to convert_for_condition. (IRState::checkedIndex): Rename to d_checked_index. (IRState::boundsCond): Rename to d_bounds_condition. (IRState::arrayBoundsCheck): Rename to array_bounds_check. (IRState::assertCall): Rename to d_assert_call. (IRState::doLineNote): Move to irstate.h. * d-irstate.cc (IRBase::getLocalContext): Remove function. * d-decls.cc (VarDeclaration::toSymbol): Build decl lang specific for decl to point back to D front end type. (FuncDeclaration::toSymbol): Likewise. 2013-05-23 Iain Buclaw * d-codegen.cc (AggLayout::finish): Unset TYPE_SIZE before re-calculating. * d-ctype.cc (TypeStruct::toCtype): Don't call decl_attribute on the type twice. 2013-05-21 Iain Buclaw * d-lang.cc (d_gcc_dump_source): Remove function. (d_post_options): Set flag_excess_precision_cmd as standard. * d-gcc-real.cc (real_t::convert): Remove function. (real_t::floatCompare): Remove function. (real_t::operator): Always perform floating point compilation at the precision of the target real mode. * d-todt.cc (dt_last): Remove function. (dtlist_to_tree): Rename to dtvector_to_tree. (dt_cons): Replace TREE_CHAIN implementation for use of CONSTRUCTOR. (dt_chainon): Likewise. (dt_container): Likewise. (dt_container2): Likewise. (StructInitializer::toDt): Likewise. (StructLiteralExp::toDt): Likewise. 2013-05-17 Iain Buclaw * d-codegen.cc (IRState::convertTo): Replace with d_convert and convert_expr. (IRState::declContext): Replace with d_decl_context. (IRState::functionNeedsChain): Replace with needs_static_chain. (IRState::label): Replace with d_build_label. (IRState::emitTemplates): Move to ObjectFile. (functionDegenerateClosure): Replace with is_degenerate_closure. (get_object_method): Assert that function is a method. (IRState::startCond): Move to IRBase. (IRState::startElse): Likewise. (IRState::endCond): Likewise. (IRState::startLoop): Likewise. (IRState::continueHere): Likewise. (IRState::setContinueLabel): Likewise. (IRState::exitIfFalse): Likewise. (IRState::endLoop): Likewise. (IRState::startCase): Likewise. (IRState::doCase): Likewise. (IRState::endCase): Likewise. (IRState::continueLoop): Likewise. (IRState::exitLoop): Likewise. (IRState::startTry): Likewise. (IRState::startCatches): Likewise. (IRState::startCatch): Likewise. (IRState::endCatch): Likewise. (IRState::endCatches): Likewise. (IRState::startFinally): Likewise. (IRState::endFinally): Likewise. (IRState::doReturn): Likewise. (IRState::doJump): Likewise. (IRState::pushLabel): Likewise. (IRState::checkSwitchCase): Likewise. (IRState::checkGoto): Likewise. (IRState::checkPreviousGoto): Likewise. * d-elem.cc (CatAssignExp::toElem): Call postblit on appending array of structs if required. 2013-05-16 Johannes Pfau * d-incpath.cc (prefixed_path): use cpp_PREFIX instead of cpp_GCC_INCLUDE_DIR for relocation. 2013-05-16 Iain Buclaw * d-codegen.cc (IRState::convertForAssignment): Remove use of CtorEltMaker wrapper for vec. (d_array_value): Likewise. (build_delegate_cst): Likewise. (extract_from_method_call): Likewise. * d-elem.cc (NewExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (AssocArrayLiteralExp::toElem): Likewise. (StructLiteralExp::toElem): Likewise. (NullExp::toElem): Likewise. (VectorExp::toElem): Likewise. * d-objfile.cc (build_moduleinfo): Likewise. * d-todt.cc (dt_container): Likewise. (dt_container2): Likewise. * d-asmstmt.cc (ExtAsmStatement::toIR): Remove use of ListMaker wrapper for tree chaining. * d-builtins.c (d_bi_builtin_func): Likewise. (d_bi_builtin_type): Likewise. (d_gcc_magic_builtins_module): Likewise. (d_gcc_magic_libbuiltins_module): Likewise. * d-codegen.cc (build_attributes): Likewise. (IRState::call): Likewise. (IRState::buildFrameForFunction): Likewise. (AggLayout::doFields): Likewise. (AggLayout::addField): Likewise. * d-ctype.cc (TypeEnum::toCtype): Likewise. (TypeFunction::toCtype): Likewise. * d-todt.cc (dt_container2): Likewise. * d-codegen.cc (IRState::getFrameInfo): Replace with get_frameinfo. (IRState::buildFrameForFunction): Replace with build_frame_type. (IRState::isClassNestedInFunction): Replace with d_nested_class. (IRState::isStructNestedInFunction): Replace with d_nested_struct. (IRState::getFrameForFunction): Fold into IRState::getFrameForSymbol. (IRState::getFrameForNestedClass): Likewise. (IRState::getFrameForNestedStruct): Likewise. 2013-05-15 Iain Buclaw * d-codegen.cc (IRState::buildFrameForFunction): Also copy the parameters of functions with 'in' contracts to a local frame decl. * d-lang.cc (d_handle_flatten_attribute): New function to handle D flatten attributes. 2013-05-14 Iain Buclaw * d-codegen.cc (IRState::chainLink): Remove function. (IRState::chainFunc): Remove function. (IRState::sthis): New member which holds the chain of function. (IRState::buildChain): Update to use new static chain decl. (IRState::getFrameInfo): Likewise. * d-objfile.cc (FuncDeclaration::buildClosure): Likewise. (FuncDeclaration::toObjFile): Default the function static chain decl to null unless vthis is given for the function. 2013-05-13 Iain Buclaw * d-lang.cc (d_handle_noinline_attribute): New function to handle D noinline attributes. (d_handle_forceinline_attribute): New function to handle D forceinline attributes. * d-elem.cc (StructLiteralExp::toElem): Return the struct initialiser symbol directly if the tree has already been built. * d-decls.cc (Dsymbol::toSymbolX): Constify the mangling name to use. 2013-05-10 Iain Buclaw * d-typinf.cc: New file containing type info routines originally in the D Front End. * d-todt.cc (dt_last): New helper function to retrieve last node in a dt_t tree list. (dt_cons): New helper function to append nodes to the end of a list. (dt_chainon): New helper function to concatenate two lists together. (dt_container): New helper function to build a ctor from a list. (build_vptr_monitor): New helper function to generate the class vtable, and put out __vptr and __monitor. symbol default values in a class declaration. (dtlist_to_tree): New helper function to convert a dt_t list into a constructor tree. (Type::toDt): Implement routines for new dt_t format. (TypeInfoDeclaration::toDt): Likewise. (Initializer::toDt): Likewise. (Expression::toDt): Likewise. (Declaration::toDt): Likewise. * d-objfile.cc (Dsymbol::toObjFile): Update for new dt_t format. (Module::genmoduleinfo): Likewise. (Symbol::Symbol): Moved from symbol.cc (Obj::objmod): Remove abstraction layer. (Obj::moduleinfo): Renamed to build_moduleinfo. (obj_tlssections): Renamed to build_tlssections. (outdata): Renamed to d_finish_symbol. (check_static_sym): Moved into d_finish_symbol. * d-codegen.cc (d_gcc_emit_local_variable): Remove. * d-decls.cc (Dsymbol::toSymbolX): Update to not call symbol_calloc. (FuncDeclaration::toThunkSymbol): Likewise. (ClassDeclaration::toSymbol): Build type as d_unknown_type_node. (InterfaceDeclaration::toSymbol): Likewise. (Module::toSymbol): Likewise. (ClassDeclaration::toVtblSymbol): Update call to toSymbolX. (AggregateDeclaration::toInitializer): Likewise. (TypedefDeclaration::toInitializer): Likewise. (EnumDeclaration::toInitializer): Likewise. * d-ir.cc (CaseStatement::toIR): Don't call static_sym. * d-lang.cc (rtlsym): Remove symbol. (D_DECL_READONLY_STATIC): Remove macro. (d_unknown_type_node): New LANG_TYPE node for marking TypeInfo_Class, Interface, and ModuleInfo types that are of a variable size determined at compile time. * d-elem.cc (StringExp::toElem): Clean up for new dt_t format. * symbol.cc: Remove file. 2013-05-08 Iain Buclaw * d-codegen.cc (IRState::getFrameInfo): Don't create a frame/closure for member functions, only required for nested. * d-elem.cc (Expression::toElemDtor): Call dtors in the correct order. (DeclarationExp::toElem): Don't call dtor on static, manifest, or extern symbols upon declaration. (AssignExp::toElem): Only call postblit on lvalues in assignment. (ArrayLiteralExp::toElem): Always generate literals on heap. 2013-05-06 Iain Buclaw * d-elem.cc (StructLiteralExp::toElem): Return the default initialiser symbol if one exists. * d-builtins.c (d_gcc_magic_libbuiltins_check): Override the function type with the correct built-in function type as defined in backend. 2013-04-15 Iain Buclaw * d-elem.cc (IdentityExp::toElem): Remove special handling of class, reference and array types. 2013-04-12 Iain Buclaw * d-codegen.cc (maybe_make_temp): Save call expressions so aren't evaluated more than once. (d_has_side_effects): Remove check for exceptional class types. 2013-04-10 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Harden logic for marking functions pure as in 'has no side effects'. 2013-04-07 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Push deferred functions to FuncDeclaration::deferred. * d-elem.cc (DelegateExp::toElem): Likewise. (FuncExp::toElem): Likewise. * d-objfile.cc (ObjectFile::shouldEmit): Likewise. (FuncDeclaration::toObjFile): Process all deferred functions in FuncDeclaration::deferred. * symbol.cc (Symbol::deferredNestedFuncs): Remove. 2013-04-05 Iain Buclaw * d-elem.cc (FuncExp::toElem): Defer function literals and lambdas until parent function has finished processing. 2013-04-04 Iain Buclaw * d-codegen.cc (IRState::buildChain): Use __frame decl directly when setting up the function frame. (maybe_set_builtin_frontend): Exit early if symbol has no parent. * d-decls.cc (FuncDeclaration::toSymbol): Defer all nested functions, not just templated instances. * d-objfile.cc (FuncDeclaration::toObjFile): Delay processed deferred nested functions until function has finished being generated. (ObjectFile::shouldEmit): Don't emit nested functions if the parent function hasn't finished processing. 2013-04-03 Iain Buclaw * d-codegen.cc (maybe_set_builtin_frontend): Merged from maybe_set_builtin and maybe_set_libcall. * d-decls.cc (FuncDeclaration::toSymbol): Use maybe_set_builtin_frontend. 2013-03-31 Iain Buclaw * d-lang.cc (d_init_options): Default module info emission to on. (d_handle_option): New femit-moduleinfo switch. * d-objfile.cc (Module::genobjfile): Don't emit module if disabled explicitly. * d-builtins.cc (is_intrinsic_module_p): New function to test whether module is core.bitops. (is_math_module_p): New function to test whether module is std.math or core.stdc.math. (is_builtin_va_arg_p): New function to test whether symbol is specially handled va_arg template. (is_builtin_va_start_p): New function to test whether symbol is specially handled va_start template. * d-codegen.cc (IRState::binding): Replace with bind_expr. (IRState::mathModule): Replace with std_math_module. (IRState::mathCoreModule): Replace with core_math_module. (IRState::intrinsicModule): Replace with std_intrinsic_module. (IRState::cstdargTemplateDecl): Replace with va_arg_template. (IRState::stdargTemplateDecl): Replace with va_arg2_template. (IRState::cstdargStartTemplateDecl): Replace with va_start_template. (IRState::getLibCallDecl): Replace with get_libcall. (IRState::maybeSetLibCallDecl): Replace with maybe_set_libcall. (IRState::libCall): Replace with build_libcall. (IRState::maybeSetUpBuiltin): Replace with maybe_set_builtin. (IRState::Intrinsic): Move enum out of IRState. 2013-03-30 Iain Buclaw * d-codegen.cc (IRState::darrayPtrRef): Replace with d_array_ptr. (IRState::darrayLenRef): Replace with d_array_length. (IRState::darrayVal): Replace with d_array_value. (IRState::darrayString): Replace with d_array_string. (IRState::arrayLength): Replace with get_array_length. (get_object_method): Remove dependancy on irs parameter. * d-lang.cc (d_init): Use static bool std_inc to determine whether to include standard module paths. (d_post_options): Canonicalize the input filename. (d_parse_file): Correctly catch cases where input file is stdin. 2013-03-27 Iain Buclaw * d-codegen.cc (IRState::getFrameInfo) Create a custom static chain for all nested functions. * d-gcc-includes.h: Rename to d-system.h 2013-03-23 Iain Buclaw * d-builtins.c (d_bi_init): Set REALPAD to be TYPE_PRECISION of long_double_type_node. * d-codegen.cc (IRState::twoFieldType): Replace with build_two_field_type. (IRState::arrayOpNotImplemented): Replace with unhandled_arrayop_p. (IRState::delegateMethodRef): Replace with delegate_method. (IRState::delegateObjectRef): Replace with delegate_object. (IRState::delegateVal): Replace with build_delegate_cst. (IRState::methodCallExpr): Replace with build_method_call. (IRState::extractMethodCallExpr): Replace with extract_from_method_call. (IRState::objectInstanceMethod): Replace with get_object_method. (IRState::twoFieldCtor): Remove. (IRState::call): Assert that if calling a normal FUNCTION_TYPE, 'object' is not set. * d-ctype.cc (TypeDelegate::toCtype): Build a METHOD_TYPE for the .func field type in delegates. * d-lang.h (D_IS_METHOD_CALL_EXPR): Rename to D_METHOD_CALL_EXPR. * d-objfile.cc (FuncDeclaration::toObjFile): Remove assert for chain function. 2013-03-20 Johannes Pfau * d-codegen.cc (IRState::objectInstanceMethod): Recursively check for TOKsuper / TOKdottype. Do not ignore CastExp. * d-elem.cc (IdentityExp::toElem): Ignore padding in bitwise floating point comparisons. * testsuite: Cleanup. Remove invalid tests, adjust tests, etc. 2013-03-20 Iain Buclaw * d-codegen.cc (IRState::objectInstanceMethod): Get function pointer off function TREE_TYPE. (build_deref): Handle cases where expression to dereference is an address expression. (modify_expr): New function overload to set return type directly. * d-elem.cc (CatAssignExp::toElem): Use new modify_expr. (AssignExp::toElem): Likewise. * d-decls.cc (FuncDeclaration::toSymbol): Don't build a method type for nested functions / delegates. Just add on the hidden 'this' pointer containing the custom static chain/closure object. * d-codegen.cc (GlobalValues): Replace with current_module, current_irs, object_file. (IRState::getFuncType): Replace with get_function_type. (IRState::isCallByAlias): Replace with call_by_alias_p. (IRState::isFuncType): Replace with function_type_p. (IRState::doExp): Remove. * d-asmstmt.cc (ExtAsmStatement::syntaxCopy): Use arraySyntaxCopy to copy front end expressions. * d-codegen.cc (AssignExp::toElem): Call _d_arrayassign / _d_arrayctor when assigning arrays of structs. 2013-03-18 Iain Buclaw * d-codegen.cc (IRState::realPart): Replace with real_part. (IRState::imagPart): Replace with imaginary_part. (IRState::integerConstant): Replace with build_integer_cst. (IRState::floatConstant): Replace with build_float_cst. (IRState::hwi2toli): Replace with cst_to_hwi. (IRState::addressOf): Replace with build_address. (IRState::markAddressable): Replace with d_mark_addressable. (IRState::markUsed): Replace with d_mark_used. (IRState::markRead): Replace with d_mark_read. (IRState::indirect): Replace with indirect_ref. (IRState::pvoidOkay): Replace with void_okay_p. (IRState::maybeCompound): Replace with maybe_compound_expr. (IRState::maybeVoidCompound): Replace with maybe_vcompound_expr. (IRState::isErrorMark): Replace with error_mark_p. (IRState::getTargetSizeConst): Replace with tree_to_hwi. (IRState::modify): Replace with modify_expr. (IRState::vmodify): Replace with vmodify_expr. (IRState::vinit): Replace with build_vinit. (IRState::nop): Replace with build_nop. (IRState::vconvert): Replace with build_vconvert. (IRState::boolOp): Replace with build_boolop. (IRState::compound): Replace with compound_expr. (IRState::voidCompound): Replace with vcompound_expr. (IRState::component): Replace with component_ref. (IRState::errorMark): Replace with error_mark. (IRState::typesSame): Replace with d_types_same. (IRState::typesCompatible): Replace with d_types_compatible. (IRState::getDType): Replace with build_dtype. (IRState::getObjectType): Replace with build_object_type. (IRState::isDeclarationReferenceType): Replace with decl_reference_p. (IRState::trueDeclarationType): Replace with declaration_type. (IRState::isArgumentReferenceType): Replace with arg_reference_p. (IRState::trueArgumentType): Replace with type_passed_as. (IRState::arrayType): Replace with d_array_type. (IRState::addTypeAttribute): Replace with insert_type_attributes. (IRState::addDeclAttribute): Replace with insert_decl_attributes. (IRState::attributes): Replace with build_attributes. (IRState::addTypeModifiers): Replace with insert_type_modifiers. (IRState::maybeMakeTemp): Replace with maybe_make_temp. (IRState::isFreeOfSideEffects): Replace with d_has_side_effects. (IRState::pointerOffsetOp): Replace with build_offset_op. (IRState::pointerOffset): Replace with build_offset. (IRState::buildCall): Replace with d_build_call. (IRState::exceptionObject): Replace with build_exception_object. 2013-03-17 Iain Buclaw * d-asmstmt.cc (d_build_asm_stmt): Remove. (ExtAsmStatement::ExtAsmStatement): Update to match renamed members. (ExtAsmStatement::syntaxCopy): Likewise. (ExtAsmStatement::semantic): Likewise. (ExtAsmStatement::toCBuffer): Likewise. (ExtAsmStatement::comeFrom): New. (ExtAsmStatement::blockExit): Don't error if must not throw. (naturalString): Remove. (ExtAsmStatement::toIR): Inline IRState::doAsm implementation. * d-codegen.cc (IRState::doAsm): Remove. * d-decls.cc (FuncDeclaration::toSymbol): Don't generate 'naked' attribute. (binfo_for): Move into d-decls.cc. (intfc_binfo_for): Likewise. (ClassDeclaration::toDebug): Likewise. (EnumDeclaration::toDebug): Likewise. (TypedefDeclaration::toDebug): Likewise. (StructDeclaration::toDebug): Likewise. * d-objfile.cc (FuncDeclaration::toObjFile): Move into d-objfile.cc. (FuncDeclaration::buildClosure): Likewise. (Module::genobjfile): Likewise. * d-glue.cc: Remove file. 2013-03-16 Iain Buclaw * d-ir.cc (SynchronizedStatement::toIR): Remove implementation as is now handled by the frontend. 2013-03-15 Iain Buclaw * d-codegen.cc (IRState::maybeExpandSpecialCall): Handle ref argptr arguments. 2013-03-13 Iain Buclaw * d-builtins.c (handle_alias_attribute): New function to handle internal 'alias' attribute. (handle_weakref_attribute): New function to handle internal 'weakref' attribute. * d-objfile.cc (ObjectFile::outputThunk): Define thunks to external symbols as weakref, alias 2013-03-12 Johannes Pfau * patch-versym-os-4.8.x (mingw32.h): Fix typo * patch-versym-cpu-4.8.x (mips.h): Fix typo Update version symbols to latest dlang specification. 2013-03-10 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Delay setting TREE_TYPE as function type could be hidden in a nested function not yet built. * d-codegen.cc (IRState::findThis): Don't get 'this' from outer function if it's a closure type. This has already been handled by IRState::getFrameForSymbol. (IRState::buildChain): Give frame decl debug name '__frame'. Always set '__chain' link field. (IRState::getFrameInfo): Don't build a frame for all nested functions. Search through nested aggregates for static chain in outer functions. * d-codegen.h (IRState::useParentChain): Remove. * d-glue.cc (FuncDeclaration::toObjFile): Don't call useParentChain. Don't create a local var for the chain link for a function. (FuncDeclaration::buildClosure): Always set '__chain' link field. 2013-03-08 Iain Buclaw * d-codegen.cc (d_gcc_force_templates): Only check for emitting templates as private. * d-lang.cc (d_handle_option): Remove -femit-templates= option. * d-objfile.cc (ObjectFile::makeDeclOneOnly): Fix code logic so fallback method could be reached. * d-objfile.h (TEall, TEauto): Remove. 2013-03-07 Iain Buclaw * d-ir.cc (ReturnStatement::toIR): Don't call postblit on return. * d-codegen.cc (IRState::trueDeclarationType): Don't set D_TYPE_ADDRESSABLE. (IRState::makeTemp): Remove. (IRState::maybeMakeTemp): Copy makeTemp into function. * d-glue.cc (d_genericize): Remove D_TYPE_ADDRESSABLE handling. * d-lang.h (D_TYPE_ADDRESSABLE): Remove macro. 2013-03-04 Johannes Pfau * d-ctype.cc (Type::toCtype): Always call gen.addTypeModifiers to make sure TYPE_MAIN_VARIANT is set. Reuse tree from unqualified variant for that. Also cache the resulting qualified tree. (TypeTypedef::toCtype): Likewise. (TypeEnum::toCtype): Likewise. (TypeStruct::toCtype): Likewise. (TypeFunction::toCtype): Likewise. (TypeVector::toCtype): Likewise. (TypeSArray::toCtype): Likewise. (TypeDArray::toCtype): Likewise. (TypeAArray::toCtype): Likewise. (TypeDelegate::toCtype): Likewise. (TypeClass::toCtype): Likewise. * d-objfile.cc (ObjectFile::giveDeclUniqueName): Make sure DECL_NAME is set 2013-03-01 Iain Buclaw * d-decls.cc (VarDeclaration::toSymbol): Remove use of c_ident. (FuncDeclaration::toSymbol): Likewise. * d-builtins.c (handle_noreturn_attribute): Assert that this is only used for internal purposes. (handle_const_attribute): Likewise. (handle_malloc_attribute): Likewise. (handle_pure_attribute): Likewise. (handle_nonnull_attribute): Likewise. (handle_nothrow_attribute): Likewise. (handle_sentinel_attribute): Likewise. (handle_transaction_pure_attribute): Likewise. (handle_returns_twice_attribute): Likewise. * d-glue.cc (FuncDeclaration::toObjFile): Result variables have no default initialiser. * d-codegen.cc (IRState::emitLocalVar): Add in assert that the local variable has no initialiser if called with no_init = true. (IRState::getLibCallDecl): Mark exceptional library functions as noreturn. (IRState::attributes): Gracefully handle @attribute, and @attribute(null). 2013-02-28 Jernej Krempus * d-builtins.c (d_attribute_table): Renamed it to d_builtins_attribute_table. * d-lang.cc (d_attribute_table): Added an empty table * d-lang.cc (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Defined it as d_builtins_attribute_table. * d-lang.h (d_builtins_attribute_table): Added a declaration. * d-codegen.cc (IRState::attributes): Changed it so it goes through in_attrs and looks for any @gcc.attribute.attribute("attr_name"). * d-objfile.cc (ObjectFile::setupSymbolStorage): Pass userAttributes instead of attributes in all calls to IRState::attributes. * d-ctype.cc (TypeTypedef::toCtype): Likewise. (TypeEnum::toCtype): Likewise. (TypeStruct::toCtype): Likewise. (TypeClass::toCtype): Likewise. * libphobos/libdruntime/gcc/attribute.d: New file. 2013-02-28 Iain Buclaw * d-lang.cc (d_handle_option): Remove OPT_fdeprecated and OPT_Wsign_compare, add handling for OPT_Wdeprecated. (d_post_options): Handle Wdeprecated and Werror switch combination. 2013-02-27 Iain Buclaw * d-codegen.cc (ArrayScope::ArrayScope): Don't setup length var if its value is known at compile time. (ArrayScope::setArrayExp): Likewise. * d-decls.cc (uniqueName): Remove function. (VarDeclaration::toSymbol): Set decl assembler name directly. (FuncDeclaration::toSymbol): Likewise. 2013-02-15 Iain Buclaw * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro. 2013-02-14 Iain Buclaw * d-lang.h (D_DECL_IS_CONTRACT): Remove macro. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. 2013-02-13 Iain Buclaw * d-lang.cc (d_gcc_is_target_win32): Remove. (d_add_builtin_version): New function to handle define_builtin callback from backend. * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic bt. * d-builtins.c: Merge with d-builtins2.cc. * d-builtins2.cc: Remove. 2013-02-07 Johannes Pfau * d-lang.cc (d_init): Use gcc's config system for predefined OS versions. * setup-gcc.sh: Likewise. * target-ver-syms.sh: Likewise. 2013-02-05 Iain Buclaw * d-builtins2.cc (gcc_type_to_d_type): Remove STRUCTTHISREF condition. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. * d-elem.cc (ThisExp::toElem): Likewise. * d-ctype.cc (TypeSArray::toCtype): Remove SARRAYVALUE condition. * d-codegen.cc (IRState::isDeclarationReferenceType): Likewise. (IRState::isArgumentReferenceType): Likewise. 2013-02-01 Johannes Pfau * d-lang.cc (d_init): Use gcc's config system for predefined CPU versions. (d_init): Fix definition of D_LP64 version. * setup-gcc.sh: Likewise. * target-ver-syms.sh: Likewise. Copyright (C) 2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2014 ================================================ 2014-12-14 Iain Buclaw * Make-lang.in (check_gdc_parallelize): Update for testsuite changes. * d-convert.cc (d_convert_basic): Avoid stack overflow when converting from pointer to integer. * d-objfile.cc (FuncDeclaration::toObjFile): Emit correct frame information for closures rather than generic void pointers. 2014-11-10 Iain Buclaw * d-elem.cc (CatExp::toElem): Split dynamic arrays when passing as varargs to arraycatT and arraycatnT. 2014-11-09 Iain Buclaw * d-codegen.cc (build_vthis): Handle getting static chain for nested templated structs. 2014-09-07 Iain Buclaw * d-elem.cc (ArrayLiteralExp::toElem): Remove special handling for immutable arrays. 2014-08-03 Iain Buclaw * d-longdouble.cc (longdouble::formatHex): Convert buffer to uppercase for use in mangling templates. 2014-07-29 Iain Buclaw * d-elem.cc (NewExp::toElem): Check for opaque structs before continuing to generate the new expression. * d-lang.h.cc (d_vtbl_ptr_type_node): Renamed to vtbl_ptr_type_node. (d_boolean_type_node): Renamed to bool_type_node. (d_char_type_node): Renamed to char8_type_node. (d_wchar_type_node): Renamed to char16_type_node. (d_dchar_type_node): Renamed to char32_type_node. (d_ifloat_type_node): Renamed to ifloat_type_node. (d_idouble_type_node): Renamed to idouble_type_node. (d_ireal_type_node): Renamed to ireal_type_node. (byte_type_node, ubyte_type_node): New macros for fixed integral types in D. (short_type_node, ushort_type_node): Likewise. (int_type_node, uint_type_node): Likewise. (long_type_node, ulong_type_node): Likewise. (cent_type_node, ucent_type_node): Likewise. * d-builtins.c (d_init_builtins): Initialise all D specific type nodes. * d-codegen.cc (d_bounds_condition): Use D-specific type macros instead of backend C types. (layout_aggregate_type): Likewise. (build_integer_cst): Likewise. (build_boolop): Likewise. * d-convert.cc (d_build_truthvalue_op): Likewise. (d_truthvalue_conversion): Likewise. * d-ctype.cc (Type::toCtype): Likewise. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. * d-elem.cc (CmpExp::toElem): Likewise. (OrOrExp::toElem): Likewise. (NotExp::toElem): Likewise. * d-lang.cc (d_type_for_mode): Likewise. (d_type_for_size): Likewise. (d_signed_or_unsigned_type): Likewise. 2014-07-23 Iain Buclaw * d-ctype.cc (TypeFunction::toCtype): Only check for ref return for functions returning non-void. 2014-07-21 Iain Buclaw * d-objfile.cc (output_declaration_p): Don't emit any declarations from the gcc.attribute module. (StructDeclaration::toObjFile): Call output_declaration_p. * d-glue.cc (verror): Only call vasprintf on the initial format string. 2014-07-17 Iain Buclaw * d-lang.cc (d_init_options_struct): Set flag_wrapv as on by default. 2014-07-14 Iain Buclaw * d-elem.cc (NewExp::toElem): Don't initialise a new'd struct at the caller. The callee ensures this is done. 2014-07-13 Iain Buclaw * d-objfile.cc (d_finish_symbol): Always set TREE_STATIC for symbols being sent to the backend here. 2014-07-12 Iain Buclaw * d-objfile.cc (d_finish_symbol): Don't set DECL_INITIAL if the initialiser is all zeros. 2014-07-10 Iain Buclaw * d-builtins.cc (lookup_ctype_name): Remove function. (string_type_node): Move to static declaration from d_global_trees. (const_string_type_node): Likewise. (wint_type_node): Likewise. (intmax_type_node): Likewise. (uintmax_type_node): Likewise. (signed_size_type_node): Likewise. (d_init_builtins): Update. * d-lang.cc (d_type_for_mode): Return only fixed size types. (d_type_for_size): Likewise. (d_signed_or_unsigned_type): Likewise. (d_unsigned_type): Remove duplicated code from d_signed_or_unsigned_type. (d_signed_type): Likewise. 2014-07-03 Iain Buclaw * d-objfile.cc (finish_thunk): Use set_decl_section_name, copy the implicit section flag. (setup_symbol_storage): Use decl_default_tls_model. 2014-06-26 Iain Buclaw * d-codegen.h (d_types_compatible): Remove function. (d_types_same): Use more conservative approach to type equality. * d-codegen.cc (get_libcall): Allow backend to be able to optimise closure memory allocations. (convert_for_assignment): Use d_types_same. * d-elem.cc (CatExp::toElem): Likewise. (BinExp::toElemBin): Likewise. (CatAssignExp::toElem): Likewise. (StructLiteralExp::toElem): Likewise. 2014-06-14 Iain Buclaw * d-elem.cc (CondExp::toElem): Handle void type condition expressions. (AssignExp::toElem): Use ismemset to test for initialising arrays with a single value. (StructLiteralExp::toElem): Build static initialiser if a symbol was created by the front-end. * d-codegen.h (d_types_compatible): First check equality of types, then implicit compatibility. * d-convert.cc (d_default_conversion): Remove function, fold implementation into... (d_truthvalue_conversion): ... here. 2014-06-12 Iain Buclaw * d-convert.cc (d_scalar_conversion): Remove function. (d_build_truthvalue_op): Update. (d_truthvalue_conversion): Update. * d-codegen.cc (get_frame_for_symbol): Remove glue-specific error messages and refactor. (build_vthis): Likewise. (get_framedecl): Likewise. * d-elem.cc (AssignExp::toElem): Update call to build_vthis. (NewExp::toElem): Likewise. (StructLiteralExp::toElem): Likewise. * d-objfile.cc (Dsymbol::toObjFile): Fix build warning. * d-codegen.cc (d_decl_context): Always return parent context for functions nested in functions. (is_degenerate_closure): Remove function. (needs_static_chain): Remove function. * d-decls.cc (FuncDeclaration::toSymbol): Remove workaround for cgraph nesting structure, saving the original context decl. * d-lang.h (D_DECL_STATIC_CHAIN): Remove macro. * d-objfile.cc (Symbol::Symbol): Remove ScontextDecl field. (FuncDeclaration::toObjFile): Remove workaround for cgraph nesting structure, restoring the original context decl. Delay building the cgraph node until... (d_finish_function): ... here, where the function is unnested. 2014-06-11 Iain Buclaw * d-objfile.cc (d_finish_function): Update the callgraph to reflect unnesting of the function, as unravelling has already been handled by the frontend. Do not delay calling cgraph_finalize_function. 2014-06-09 Iain Buclaw * d-objfile.cc (d_comdat_group): Return a decl. * d-decl.cc (FuncDeclaration::toThunkSymbol): Don't set comdat group. * d-elem.cc (EqualExp::toElem): Always store temporaries when comparing two dynamic arrays. 2014-06-08 Iain Buclaw * d-decls.cc (TypeInfoDeclaration::toSymbol): Add assert that Error types never reach the backend. * d-typinf.cc (Type::getTypeInfo): Likewise. 2014-06-08 Iain Buclaw * dfrontend: Update to D front-end version 2.065. * d-codegen.cc (d_build_call): Evaluate side effects of the object parameter for method or delegate calls before passing. (libcall_ids): Rename _d_array_bounds to _d_arraybounds. (get_libcall): Update parameter types for _d_arraycopy. (finish_aggregate_type): Update for frontend UDA changes. * d-ctype.cc (TypeTypedef::toCtype): Update for frontend UDA changes. (TypeEnum::toCtype): Likewise. (TypeStruct::toCtype): Likewise. (TypeClass::toCtype): Likewise. * d-elem.cc (BoolExp::toElem): New function. * d-lang.cc (rootmodule): New declaration for frontend entrypoint changes. (genCmain): Update for frontend entrypoint changes. (d_handle_option): Don't duplicate memory for argument values. (d_parse_file): Don't duplicate memory for source filenames. * d-objfile.cc (VarDeclaration::toObjFile): Don't emit instantiated manifest constants to debug. (TemplateInstance::toObjFile): Update for frontend changes. (output_template_p): Remove function. (output_declaration_p): Update for frontend changes. (setup_symbol_storage): Update for frontend UDA changes. * d-target.cc (Target::reverseCppOverloads): New declaration. * d-typinf.cc (Type::getInternalTypeInfo): Update for frontend changes. (Type::getTypeInfo, Type::getTypeInfoDeclaration): Likewise. (TypeTypedef::getTypeInfoDeclaration): Likewise. (TypePointer::getTypeInfoDeclaration): Likewise. (TypeDArray::getTypeInfoDeclaration): Likewise. (TypeSArray::getTypeInfoDeclaration): Likewise. (TypeAArray::getTypeInfoDeclaration): Likewise. (TypeStruct::getTypeInfoDeclaration): Likewise. (TypeClass::getTypeInfoDeclaration): Likewise. (TypeVector::getTypeInfoDeclaration): Likewise. (TypeEnum::getTypeInfoDeclaration): Likewise. (TypeFunction::getTypeInfoDeclaration): Likewise. (TypeDelegate::getTypeInfoDeclaration): Likewise. (TypeTuple::getTypeInfoDeclaration): Likewise. (createTypeInfoArray): Likewise. * d-intrinsics.def: New file for declaring D intrinsics. * d-builtins.cc (std_intrinsic_module, std_math_module) (core_math_module, va_arg_template, va_arg2_template) (va_start_template): Remove declarations. (is_intrinsic_module_p, is_math_module_p, is_builtin_va_arg_p) (is_builtin_va_start_p, d_gcc_magic_stdarg_check) (d_gcc_magic_stdarg_module): Remove functions. (d_gcc_magic_builtins_module): Rename to d_build_builtins_module. (d_gcc_magic_libbuiltins_module): Rename to maybe_set_builtin. (d_gcc_magic_libbuiltins_check): Rename to maybe_set_builtin_1. (gcc_type_to_d_type): Rename to build_dtype. (gcc_cst_to_d_expr): Rename to build_expression. (d_gcc_eval_builtin): Remove function. (eval_builtin): Moved to... * d-glue.cc (eval_builtin): New function, updated for glue changes. (FuncDeclaration::isBuiltin): New function to determine whether a given function symbol is a compiler intrinsic. * d-codegen.cc (maybe_expand_builtin): Rename to expand_intrinsic. (Intrinsic): Remove enum declaration, replaced with... (intrinsic_code): New enum for compiler intrinsics. (intrinsic_decls): New declaration for store intrinsic information. (expand_intrinsic_bt): Update signature. (maybe_set_intrinsic): New function to replace... (maybe_set_builtin_frontend): Remove function. * d-decls.cc (FuncDeclaration::toSymbol): Update for glue changes. * d-builtins.c: Rename to d-builtins.cc * d-gt.c: Rename to d-gt.cc * d-spec.c: Rename to d-spec.cc * d-toir.cc: Renamed to toir.cc * toir.cc: New file, re-implement toIR methods as a visitor. * d-codegen.cc (insert_type_modifiers): Handle MODwildconst modifiers. (build_ir): New function. * d-objfile.cc (FuncDeclaration::toObjFile): Use build_ir to walk front-end IR trees. * d-decls.cc (VarDeclaration::toSymbol): Mark compiler temporaries as DECL_ARTIFICIAL. (ClassDeclaration::toVtblSymbol): Update for front-end changes. * d-builtins.c (gcc_type_to_d_type): Likewise. * d-elem.cc (CatAssignExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (BoolExp::toElem): Remove function. (ComExp::toElem): Assert that unhandled array operations no longer leak from the front-end. (NegExp::toElem): Likewise. * d-glue.cc (Global::init): Initialise new member run_noext. * d-incpath (add_import_path): Update for front-end changes. * d-lang.cc (d_add_builtin_version): Likewise. * d-todt.cc (StructDeclaration::toDt): Likewise. * d-toir.cc (LabelStatement::toIR): Don't delete forward references. (GotoStatement::toIR): Assert that undefined labels no longer leak from the front-end. 2014-05-31 Iain Buclaw * d-todt.cc (dt_container): Properly handle zero length static arrays. * d-codegen.h (build_dtype): Rename to lang_dtype. (build_ddecl): Rename to lang_ddecl. 2014-05-21 Iain Buclaw * d-builtins.c (d_init_builtins): Use void_node instead of d_void_zero_node. * d-lang.h (d_void_zero_node): Remove. * d-elem.cc (AndAndExp::toElem): Adjust. (OrOrExp::toElem): Likewise. (AssertExp::toElem): Likewise. (TupleExp::toElem): Likewise. * d-builtins.c (d_init_builtins): Use null_pointer_node instead of d_null_pointer. * d-lang.h (d_null_pointer): Remove. * d-codegen.cc (convert_expr): Adjust. (get_frame_for_symbol): Likewise. (build_vthis): Likewise. (get_framedecl): Likewise. * d-elem.cc (DeleteExp::toElem): Likewise. (CallExp::toElem): Likewise. (AssertExp::toElem): Likewise. (NewExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (NullExp::toElem): Likewise. * d-objfile.cc (ClassDeclaration::toObjFile): Likewise. (InterfaceDeclaration::toObjFile): Likewise. (FuncDeclaration::toObjFile): Likewise. (build_moduleinfo): Likewise. * d-todt.cc (TypeInfoTypedefDeclaration::toDt): Likewise. (TypeInfoEnumDeclaration::toDt): Likewise. (TypeInfoStructDeclaration::toDt): Likewise. 2014-05-18 Iain Buclaw * d-longdouble.cc (longdouble::from_shwi): Rename to from_int. (longdouble::from_uhwi): Rename to from_uint. (longdouble::to_shwi): Rename to to_int. (longdouble::to_uhwi): Rename to to_uint. (longdouble::set): Adjust. (longdouble::operator): Likewise. * d-lang.cc (alloc_binding_level): Adjust. (build_d_type_lang_specific): Likewise. (build_d_decl_lang_specific): Likewise. * d-lang.h (lang_type): Don't use variable_size gty attribute. * d-codegen.cc (cst_to_hwi): Remove function. * d-codegen.cc (tree_to_hwi): Remove function. * d-builtins.c (gcc_type_to_d_type): Adjust. (gcc_cst_to_d_expr): Likewise. * d-convert.cc (d_truthvalue_conversion): Use integer_zerop. (get_nonnull_operand): Use tree_fits_uhwi_p. * d-longdouble.cc (longdouble::from_int): Adjust. (longdouble::from_uint): Likewise. (longdouble::to_int): Likewise. 2014-04-30 Johannes Pfau * d-lang.cc (d_init): Define GNU_SEH_Exceptions and GNU_DWARF2_Exceptions versions. 2014-04-21 Iain Buclaw * d-lang.cc (d_init_options): Default deprecation warnings to off. * d-ctype.cc (TypeDelegate::toCtype): Propogate TREE_ADDRESSABLE from the base function to the delegatised copy. 2014-04-15 Johannes Pfau * d-lang.cc (d_handle_noclone_attribute): New function to handle noclone attribute. noclone is required by the naked attribute. * d-elem.cc (SymbolExp::toElem): Convert symbols to the expression type. 2014-04-13 Iain Buclaw * d-codegen.cc (get_frameinfo): Don't copy the node for frame record. * d-irstate.cc (IRState::endCatches): Rebuild the STATEMENT_LIST of catches in a TRY_CATCH_EXPR if it gets optimised away by IRState::popStatement. * d-codegen.cc (d_attribute_p): Provide access to target attributes. 2014-03-31 Iain Buclaw * d-codegen.cc (error_mark_p): Removed function, replace uses with error_operand_p. (error_mark): Removed function, replace uses with error_mark_node. * d-ctype.cc (Type::toCtype): Return d_unknown_type_node for frontend error types. * d-objfile.cc (VarDeclaration::toObjFile): Don't build CONST_DECLs for non-scalar manifests. 2014-03-23 Iain Buclaw * d-decls.cc (Dsymbol::toImport): Prevent GC from collecting IMPORTED_DECL nodes whilst front-end compilation in progress. 2014-03-19 Iain Buclaw * d-codegen.cc (AggLayout::visit): Rename to layout_aggregate_type. (AggLayout::doFields, AggLayout::doInterfaces): Remove function and move implementation into layout_aggregate_type. (AggLayout::addField): Rename to insert_aggregate_field. (AggLayout::finish): Rename to finish_aggregate_type. * d-codegen.h (AggLayout): Update definition. * d-ctype.cc (TypeStruct::toCtype): Update for glue changes. (TypeFunction::toCtype): Fix ICE on generic function types. (TypeClass::toCtype): Move generation of vptr and monitor fields into layout_aggregate_type. Moved generation of TYPE_METHODS from ... * d-objfile.cc (FuncDeclaration::toObjFile): ... here into TypeClass::toCtype. Don't build up TYPE_METHODS on a per-function basis, generate the entire vtable. 2014-03-18 Iain Buclaw * d-decls.cc (Dsymbol::toSymbolX): Set the symbol prettyIdent. (Dsymbol::toImport): Emit packages as their fully qualified names. (ClassDeclaration::toSymbol): Distinguish between the classinfo assembler and decl name. (InterfaceDeclaration::toSymbol): Likewise for interface symbol. (Module::toSymbol): Likewise for moduleinfo symbol. (ClassDeclaration::toVtblSymbol): Likewise for class vtable symbol. (AggregateDeclaration::toInitializer) (TypedefDeclaration::toInitializer, EnumDeclaration::toInitializer): Likewise for default initialisers. * d-objfile.cc (Module::genobjfile): Don't set-up moduleinfo symbol storage twice. 2014-03-17 Iain Buclaw * d-codegen.cc (d_decl_context): Fix null pointer dereference. * d-objfile.cc (FuncDeclaration::toObjFile): Don't override the setting of DECL_CONTEXT on the declaration here. (d_finish_symbol): Likewise. * d-objfile.cc (VarDeclaration::toObjFile): Move the generation of manifest constants to ... * d-decls.cc (VarDeclaration::toSymbol): ... here, and emit them as CONST_DECLs. Set the DECL_CONTEXT for all variable symbols. * d-builtins.cc (d_gcc_magic_builtins_module): Don't store compiler generated builtins in Symbol::isym, use Symbol::csym instead. (d_gcc_magic_libbuiltins_check): Likewise. * d-codegen.cc (d_decl_context): Return the imported symbol tree of modules where the NAMESPACE_DECL is now stored. (d_build_module): Remove function. Move implementation to ... * d-decls.cc (Dsymbol::toImport): ... here. Build an IMPORTED_DECL for all imported declarations. (FuncDeclaration::toSymbol): Remove special handling of Symbol::isym. (Module::toSymbol): Remove call to d_build_module. * d-objfile.cc (Dsymbol::toObjFile): Handle emission of IMPORTED_DECL symbols to debug. 2014-03-16 Iain Buclaw * d-codegen.cc (build_attributes): Ensure D-specific attributes have their value interpreted through CTFE. 2014-02-21 Iain Buclaw * d-codegen.cc (d_build_module): Update signature to accept a Loc location to the module declaration. * d-decls.cc (Module::toSymbol): Update call to d_build_module. Set TREE_PUBLIC/DECL_EXTERNAL to distingush which modules are being compiled. * d-objfile.cc (Dsymbol::toObjFile): Handle Import symbols, and emit debug information for imported modules. (ImportStatement::toIR): Likewise. (set_input_location): New function to implement the equivalent of set_decl_location, but instead sets input_location. 2014-02-19 Johannes Pfau * d-objfile.cc (build_call_function): Call set_input_location to set debug info correctly 2014-02-18 Iain Buclaw * d-objfile.cc (VarDeclaration::toObjFile): Remove toplevel check. DECL_CONTEXT is never set on manifest constants. (d_finish_compilation): Remove fancy check on force outputting symbols to object file. (build_type_decl): Don't emit the qualified identifier in debug information. The fully qualified name is now determined through the NAMESPACE_DECL context chain. * d-ctype.cc (TypeEnum::toCtype): Likewise for enum members. (VarDeclaration::toSymbol): Likewise for static variables. (FuncDeclaration::toSymbol): Likewise for functions. * d-decls.cc (FuncDeclaration::toSymbol): Don't emit the 'D main' symbol to debug as plain 'main'. * d-objfile.cc (VarDeclaration::toObjFile): Don't emit the qualified identifier of manifest constants in debug information. 2014-02-17 Iain Buclaw * d-codegen.cc (d_build_module): New function. * d-decls.cc (Module::toSymbol): Use d_build_module to build up the qualified module namespace. * d-codegen.cc (expand_intrinsic_op, expand_intrinsic_op2): New functions to build a call to a builtin code. (expand_intrinsic_bsr, expand_intrinsic_bt): New functions to expand a BUILTIN_FRONTEND call to core.bitop intrinsics. (expand_intrinsic_vaarg, expand_intrinsic_vastart): New functions to expand a BUILTIN_FRONTEND call to core.vararg intrinsics. (maybe_expand_builtin): Update. 2014-02-16 Iain Buclaw * d-decls.cc (Module::toSymbol): Build a NAMESPACE_DECL to populate the DECL_CONTEXT of toplevel functions. * d-codegen.cc (d_decl_context): Return the enclosing module NAMESPACE_DECL as the decl context only when the symbol is extern(D) and not D main. 2014-02-15 Iain Buclaw * d-decls.cc (VarDeclaration::toSymbol): Don't call setup_symbol_storage until after SET_DECL_ASSEMBLER_NAME has been set. * d-decls.cc (VarDeclaration::toSymbol): Give prettyIdent precedence for the DECL_NAME over the simple identifier. (FuncDeclaration::toSymbol): Likewise. * d-objfile.cc (d_finish_symbol): Remove setting DECL_NAME as prettyIdent, this has already been done in Declaration::toSymbol. (d_finish_function): Likewise. * d-decls.cc (VarDeclaration::toSymbol): Call set_user_assembler_name if pragma(mangle) was seen. (FuncDeclaration::toSymbol): Likewise. 2014-02-12 Johannes Pfau * d-decls.cc (FuncDeclaration::toSymbol): Do not set TREE_NOTHROW on nothrow functions. * d-decls.cc (TypeInfoDeclaration::toSymbol): Call relayout_decl after changing the type. 2014-02-03 Iain Buclaw * d-codegen.cc (d_build_call): Remove special handling of flag_split_darrays switch. (maybe_expand_builtin): Likewise. * d-elem.cc (CatExp::toElem): Likewise. * lang.opt (fsplit-dynamic-arrays): Remove. 2014-02-02 Iain Buclaw * d-glue.cc (readFile, writeFile, ensurePathToNameExists): Define. * d-incpath.cc (add_import_path): Update for frontend changes. (add_fileimp_path): Likewise. * d-lang.cc (deps_write): Likewise. (d_parse_file): Likewise. * d-todt.cc (Dts): Update define for frontend changes. * d-decls.cc (ClassDeclaration::toVtblSymbol): Don't mark __vtbl symbols as virtual. They are global static symbols. 2014-01-12 Iain Buclaw * d-decls.cc (EnumDeclaration::toDebug): Build TYPE_DECL only for enumeral types. 2014-01-06 Iain Buclaw * d-ctype.cc (TypeClass::toCtype): Don't add __monitor field for extern(C++) classes. * d-builtins.c (d_gcc_magic_module): Remove tdata. * d-codegen.cc (build_interface_binfo): Likewise. * d-ctype.cc (TypeEnum::toCtype): Likewise. (TypeClass::toCtype): Likewise. * d-lang.cc (deps_write): Likewise. 2014-01-05 Iain Buclaw * d-ctype.cc (TypeEnum::toCtype): Don't push CONST_DECLs into current function. * d-decls.cc (FuncDeclaration::toThunkSymbol): Don't mark symbol as TREE_PRIVATE, just TREE_PUBLIC as false. (StructLiteralExp::toSymbol): Likewise. (ClassReferenceExp::toSymbol): Likewise. * d-objfile.cc (d_comdat_linkage): Likewise. (d_finish_symbol): Likewise. (build_moduleinfo): Likewise. * config-lang.in: Add d-lang.cc to gtfiles. * d-irstate.h (IRState::varsInScope): Change from Array to vec<> type. (IRState::statementList_): Likewise. (IRState::scopes_): Likewise. (IRState::loops_): Likewise. (IRState::labels_): Likewise. * d-lang.h (d_bi_builtin_func): Remove declaration. (d_bi_builtin_type): Likewise. (d_keep_list): Likewise. * d-objfile.h (Symbol::thunks): Change from Array to vec<> type. (ModuleInfo::classes): Likewise. (ModuleInfo::ctors): Likewise. (ModuleInfo::dtors): Likewise. (ModuleInfo::ctorgates): Likewise. (ModuleInfo::sharedctors): Likewise. (ModuleInfo::shareddtors): Likewise. (ModuleInfo::sharedctorgates): Likewise. (ModuleInfo::unitTests): Likewise. (build_simple_function): Remove declaration. (build_call_function): Likewise. (build_ctor_function): Likewise. (build_dtor_function): Likewise. (build_unittest_function): Likewise. * d-builtins.c (bi_fn_list): Rename to gcc_builtins_functions. (bi_lib_list): Rename to gcc_builtins_libfuncs. (bi_type_list): Rename to gcc_builtins_types. (builtin_converted_types): Remove. (builtin_converted_decls): Change from Array to vec<> type. (gcc_type_to_d_type): Update. (d_bi_builtin_func): Remove and move to d_builtin_function. (d_bi_builtin_type): Remove and move to d_register_builtin_type. (d_gcc_magic_builtins_module): Update. * d-ctype.cc (TypeClass::toCtype): Remove unused var. * d-decls.cc (FuncDeclaration::toThunkSymbol): Update for change to vec<> type. * d-elem.cc (CatExp::toElem): Change stashed vars from Array to vec<>. (Expression::toElemDtor): Update for change to vec<> type. * d-irstate.cc (IRState::startFunction): Likewise. (IRState::endFunction): Likewise. (IRState::addExp): Likewise. (IRState::pushStatementList): Likewise. (IRState::popStatementList): Likewise. (IRState::getLabelBlock): Likewise. (IRState::getLoopForLabel): Likewise. (IRState::beginFlow): Likewise. (IRState::endFlow): Likewise. (IRState::startScope): Likewise. (IRState::pushLabel): Likewise. (IRState::checkGoto): Likewise. (IRState::checkPreviousGoto): Change from Array to Blocks type. * d-lang.cc (global_declarations): Change from Array to vec<> type. (d_add_global_declaration): Update for change to vec<> type. (d_write_global_declarations): Likewise. (d_keep_list): Make static to source file. * d-objfile.cc (static_ctor_list): Change from Array to vec<> type. (static_dtor_list): Likewise. (Module::genobjfile): Update for change to vec<> type. (d_finish_module): Likewise. (d_finish_function): Likewise. (deferred_thunks): Change from ArrayBase<> to vec<> type. (write_deferred_thunks): Update for change to vec<> type. (use_thunk): Likewise. (build_simple_function): Make static to source file. (build_call_function): Likewise. (build_ctor_function): Likewise. (build_dtor_function): Likewise. (build_unittest_function): Likewise. 2014-01-02 Iain Buclaw * d-objfile.cc (setup_symbol_storage): Use output_module_p on template instantiating module to determine if symbol is externally compiled. (d_finish_function): Set function local if function body was compiled. * d-decls.cc (Dsymbol::toSymbolX): Use unsigned integer format for the prefix string length. Copyright (C) 2014 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2015 ================================================ 2015-10-07 Iain Buclaw * d-decls.cc (StructLiteralExp::toSymbol): Use letter prefix for anonymous name. Don't set TREE_READONLY. (ClassReferenceExp::toSymbol): Likewise. 2015-10-06 Iain Buclaw * d-codegen.cc (build_struct_literal): New function. (layout_aggregate_members): Handle variables that are really tuples. * d-elem.cc (StructLiteralExp::toElem): Handle slicing void arrays. Use build_struct_literal to handle anonymous records. * d-lang.h (d_unknown_type_node): Rename to unknown_type_node, update in all files. 2015-10-03 Iain Buclaw * d-codegen.cc (build_two_field_type): Use DECL_FIELD_CONTEXT to access field context decl. (build_frame_type): Likewise. (lookup_anon_field): New function. (component_ref): Use it. (fixup_anonymous_offset): New function. (layout_aggregate_members): New function. (layout_aggregate_type): Move generation of fields into layout_aggregate_members. (insert_aggregate_field): Update signature, update all callers. (finish_aggregate_type): Likewise. * d-todt.cc (dt_container2): Use DECL_FIELD_CONTEXT to access field context decl. * types.cc (TypeVisitor::visit (TypeStruct)): Likewise. (TypeVisitor::visit (TypeClass)): Likewise. * d-tree.h (ANON_AGGR_TYPE_P): New type macro. 2015-08-25 Iain Buclaw * d-builtins.cc (maybe_set_builtin_1): Remove va_list handling. (d_init_builtins): Don't represent static array va_list as reference. * d-codegen.cc (convert_for_argument): Handle va_list as a static array. (declaration_type): Likewise. (type_passed_as): Likewise. (decl_reference_p): Renamed to declaration_type_kind, update to return how type is represented internally, updated all callers. (arg_reference_p): Renamed to argument_type_kind, update to return how type is represented internally, updated all callers. * d-codegen.h (type_kind): Declare. 2015-08-22 Iain Buclaw * toir.cc (IRVisitor::visit (TryCatchStatement)): Always emit call to LIBCALL_BEGIN_CATCH at the start of the catch. * d-elem.cc (AssertExp::toElem): Stabilize reference to class object before passing it to _d_invariant. 2015-08-20 Iain Buclaw * toir.cc (IRVisitor::visit): Set input location in all visitors that either throw an ICE or sorry message. 2015-08-19 Iain Buclaw * Make-lang.in: Replace uses of $(target_alias) with $(target_noncanonical). 2015-08-17 Iain Buclaw * types.cc (TypeVisitor::visit (TypeEnum)): Set ENUM_IS_SCOPED on all enumeral types. * d-lang.cc (d_init_options_struct): Remove setting flag_evaluation_order. 2015-08-10 Iain Buclaw * d-elem.cc (HaltExp::toElem): Use __builtin_trap to halt execution, rather than the library abort() call. 2015-08-07 Iain Buclaw * d-codegen.cc (build_closure): Update signature, update all callers. (build_vthis): Likewise. (get_frame_for_symbol): Likewise. (build_local_var): Likewise. (get_decl_tree): Likewise. (start_function): Likewise. * d-irstate.h (IRState): Move func, mod, sthis, deferred, statementList, and varsInScope fields to... * d-tree.h (language_function): Here, updated all uses. * d-irstate.h: Remove file. (IRState): Remove all uses everywhere. 2015-08-07 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Remove d-irstate.o. * d-tree.h (d_label_use_entry): New structure. (d_label_entry): New structure. (binding_level): Add level_kind field. (language_function): Add hash table field for labels. (D_LABEL_VARIABLE_CASE): New macro. * d-codegen.cc (pop_binding_label): New function. (pop_label): New function. (push_binding_level): Update signature. (pop_binding_level): Update signature. Handle declared or used labels. (build_array_set): Update for push/pop binding changes. (check_goto): New function. (check_previous_goto): New function. (d_lookup_label): Remove function. (lookup_label): New function. (lookup_bc_label): New function. (define_label): New function. * d-objfile.cc (FuncDeclaration::toObjFile): Update for push/pop binding changes. * toir.cc (IRVisitor): Add break and continue label fields. (IRVisitor::IRVisitor): Initialize here. (IRVisitor::start_scope): Update signature. (IRVisitor::end_scope): Return the finished scope, updated all callers. (IRVisitor::push_break_label): New function. (IRVisitor::pop_break_label): New function. (IRVisitor::push_continue_label): New function. (IRVisitor::pop_continue_label): New function. (IRVisitor::start_condition): Remove function. (IRVisitor::start_else): Remove function. (IRVisitor::end_condition): Remove function. (IRVisitor::start_catches): Remove function. (IRVisitor::start_catch): Remove function. (IRVisitor::end_catch): Remove function. (IRVisitor::end_catches): Remove function. (IRVisitor::start_finally): Remove function. (IRVisitor::end_finally): Remove function. (IRVisitor::start_case): Remove function. (IRVisitor::end_case): Remove function. * d-irstate.cc: Remove. 2015-08-06 Iain Buclaw * config-lang.in (gtfiles): Replace d-lang.h for d-tree.h * d-lang.h: Move all GTY structures to d-tree.h, updated all source header dependencies. * d-tree.h: New file. 2015-08-04 Iain Buclaw * toir.cc (IRVisitor::start_condition): Don't cache condition. (IRVisitor::start_else): Return the then body, updated all callers. (IRVisitor::end_condition): Update signature. (IRVisitor::start_catches): Return the try body, updated all callers. (IRVisitor::start_catch): Don't cache catch type. (IRVisitor::end_catch): Update signature. (IRVisitor::end_catches): Update signature. (IRVisitor::start_finally): Return the try body, updated all callers. (IRVisitor::end_finally): Update signature. (IRVisitor::start_case): Don't cache the condition. (IRVisitor::end_case): Update signature. * d-codegen.cc (convert_for_assignment): Use size_type_node for index. * d-irstate.cc (IRState::beginFlow): Remove call to push_stmt_list. 2015-08-04 Iain Buclaw * d-codegen.cc (push_stmt_list): New function. (pop_stmt_list): New function. (add_stmt): New function. (start_function): New function. (end_function): New function. (expand_decl): Update to use new interface. (build_closure): Likewise. (push_binding_level): Moved from d-lang.cc. (pop_binding_level): Likewise. * d-lang.cc (d_init): Inline call to init_global_binding_level. (alloc_binding_level): Remove function. (push_binding_level): Remove function. (pop_binding_level): Remove function. (init_global_binding_level): Remove function. (set_decl_binding_chain): Remove function. * d-elem.cc (DeclarationExp::toElem): Likewise. * d-objfile.cc (VarDeclaration::toObjFile): Likewise. (FuncDeclaration::toObjFile): Likewise. * toir.cc (IRVisitor::start_scope): Moved from d-irstate.cc, updated all callers in IRVisitor. (IRVisitor::end_scope): Likewise. (IRVisitor::is_return_label): Likewise. (IRVisitor::do_label): Likewise. (IRVisitor::do_jump): Likewise. (IRVisitor::start_condition): Likewise. (IRVisitor::start_else): Likewise. (IRVisitor::end_condition): Likewise. (IRVisitor::start_catches): Likewise. (IRVisitor::start_catch): Likewise. (IRVisitor::end_catch): Likewise. (IRVisitor::end_catches): Likewise. (IRVisitor::start_finally): Likewise. (IRVisitor::end_finally): Likewise. (IRVisitor::end_loop): Likewise. (IRVisitor::start_case): Likewise. (IRVisitor::end_case): Likewise. (build_ir): Update signature. 2015-08-01 Iain Buclaw * Make-lang.in (DMD_COMPILE): Declare as COMPILE with WARN_CXXFLAGS replaced with DMD_WARN_CXXFLAGS. (DMDGEN_COMPILE): Declare as DMD_COMPILE but with COMPILER replaced with COMPILER_FOR_BUILD. (d/idgen): Use LINKER_FOR_BUILD. (d/impcvgen): Likewise. (d/%.o): Use DMD_COMPILE and POSTCOMPILE. (d/%.dmdgen.o): Use DMDGEN_COMPILE and POSTCOMPILE. 2015-07-27 Iain Buclaw * d-codegen.cc (current_irstate): Remove. (d_build_call): Check cfun before dereferencing. * d-codegen.h (current_irstate): Redefine as macro. * d-irstate.cc (IRState::IRState): Remove. (IRState::startFunction): Initialize language-specific cfun field. (IRState::endFunction): Free language-specific cfun field. * d-lang.cc (d_parse_file): Don't initialize current_irstate. * d-lang.h (language_function): Add irs field. * d-objfile.cc (Dsymbol::toObjFile): Check cfun. (FuncDeclaration::toObjFile): Adjust start and end calls. 2015-07-26 Iain Buclaw * d-irstate.cc (IRState::doArraySet): Remove function. * d-codegen.cc (build_array_set): New function. * d-elem.cc (AssignExp::toElem): Use build_array_set. (StructLiteralExp::toElem): Likewise. * d-codegen.cc (build_array_set): Don't set this_block, update call to pop_binding_level. * d-irstate.cc (IRState::endFunction): Update assert. (IRState::startScope): Move IRState::startBindings here, clean-up. (IRState::endScope): Move IRState::endBindings here, clean-up. (IRState::startBindings): Remove function. (IRState::endBindings): Likewise. (IRState::currentScope): Likewise. (IRState::scopes_): Remove. * d-lang.cc (pop_binding_level): Update signature, clean-up. (d_pushdecl): Don't set names_end. (binding_level::names_end): Remove. (binding_level::this_block): Remove. (FuncDeclaration::toObjFile): Clean-up. 2015-07-24 Sebastien Alaiwan * d-lang.cc (deps_write): Use StringTable instead of hash_set of string pointers. 2015-07-23 Iain Buclaw * d-attribs.h: Adjust includes. * d-builtins.cc: Likewise. * d-codegen.cc: Likewise. * d-convert.cc: Likewise. * d-decls.cc: Likewise. * d-elem.cc: Likewise. * d-glue.cc: Likewise. * d-incpath.cc: Likewise. * d-irstate.cc: Likewise. * d-lang.cc: Likewise. * d-longdouble.cc: Likewise. * d-objfile.cc: Likewise. * d-port.cc: Likewise. * d-target.cc: Likewise. * d-todt.cc: Likewise. * toir.cc: Likewise. * types.cc: Likewise. 2015-07-22 Iain Buclaw * d-codegen.cc (convert_expr): Warn about casts between imaginary and non-imaginary types. * d-convert (d_convert_basic): Rename to convert, handle conversions between complex and imaginary types. (convert): Remove. (d_build_truthvalue_op): Update to call convert. (d_truthvalue_conversion): Likewise. * d-builtins.cc (d_init_builtins): Build imaginary types as distinct floating point type nodes. * d-codegen.cc (build_float_modulus): Update to handle imaginary types. (d_array_type): Use the front-end equivalent of sizetype to represent the index type of arrays. (build_array_index): Likewise. (build_offset_op): Likewise. (expand_intrinsic): Only get the inner callee if it's an address. * d-codegen.h (component_ref, modify_expr, vmodify_expr, build_vinit) (build_nop, build_vconvert, build_boolop, compound_expr) (vcompound_expr, real_part, imaginary_part): Move to d-codegen.cc, use fold build functions for codegen. * d-codeden.cc (build_address): Use build_fold_addr_expr_with_type, remove special handling of taking an address of an indirect ref. (return_expr): New function. (complex_expr): New function. (indirect_ref): Use fold build functions for codegen. (build_deref): Likewise. (build_array_index): Likewise. (build_offset_op): Likewise. (void_okay_p): Likewise. (build_binary_op): Likewise. (build_float_modulus): Likewise. * d-objfile.cc (FuncDeclaration::toObjFile): Likewise. * d-elem.cc (MinExp::toElem): Likewise. (AddExp::toElem): Likewise. (NotExp::toElem): Likewise. (ComExp::toElem): Likwise. (NegExp::toElem): Likewise. * d-irstate.cc (IRState::doLabel): Likewise. (IRState::doReturn): Likewise. (IRState::doJump): Likewise. * d-attribs.c: Adjust includes for flags.h changes. * d-builtins.cc: Likewise. * d-codegen.cc: Likewise. * d-convert.cc: Likewise. * d-elem.cc: Likewise. * d-decls.cc: Likewise. * d-glue.cc: Likewise. * d-incpath.cc: Likewise. * d-irstate.cc: Likewise. * d-lang.cc: Likewise. * d-longdouble.cc: Likewise. * d-objfile.cc: Likewise. * d-port.cc: Likewise. * d-target.cc: Likewise. * d-todt.cc: Likewise. * toir.cc: Likewise. * types.cc: Likewise. 2015-07-20 Sebastien Alaiwan * d-lang.cc (is_system_module): Extract function. (write_one_dep): Extract function. (deps_write): Eliminate duplicated dependencies, include indirect and private dependencies. 2015-07-19 Sebastien Alaiwan * d-lang.cc (d_parse_file): Set ref flag on the module and make deps file handle. 2015-07-11 Iain Buclaw * d-codegen.cc (convert_for_assignment): Remove handling of zero initialising a structure using memset. (d_build_call): Removing handling of setting of return slot optimisation on in call expression. * d-elem.cc (AssignExp::toElem): Emit a memset to zero initialise structures here. Set return slot optimisation on construction of static arrays and structs only. 2015-07-07 Iain Buclaw * d-codegen.cc (expand_intrinsic_arith): Use build_deref to handle ref parameters being used for the 'overflow' parameter. 2015-07-03 Iain Buclaw * d-elem.cc (StringExp::toElem): Zero-terminate all string literals types, except for static arrays. * d-objfile.cc (build_type_decl): Add TYPE_DECLs to global declarations, don't call rest_of_decl_declaration. (d_finish_compilation): Call rest_of_decl_declaration on TYPE_DECLs. (Dsymbol::toObjFile): Don't try to handle tuples when emitting import declarations to debug. * d-builtins.cc (builtin_sym): Use StructDeclaration for decl field. (build_dtype): Don't handle anonymous structs. Create a stub parent module for the declaration symbol. (d_build_builtins_module): Always override the parent module of converted struct declarations. (maybe_set_builtin_1): Convert all static array parameters to ref parameters, not just va_list. 2015-07-01 Iain Buclaw * d-attribs.c (d_handle_section_attribute): Use VAR_P throughout. (d_handle_weak_attribute): Use VAR_OR_FUNCTION_DECL_P. * d-codegen.cc (convert_for_assignment): Use VAR_P. * d-lang.cc (pop_binding_level): Likewise. (d_types_compatible_p): Likewise. * d-objfile.cc (setup_symbol_storage): Likewise. (mark_needed): Likewise. (d_finish_compilation): Likewise. 2015-06-30 Iain Buclaw * intrinsics.def: Added ADDS, ADDSL, ADDU, ADDUL, SUBS, SUBSL, NEGS, NEGSL, MULS, MULSL, MULU, and MULUL intrinsic definitions. * d-codegen.cc (expand_intrinsic_arith): New function. (expand_intrinsic): Add cases for core.checkedint functions adds, addu, subs, subu, negs, muls, and mulu intrinsics. 2015-06-27 Iain Buclaw * Make-lang.in (D_DMD_H): Remove. (D_TREE_H): Likewise. (CFLAGS-d/d-spec.o): Declare extra CFLAGS for building driver. (d-warn): Declare default warning flags for compiler. (D_DMD_OBJS): Remove 'dmd' from the object file suffix. (D_GLUE_OBJS): Remove 'cglue' and 'glue' from object file suffix. (D_GENERATED_OBJS): Remove 'gen' from the object file suffix. (D_BORROWED_C_OBJS): Remove. (CFLAGS-d/id.o): Declare extra CFLAGS for building generated sources. (CFLAGS-d/impcnvtab.o): Likewise. * types.cc (TypeVisitor::visit (TypeClass)): Build a pointer type for classes, not a reference type. * types.cc (TypeVisitor::visit (TypeDelegate)): Don't build a METHOD_TYPE for delegates, as that requires knowing the underlying record type for the 'this' object parameter. (TypeVisitor::visit (TypeEnum): Don't call rest_of_type_compilation. (TypeVisitor::visit (TypeClass): Likewise. (TypeVisitor::visit (TypeStruct): Likewise. * d-decls.cc (TypeInfoDeclaration::toSymbol): Assert class is a pointer type, not a reference type. (FuncDeclaration::toSymbol): Don't convert nested functions into a METHOD_TYPE to be strictly compatible with delegates. * d-codegen.cc (convert_for_argument): Use correct accessors for array .ptr and .length properties. (expand_intrinsic_vaarg): Don't remove the va_list pointer reference, as the backend now assumes this is what the front-end sets up. (d_build_call): Remove assert as delegates and nested functions are no longer represented as METHOD_TYPE. (build_vthis_type): New function. (d_decl_context): Don't set static/__gshared declaration context as anything other than the enclosing module of the declaration. * toir.cc (IRVisitor::visit (ExtAsmStatement)): Support named labels by calling resolve_asm_operand_names. * d-builtins.cc (d_backend_init): Remove. (d_backend_term): Remove. * d-lang.cc (d_write_global_declarations): Remove langhook. (d_init): Move d_backend_init implementation here. (d_parse_file): Move d_write_global_declarations implementation here. (d_finish_compilation): Remove calls to finalize_compilation_unit, check_global_declarations, and emit_debug_global_declarations. (d-system.h): Remove file. Move all includes into local sources. 2015-06-22 Iain Buclaw * d-codegen.cc (d_build_call): Only apply CALL_EXPR_RETURN_SLOT_OPT to calls returning an aggregate. (expand_intrinsic): Use CALL_EXPR_FN and CALL_EXPR_ARG directly. (layout_aggregate_type): Update signature. (insert_aggregate_field): Likewise. (finish_aggregate_type): Likewise. * d-codegen.h (AggLayout): Remove helper class. (AddrOfExpr): Remove helper class. (CallExpr): Remove helper class. * d-elem.cc (InExp::toElem): Use build_address directly. (CatAssignExp::toElem): Likewise. (IndexExp::toElem): Likewise. (RemoveExp::toElem): Likewise. * types.cc (TypeVisitor::visit (TypeFunction)): Only apply TREE_ADDRESSABLE to function types returning an aggregate. (TypeVisitor::visit (TypeStruct)): Update for layout_aggregate_type and finish_aggregate_type changes. (TypeVisitor::visit (TypeClass)): Likewise. 2015-06-21 Iain Buclaw * d-objfile.cc (setup_symbol_storage): Mark declarations as private or protected for the benefit of debug code. * d-elem.cc (ArrayLiteralExp::toElem): Only set a value at the given index in the array constructor if it is non-zero. (AssignExp::toElem): Use memset it assigning/initialising an array with all zeroes. (IndexExp::toElem): Simplify codegen to use a placeholder variable for the dollar length. (SliceExp::toElem): Likewise. * d-codegen.cc (ArrayScope): Remove helper class. * Make-lang.in (cc1d$(exeext)): Use link mutex. 2015-05-03 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Rename d-ctype.cc to types.cc. (d-spec.o): Rename d-spec.cc to d-spec.c * types.cc (build_ctype): New function. (Type::toCtype): Convert toCtype methods to use Visitor interface. 2015-04-29 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Add d-attribs.o. Remove d-gt.o. * d-attribs.c: New file. * d-builtins.cc: Move attribute handler functions to d-attribs.c * d-lang.cc: Likewise. Added include for gtype-d.h from d-gt.cc. * d-gt.cc: Remove file. 2015-04-27 Iain Buclaw * d-builtins.cc, d-convert.cc, d-ctype.cc, d-decls.cc, d-elem.cc, d-glue.cc, d-incpath.cc, d-irstate.cc, d-longdouble.cc, d-port.cc, d-target.cc, d-typinf.cc, toir.cc: Re-order included headers. * d-codegen.h, d-dmd-gcc.h, d-irstate.h, d-lang.h, d-objfile.cc, d-system.h: Remove all includes from headers. * d-codegen.cc: Re-order included headers. (build_attributes): Use ctfeInterpret instead of optimize. * d-lang.cc: Re-order included headers. (d_init_options): Don't use tristate enum for flag_emit_templates. (d_handle_option): Likewise. * d-objfile.cc: Re-order included headers. (output_declaration_p): Update check for flag_emit_templates. (setup_symbol_storage): Likewise. * d-todt.cc: Re-order included headers. (ExpInitializer::toDt): Use ctfeInterpret instead of optimize. (TypeInfoTupleDeclaration::toDt): Likewise. 2015-04-20 Iain Buclaw * d-codegen.cc (build_exception_object): Remove. * runtime.def (BEGIN_CATCH): Declare runtime function __gdc_begin_catch. * toir.cc (IRVisitor::visit::TryCatchStatement): Use LIBCALL_BEGIN_CATCH to get the correct exception object for handler. 2015-04-18 Iain Buclaw * d-codegen.cc (d_build_call): Set CALL_EXPR_RETURN_SLOT_OPT on calls to functions that return an aggregate or array that returns in memory. (build_memref): New function. (get_object_method): Use build_memref instead of building a POINTER_PLUS_EXPR for vtable dereferences. * d-objfile.cc (FuncDeclaration::toObjFile): Support NRVO on ARRAY_TYPE's that may not return in registers. * d-ctype.cc (TypeFunction::toCtype): Don't mark TREE_ADDRESSABLE when returning non-POD types by reference. 2015-04-15 Iain Buclaw * d-decls.cc (EnumDeclaration::toDebug): Remove. (ClassDeclaration::toDebug): Remove. (StructDeclaration::toDebug): Remove. * d-ctype.cc (TypeEnum::toCtype): Call rest_of_type_compilation here. (TypeClass::toCtype): Likewise. (TypeStruct::toCtype): Likewise. 2015-04-12 Iain Buclaw * d-objfile.cc (get_decl_tree): Check and generate correct code for when a non-local 'this' is accessed through a closure pointer. (FuncDeclaration::toObjFile): Remove check for _arguments. * d-codegen.cc (build_local_var): Likewise. 2015-04-11 Johannes Pfau * d-objfile.cc (setup_symbol_storage): Mark functions without body as DECL_EXTERNAL. 2015-04-08 Iain Buclaw * d-codegen.cc (get_decl_tree): Get correct non-local 'this' decl by constructing component reference through parent link of nested classes. * d-builtins.cc (DEF_FUNCTION_TYPE_VAR_8): Remove. (DEF_FUNCTION_TYPE_VAR_12): Likewise. (DEF_FUNCTION_TYPE_VAR_7, DEF_FUNCTION_TYPE_VAR_11): New macros. 2015-04-07 Iain Buclaw * d-objfile.cc (output_declaration_p): Remove check for semanticRun. (FuncDeclaration::toObjFile): Name bool parameter force_p, allow it to override the initial output_declaration_p check. Force run all semantic passes for symbols that it routine is generating code for. (d_finish_function): Don't mark TREE_STATIC on functions that are really DECL_EXTERN. (finish_thunk): Force thunks referencing external methods to be expanded to gimple. * d-decls.cc (FuncDeclaration::toThunkSymbol): Call toObjFile on all thunk target functions. 2015-04-05 Johannes Pfau * d-lang.cc (d_handle_section_attribute): New function. * d-builtins.cc (handle_alias_attribute): Move to d-lang.cc to support attribute(alias) in user code. * d-lang.cc (d_handle_alias_attribute): Ditto. * d-lang.cc (d_handle_weak_attribute): New function. * d-decls.cc (FuncDeclaration::toSymbol): Do not set DECL_DECLARED_INLINE_P prematurely. 2015-03-21 Johannes Pfau * d-lang.cc (d_init): Add GNU_EMUTLS version. * d-objfile.cc (build_emutls_function): New function. * d-objfile.cc (VarDeclaration::toObjFile): Collect all TLS variables in a module into tlsVars array. * d-objfile.cc (genmoduleinfo): Add reference to __modtlsscan function generated by build_emutls_function to moduleinfo. 2015-02-02 Iain Buclaw * config-lang.in: Remove lang_requires_boot_languages. * d-incpath.cc (iprefix): Remove global variable. (multilib_dir): Ditto. (prefixed_path): Add iprefix parameter. (add_import_paths): Add iprefix and imultilib parameter. Use cpp_include_defaults to get list of import paths. * d-lang.cc (iprefix_dir): New static variable to cache -iprefix switch. (imultilib_dir): New static variable to cache -imultilib switch. (d_init): Pass iprefix_dir and imultilib_dir to add_import_paths. (d_handle_option): Use new static variables. 2015-02-01 Iain Buclaw * d-lang.cc: Remove d-confdef.h header. * d-incpath.cc: Ditto. * d-spec.cc: Ditto. 2015-01-31 Iain Buclaw * d-incpath.cc (add_phobos_versyms): Remove function. * d-lang.cc (d_init): Remove call to add_phobos_versyms. 2015-01-28 Iain Buclaw * d-builtins.cc (DEF_FUNCTION_TYPE_VAR_8) (DEF_FUNCTION_TYPE_VAR_12): New macros. 2015-01-24 Johannes Pfau * d-builtins.cc (d_build_builtins_module): Mark builtin functions as @nogc. 2015-01-18 Iain Buclaw * Make-lang.in: Update for D frontend changes. * d-asmstmt.cc: Remove file. * d-builtins.cc (build_dtype): No longer set struct handle. (d_gcc_paint_type): Move to Target::paintAsType. * d-codegen.cc (convert_expr): No longer call getImpl on associative array conversions. Add case for converting void pointers to delegates. (unhandled_arrayop_p): Remove. (build_two_field_type): Use layout_type instead of building TYPE_STUB_DECL and calling rest_of_decl_compilation. (build_binop_assignment): New function. (libcall_ids): Remove static variable. (get_libcall): New function. (maybe_set_intrinsic): Remove druntime library call handling. (expand_intrinsic_vaarg): Dereference ref va_list parameters. (build_closure): New function. (WrappedExp::WrappedExp): Move to frontend sources. (WrappedExp::toCBuffer): Ditto. * d-codegen.h (LibCallFlag): New enum. (LibCall): Use runtime.def macro to define members. * d-ctype.cc (Type::toCParamtype): Remove function. (TypeTypedef::toCParamtype): Ditto. (TypeClass::toSymbol): Ditto. (TypeFunction::retStyle): Move to retStyle. (TypeSArray::toCParamtype): Ditto. (Type::toSymbol): Ditto. (Type::totym): Ditto. (TypeFunction::totym): Ditto. * d-decls.cc (Dsymbol::toSymbolX): Update for frontend changes. (Dsymbol::toImport): Ditto. (VarDeclaration::toSymbol): Ditto. (FuncDeclaration::toSymbol): Ditto. (InterfaceDeclaration::toSymbol): Use TREE_READONLY instead of (EnumDeclaration::toDebug): Only call rest_of_type_compilation on ENUMERAL_TYPE types. TREE_CONSTANT to declare that the symbol cannot be modified. (ClassDeclaration::toVtblSymbol): Ditto. (AggregateDeclaration::toInitializer): Ditto. (EnumDeclaration::toInitializer): Ditto. (TypedefDeclaration::toInitializer): Remove function. (TypedefDeclaration::toDebug): Ditto. (Dsymbol::cvMember): Remove stub function. (EnumDeclaration::cvMember): Ditto. (FuncDeclaration::cvMember): Ditto. (VarDeclaration::cvMember): Ditto. (TypedefDeclaration::cvMember): Ditto. * d-elem.cc (XorExp::toElem): Remove call to unhandled_arrayop_p. (OrExp::toElem): Ditto. (AndExp::toElem): Ditto. (UshrExp::toElem): Ditto. (ShrExp::toElem): Ditto. (ShlExp::toElem): Ditto. (ModExp::toElem): Ditto. (DivExp::toElem): Ditto. (MulExp::toElem): Ditto. (MinExp::toElem): Ditto. (AddExp::toElem): Ditto. (XorAssignExp::toElem): Ditto. (OrAssignExp::toElem): Ditto. (AndAssignExp::toElem): Ditto. (UshrAssignExp::toElem): Ditto. (ShrAssignExp::toElem): Ditto. (ShlAssignExp::toElem): Ditto. (ModAssignExp::toElem): Ditto. (DivAssignExp::toElem): Ditto. (MulAssignExp::toElem): Ditto. (PowAssignExp::toElem): Ditto. (MinAssignExp::toElem): Ditto. (AddAssignExp::toElem): Ditto. (BinExp::toElemBin): Move to build_binop_assignment. (AssignExp::toElem): Update for frontend changes. (DelegatePtrExp::toElem): New function. (DelegateFuncptrExp::toElem): New function. (DelegateExp::toElem): Update for frontend changes. (FuncExp::toElem): Ditto. (NewExp::toElem): Ditto. (StringExp::toElem): Don't set TREE_READONLY on string literals. (AssocArrayLiteralExp::toElem): Remove codegen rewrite for new associative array implementation. * d-glue.cc (Global::isSpeculativeGagging): Remove function. (Dsymbol::ungagSpeculative): Ditto. (Ungag::~Ungag): Ditto. (Loc::toChars): Update for new column diagnostic support. (Loc::Loc): Ditto. (Loc::equals): Ditto. (error): Ditto. (binary): Remove function. (asmSemantic): New function. (retStyle): New function. (FuncDeclaration::isBuiltin): Rename to isBuiltin. * d-intrinsics.def: Rename to intrinsics.def. * d-irstate.cc (IRState::addExp): Remove old warning to catch statements with no side effects. Now handled in frontend. * d-lang.cc (d_init_options): Update for frontend changes. (d_initialize_diagnostics): Remove function. (d_add_builtin_version): Update for frontend changes. (d_init): Ditto. (d_handle_option): Ditto. (d_post_options): Ditto. (d_parse_file): Ditto. * d-objfile.cc (Nspace::toObjFile): New function. (StructDeclaration::toObjFile): Update for frontend changes. (TypedefDeclaration::toObjFile): Remove function. (TemplateInstance::toObjFile): Update for frontend changes. (TemplateMixin::toObjFile): Ditto. (unnest_function): New function. (output_declaration_p): Update for frontend changes. (FuncDeclaration::toObjFile): Ditto. (FuncDeclaration::buildClosure): Move to buildClosure. (get_linemap): Update for frontend changes. (build_simple_function): Ditto. (build_call_function): Ditto. * d-target.cc (Target::va_listType): New function. (Target::paintAsType): Ditto. * d-todt.cc (dt_container2): Do not set TREE_READONLY on initialisers. (dt_container): Ditto. (ClassReferenceExp::toDt2): Update for C++ class support. (ClassReferenceExp::toInstanceDt): Ditto. (TypeTypedef::toDt): Remove function. (TypeInfoTypedefDeclaration::toDt): Ditto. (TypeInfoAssociativeArrayDeclaration::toDt): Update typeinfo size. (TypeInfoAssociativeArrayDeclaration::toDt): Remove reference to impl field in TypeInfo struct. (TypeInfoStructDeclaration::toDt): Update for frontend changes. * d-typinf.cc (Type::getTypeInfo): Update for frontend changes. (TypeTypedef::getTypeInfoDeclaration): Remove function. (createTypeInfoArray): Remove function. * runtime.def: New file. * toir.cc (IRVisitor::visit::DtorExpStatement): Remove function. (IRVisitor::visit::ExtAsmStatement): Update for frontend changes. 2015-01-17 Iain Buclaw * d-elem.cc (UshrAssignExp::toElem): Remove integer promotion on left hand side of unsigned right shift expression. 2015-01-13 Iain Buclaw * d-system.h: Include hash-set.h, machmode.h, vec.h, double-int.h, input.h, alias.h, symtab.h and inchash.h due to flattening of tree.h. * d-gt.cc: Ditto. 2015-01-02 Iain Buclaw * d-codegen.h (build_boolop): Don't eagerly fold comparison expressions. Copyright (C) 2015 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2016 ================================================ 2016-12-28 Iain Buclaw * expr.cc (ExprVisitor::visit(VarExp)): Remove type forced conversion. 2016-12-28 Iain Buclaw * d-lang.cc (d_handle_option): Handle -ftransition=safe. * lang.opt (ftransition=safe): Add compiler option. 2016-12-28 Iain Buclaw * d-lang.cc (d_init_options): Initialize hdrStripPlainFunctions. (d_post_options): Add post option handling of flag. 2016-12-27 Iain Buclaw * d-codegen.cc (layout_aggregate_type): Adjust layout of D interfaces. Only add a __vptr field if no base interfaces, don't add __monitor. 2016-12-27 Iain Buclaw * d-lang.cc (d_parse_file): Run runDeferredSemantic2 after semantic2. 2016-12-26 Iain Buclaw * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Use getElement to index elements array. (ExprVisitor::visit(VectorExp)): Likewise. 2016-12-25 Iain Buclaw * Make-lang.in (D_DMD_OBJS): Add d/objc.o * types.cc (TypeVisitor::visit(TypeFunction)): Handle ObjC linkage. 2016-12-25 Iain Buclaw * d-decls.cc (mangle_decl): New function. (make_internal_name): Update. (get_symbol_decl): Update. 2016-12-24 Iain Buclaw * expr.cc (ExprVisitor::needs_dtor): New function. (ExprVisitor::lvalue_p): New function. (ExprVisitor::visit(AssignExp)): Check both for postblit and dtors when generating array assignments. 2016-12-24 Iain Buclaw * d-codegen.cc (convert_expr): Allow upcasting C++ classes. (build_class_instance): Generate initial values of vtable interfaces before class fields. (layout_aggregate_type): Layout vtable interfaces before class fields. * d-decls.cc (get_symbol_decl): Build DECL_ARGUMENTS for functions that have no body. 2016-12-22 Iain Buclaw * d-target.cc (Target::cppExceptions): New variable. (Target::init): Initialize it. (Target::prefixName): New function. 2016-12-19 Iain Buclaw * d-objfile.cc (ClassDeclaration::toObjFile): Use layout_classinfo to generate TypeInfo for classes. (InterfaceDeclaration::toObjFile): Likewise. * d-todt.cc (build_vptr_monitor): Remove function. * typeinfo.cc (TypeInfoVisitor::set_field): New function. (TypeInfoVisitor::layout_interfaces): New function. (TypeInfoVisitor::layout_interface_vtables): New function. (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Implement. (layout_classinfo): New function. 2016-12-18 Iain Buclaw * typeinfo.cc (TypeInfoVisitor): Use build_typeinfo instead of get_typeinfo_decl. * d-objfile.cc (ClassDeclaration::toObjFile): Use build_constructor to build the vtable, instead of using dt_cons. 2016-12-18 Iain Buclaw * d-decls.cc (layout_moduleinfo_fields): Use finish_aggregate_type instead of layout_type. (layout_classinfo_interfaces): Likewise. 2016-12-17 Iain Buclaw * d-builtins.cc (build_dtype): Use static create method for allocating frontend types. * d-codegen.cc (declaration_type): Likewise. (type_passed_as): Likewise. (get_libcall): Likewise. * d-lang.cc (d_parse_file): Likewise. * d-objfile.cc (build_simple_function_decl): Likewise. (build_emutls_function): Likewise. * d-todt.cc (StructDeclaration::toDt): Likewise. * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoInterfaceDeclaration)): Likewise. 2016-12-17 Johannes Pfau * d-decls.cc (copy_struct): Also copy and update TYPE_METHODS. * d-spec.c (lang_specific_driver): Do not link in math, thread and time libraries. Use a spec file instead to do this. (lang_specific_pre_link): Load libgphobos.spec to set up the link dependencies for libgphobos. 2016-12-13 Iain Buclaw * d-builtins.cc (build_dtype): Cache all allocated frontend types. (builtin_sym): Update constructor. (builtin_converted_decls): Rename to builtin_converted_syms. (d_build_builtins_module): Check if decl set before assigning parent. 2016-12-13 Iain Buclaw * d-builtins.cc (build_dtype): Set type modifiers on frontend type. 2016-12-12 Iain Buclaw * d-builtins.cc (build_dtype): Don't set default parameter storage class as const. 2016-12-12 Iain Buclaw * d-decls.cc (add_moduleinfo_field): New function. (layout_moduleinfo_fields): New function. (get_moduleinfo_decl): Use record type for moduleinfo decl. * d-objfile.cc (build_moduleinfo_symbol): Delay calling get_moduleinfo_decl until after ModuleInfo type is validated. (d_finish_symbol): Remove check for unknown_type_node. 2016-12-11 Iain Buclaw * d-decls.cc (copy_struct): New function. (layout_classinfo_interfaces): New function. (get_classinfo_decl): Use record type for classinfo decl. * d-codegen.cc (create_field_decl): New function. Use it instead of build_decl when creating a new FIELD_DECL. 2016-12-11 Iain Buclaw * d-builtins.cc (build_dtype): Don't build generic function types. (d_build_builtins_module): Remove check. 2016-12-10 Iain Buclaw * d-codegen.cc (build_vindex_ref): Move saving of object to callers. * expr.cc (ExprVisitor::visit(CallExp)): Save object reference before passing to build_vindex_ref. (ExprVisitor::visit(DelegateExp)): Likewise. 2016-12-07 Iain Buclaw * d-spec.c (lang_specific_driver): Remove error handling. * d-lang.cc (d_parse_file): Don't error twice. 2016-12-06 Iain Buclaw * d-spec.c (lang_specific_driver): Remove 'added' variable. 2016-12-04 Iain Buclaw * d-decls.cc (get_symbol_decl): Use needsCodegen to determine whether template instance is extern or not. 2016-12-02 Iain Buclaw * d-glue.cc (escapePath): Move to dfrontend. (readFile): Likewise. (writeFile): Likewise. (ensurePathToNameExists): Likewise. 2016-12-01 Iain Buclaw * d-target.cc: Include memmodel.h. * d-attrib.c (d_handle_section_attribute): No longer set user_defined_section_attribute. 2016-11-25 Iain Buclaw * types.cc (TypeVisitor::visit(Type)): Update. 2016-11-24 Iain Buclaw * d-codegen.cc (build_struct_literal): Stop after first field assignment in union constructor. (build_class_instance): Skip void initialized fields. * expr.cc (ExprVisitor::visit(StructLiteralExp)): Likewise. 2016-11-22 Iain Buclaw * d-decls.cc (get_symbol_decl): Don't set alignment if STRUCTALIGN_DEFAULT. 2016-11-21 Iain Buclaw * d-todt.cc (ClassDeclaration::toDt): Update. (ClassDeclaration::toDt2): Remove function. (TypeSArray::toDtElem): Remove function. (dt_chainon): Remove function. (dt_zeropad): Remove function. (dt_container): Remove function. (dt_container2): Rename to dt_container. All callers updated. * d-objfile.cc (VarDeclaration::toObjFile): Update. 2016-11-20 Iain Buclaw * d-lang.cc (copy_lang_decl): Rename to d_dup_lang_specific_decl. (LANG_HOOKS_DUP_LANG_SPECIFIC_DECL): Redefine. * d-decls.cc (make_alias_for_thunk): Call dup_lang_specific_decl. (make_thunk): Likewise. 2016-11-19 Iain Buclaw * d-codegen.h (FuncFrameInfo): Remove type. All users updated to interface with new frame macro accessors. (build_frame_type): Mark as static. (get_frameinfo): Update to return a tree type. * d-lang.cc (LANG_HOOKS_TREE_SIZE): Redefine. (LANG_HOOKS_PRINT_XNODE): Redefine. (d_tree_size): New function. (d_print_xnode): New function. (d_tree_node_structure): New function. * d-tree.def (FUNCFRAME_INFO): New tree_code. * d-tree.h (tree_frame_info): New type. (FRAMEINFO_CREATES_FRAME): New macro accessor. (FRAMEINFO_STATIC_CHAIN): New macro accessor. (FRAMEINFO_IS_CLOSURE): New macro accessor. (FRAMEINFO_TYPE): New macro accessor. (lang_decl): Replace frame_info field with a tree type. (d_tree_node_structure_enum): New type. (lang_tree_node): Update GTY tags. 2016-11-19 Iain Buclaw * d-decls.cc (setup_symbol_storage): Remove function. (Dsymbol::toSymbol): Remove function and all overrides. All callers updated to call ... (get_symbol_decl): ... New function. 2016-11-06 Iain Buclaw * d-lang.cc (output_modules): Remove variable. (output_module): Remove variable. (d_gcc_get_output_module): Remove function. All callers updated to use Module::rootModule. * d-objfile.cc (FuncDeclaration::toObjFile): Mark all functions being constructed here as TREE_STATIC. (output_module_p): Remove function. All callers updated to call Module::isRoot. 2016-11-05 Iain Buclaw * d-decls.cc (get_template_storage_info): Remove function. (setup_symbol_storage): Use Dsymbol::isInstantiated instead. 2016-11-05 Iain Buclaw * d-codegen.cc (build_struct_literal): Handle anonymous fields. (build_class_instance): New functions. (find_aggregate_field): Update signature. All callers updated. * d-todt.cc (dt_chainon): Mark as static. (dt_zeropad): Likewise. (dt_container): Likewise. (ClassReferenceExp::toInstanceDt): Remove function. (ClassReferenceExp::toDt2): Remove function. 2016-11-01 Iain Buclaw * d-tree.h (lang_decl): Remove readonly field. (DECL_LANG_READONLY): Remove macro. All callers updated. 2016-10-29 Iain Buclaw * d-decls.cc (ClassReferenceExp::toSymbol): Use class record type for static symbol. * d-lang.cc (global_context): New static variable. (global_declarations): New static variable. (d_nametype): Pass built-in types to debug_hooks::type_decl. (d_add_global_declaration): Remove function, update all callers. (get_global_context): New function. (d_pushdecl): Push decls to global, or bindings list here. (StructDeclaration::toObjFile): Send type decl to d_pushdecl. (ClassDeclaration::toObjFile): Likewise. (InterfaceDeclaration::toObjFile): Likewise. (EnumDeclaration::toObjFile): Likewise. (FuncDeclaration::toObjFile): Send finished decl to d_pushdecl. (d_finish_symbol): Likewise. (emit_modref_hooks): Likewise. (d_comdat_linkage): Don't set DECL_COMDAT on non-public decls. (setup_symbol_storage): Don't set DECL_ABSTRACT_P on templates. (d_finish_compilation): Remove check for type decls. (build_type_decl): Don't add to global decl list, just call rest_of_decl_compilation. * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Send finished decl to d_pushdecl. * toir.cc (IRVisitor::visit(SwitchStatement)): Likewise. (IRVisitor::end_scope): Mark bind expr as having side effects. * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoTupleDeclaration)): Send finished decl to d_pushdecl. 2016-10-29 Iain Buclaw * d-codegen.cc (layout_aggregate_type): Continue searching based on aggregate members, not just fields. * types.cc (TypeVisitor::visit(TypeEnum)): Use void for opaque enums. (TypeVisitor::visit(TypeStruct)): Don't give opaque structs a size. 2016-10-27 Iain Buclaw * expr.cc (ExprVisitor::visit(AssignExp)): Don't set TREE_ADDRESSABLE. * d-codegen.cc (build_assign): Handle setting up INIT_EXPR from a value returning via NRVO here instead. 2016-10-26 Iain Buclaw * d-codegen.cc (d_build_call): Only convert CALL_EXPRs into a TARGET_EXPR if return type is TREE_ADDRESSABLE. (build_assign): Use TARGET_EXPR accessors. (compound_expr): Likewise. 2016-10-15 Iain Buclaw * d-codegen.h (d_types_same): Return early if types are identical. 2016-10-09 Iain Buclaw * d-decls.cc (FuncDeclaration::toThunkSymbol): Rename to make_thunk. All callers updated. (finish_thunk): Update signature. 2016-10-09 Iain Buclaw * d-objfile.h (Thunk): Remove type, move offset field to ... * d-tree.h (lang_decl): ... here. Replace Thunk field with a tree. (THUNK_LANG_OFFSET): New macro accessor. * d-lang.cc (copy_lang_decl): New function. * d-decls.cc (FuncDeclaration::toThunkSymbol): Use new thunk macros. 2016-10-09 Iain Buclaw * d-decls.cc (finish_thunk): Add assert that current_function_decl is never set when function is called. (DeferredThunk): Remove type. (deferred_thunks): Remove variable. (write_deferred_thunks): Remove function. All callers updated. (use_thunk): Remove function. (FuncDeclaration::toThunkSymbol): Call finish_thunk when done. 2016-10-08 Iain Buclaw * d-objfile.cc (deferred_thunks): Move to d-decls.cc. (write_deferred_thunks): Likewise. (use_thunk): Likewise. Mark as static. (thunk_labelno): Likewise. (make_alias_for_thunk): Likewise. (finish_thunk): Likewise. 2016-10-08 Iain Buclaw * d-decls.cc (setup_symbol_storage): Remove unused parameters. 2016-10-07 Iain Buclaw * d-decls.cc (ClassReferenceExp::toSymbol): Rename to build_new_class_expr. All callers updated. (StructLiteralExp::toSymbol): Remove function. Inline into caller ... * expr.cc (ExprVisitor::visit(AddrExpr)): ... here. 2016-10-07 Iain Buclaw * d-decls.cc (TypeInfoDeclaration::toSymbol): Rename to get_typeinfo_decl. All callers updated. (TypeInfoDeclVisitor): New visitor helper for get_typeinfo_decl. * d-codegen.cc (get_decl_tree): Add check for building typeinfo decls. 2016-10-05 Iain Buclaw * d-decls.cc (AggregateDeclaration::toInitializer): Rename to aggregate_initializer. All callers updated. (EnumDeclaration::toInitializer): Rename to enum_initializer. (Module::toSymbol): Rename to get_moduleinfo_decl. (ClassDeclaration::toSymbol): Rename to get_classinfo_decl. (InterfaceDeclaration::toSymbol): Merge into get_classinfo_decl. 2016-10-03 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Remove saving of current module decl before calling semantic. (StructLiteralExp::toSymbol): Don't handle sinit. (ClassReferenceExp::toSymbol): Likewise. (AggregateDeclaration::toInitializer): Likewise. (EnumDeclaration::toInitializer): Likewise. * d-glue.cc (toInitializer): Remove function. * d-objfile.cc (FuncDeclaration::toObjFile): Remove saving of current module decl before calling semantic. * expr.cc (ExprVisitor::visit(CallExpr)): Replace accesses of sinit field with useStaticInit. (ExprVisitor::visit(StructLiteralExp)): Likewise. 2016-10-03 Iain Buclaw * d-decls.cc (ClassDeclaration::toVtblSymbol): Rename to get_vtable_decl. All callers updated. 2016-10-03 Iain Buclaw * d-objfile.cc (setup_symbol_storage): Move function to ... * d-decls.cc (setup_symbol_storage): ... here. Mark as static. (get_template_storage_info): Likewise. 2016-10-03 Iain Buclaw * d-codegen.cc (call_by_alias_p): Check whether caller and callee are nested in the same parent function. * expr.cc (ExprVisitor::visit(CallExp)): Set TREE_PUBLIC directly instead of calling setup_symbol_storage. 2016-10-03 Iain Buclaw * d-objfile.cc (VarDeclaration::toObjFile): Always generate DECL_INITIAL for all kinds of var decls. * d-codegen.cc (build_address): Use the DECL_INITIAL directly if taking the address of a CONST_DECL. 2016-10-02 Iain Buclaw * d-tree.h (DECL_LANG_TREE): Remove macro. All callers updated. 2016-10-02 Iain Buclaw * d-objfile.h (Symbol): Remove struct. Update all functions to return a tree instead. Remove all new allocations of Symbol. * d-tree.h (DECL_LANG_READONLY): Update accessor. (DECL_LANG_INITIAL): Likewise. (DECL_LANG_TREE): Likewise. (SET_DECL_LANG_FRAME_FIELD): Likewise. (DECL_LANG_FRAME_FIELD): Likewise. (SET_DECL_LANG_NRVO): Likewise. (DECL_LANG_NRVO): Likewise. (DECL_LANG_THUNKS): Likewise. (DECL_LANG_FRAMEINFO): Likewise. 2016-10-01 Iain Buclaw * d-objfile.h (Symbol): Remove symbol identifier field. * d-tree.h (DECL_LANG_IDENTIFIER): Remove macro. Update callers to instead use DECL_ASSEMBLER_NAME. (DECL_LANG_PRETTY_NAME): Remove macro. 2016-09-26 Johannes Pfau * d-objfile.cc (d_finish_function): Handle template mixins (issue 231). 2016-09-25 Iain Buclaw * d-decls.cc (Dsymbol::toSymbolX): Remove function, update all callers to use ... (make_internal_name): ... New function. * d-objfile.h (Symbol): Replace char* fields with tree. * d-tree.h (lang_identifier): Add pretty_ident field. (IDENTIFIER_PRETTY_NAME): New macro accessor. (DECL_LANG_PRETTY_NAME): Update to use IDENTIFIER_PRETTY_NAME. 2016-09-19 Iain Buclaw * d-objfile.h (Symbol): Move declaration-specific fields to ... * d-tree.h (lang_decl): ... here. (DECL_LANG_READONLY): Update to reference lang_decl field. (DECL_LANG_INITIAL): Likewise. (DECL_LANG_FRAME_FIELD): Likewise. (DECL_LANG_NRVO): Likewise. (DECL_LANG_THUNKS): Likewise. (DECL_LANG_FRAMEINFO): Likewise. (SET_DECL_LANG_FRAME_FIELD): New setter macro, update all callers. (SET_DECL_LANG_NRVO): Likewise. 2016-09-19 Iain Buclaw * d-builtins.cc (d_build_builtins_module): Set DECL_LANG_SPECIFIC before using any DECL_LANG accessor macros. (maybe_set_builtin_1): Likewise. * d-codegen.cc (maybe_set_intrinsic): Likewise. (layout_aggregate_members): Likewise. d-decls.cc (VarDeclaration::toSymbol): Likewise. (FuncDeclaration::toThunkSymbol): Likewise. (ClassDeclaration::toSymbol): Likewise. (InterfaceDeclaration::toSymbol): Likewise. (Module::toSymbol): Likewise. (StructLiteralExp::toSymbol): Likewise. (ClassReferenceExp::toSymbol): Likewise. (ClassDeclaration::toVtblSymbol): Likewise. (AggregateDeclaration::toInitializer): Likewise. (EnumDeclaration::toInitializer): Likewise. 2016-09-19 Iain Buclaw * d-tree.h (DECL_LANG_IDENTIFIER): New macro accessor, use instead of direct field accesses. (DECL_LANG_PRETTY_NAME): Likewise. (DECL_LANG_READONLY): Likewise. (DECL_LANG_INITIAL): Likewise. (DECL_LANG_TREE): Likewise. (DECL_LANG_FRAME_FIELD): Likewise. (DECL_LANG_NRVO): Likewise. (DECL_LANG_THUNKS): Likewise. (DECL_LANG_FRAMEINFO): Likewise. 2016-09-18 Iain Buclaw * imports.cc (ImportVisitor::visit(ScopeDsymbol)): New visit method. 2016-09-17 Iain Buclaw * d-todt.cc (ArrayInitializer::toDt): Update to use build_expr. * d-codegen.cc (d_array_value): Don't override default const and static bits for array constructors. 2016-09-16 Iain Buclaw * d-codegen.cc (lower_struct_comparison): Don't compare vectors in the same way as integers. 2016-09-11 Iain Buclaw * d-todt.cc (Type::toDt): Remove function, inline into callers. (TypeVector::toDt): Likewise. (TypeSArray::toDt): Likewise. (TypeStruct::toDt): Likewise. 2016-09-11 Iain Buclaw * d-decls.cc (FuncDeclaration::toSymbol): Save current module decl before calling function semantic. * d-objfile.cc (FuncDeclaration::toObjFile): Likewise. 2016-09-11 Iain Buclaw * types.cc: Document and reformat file. 2016-09-10 Johannes Pfau * d-objfile.cc (setup_symbol_storage): Setup TREE_PUBLIC before calling decl_default_tls_model. * d-typeinfo.cc (TypeInfoVisitor::find_field): Move method... * d-codegen.cc (find_aggregate_field): here. * d-objfile.cc (build_simple_function): Extract some code into new function. (build_simple_function_decl): Extracted from build_simple_function. * d-objfile.cc (build_moduleinfo): Split into emit_moduleinfo_hooks and emit_modref_hooks. (build_dso_registry_var): New function. (emit_dso_registry_cdtor): Likewise. (emit_dso_registry_helpers): Likewise. (emit_dso_registry_hooks): Likewise. (emit_moduleinfo_hooks): Only emit hooks if required druntime functions are available. * d-objfile.cc (Module::genmoduleinfo): Rename to build_moduleinfo_symbol. (emit_moduleinfo_hooks): rename to Module::genmoduleinfo. (Module::genmoduleinfo): only call build_moduleinfo_symbol when emitting module info registry code. * d-spec.c (lang_specific_driver): Add -shared-libphobos option, default to static libphobos. * d-lang.opt: Likewise. * d-spec.c: Rename libgphobos2 to libgphobos. 2016-07-11 Iain Buclaw * d-codegen.cc (get_frameinfo): Use hasNestedFrameRefs to determine whether a frame should be created. 2016-07-02 Iain Buclaw * d-objfile.cc (FuncDeclaration::toObjFile): Always convert the DECL_RESULT of NRVO-capable functions into reference decls. 2016-06-21 Iain Buclaw * d-attribs.c (handle_nonnull_attribute): Accept the nonnull attribute in type-generic builtins. * d-codegen.cc (d_build_call): Check AGGREGATE_TYPE_P before testing for aggregate_value_p. 2016-06-20 Johannes Pfau * d-lang.cc (d_handle_option): Add new -ftransition=dip25 and -fmax-error-messages switches. * lang.opt: Likewise. 2016-06-19 Iain Buclaw * d-codegen.cc (get_decl_tree): Remove assert for RESULT_DECL. (convert_for_argument): Handle lazy arguments early. (argument_reference_p): Handle types marked TREE_ADDRESSABLE. (lvalue_p): Add case for TARGET_EXPR. (d_mark_addressable): Likewise. (build_assign): Likewise. (compound_expr): Likewise. (build_target_expr): New function. (d_build_call): Always set CALL_EXPR_RETURN_SLOT_OPT for all calls that return an aggregate in memory. * d-decls.cc (VarDeclaration::toSymbol): Handle reference parameters. * d-lang.cc (d_gimplify_expr): Handle taking address of constructor. * d-objfile.cc (FuncDeclaration::toObjFile): Handle reference return. * expr.cc (ExprVisitor::visit(AssignExp)): Mark LHS as addressable if RHS assignment is a returned aggregate. * types.cc (TypeVisitor::visit(TypeStruct)): Mark the RECORD_TYPE of non-trivial structs as TREE_ADDRESSABLE. (TypeVisitor::visit(TypeClass)): Mark all classes as TREE_ADDRESSABLE. (TypeVisitor::visit(TypeFunction)): Don't set TREE_ADDRESSABLE. (TypeVisitor::visit(TypeDelegate)): Likewise. 2016-06-19 Iain Buclaw * d-codegen.cc (lvalue_p): Add more cases to look for. (build_address): Mark expression as addressable after stabilizing. (d_mark_addressable): Remove special cases. (d_mark_used): Add cases for other kinds of DECLs. (build_struct_comparison): Stabilize before saving. (modify_expr): Remove overload. Updated all callers. (build_vinit): Remove function. Updated all callers to use ... (build_assign): ... New function. (lvalue_p): Remove tests in default case. * expr.cc (build_expr_dtor): Rewrite assignments to elide a temporary. 2016-06-16 Iain Buclaw * d-codegen.cc (make_temp): Rename to d_save_expr. (maybe_make_temp): Remove function. Updated all callers to use d_save_expr(). (vcompound_expr): Remove function. Updated all callers to use compound_expr(). (maybe_compound_expr): Likewise. (maybe_vcompound_expr): Likewise. (vmodify_expr): Remove function. Updated all callers to use modify_expr(). (lvalue_p): New function. 2016-06-15 Iain Buclaw * d-codegen.cc (add_stmt): Don't add statements without side effects. Push each COMPOUND_EXPR as a separate statement. (build_local_temp): Use input_location. (create_temporary_var): Likewise. (d_has_side_effects): Remove function. Updated all callers to use TREE_SIDE_EFFECTS. (stabilize_expr): New function. Updated all routines that check for COMPOUND_EXPR to use it. * expr.cc (ExprVisitor::visit(EqualExp)): Use maybe_make_temp to save expressions. Use build_boolop for constructed conditions. (ExprVisitor::visit(CatAssignExp)): Stabilize RHS before assignment. (ExprVisitor::visit(NewExp)): Don't always create SAVE_EXPR. (ExprVisitor::visit(AssocArrayLiteralExp)): Likewise. (ExprVisitor::visit(ArrayLiteralExp)): Evaluate elements before appending to constructor fields. (ExprVisitor::visit(StructLiteralExp)): Likewise. 2016-06-12 Iain Buclaw * d-convert.cc (d_build_truthvalue_op): Fold truthvalue operation. (d_truthvalue_conversion): Use zero constant of expression type. 2016-06-09 Iain Buclaw * d-codegen.cc (build_address): Handle ERROR_MARK and COMPOUND_EXPR. (build_nop): Likewise. (indirect_ref): Likewise. (build_deref): Likewise. (d_build_call): Only create temporaries if more than one argument has side effects. * expr.cc (get_compound_value): Remove function. (build_expr_dtor): Wrap cleanups in a TRY_FINALLY_EXPR only if the expression has side effects. 2016-06-08 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Remove d-typinf.o, add typeinfo.o. * d-codegen.cc (build_typeinfo): Move to ... * typeinfo.cc: ... here. New file. * d-objfile.cc (TypeInfoDeclaration::toObjFile): Use layout_typeinfo. * d-todt.cc (verify_structsize): Remove function. (TypeInfoDeclaration::toDt): Remove function and overrides. * d-typinf.cc: Remove file. Contents moved to typeinfo.cc. * expr.cc (ExprVisitor::visit(DeleteExp)): Use build_typeinfo. (ExprVisitor::visit(NewExp)): Likewise. 2016-06-08 Iain Buclaw * dfrontend: Update to D front-end version 2.068. * d-codegen.cc (insert_type_modifiers): Don't build TYPE_QUAL_VOLATILE types. Set TYPE_SHARED instead. (insert_aggregate_field): Propagate TYPE_SHARED to TREE_ADDRESSABLE. (array_bounds_check): Use BOUNDSCHECK interface. * d-lang.cc (d_init_options): Likewise. (d_init): Likewise. (d_handle_option): Likewise. (d_post_options): Likewise. * d-decls.cc (VarDeclaration::toSymbol): Propagate TYPE_SHARED_to TREE_ADDRESSABLE. * d-objfile.cc (ClassDeclaration::toObjFile): Make overload shadowing an error. Remove call to _d_hidden_func. (TypeInfoDeclaration::toObjFile): Updated template emission rules. (FuncDeclaration::toObjFile): Likewise. * d-port.cc (Port::readwordLE): New function. (Port::readwordBE): New function. (Port::readlongLE): New function. (Port::readlongBE): New function. * d-todt.cc (dt_container2): Handle error_mark_node. (dt_container): Likewise. (TypeInfoStructDeclaration::toDt): Updated template emission rules. * d-typinf.cc (genTypeInfo): Likewise. (getTypeInfo): Remove function. (getTypeInfoType): New function. (isSpeculativeType): New function. * d-tree.h (TYPE_SHARED): New macro. * expr.cc (ExprVisitor::visit(CondExp)): Don't generate dtors in condition expression. (ExprVisitor::visit(AssignExp)): Update for frontend changes. (ExprVisitor::visit(DeleteExp)): Likewise. (ExprVisitor::visit(CallExp)): Likewise. (ExprVisitor::visit(DelegateExp)): Likewise. (ExprVisitor::visit(TypeidExp)): New function. * lang.opt (bounds_check_set_manually): Remove variable. (ftransition=complex): New option. * runtime.def (HIDDEN_FUNC): Remove runtime function. 2016-06-07 Iain Buclaw * d-codegen.cc (build_alignment_field): New function. (build_struct_literal): Update signature, updated all callers. Add anonymous fields to fill alignment holes in constructor. (fill_alignment_field): Remove function. (fill_alignment_holes): Remove function. (finish_aggregate_type): Don't add anonymous fields. 2016-06-05 Iain Buclaw * d-codegen.cc (d_build_call): Separate parameter to pass from it's construction expression. * expr.cc (build_dtor_list): New function. (get_compound_value): New function. (build_expr_dtor): Update to use helper functions. (build_return_dtor): New function. * toir.cc (IRVisitor::visit(ReturnStatement)): Use it. 2016-06-04 Iain Buclaw * d-codegen.cc (build_deref): Handle ERROR_MARK nodes early. (build_array_index): Likewise. 2016-05-29 Johannes Pfau * toir.cc (IRVisitor::visit(SwitchStatement)): Set correct type for the string table for switch(string) statements. 2016-05-24 Iain Buclaw * d-codegen.cc (convert_expr): Return empty constructor for null to associative array conversions. * expr.cc (ExprVisitor::visit(NullExp)): Likewise. 2016-05-21 Iain Buclaw * d-codegen.cc (build_struct_literal): Don't set TREE_STATIC. (build_boolop): Remove side effects from aggregate types only. * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Don't check initializer_constant_valid_p until after constructor is built. (ExprVisitor::visit(StructLiteralExp)): Likewise. 2016-05-16 Iain Buclaw * expr.cc (ExprVisitor::visit(AssignExp)): Build the rhs constructor before the lhs declaration. (ExprVisitor::visit(DeclarationExp)): Compile the declaration and initializer before pushing it to vars_in_scope. (build_expr_dtor): Compound all dtors in reverse. 2016-05-16 Johannes Pfau * expr.cc (ExprVisitor::visit(IdentityExp*)): Remove side-effects before comparing two floating point types. * d-codegen.cc (build_struct_comparison): Remove side-effects before comparing two values. (build_boolop): Likewise. 2016-05-15 Iain Buclaw * d-todt.cc (Expression::toDt): Remove function and all overrides. Update all callers to use build_expr. * expr.cc (ExprVisitor::visit(SymOffExp)): Move check for non-constant expressions in static initializer data to ... (build_expr): ... here. * toir.cc (IRVisitor::visit(SwitchStatement)): Build array of indexes directly using build_artificial_decl. 2016-05-15 Iain Buclaw * expr.cc (ExprVisitor::visit(IdentityExp*)): Remove side-effects before comparing two dynamic arrays. 2016-05-14 Iain Buclaw * d-codegen.cc (get_decl_tree): First check if cfun is set. * d-todt.cc (StructLiteralExp::toDt): Update call to build_expr. (SymOffExp::toDt): Likewise. (VarExp::toDt): Likewise. (FuncExp::toDt): Likewise. (VectorExp::toDt): Likewise. * expr.cc (ExprVisitor::visit(SymbolExp)): Remove function. (ExprVisitor::visit(SymOffExp)): New function. (ExprVisitor::visit(VarExp)): New function. (ExprVisitor::visit(StructLiteralExp)): Don't return static initializer symbol if constant literal requested. 2016-05-13 Iain Buclaw * d-codegen.cc (build_struct_literal): Maybe set TREE_CONSTANT or TREE_STATIC on the returned constructor. Allow building struct literals with initializer list out of order. Add check and error when initializer overlaps previous field. Don't explicitly set empty initializers for anonymous aggregates or artificial fields. 2016-05-12 Iain Buclaw * d-codegen.cc (build_array_from_val): New function. * expr.cc (ExprVisitor::visit(StructLiteralExp)): Use it. 2016-05-11 Iain Buclaw * d-codegen.cc (convert_expr): Use build_nop to cast between two static arrays of the same size. * d-todt.cc (IntegerExp::toDt): Update call to build_expr. (RealExp::toDt): Likewise. (ComplexExp::toDt): Likewise. (StringExp::toDt): Likewise. (NullExp::toDt): Use build_expr to generate initializer. (ArrayLiteralExp::toDt): Likewise. (CastExp::toDt): Likewise. (ClassReferenceExp::toDt): Likewise. (ClassReferenceExp::toDtI): Remove function. * expr.cc (ExprVisitor::visit(CastExp)): Forward constp to the next leaf expression in the tree. (ExprVisitor::visit(AddrExp)): Likewise. (ExprVisitor::visit(FuncExp)): Likewise. (ExprVisitor::visit(ArrayLiteralExp)): Likewise. (ExprVisitor::visit(StructLiteralExp)): Likewise. (ExprVisitor::visit(VectorExp)): Likewise. (ExprVisitor::visit(ClassReferenceExp)): Adjust reference for constp. 2016-05-09 Iain Buclaw * d-objfile.cc (get_unique_name): Remove function. (build_artificial_decl): New function. (d_finish_symbol): Use build_artificial_decl. (build_moduleinfo): Likewise. * d-decls.cc (StructLiteralExp::toSymbol): Likewise. (ClassReferenceExp::toSymbol): Likewise. 2016-05-07 Iain Buclaw * expr.cc (ExprVisitor::visit(BinExp)): New function. (ExprVisitor::visit(XorExp)): Remove function. (ExprVisitor::visit(OrExp)): Likewise. (ExprVisitor::visit(AndExp)): Likewise. (ExprVisitor::visit(UshrExp)): Likewise. (ExprVisitor::visit(ShrExp)): Likewise. (ExprVisitor::visit(ShlExp)): Likewise. (ExprVisitor::visit(ModExp)): Likewise. (ExprVisitor::visit(DivExp)): Likewise. (ExprVisitor::visit(MulExp)): Likewise. (ExprVisitor::visit(MinExp)): Likewise. (ExprVisitor::visit(AddExp)): Likewise. (ExprVisitor::visit(BinAssignExp)): New function. (ExprVisitor::visit(XorAssignExp)): Remove function. (ExprVisitor::visit(OrAssignExp)): Likewise. (ExprVisitor::visit(AndAssignExp)): Likewise. (ExprVisitor::visit(ShrAssignExp)): Likewise. (ExprVisitor::visit(ShlAssignExp)): Likewise. (ExprVisitor::visit(ModAssignExp)): Likewise. (ExprVisitor::visit(DivAssignExp)): Likewise. (ExprVisitor::visit(MulAssignExp)): Likewise. (ExprVisitor::visit(PowAssignExp)): Likewise. (ExprVisitor::visit(MinAssignExp)): Likewise. (ExprVisitor::visit(AddAssignExp)): Likewise. 2016-05-06 Iain Buclaw * expr.cc (ExprVisitor::ExprVisitor): Update signature. (ExprVisitor::visit(AddrExp)): Handle constant expressions. (ExprVisitor::visit(FuncExp)): Likewise. (ExprVisitor::visit(ComplexExp)): Likewise. (ExprVisitor::visit(StringExp)): Likewise. (ExprVisitor::visit(ArrayLiteralExp)): Likewise. (ExprVisitor::visit(StructLiteralExp)): Likewise. (ExprVisitor::visit(NullExp)): Likewise. (ExprVisitor::visit(ClassReferenceExp)): Likewise. (build_expr): Update signature. 2016-05-05 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Add d/expr.o. Remove d/d-elem.o * d-codegen.cc (size_mult_expr): New function. * d-tree.h (build_expr): New function, update all callers to toElem. (build_expr_dtor): New function, update all callers to toElemDtor. * expr.cc: New file. * d-elem.cc: Remove file. 2016-05-03 Iain Buclaw * d-target.cc (Target::init): Target::realpad value should be size minus precision. 2016-04-29 Iain Buclaw * d-codegen.cc (finish_aggregate_type): Use SET_TYPE_ALIGN. * types.cc (TypeVisitor::visit(TypeStruct)): Likewise. * d-decls.cc (ClassDeclaration::toVtblSymbol): Use SET_DECL_ALIGN. * d-objfile.cc (d_finish_symbol): Likewise. * d-target.cc (Target::fieldalign): Likewise. 2016-04-29 Iain Buclaw * d-todt.cc (TypeSArray::toDtElem): Remove special handling for arrays of vectors. 2016-04-23 Iain Buclaw * d-builtins.cc (build_dtype): Make function static. * d-lang.cc (d_init_exceptions): Remove function. * d-codegen.h: Move visitor declarations to ... * d-tree.h: ... here. (lang_decl): Remove `d_` prefix from fields. (lang_type): Likewise. * d-lang.cc (build_d_type_lang_specific): Rename to build_lang_type. (build_d_decl_lang_specific): Rename to build_lang_decl. * imports.cc: Update includes. 2016-03-29 Johannes Pfau * d-objfile.cc (d_comdat_linkage): Rewrite template duplicate handling to generate only one backend tree for all duplicates. (FuncDeclaration::toObjFile): Likewise. (VarDeclaration::toObjFile): Likewise. * d-decls.cc (FuncDeclaration::toSymbol): Likewise. (VarDeclaration::toSymbol): Likewise. * d-objfile.cc (get_template_storage_info): Extract function from setup_symbol_storage. (setup_symbol_storage): Likewise. * d-tree.h (lang_identifier): Add field for Dsymbol. (IDENTIFIER_LANG_SPECIFIC): New macro. (IDENTIFIER_DSYMBOL): Likewise. 2016-03-29 Iain Buclaw * d-codegen.cc (fill_alignment_field): Call layout_decl on field. (finish_aggregate_type): Add assertion that TYPE_MODE is equal. 2016-03-29 Iain Buclaw * d-codegen.cc (convert_expr): Replace call build_integer_cst with size_int. (convert_for_assignment): Likewise. (build_struct_comparison): Likewise. (d_assert_call): Likewise. * d-elem.cc (IdentityExp::toElem): Likewise. (AssignExp::toElem): Likewise. (IndexExp::toElem): Likewise. (SymbolExp::toElem): Likewise. (NewExp::toElem): Likewise. (ArrayLiteralExp::toElem): Likewise. (AssocArrayLiteralExp::toElem): Likewise. 2016-03-28 Iain Buclaw * d-tree.h (CLASS_TYPE_P): New macro. * d-codegen.cc (build_struct_literal): Check RECORD_OR_UNION_TYPE_P before testing ANON_AGGR_TYPE_P. (fill_alignment_field): New function. (fill_alignment_holes): New function. (finish_aggregate_type): Call fill_alignment_holes before computing backend type mode. 2016-03-28 Iain Buclaw * d-tree.h (D_METHOD_CALL_EXPR): Removed `D_' prefix from macro, updated all callers. (D_TYPE_IMAGINARY_FLOAT): Likewise. (D_LABEL_VARIABLE_CASE): Likewise. * d-codegen.cc (build_delegate_cst): Always return valid constructor. (get_object_method): Remove function. (build_vindex_ref): New function. * d-elem.cc (FuncExp::toElem): Use the real function pointer type when converting to delegate. (CallExp::toElem): Handle setting up virtual functions directly. (DelegateExp::toElem): Likewise. (DotVarExp::toElem): Remove handling of virtual functions. 2016-03-28 Iain Buclaw * d-codegen.h (lang_dtype): Remove function. (lang_ddecl): Remove function. * d-tree.h (TYPE_LANG_FRONTEND): New macro, replace all uses of lang_dtype function. (DECL_LANG_FRONTEND): New macro. * d-attribs.c: Update includes. * d-builtins.cc: Likewise. * d-codegen.cc: Likewise. * d-incpath.cc: Likewise. * d-lang.cc: Likewise. * d-objfile.cc: Likewise. 2016-03-27 Iain Buclaw * d-codegen.h (function_type_p): Remove function. * d-codegen.cc (d_build_call): Use FUNC_OR_METHOD_P macro. (build_bounds_condition): Update signature. (d_assert_call): Likewise. (insert_aggregate_field): Likewise. * d-objfile.cc (get_linemap): Likewise. * d-lang.h: Remove file, updated all includes. Moved forward declarations of types and functions to ... * d-tree.h: ... here. 2016-03-20 Iain Buclaw * d-codegen.cc (d_checked_index): Remove function. (d_bounds_condition): Remove function. (build_bounds_condition): New function. * d-elem.cc (IndexExp::toElem): Use build_bounds_condition. (SliceExp::toElem): Likewise. (EqualExp::toElem): Convert expressions to dynamic arrays when inlining comparison. Don't pass zero length arrays to memcmp. 2016-03-19 Iain Buclaw * d-codegen.cc (d_array_convert): New function overload. * d-elem.cc (CatExp::toElem): Call new runtime function _d_arraycatnTX when flattening multiple concatenations. (NewExp::toElem): Update call construction for new signatures of runtime functions _d_newarraymTX and _d_newarraymiTX. * runtime.def (NEWARRAYMTX): Update signature. (NEWARRAYMITX): Likewise, (ARRAYCATNT): Remove runtime function. (ARRAYCATNTX): New runtime function. 2016-03-07 Iain Buclaw * imports.cc (ImportVisitor::visit(Declaration)): Don't assume toSymbol method will cache it's result. 2016-03-06 Iain Buclaw * dfrontend: Update root library to 2.068. * Make-lang.in (D_DMD_OBJS): Add newdelete.o * d-target.cc (Target::classinfosize): New variable, replaces all uses of global CLASSINFO_SIZE. (Target::init): Initialize it. * d-decls.cc (ClassInfoDeclaration::toSymbol): Remove function. 2016-03-05 Iain Buclaw * dfrontend: Update to D front-end version 2.067. * Make-lang.in (D_DMD_OBJS): Add new frontend sources. * d-builtins.cc (d_build_builtins_module): Update signature. (maybe_set_builtin): Rename to d_maybe_set_builtin, update signature. (d_gcc_magic_module): Remove function. * d-codegen.cc (expand_volatile_load): New function. (expand_volatile_store): New function. (expand_intrinsic): Handle volatileLoad and volatileStore intrinsics. * d-decls.cc (Module::toModuleAssert): Remove function. (Module::toModuleUnittest): Remove function. (Module::toModuleArray): Remove function. (TypeAArray::aaGetSymbol): Remove function. * d-elem.cc (AssignExp::toElem): Call _d_arrayassign_{l,r} when generating dynamic array assignment. (IndexExp::toElem): Call _aaGetY when indexing an associative array. (SliceExp::toElem): Use known CTFE result to check whether bounds checks are necessary. (DeleteExp::toElem): Call _d_delstruct when deleting a struct pointer. (Expression::toElemDtor): Don't run cleanup of temporary if it's constructor thrown an exception. (NewExp::toElem): Handle special construction of new() arguments. * d-glue.cc (Loc::Loc): Update signature. (error): Likewise. (toInitializer): New function. * d-lang.cc (d_handle_option): Replace deprecated handlers. (d_post_options): Set flag_max_errors. (d_parse_file): Process any modules marked as builtin. * d-objfile.cc (ClassDeclaration::toObjFile): Don't write out ctors in the vtable marked @disable. * d-target.cc (Target::loadModule): New function. (Target::checkVectorType): New function. * d-specs.c (lang_specific_driver): Handle -v option. * lang-specs.h: Pass -v option to to frontend. 2016-03-04 Iain Buclaw * imports.cc: New file. * d-decls.cc (Dsymbol::toImport): Remove function, update all callers to use build_import_decl. 2016-03-03 Iain Buclaw * d-objfile.cc (gcc_attribute_p): New function. (output_declaration_p): Inline into FuncDeclaration::ObjFile. (unnest_function): Likewise. (FuncDeclaration::toObjFile): Remove named parameter, update all callers to ignore it. (d_comdat_group): Use DECL_ASSEMBLER_NAME for the comdat group. (d_comdat_linkage): Catch duplicate instantiations of templates, put them in the same comdat group. (setup_symbol_storage): Mark templates not to be written as abstract. (d_finish_function): Don't send DECL_ABSTRACT_P functions to backend. (d_finish_compilation): Mark all symbols as needed. * d-objfile.cc: Remove redundant bool parameter from all lowering routines for symbols, update all callers. 2016-02-22 Eugene Wissner * d-lang.cc (d_init): Remove short_double parameter from build_common_tree_nodes. 2016-02-20 Iain Buclaw * intrinsics.def: Split signature macros into three groups. Attributes, types, and helper generators. * d-elem.cc (needsPostblit): Change signature to return boolean, updated all callers. (AssignExp::toElem): Don't assign destination to a temporary in arraycopy call. * toir.cc (IRVisior::visit(ThrowStatement)): Use NOP_EXPR cast to convert thrown exception to Object. (IRVisitor::visit(TryCatchStatement)): Use NOP_EXPR cast to convert caught Object to thrown exception. * d-codegen.cc (void_okay_p): Lazily build the convert to type. * d-lang.cc (parse_int): Remove function. (d_handle_option): Use integral_argument to parse numbers. * d-codegen.cc (lower_struct_comparison): Built custom type if lang_hooks.types.type_for_mode returns nothing. * d-lang.cc (d_type_for_mode): Always support cent/ucent modes. (d_type_for_size): Add support for cent/ucent precision types. (d_signed_or_unsigned_type): Always support cent/ucent precisions. * d-codegen.cc (d_build_call): Remove type promotion handling for variadic arguments. (expand_intrinsic_vaarg): Likewise. * d-lang.cc (d_type_promotes_to): Likewise. * d-elem.cc (AddrExp::toElem): Take address of the static const symbol for the struct literal, not the const constructor. (CallExp::toElem): Don't pass generated static struct literal symbol as the object parameter for DotVar call expressions. * d-codegen.cc (type_va_array): New function. (declaration_type_kind): Remove function. (declaration_reference_p): New function, update all callers of declaration_type_kind. (argument_type_kind): Remove function. (argument_reference_p): New function, update all callers of argument_type_kind. (build_address): Remove special handling of static array va_list. * d-codegen.h (type_kind): Remove enum. 2016-02-18 Iain Buclaw * d-codegen.cc (build_condition): New function. Update all callers that generate a COND_EXPR that returns a value to use it. (build_vcondition): New function. Update all callers that generate a void COND_EXPR to use it. * toir.cc (IRVisitor::visit(DoStatement)): Build a COND_EXPR instead of an EXIT_EXPR to break from the loop. (IRVisitor::visit(ForStatement)): Likewise. 2016-02-14 Iain Buclaw * d-elem.cc: Remove redundant IRState parameter from all lowering routines for expressions, update all callers. 2016-02-07 Iain Buclaw * d-codegen.cc (build_array_set): Use POSTINCREMENT_EXPR to adjust array pointer. (identity_compare_p): New function. (build_struct_memcmp): Refactor into ... (lower_struct_comparison): ... New function. (build_struct_comparison): New function. (build_array_struct_comparison): New function. * d-elem.cc (IdentityExp::toElem): Use build_struct_comparison for RECORD_TYPE values. (EqualExp::toElem): Likewise. Use memcmp for array of structs that pass test for identity_compare_p, or fallback to build_array_struct_comparison. (NewExp::toElem): Remove setting of StructLiteralExp::fillHoles. (StructLiteralExp::toElem): Ignore StructLiteralExp::fillHoles, unless building a union literal. 2016-02-03 Iain Buclaw * d-elem.cc (AssignExp::toElem): Pass parameters for arraycopy and arrayassign in the correct order. 2016-01-31 Iain Buclaw * longdouble.h (longdouble): Use one contiguous array for the real_value data payload. 2016-01-23 Iain Buclaw * toir.cc (IRVisitor::visit (ExtAsmStatement): Do validation of input and output constraints, marking operands as addressable if requested. 2016-01-10 Iain Buclaw * d-codegen.cc (empty_aggregate_p): New function. (d_build_call): Don't pass empty aggregates by value. (build_struct_memcmp): Don't compare empty aggregates by value. * d-elem.cc (IdentityExp::toElem): Likewise. (EqualExp::toElem): Likewise. * (StructLiteralExp::toElem): Don't create temporaries or initialize holes for empty aggregates. * d-lang.cc (empty_modify_p): New function. (d_gimplify_expr): Remove assignments that involve empty aggregates. 2016-01-09 Iain Buclaw * d-builtins.cc (d_builtin_type): Define DEF_FUNCTION_TYPE_9, DEF_FUNCTION_TYPE_10, and DEF_FUNCTION_TYPE_11. (d_init_builtins): Likewise. * d-longdouble.cc (machineMode): Remove function. (longdouble::init): Don't use initialize real format by reference. (longdouble::operator+): Use real_arithmetic instead of REAL_ARITHMETIC. (longdouble::operator-): Likewise. (longdouble::operator*): Likewise. (longdouble::operator/): Likewise. (longdouble::operator%): Likewise. * d-port.cc (Port::isSignallingNan): Use REAL_VALUE_ISSIGNALING_NAN. (Port::fequal): Use real_identical instead of REAL_VALUES_IDENTICAL. * d-target.cc: Include stor-layout.h header. * lang.opt: Remove documentation for switches defined elsewhere. 2016-01-09 Iain Buclaw * d-codegen.cc (get_libcall): Use set_call_expr_flags to apply runtime function attributes. * d-codegen.h (LibCallFlag): Remove type. * runtime.def: Replace LibCallFlag with ECF everywhere. Copyright (C) 2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/ChangeLog-2017 ================================================ 2017-12-23 Iain Buclaw * intrinsics.def (INTRINSIC_MULUI): Declare. 2017-12-19 Iain Buclaw * d-codegen.cc (build_target_expr): Update signature. (force_target_expr): New function. (build_address): Use force_target_expr to store temporary. (d_build_call): Likewise. * d-lang.cc (d_gimplify_expr): Likewise. * d-tree.h (language_function): Update type for vars_in_scope from vec to vec. (force_target_expr): Declare. * decl.cc (DeclVisitor::visit(VarDeclaration)): Put vars with scope destructors into a TARGET_EXPR, setting its cleanup. (declare_local_var): Don't push vars with scope destructors into the function binding level. * expr.cc (ExprVisitor::visit(DeclarationExp)): Don't handle scope destructors. (ExprVisitor::visit(CallExp)): Handle calling constructors using temporary objects. (build_dtor_list): Remove function. (build_expr_dtor): Put result into a CLEANUP_POINT_EXPR if any new temporaries needing destruction were added to scope. (build_return_dtor): Likewise. * toir.cc (add_stmt): Set CLEANUP_POINT_EXPR type as void. 2017-12-19 Iain Buclaw * d-attribs.c (attr_noreturn_exclusions): New array. (attr_returns_twice_exclusions, attr_const_pure_exclusions): Likewise. (attr_inline_exclusions, attr_noinline_exclusions): Likewise. (d_langhook_common_attribute_table): Swap affects_identity and handler fields. Initialize new member of struct attribute_spec. (d_langhook_attribute_table): Likewise. (handle_weakref_attribute): Remove function. 2017-12-17 Iain Buclaw * d-codegen.cc (stabilize_expr): Handle assignment expressions. (get_frame_for_symbol): Adjust the 'this' field of frames of overridden interface functions. * d-diagnostic.cc (expand_format): Rewrite '%X' format as '%x'. * decl.cc (DeclVisitor::visit(ClassDeclaration)): Handle future attribute. * expr.cc (ExprVisitor::binop_assignment): Ensure RHS is evaluated before LHS. (ExprVisitor::visit(SliceExp)): Always save lower bounds if upper has any side effects. * typeinfo.cc (TypeInfoVisitor::TypeInfoClassDeclaration): Use ClassDeclaration::isAbstract. (TypeInfoVisitor::visit(TypeInfoTupleDeclaration)): Mark internal reference as public and hidden. 2017-12-10 Iain Buclaw * d-codegen.cc (build_alignment_field): Set DECL_PADDING_P and DECL_FIELD_CONTEXT on generated fields. (build_struct_literal): Use build_zero_cst to generate padding. * decl.cc (build_type_decl): Set public and decl assembler name. 2017-12-10 Iain Buclaw * types.cc (TypeVisitor::visit(TypeClass)): Check for duplicate declarations before adding method. 2017-12-09 Iain Buclaw * expr.cc (ExprVisitor::visit(AddrExp)): Build internal struct literal symbol before generating its initializer. 2017-12-09 Iain Buclaw * d-lang.cc (d_parse_file): Set first_global_object_name. 2017-12-09 Iain Buclaw * lang.opt (fmodule-filepath=): Rename to fmodule-file. * d-lang.cc (d_handle_option): Update case for OPT_fmodule_file_. 2017-12-09 Iain Buclaw * d-tree.h (CALL_EXPR_ARGS_ORDERED): Define. * d-codegen.cc (d_build_call): Set CALL_EXPR_ARGS_ORDERED for functions with D linkage. * d-lang.cc (d_gimplify_expr): Handle CALL_EXPR_ARGS_ORDERED. 2017-12-09 Eugene Wissner * toir.cc (IRVisitor::visit(SwitchStatement)): Set SWITCH_ALL_CASES_P on switch statements. Set SWITCH_BREAK_LABEL_P on the artificial label created for break statements from a switch. 2017-12-04 Eugene Wissner * toir.cc (IRVisitor::visit(SwitchStatement)): Build SWITCH_EXPR using build2 instead of build3. 2017-11-14 Eugene Wissner * decl.cc (finish_thunk): Drop frequency argument from symbol_table::create_edge. * d-lang.cc (d_post_options): Set default value of -Wreturn-type to false. 2017-11-11 Iain Buclaw * d-codegen.cc (build_float_cst): Remove float rounding check. * d-longdouble.cc (longdouble::to_int): Don't round floats before int conversion. * expr.cc (ExprVisitor::binary_op): Handle excess precision. (ExprVisitor::visit(NegExp)): Likwise. 2017-10-31 Iain Buclaw * d-codegen.cc (build_address): Store CST nodes into a TARGET_EXPR before taking its address. 2017-10-08 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Remove newdelete.o. * d-incpath.cc (add_globalpaths): Handle NULL target path. 2017-10-01 Iain Buclaw * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Properly check base classes for pointers. 2017-09-28 Iain Buclaw * expr.cc (ExprVisitor::visit(StringExp)): Add extra null terminator onto string type, not the literal. 2017-09-26 Iain Buclaw * types.cc (make_array_type): Move checking of void static arrays here. 2017-09-24 Iain Buclaw * d-attribs.c: Add include for attribs.h. * d-codegen.cc (copy_aggregate_type): Remove TYPE_METHODS. (lower_struct_comparison): Use opt_scalar_int_mode. * d-target.cc (Target::_init): Use TYPE_MAX_VALUE instead of TYPE_MAXVAL. (Target::isVectorTypeSupported): Update call to scalar_mode_supported_p. * decl.cc (DeclVisitor::visit(Import)): Pass false as new argument to the imported_module_or_decl hook. * types.cc (TypeVisitor::visit(TypeClass)): Remove TYPE_METHODS. 2017-09-14 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Add blockexit.o, initsem.o, inlinecost.o, safe.o, staticcond.o, and typesem.o. * d-attribs.c (uda_attribute_p): Use get_identifier to compare strings. (build_attributes): Handle empty string expressions. * d-builtins.cc (build_frontend_type): Use static create methods to 'new' front-end types, expressions, and declarations. (d_eval_constant_expression): Likewise. (build_alias_declaration): Likewise. (d_build_builtins_module): Likewise. * d-codegen.cc (declaration_type): Likewise. (type_passed_as): Likewise. (get_frame_for_symbol): Remove dependency on id.h. (get_frameinfo): Don't overwrite FRAMEINFO_CREATES_FRAME if function has nested frame references. * d-convert.cc (convert_for_assignment): Allow static arrays to be initialized with a zero integer value. * d-frontend.cc (genCmain): Remove dependency on id.h. * d-frontend.h (initializerToExpression): Add declaration. (gendocfile): Add declaration. (initTraitsStringTable): Remove. * d-lang.cc (deps_write): Remove dependency on id.h. (deps_add_target): Don't call StringTables's destructor. (d_init): Remove calls to deleted front-end initialize functions. * decl.cc (DeclVisitor::visit(PragmaDeclaration)): Remove dependency on id.h. (DeclVisitor::visit(VarDeclaration)): Call initializerToExpression to get the initializer of decl. (build_decl_tree): Remove dependency on id.h. (layout_class_initializer): Use static create method to 'new' front-end expression. * expr.cc (ExprVisitor::visit(AssignExp)): Handle static array assignment where RHS is integer zero. (ExprVisitor::visit(VarExp)): Remove dependency on id.h. (ExprVisitor::visit(StringExp)): Handle empty string expressions. * modules.cc (get_internal_fn): Use FuncDeclaration::genCfunc to create function decl. (build_module_tree): Remove dependency on id.h. * toir.cc (IRVisitor::visit(ExtAsmStatement)): Handle empty string expressions. * typeinfo.cc (make_frontend_typeinfo): Use static create methods to 'new' front-end declarations. (create_tinfo_types): Remove dependency on id.h. (get_cpp_typeinfo_decl): Likewise. (create_typeinfo): Likewise. 2017-08-23 Johannes Pfau * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoStructDeclaration)): Do not send member functions to backend here. 2017-08-19 Iain Buclaw * d-convert.cc (convert_expr): Use build_zero_cst for casts from typeof(null). 2017-08-13 Iain Buclaw * d-target.cc (Target::isVectorOpSupported): Disallow vectors in conditional and logical operators. 2017-08-08 Iain Buclaw * intrinsics.cc (maybe_expand_intrinsic): Handle isNaN(), isInfinity() and isFinite() intrinsics. * intrinsics.def: Add INTRINSIC_ISNAN, INTRINSIC_ISINFINITY, and INTRINSIC_ISFINITE. 2017-08-08 Iain Buclaw * intrinsics.cc (expand_intrinsic_popcnt): New function. (maybe_expand_intrinsic): Handle INTRINSIC_POPCNT. * intrinsics.def (INTRINSIC_POPCNT): Declare. 2017-08-06 Iain Buclaw * d-frontend.cc (isBuiltin): Remove restriction on builtins. (eval_builtin): Check DECL_INTRINSIC_CODE. * d-tree.h (intrinsic_code): Add enum declaration. (lang_decl): Add intrinsic field. (DECL_INTRINSIC_CODE): New macro. (DECL_BUILT_IN_CTFE): New macro. * decls.cc (get_symbol_decl): Initialize DECL_INTRINSIC_CODE. * intrinsics.cc (intrinsic_decl): Add ctfeonly field. (maybe_set_intrinsic): Set frontend builtin flag only if the function is CTFE-able. Set BUILT_IN_FRONTEND if function has no body. (clear_intrinsic_flag): Clear DECL_INTRINSIC_CODE instead of frontend builtin flag. (maybe_expand_intrinsic): Handle INTRINSIC_TAN intrinsics. Call clear_intrinsic_flag on CTFE built-ins if semantic has finished. * intrinsics.def: Add INTRINSIC_TAN. (DEF_D_BUILTIN): New macro. (DEF_CTFE_BUILTIN): New macro. 2017-08-06 Iain Buclaw * decl.cc (DeclVisitor::visit): Don't set input_location. (build_decl_tree): Handle set and restore of input_location. (declare_local_var): Don't set input_location. * expr.cc (build_expr): Handle set and restore of input_location. * imports.cc (build_import_decl): Likewise. * modules.cc (get_dso_registry_fn): Use UNKNOWN_LOCATION for declaration of _d_dso_registry. * runtime.cc (build_libcall_decl): Use UNKNOWN_LOCATION for declaration of library functions. * toir.cc (IRVisitor::visit): Don't set input_location. (IRVisitor::build_stmt): New function. (IRVisitor::do_jump): Update signature. (build_function_body): Use IRVisitor::build_stmt. * typeinfo.cc (layout_classinfo_interfaces): Don't set input_location. * types.cc (layout_aggregate_members): Likewise. (layout_aggregate_type): Likewise. 2017-08-05 Iain Buclaw * d-codegen.cc (build_boolop): Handle VECTOR_TYPE comparisons. * d-target.cc (Target::checkVectorType): Rename to Target::isVectorTypeSupported. (Target::isVectorOpSupported): New function. * expr.cc (ExprVisitor::visit(IdentityExp)): Don't memcmp floating point vectors. (ExprVisitor::visit(CmpExp)): Handle always true or always false vector comparisons. 2017-08-02 Iain Buclaw * typeinfo.cc (SpeculativeTypeVisitor::visit(TypeClass)): Don't emit typeinfo for speculative class types. 2017-07-29 Iain Buclaw * d-lang.cc (build_lang_decl): Handle compiler generated typeinfo that also appear in code. * d-tree.h (lang_identifier): Add decl_tree. (IDENTIFIER_DECL_TREE): New macro. * decl.cc (declare_extern_var): Re-use already generated decl if called with the same identifier twice. 2017-07-29 Iain Buclaw * decl.cc (d_finish_decl): Replace ENABLE_TREE_CHECKING macro with flag_checking. 2017-07-28 Iain Buclaw * d-tree.h (D_DECL_ONE_ONLY): Remove macro accessor. * decl.cc (DeclVisitor::visit(StructDeclaration)): Move call to d_comdat_linkage here. (DeclVisitor::visit(ClassDeclaration)): Likewise. (DeclVisitor::visit(InterfaceDeclaration)): Likewise. (DeclVisitor::visit(EnumDeclaration)): Likewise. (get_symbol_decl): Move call to mark_needed here. (declare_extern_var): Mark compiler generated symbols as needed. (make_thunk): Remove copy of D_DECL_ONE_ONLY. (get_vtable_decl): Don't call d_comdat_linkage. (aggregate_initializer_decl): Likewise. (enum_initializer_decl): Likewise. * modules.cc (d_finish_compilation): Don't call mark_needed. * typeinfo.cc (get_classinfo_decl): Don't call d_comdat_linkage. 2017-07-28 Iain Buclaw * d-spec.c (lang_specific_driver): Always add `-o' option when compiling D sources. 2017-07-28 Iain Buclaw * d-frontend.cc (genCmain): Don't error if entrypoint not found. 2017-07-18 Iain Buclaw * d-lang.cc (d_types_compatible_p): Check that both types are RECORD_TYPE before using record-specific flag comparison. 2017-07-15 Iain Buclaw * d-builtins.cc (d_build_d_type_nodes): Set TYPE_DYNAMIC_ARRAY on array_type_node. * d-codegen.cc (build_delegate_cst): Set TYPE_DELEGATE on internal delegate constant types. * d-frontend.h (cppTypeInfoMangle): Remove declaration. (toCppMangleItanium): Add declaration. (cppTypeInfoMangleItanium): Add declaration. * d-lang.cc (d_types_compatible_p): Use type flags to determine compatibility. Return false instead of doing size comparison. * d-target.cc (Target::toCppMangle): New function. (Target::cppTypeInfoMangle): New function. (Target::cppTypeMangle): New function. (Target::systemLinkage): New function. * d-tree.h (TYPE_DYNAMIC_ARRAY): New macro. (TYPE_DELEGATE): New macro. (TYPE_ASSOCIATIVE_ARRAY): New macro. * typeinfo.cc (layout_cpp_typeinfo): Use Target::cppTypeInfoMangle. * types.cc (TypeVisitor::visit(TypeDArray)): Set TYPE_DYNAMIC_ARRAY. (TypeVisitor::visit(TypeAArray)): Set TYPE_ASSOCIATIVE_ARRAY. (TypeVisitor::visit(TypeDelegate)): Set TYPE_DELEGATE. 2017-07-11 Iain Buclaw * d-target.cc (Target::loadModule): Check module identifier if a declaration doesn't exist. * typeinfo.cc (make_frontend_typeinfo): Use module location instead if a declaration doesn't exist. 2017-06-28 Iain Buclaw * d-frontend.cc (CTFloat::hash): New function. 2017-06-25 Iain Buclaw * d-codegen.cc (d_array_string): Remove function. (d_assert_call): Inline implementation of d_array_string here. * d-tree.h (d_array_string): Remove declaration. * typeinfo.cc (TypeInfoVisitor::layout_string): New function. (TypeInfoVisitor::visit): Update calls to d_array_string to use layout_string instead. 2017-06-25 Iain Buclaw * toir.cc (IRVisitor::visit(ExtAsmStatement)): Set ASM_VOLATILE_P only if statement is not marked with pure attribute. 2017-06-25 Iain Buclaw * d-lang.cc (d_parse_file): Print all predefined version identifiers if verbose. 2017-06-24 Iain Buclaw * d-frontend.cc (Global::_init): Remove memset for global.params. 2017-06-24 Iain Buclaw * Make-lang.in (D_ALL_OBJS): Add D_TARGET_OBJS. * d-builtins.cc (d_add_builtin_version): Move here from d-lang.cc. (d_init_versions): New function. * d-lang.cc (d_init): Call d_init_versions. * d-target-def.h: New file. * d-target.cc (Target::critsecsize): Replace with call to targetdm.critsec_size. * d-target.def: New file. * d-target.h: New file. * d-tree.h (d_init_versions): Add declaration. 2017-06-20 Iain Buclaw * expr.cc (ExprVisitor::visit(BinAssignExp)): Strip promotions from both signed and unsigned rshift assignments. 2017-06-17 Iain Buclaw * d-diagnostic.cc (expand_format): New function. (d_diagnostic_report_diagnostic): New function. (error, verror): Update format attributes. Use function d_diagnostic_report_diagnostic instead of xvasprintf. (errorSupplemental, verrorSupplemental): Likewise. (warning, vwarning): Likewise. (warningSupplemental, vwarningSupplemental): Likewise. (deprecation, vdeprecation): Likewise. (deprecationSupplemental, vdeprecationSupplemental): Likewise. 2017-06-15 Iain Buclaw * expr.cc (ExprVisitor::visit(AssertExp)): Don't call invariant on interface objects. 2017-06-12 Iain Buclaw * expr.cc (ExprVisitor::visit(DelegateExp)): Convert object to right type before using it. 2017-06-12 Iain Buclaw * d-decls.cc (get_decl_tree): Find the first parent member function before constructing non-local `this' decl. 2017-06-10 Iain Buclaw * d-builtins.cc (build_frontend_type): Allow all vector types to be included in builtins module. 2017-06-09 Iain Buclaw * types.cc (TypeVisitor::visit(TypeStruct)): Let struct alignment override the alignsize. 2017-06-09 Iain Buclaw * d-codegen.cc (d_decl_context): Use origin template declaration as context for instantiated type symbols. 2017-06-08 Iain Buclaw * d-attribs.c (d_handle_weak_attribute): Use quoted string format. * decls.cc (finish_thunk): Update call to create_edge for new API. 2017-06-08 Iain Buclaw * expr.cc (ExprVisitor::visit(StringExp)): Create string type that is same length as string value literal. 2017-05-27 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Rename object.o to rootobject.o. 2017-05-26 Iain Buclaw * decl.cc: Remove include for dumpfile.h. (finish_function): Use dump_function to for dumping original ASTs. 2017-05-24 Iain Buclaw * config-lang.in (gtfiles): Add typeinfo.cc. * d-codegen.cc (d_build_call_list): Remove function. (d_build_call_nary): Remove function. (build_binary_op): Remove function. (build_binop_assignment): Remove function. (build_vthis_type): Rename to build_vthis_function. (create_field_decl): Move to decl.cc. * d-lang.cc (genCmain): Moved to d-frontend.cc. (builtin_modules): Declare static. (d_add_builtin_module): New function. (d_add_entrypoint_module): New function. * expr.cc (ExprVisitor::binary_op): New function. (ExprVisitor::binop_assignment): New function. * intrinsic.cc (expand_intrinsic): Rename to maybe_expand_intrinsic. * runtime.cc (build_libcall): Updated signature. * types.cc (make_two_field_type): Remove function. (make_struct_type): New function. 2017-05-22 Iain Buclaw * Make-lang.in (D_OBJS): Add intrinsics.o and runtime.o. * d-codegen.h: Remove file. * intrinsics.cc: New file. * runtime.cc: New file. 2017-05-21 Iain Buclaw * d-codegen.cc: Remove include for d-dmd-gcc.h. * d-dmd-gcc.h: Rename to d-frontend.h. Update all includes. * d-frontend.cc (Global::_init): Remove unnecessary initialization. * expr.cc: Remove include for d-dmd-gcc.h. 2017-05-21 Iain Buclaw * d-attribs.c (handle_sentinel_attribute): Remove function. (ignore_attribute): Remove function. (d_langhook_common_attribute_table): Remove sentinel and tm regparm from common attribute table. (d_langhook_format_attribute_table): Remove variable. * d-lang.cc (LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE): Remove macro. (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Remove macro. (d_post_options): Don't set flag_unit_at_a_time. (d_nametype): Remove function. * types.cc (TypeVisitor::visit(TypeBasic)): Set TYPE_NAME. (TypeVisitor::visit(TypeVector)): Likewise. 2017-05-20 Iain Buclaw * Make-lang.in (D_OBJS): Remove d-objfile.o. Add modules.o. * d-codegen.cc (get_linemap): Move function here. * d-objfile.cc: Remove file. * d-objfile.h: Remove header. * d-tree.h (GDC_PREFIX): New macro. * decl.cc (make_internal_name): Rename to mangle_internal_decl. (DeclVisitor): Move class here. (gcc_attribute_p): Move function here. (build_decl_tree): Likewise. (d_finish_decl): Likewise. (start_function): Likewise. (finish_function): Likewise. (mark_needed): Likewise. (base_vtable_offset): Likewise. (build_artificial_decl): Likewise. (build_type_decl): Likewise. (d_comdat_group): Likewise. (d_comdat_linkage): Likewise. (add_moduleinfo_field): Move to modules.cc (layout_moduleinfo_fields): Likewise. (get_moduleinfo_decl): Likewise. * modules.cc: New file. 2017-05-10 Iain Buclaw * imports.cc (ImportVisitor::visit(Import)): New function. 2017-05-06 Iain Buclaw * d-objfile.cc (DeclVisitor::visit(Module)): Set input_location before walking module members. (get_linemap): Return input_location if no filename set. (set_input_location): Remove function. Update all callers to set input_location directly. (set_decl_location): Remove function. Update all callers to pass get_linemap to build_decl, or use input_location. * types.cc (insert_aggregate_field): Update signature. 2017-04-30 Iain Buclaw * d-objfile.cc (start_function): Update signature. (finish_function): Update signature. (DeclVisitor::visit(FuncDeclaration)): Move function construction to start_function. Move function finalization to finish_function. (set_function_end_locus): Remove function. (d_finish_function): Remove function. (build_simple_function_decl): Don't set frontend body. (build_simple_function): Update signature. Use start/finish function to compile the body. (emit_dso_registry_cdtor): Likewise. * expr.cc (ExprVisitor::visit(WrappedExp)): Remove function. 2017-04-29 Iain Buclaw * d-diagnostic.cc (verror): Use xvasprintf. (verrorSupplemental): Likewise. (vwarning): Likewise. (vwarningSupplemental): Likewise. (vdeprecation): Likewise. (vdeprecationSupplemental): Likewise. 2017-04-24 Iain Buclaw * d-tree.h (d_tree_index): Add DTI_VTABLE_ENTRY_TYPE, DTI_VTBL_INTERFACE_TYPE, DTI_ARRAY_TYPE, and DTI_NULL_ARRAY. (vtable_entry_type): New macro. (vtbl_interface_type_node): New macro. (array_type_node): New macro. (null_array_node): New macro. * d-builtins.cc (d_build_d_type_nodes): Initialize new trees. * d-codegen.cc (build_struct_literal): Allow NULL index when looking for next field to initialize. (copy_aggregate_type): New function. * d-target.cc (Target::loadModule): Look for object module, call create_tinfo_types. * decl.cc (TypeInfoDeclVisitor): Move to typeinfo.cc. (get_typeinfo_decl): Likewise. (copy_struct): Remove function. Updated callers to use copy_aggregate_type. (layout_classinfo_interfaces): Move to typeinfo.cc. (get_classinfo_decl): Likewise. (get_cpp_typeinfo_decl): Likewise. * typeinfo.cc (tinfo_kind): New enum. (tinfo_types): New static variable. (get_typeinfo_kind): New function. (make_internal_typeinfo): New function. (make_frontend_typeinfo): New function. (create_tinfo_types): New function. (TypeInfoVisitor::set_field): Remove function. Update all callers to use layout_field. (TypeInfoVisitor::layout_vtable): Remove function. Update all callers to use layout_base. (TypeInfoVisitor::layout_field): New function. (TypeInfoVisitor::layout_base): New function. (builtin_typeinfo_p): New function. (genTypeInfo): Rename to create_typeinfo. (isSpeculativeType): Rename to speculative_type_p. 2017-04-23 Iain Buclaw * d-tree.h (d_function_chain): Declare macro. Update all uses of `cfun->language' to use it. 2017-04-22 Iain Buclaw * d-decls.cc: Rename to decl.cc. (get_symbol_decl): Handle typeinfo declarations. (declare_extern_var): New function. (declare_local_var): New function. (get_moduleinfo_decl): Call declare_extern_var. (get_classinfo_decl): Likewise. (get_vtable_decl): Likewise. (get_cpp_typeinfo_decl): Likewise. (aggregate_initializer_decl): Likewise. (enum_initializer_decl): Likewise. * Make-lang.in (D_OBJS): Update. * d-codegen.cc (build_local_var): Remove function. Updated all callers to use declare_local_var. (build_local_temp): Move to decl.cc. (get_decl_tree): Likewise. (expand_decl): Remove function. (build_closure): Inline expand_decl here. 2017-04-20 Iain Buclaw * d-codegen.cc (pop_binding_label): Move to toir.cc. (pop_label): Likewise. (push_binding_level): Likewise (pop_binding_level): Likewise. (push_stmt_list): Likewise. (add_stmt): Likewise. (check_goto): Move to toir.cc, make it a member of IRVisitor. (check_previous_goto): Likewise. (lookup_label): Likewise. (lookup_bc_label): Likewise. (define_label): Likewise. * toir.cc (build_ir): Rename to build_function_body. 2017-04-19 Iain Buclaw * d-target.cc: Update includes. 2017-04-19 Iain Buclaw * lang-specs.h: Remove capitalized D source suffixes. 2017-04-19 Iain Buclaw * lang-specs.h: Add rule for forwarding -iprefix and -imultilib to the compiler proper. 2017-04-19 Iain Buclaw * lang-specs.h: Remove cc1d spec. 2017-04-19 Iain Buclaw * lang-specs.h: Remove +e handling. 2017-04-18 Iain Buclaw * d-diagnostic.cc: New file. * d-frontend.cc: New file. * d-glue.cc: Remove file. * d-port.cc: Remove file. * d-longdouble.h (template operator): Remove operators. 2017-04-17 Iain Buclaw * d-incpath.cc (add_env_var_paths): Rename to add_environment_paths. (make_absolute): Remove function. (add_import_path): Rename to add_globalpaths. (add_fileimp_path): Rename to add_filepaths. 2017-04-17 Iain Buclaw * d-codegen.h (d_types_same): Renamed to same_type_p. Moved to types.cc. (build_object_type): Renamed to get_object_type. Moved to types.cc. * d-codegen.cc (type_va_array): Renamed to valist_array_p. Moved to types.cc. (d_array_type): Renamed to make_array_type. Moved to types.cc. (insert_type_modifiers): Moved to types.cc. (build_two_field_type): Likewise. (empty_aggregate_p): Likewise. (fixup_anonymous_offset): Likewise. (layout_aggregate_members): Likewise. (layout_aggregate_type): Likewise. (insert_aggregate_field): Likewise. (finish_aggregate_type): Likewise. 2017-04-17 Iain Buclaw * Make-lang.in (D_FRONTEND_OBJS): Update to match new source names. 2017-04-11 Iain Buclaw * gdc.texi: Rewrite documentation for manpages. 2017-04-08 Iain Buclaw * d-objfile.cc (DeclVisitor::visit(FuncDeclaration)): Remove logic that parent needs to be compiled before nested. 2017-04-08 Iain Buclaw * d-lang.cc (d_post_options): Don't overwrite in_fnames. (d_parse_file): Don't error about not being able to use stdin. Implement support for reading source code from stdin. 2017-04-08 Iain Buclaw * d-lang.cc (d_parse_file): Remove invalid file name checks. 2017-04-08 Iain Buclaw * d-glue.cc (Global::_init): Set global.stdmsg to stderr. 2017-04-07 Iain Buclaw * d-codgen.h (current_module_decl): Moved to d-objfile.cc. * d-objfile.h (current_module_info): Likewise. (ModuleInfoFlags): Likewise. (ModuleInfo): Likewise. * d-objfile.cc (start_function): Move updating ModuleInfo structure to ... (DeclVisitor::visit(FuncDeclaration)): ... here. Set it after finishing off the function. 2017-04-07 Iain Buclaw * d-objfile.cc (DeclVisitor::visit(FuncDeclaration)): Use push_function_decl for storing current state when switching to nested functions. Remove handling of deferred functions. * d-tree.h (language_function): Remove deferred_fns. * expr.cc (ExprVisitor::visit(DelegateExp)): Don't defer compiling the delegate lambda. (ExprVisitor::visit(FuncExp)): Likewise for function literals. (ExprVisitor::visit(VarExp)): Likewise. 2017-04-07 Iain Buclaw * d-codegen.cc (start_function): Move to d-objfile.cc, make it static. (end_function): Likewise. Renamed to finish_function. 2017-04-05 Iain Buclaw * d-codegen.cc (d_convert): Move to d-convert.cc. (convert_expr): Likewise. (convert_for_assignment): Likewise. (convert_for_argument): Likewise. (convert_for_condition): Likewise. (d_array_convert): Likewise. 2017-04-04 Iain Buclaw * d-builtins.c (d_global_trees): Move to d-lang.cc. (build_dtype): Rename to build_frontend_type. Updated all callers. (build_expression): Rename to d_eval_constant_expression. Updated all callers. (build_alias_declaration): New function. (d_build_c_type_nodes): New function. (d_build_d_type_nodes): New function. (d_define_builtins): New function. 2017-04-04 Iain Buclaw * d-attribs.c (insert_type_attribute): Use build_type_attribute_variant. (insert_decl_attribute): Use build_decl_attribute_variant. (uda_attribute_p): Remove string table, use Identifier comparison for looking up table attributes. (build_attributes): Make unknown attribute a warning, use quoted strings in diagnostic messages. 2017-04-01 Iain Buclaw * d-lang.cc (d_handle_option): Handle -fdump-d-original. (d_parse_file): Likewise. * d-target.cc (Target::maxStaticDataSize): New variable. (Target::_init): Initialize maxStaticDataSize. * lang.opt (fdump-d-original): Declare. 2017-04-01 Iain Buclaw * Make-lang.in (D_GLUE_OBJS): Remove d-todt.cc. * d-objfile.cc (build_moduleinfo_symbol): Build initializer for ModuleInfo directly from inferred type fields. (d_finish_symbol): Remove handling of DECL_LANG_INITIAL. * d-todt.cc: Remove file. * d-tree.h (lang_decl): Remove initial field. (DECL_LANG_INITIAL): Remove macro. 2017-03-31 Iain Buclaw * d-objfile.cc (DeclVisitor::visit(VarDeclaration)): Use build_expr to generate the static initializer. * d-todt.cc (Initializer::toDt): Remove function and all overrides. * expr.cc (ExprVisitor::visit(VarExp)): Use build_expr to get the constant initializer of a constant variable. 2017-03-29 Iain Buclaw * d-decls.cc (aggregate_initializer): Renamed to aggregate_initializer_decl. Updated all callers. (enum_initializer): Renamed to enum_initializer_decl. Updated all callers. (layout_class_initializer): New function. (layout_struct_initializer): New function. * d-todt.cc (ClassDeclaration::toDt): Remove function. (StructDeclaration::toDt): Remove function. 2017-03-27 Iain Buclaw * d-objfile.cc (DeclVisitor::visit(Module)): New function. (Module::genobjfile): Remove function. Updated all callers to use build_decl_tree. (layout_moduleinfo): New function. (Module::genmoduleinfo): Remove function. Update all callers to use layout_moduleinfo. 2017-03-26 Iain Buclaw * d-objfile.cc (base_vtable_offset): New function. (ClassDeclaration::baseVtblOffset): Remove function. Updated all callers to use base_vtable_offset. 2017-03-26 Iain Buclaw * d-objfile.cc (DeclVisitor): New visitor interface to supercede the toObjFile methods. (build_decl_tree): New function. (Dsymbol::toObjFile): Remove function and overrides. Updated all callers to use build_decl_tree. 2017-03-20 Iain Buclaw * d-decls.cc (get_cpp_typeinfo_decl): New function. * d-lang.cc (d_build_eh_type_type): Return classinfo for __cpp_type_info_ptr when generating catch for C++ classes. * runtime.def (CXA_BEGIN_CATCH): Define. (CXA_END_CATCH): Define. * toir.cc (IRVisitor::visit(TryCatchStatement)): Support catching classes thrown from C++. * typeinfo.cc (layout_cpp_typeinfo): New function. 2017-03-20 Iain Buclaw * d-builtins.cc (d_build_builtins_module): Always mark gcc builtins as nothrow functions. 2017-03-11 Iain Buclaw * d-longdouble.cc (CTFloat::zero): New variable. (CTFloat::one): New variable. (CTFloat::minusone): New variable. (CTFloat::half): New variable. (longdouble::set): Remove float and double overloads. (longdouble::operator float): Remove function. (longdouble::operator double): Remove function. * d-target.cc (Target::_init): Initialize floating point constants. 2017-03-11 Iain Buclaw * d-lang.cc (d_init): Replace calls to init with _init. * d-glue.cc (Global::init): Renamed to Global::_init. * d-target.cc (Target::init): Renamed to Target::_init. 2017-03-11 Iain Buclaw * d-longdouble.cc (longdouble::format): Remove function. (longdouble::formatHex): Remove function. (longdouble::dump): Remove function. (CTFloat::sprint): Inline implementation of format and formatHex here. 2017-03-11 Iain Buclaw * d-lang.cc (d_init): Remove calls to Port::init and longdouble::init. * d-longdouble.cc (real_limits): Remove variable. (longdouble::init): Remove function. (CTFloat::parse): Update to use Target::RealProperties. * d-port.cc (Port::ldbl_nan): Remove variable. (Port::snan): Remove variable. (Port::ldbl_infinity): Remove variable. (Port::ldbl_max): Remove variable. (Port::init): Remove function. (Port::isFloat32LiteralOutOfRange): Update to use Target::RealProperties. (Port::isFloat64LiteralOutOfRange): Likewise. * d-target.cc (Target::FPTypeProperties::max): Define. (Target::FPTypeProperties::min_normal): Define. (Target::FPTypeProperties::nan): Define. (Target::FPTypeProperties::snan): Define. (Target::FPTypeProperties::infinity): Define. (Target::FPTypeProperties::epsilon): Define. (Target::FPTypeProperties::dig): Define. (Target::FPTypeProperties::mant_dig): Define. (Target::FPTypeProperties::max_exp): Define. (Target::FPTypeProperties::min_exp): Define. (Target::FPTypeProperties::max_10_exp): Define. (Target::FPTypeProperties::min_10_exp): Define. (define_float_constants): New function. (Target::init): Initialize compile-time floating point properties. * longdouble.h (Mode): Remove type declaration. (real_properties): Remove type declaration. 2017-03-10 Iain Buclaw * d-longdouble.cc (CTFloat::fabs): New function. (CTFloat::isIdentical): New function. (CTFloat::isNaN): New function. (CTFloat::isSNaN): New function. (CTFloat::isInfinity): New function. (CTFloat::parse): New function. (CTFloat::sprint): New function. * d-port.cc (Port::isNan): Remove function. (Port::isSignallingNan): Remove function. (Port::isInfinity): Remove function. (Port::fequal): Remove function. (Port::strtof): Remove function. (Port::strtod): Remove function. (Port::strtold): Remove function. (Port::isFloat32LiteralOutOfRange): New function. (Port::isFloat64LiteralOutOfRange): New function. * longdouble.h (ld_sprint): Remove function. 2017-03-06 Iain Buclaw * d-glue.cc (verror): Update to handle -Wspeculative. (verrorSupplemental): Likewise. * d-lang.cc (d_init_options): Initialize module alias array. (d_init_options): Handle -fmodule-filepath= and -Wspeculative. * d-port.cc (Port::stricmp): Remove function. (Port::writelongLE): New function. (Port::writelongBE): New function. * lang.opt (Wspeculative): Declare. (fmodule-filepath=): Declare. 2017-03-06 Iain Buclaw * d-lang.cc (d_handle_option): Handle -ftransition=dip1000 * lang.opt (ftransition=dip1000): Declare. (ftransition=safe): Make alias for -ftransition=dip1000 2017-03-04 Iain Buclaw * d-codegen.cc (get_decl_tree): Handle chaining over many levels of nesting functions to get to the right parent for the 'this' field. 2017-03-04 Iain Buclaw * d-decls.cc (get_symbol_decl): Move generation of DECL_ARGUMENTS for empty body declarations to ... (make_thunk): ... here. Also set-up DECL_RESULT. (finish_thunk): Mark DECL_UNINLINEABLE on external functions. 2017-03-04 Iain Buclaw * d-decls.cc (make_thunk): Don't build thunks for functions that failed to compile. 2017-03-04 Iain Buclaw * d-objfile.cc (emit_dso_registry_hooks): Set DECL_PRESERVE_P. 2017-02-26 Iain Buclaw * d-codegen.cc (build_frame_type): Update condition for scope destruction error. * d-port.cc (Port::valcpy): New function. * expr.cc (ExprVisitor::visit(CallExp)): Generate cast of 'this' object to the right handle type before indexing. 2017-02-24 Iain Buclaw * d-glue.cc (warningSupplemental): New function. (vwarningSupplemental): New function. (deprecationSupplemental): New function. (vdeprecationSupplemental): New function. 2017-02-23 Iain Buclaw * imports.cc (ImportVisitor::visit(OverDeclaration)): New function. (ImportVisitor::visit(FuncAliasDeclaration)): New function. 2017-02-21 Iain Buclaw * d-lang.cc (d_handle_option): Handle -X and -Xf options. (d_parse_file): Update. * lang-specs.h: Add rules for -X style options. * lang.opt (X): Declare. (Xf): Declare. (fXf=): Make alias for -Xf. 2017-02-21 Iain Buclaw * lang.opt (fd-vgc): Comment out help test. (fd-verbose): Likewise. (fd-vtls): Likewise. (femit-modules): Likewise. 2017-02-20 Iain Buclaw * d-target.cc (Target::fieldalign): Adjust. 2017-02-19 Iain Buclaw * d-lang.cc (d_option_data): Add fields to support other -M options. (d_init_options): Initialize them. (deps_add_target): New function. (deps_write): Support multiple targets and phony rules. (d_handle_option): Handle gcc -M style options. (d_parse_file): Likewise. * lang-specs.h: Add rules for -M style options. * lang.opt: Declare -M style options. 2017-02-19 Iain Buclaw * d-lang.cc (is_system_module): Remove. (deps_write): Always ignore entrypoint module. 2017-02-19 Iain Buclaw * d-lang.cc (write_one_dep): Remove. (deps_write): Update signature. 2017-02-19 Iain Buclaw * d-lang.cc (iprefix_dir): Remove. (imultilib_dir): Remove. (std_inc): Remove. (d_option_data): New struct. (d_option): Declare. (d_init_options): Initialize d_option. (d_init): Update to use d_option. (d_handle_option): Likewise. (d_parse_file): Likewise. (deps_write): Update signature. 2017-02-19 Iain Buclaw * d-lang.cc (d_handle_option): Call D_handle_option_auto. * lang.opt (Wunknown-pragmas): Turn on warning with -Wall. 2017-02-18 Iain Buclaw * d-lang.cc (d_handle_option): Replace -fin with -fpreconditions; -fout with -fpostconditions. Handle -fswitch-errors. (d_post_options): Move setting of release code flags here. * lang.opt (fassert): Declare flag_assert. (fin): Make alias for -fpreconditions. (finvariants): Declare flag_invariants. (fout): Make alias for -fpostconditions. (fpostconditions): Declare. (fpreconditions): Declare. (fswitch-errors): Declare. 2017-02-18 Iain Buclaw * d-objfile.cc (PragmaDeclaration::toObjFile): Warn about unknown pragmas only if -Wunknown-pragmas. 2017-02-18 Iain Buclaw * d-glue.cc (Global::init): Initialize errorLimit to flag_max_errors. (verror): Don't halt program after invocation limit. * d-lang.cc (d_handle_option): Remove handling -fmax-error-messages. * lang.opt (fmax-error-messages): Remove option. 2017-02-18 Iain Buclaw * d-decls.cc (get_symbol_decl): Handle -Wtemplates. * d-lang.cc (d_init_options): Remove setting flag_emit_templates. (d_handle_option): Replace handling -femit-templates with -fall-instantiations. (d_pushdecl): Remove checking for flag_emit_templates. * d-tree.h (D_DECL_IS_TEMPLATE): Remove macro. * lang.opt (flag_emit_templates): Remove variable. (fall-instantiations): Declare. (femit-templates): Make alias for -fall-instantiations. (Wtemplates): Declare. 2017-02-18 Iain Buclaw * lang.opt (fassert): Update help text. (fin): Likewise. (finvariants): Likewise. (fout): Likewise. 2017-02-11 Iain Buclaw * d-objfile.cc (VarDeclaration::toObjFile): Error if a variable covers more than half the address space. 2017-02-04 Iain Buclaw * d-objfile.cc (Module::genmoduleinfo): Ignore symbol visibility when looking up module DSO symbols. 2017-01-29 Iain Buclaw * d-lang.cc (d_handle_option): Handle -ftransition=all. * lang.opt (ftransition=all): Add compiler option. 2017-01-29 Iain Buclaw * d-lang.cc (d_handle_option): Handle -ftransition=checkimports. * lang.opt (ftransition=checkimports): Add compiler option. 2017-01-28 Iain Buclaw * d-lang.cc (d_handle_option): Handle -ftransition=import. * lang.opt (ftransition=import): Add compiler option. 2017-01-25 Iain Buclaw * imports.cc (ImportVisitor::visit(EnumDeclaration)): New function. (ImportVisitor::visit(AggregateDeclaration)): New function. (ImportVisitor::visit(ClassDeclaration)): New function. (ImportVisitor::make_import): New function. (ImportVisitor::visit(AliasDeclaration)): Get decl for type alias. 2017-01-22 Iain Buclaw * expr.cc (ExprVisitor::visit(EqualExp)): Don't use memcmp on arrays of structs that define xopEquals. 2017-01-15 Iain Buclaw * d-spec.cc (lang_specific_driver): Add missing break. 2017-01-13 Iain Buclaw * d-codegen.cc (build_class_instance): Don't check for void initialized fields. * expr.cc (ExprVisitor::visit(StructLiteralExp)): Likewise. 2017-01-11 Iain Buclaw * typeinfo.cc (layout_classinfo): Use placement new to initialize typeinfo class declaration. 2017-01-02 Iain Buclaw * d-codegen,cc (get_frame_for_symbol): Use fully qualified name in error message. (build_frame_type): Always add parameters to closure vars if the function has a contract function. (get_frameinfo): Likewise, always create a frame. * expr.cc (ExprVisitor::needs_dtor): New function. (ExprVisitor::lvalue_p): New function. (ExprVisitor::visit(AssignExp)): Check for dtor in array assignments. (ExprVisitor::visit(TypeidExp)): Cast result to expression type. Copyright (C) 2017 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. ================================================ FILE: gcc/d/Make-lang.in ================================================ # Make-lang.in -- Top level -*- makefile -*- fragment for the D frontend. # Copyright (C) 2006-2018 Free Software Foundation, Inc. # GCC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # GCC is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # This file provides the language dependent support in the main Makefile. # Installation name. D_INSTALL_NAME = $(shell echo gdc|sed '$(program_transform_name)') D_TARGET_INSTALL_NAME = $(target_noncanonical)-$(shell echo gdc|sed '$(program_transform_name)') # Name of phobos library D_LIBPHOBOS = -DLIBPHOBOS=\"gphobos\" # The name for selecting d in LANGUAGES. d: d21$(exeext) # Tell GNU make to ignore these if they exist. .PHONY: d # Create the compiler driver for D. CFLAGS-d/d-spec.o += $(DRIVER_DEFINES) $(D_LIBPHOBOS) GDC_OBJS = $(GCC_OBJS) d/d-spec.o gdc$(exeext): $(GDC_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ $(GDC_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ $(EXTRA_GCC_LIBS) $(LIBS) # Create a version of the gdc driver which calls the cross-compiler. gdc-cross$(exeext): gdc$(exeext) -rm -f gdc-cross$(exeext) cp gdc$(exeext) gdc-cross$(exeext) # Use strict warnings. d-warn = $(STRICT_WARN) # D compiler and flags for building the front-end. ifeq ($(TREECHECKING),) CHECKING_DFLAGS = -frelease else CHECKING_DFLAGS = endif WARN_DFLAGS = -Wall -Wdeprecated $(NOCOMMON_FLAG) ALL_DFLAGS = $(DFLAGS-$@) $(GDCFLAGS) -fversion=IN_GCC $(CHECKING_DFLAGS) \ $(PICFLAG) $(ALIASING_FLAGS) $(COVERAGE_FLAGS) $(WARN_DFLAGS) DCOMPILE.base = $(GDC) $(NO_PIE_CFLAGS) -c $(ALL_DFLAGS) -o $@ DCOMPILE = $(DCOMPILE.base) -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).TPo DPOSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(*F).TPo $(@D)/$(DEPDIR)/$(*F).Po DLINKER = $(GDC) $(NO_PIE_FLAG) -lstdc++ # Like LINKER, but use a mutex for serializing front end links. ifeq (@DO_LINK_MUTEX@,true) DLLINKER = $(SHELL) $(srcdir)/lock-and-run.sh linkfe.lck $(DLINKER) else DLLINKER = $(DLINKER) endif # D Frontend object files. D_FRONTEND_OBJS = \ d/aav.o \ d/access.o \ d/aggregate.o \ d/aliasthis.o \ d/apply.o \ d/argtypes.o \ d/array.o \ d/arrayop.o \ d/arraytypes.o \ d/attrib.o \ d/astcodegen.o \ d/blockexit.o \ d/builtin.o \ d/canthrow.o \ d/clone.o \ d/compiler.o \ d/complex.o \ d/cond.o \ d/constfold.o \ d/cppmangle.o \ d/ctfeexpr.o \ d/ctfloat.o \ d/ctorflow.o \ d/dcast.o \ d/dclass.o \ d/declaration.o \ d/delegatize.o \ d/denum.o \ d/dimport.o \ d/dinterpret.o \ d/dmacro.o \ d/dmangle.o \ d/dmodule.o \ d/doc.o \ d/dscope.o \ d/dstruct.o \ d/dsymbol.o \ d/dsymbolsem.o \ d/dtemplate.o \ d/dversion.o \ d/entity.o \ d/errors.o \ d/escape.o \ d/expression.o \ d/expressionsem.o \ d/file.o \ d/filename.o \ d/func.o \ d/globals.o \ d/gluelayer.o \ d/hash.o \ d/hdrgen.o \ d/iasm.o \ d/iasmgcc.o \ d/id.o \ d/identifier.o \ d/impcnvtab.o \ d/imphint.o \ d/init.o \ d/initsem.o \ d/inline.o \ d/intrange.o \ d/json.o \ d/lambdacomp.o \ d/lexer.o \ d/longdouble.o \ d/mtype.o \ d/nogc.o \ d/nspace.o \ d/objc.o \ d/opover.o \ d/optimize.o \ d/outbuffer.o \ d/parse.o \ d/parsetimevisitor.o \ d/permissivevisitor.o \ d/port.o \ d/rmem.o \ d/rootobject.o \ d/safe.o \ d/sapply.o \ d/semantic2.o \ d/semantic3.o \ d/sideeffect.o \ d/speller.o \ d/statement.o \ d/statement_rewrite_walker.o \ d/statementsem.o \ d/staticassert.o \ d/staticcond.o \ d/stringtable.o \ d/target.o \ d/templateparamsem.o \ d/tokens.o \ d/traits.o \ d/transitivevisitor.o \ d/typesem.o \ d/typinf.o \ d/utf.o \ d/utils.o \ d/visitor.o # Language-specific object files for D. D_OBJS = \ d/d-attribs.o d/d-builtins.o d/d-codegen.o d/d-convert.o \ d/d-diagnostic.o d/d-frontend.o d/d-incpath.o d/d-lang.o \ d/d-longdouble.o d/d-target.o d/decl.o d/expr.o d/imports.o \ d/intrinsics.o d/modules.o d/runtime.o d/toir.o d/typeinfo.o d/types.o # All language-specific object files for D. D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_OBJS) $(D_TARGET_OBJS) d_OBJS = $(D_ALL_OBJS) d/d-spec.o d21$(exeext): $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS) +$(DLLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS) # Documentation. D_TEXI_FILES = \ d/gdc.texi \ $(gcc_docdir)/include/fdl.texi \ $(gcc_docdir)/include/gpl_v3.texi \ $(gcc_docdir)/include/gcc-common.texi \ gcc-vers.texi doc/gdc.info: $(D_TEXI_FILES) if test "x$(BUILD_INFO)" = xinfo; then \ rm -f doc/gdc.info*; \ $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \ -I $(gcc_docdir)/include -o $@ $<; \ else true; fi doc/gdc.dvi: $(D_TEXI_FILES) $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< doc/gdc.pdf: $(D_TEXI_FILES) $(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $< $(build_htmldir)/d/index.html: $(D_TEXI_FILES) $(mkinstalldirs) $(@D) rm -f $(@D)/* $(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \ -I $(srcdir)/d -o $(@D) $< .INTERMEDIATE: gdc.pod gdc.pod: d/gdc.texi -$(TEXI2POD) -D gdc < $< > $@ # Build hooks. d.all.cross: gdc-cross$(exeext) d.start.encap: gdc$(exeext) d.rest.encap: d.info: doc/gdc.info d.dvi: doc/gdc.dvi d.pdf: doc/gdc.pdf d.html: $(build_htmldir)/d/index.html d.srcinfo: doc/gdc.info -cp -p $^ $(srcdir)/doc d.srcextra: d.tags: force cd $(srcdir)/d; \ etags -o TAGS.sub *.c *.cc *.h dmd/*.h dmd/root/*.h; \ etags --include TAGS.sub --include ../TAGS.sub d.man: doc/gdc.1 d.srcman: doc/gdc.1 -cp -p $^ $(srcdir)/doc # 'make check' in gcc/ looks for check-d, as do all toplevel D-related # check targets. However, our DejaGNU framework requires 'check-gdc' as its # entry point. We feed the former to the latter here. check-d: check-gdc lang_checks += check-gdc lang_checks_parallelized += check-gdc check_gdc_parallelize = 10 # No D-specific selftests. selftest-d: # Install hooks. d.install-common: installdirs -rm -f $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext) $(INSTALL_PROGRAM) gdc$(exeext) $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext) -if test -f d21$(exeext); then \ if test -f gdc-cross$(exeext); then \ :; \ else \ rm -f $(DESTDIR)$(bindir)/$(D_TARGET_INSTALL_NAME)$(exeext); \ ( cd $(DESTDIR)$(bindir) && \ $(LN) $(D_INSTALL_NAME)$(exeext) $(D_TARGET_INSTALL_NAME)$(exeext) ); \ fi; \ fi d.install-plugin: d.install-info: $(DESTDIR)$(infodir)/gdc.info d.install-pdf: doc/gdc.pdf @$(NORMAL_INSTALL) test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc" @for p in doc/gdc.pdf; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(pdf__strip_dir) \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \ done d.install-html: $(build_htmldir)/d @$(NORMAL_INSTALL) test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)" @for p in $(build_htmldir)/d; do \ if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \ f=$(html__strip_dir) \ if test -d "$$d$$p"; then \ echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \ $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ else \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ fi; \ done d.install-man: $(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext) $(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext): doc/gdc.1 installdirs -rm -f $@ -$(INSTALL_DATA) $< $@ -chmod a-x $@ d.uninstall: -rm -rf $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext) -rm -rf $(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext) -rm -rf $(DESTDIR)$(bindir)/$(D_TARGET_INSTALL_NAME)$(exeext) -rm -rf $(DESTDIR)$(infodir)/gdc.info* # Clean hooks. d.mostlyclean: -rm -f d/*$(objext) -rm -f d/*$(coverageexts) -rm -f d/gdc$(exeext) gdc-cross$(exeext) d/d21$(exeext) d.clean: d.distclean: d.maintainer-clean: -rm -f $(docobjdir)/gdc.1 # Stage hooks. d.stage1: stage1-start -mv d/*$(objext) stage1/d d.stage2: stage2-start -mv d/*$(objext) stage2/d d.stage3: stage3-start -mv d/*$(objext) stage3/d d.stage4: stage4-start -mv d/*$(objext) stage4/d d.stageprofile: stageprofile-start -mv d/*$(objext) stageprofile/d d.stagefeedback: stagefeedback-start -mv d/*$(objext) stagefeedback/d # Include the dfrontend and build directories for headers. D_INCLUDES = -I$(srcdir)/d -J$(srcdir)/d/dmd/ddoc # Override build rules for D frontend. d/%.o: d/dmd/%.d $(DCOMPILE) $(D_INCLUDES) $< $(DPOSTCOMPILE) d/%.o: d/dmd/root/%.d $(DCOMPILE) $(D_INCLUDES) $< $(DPOSTCOMPILE) ================================================ FILE: gcc/d/config-lang.in ================================================ # config-lang.in -- Top level configure fragment for gcc D frontend. # Copyright (C) 2006-2018 Free Software Foundation, Inc. # GCC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # GCC is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # Configure looks for the existence of this file to auto-config each language. # We define several parameters used by configure: # # language - name of language as it would appear in $(LANGUAGES) # boot_language - "yes" if we need to build this language in stage1 # compilers - value to add to $(COMPILERS) language="d" boot_language=yes compilers="d21\$(exeext)" target_libs="target-libphobos target-zlib target-libbacktrace" gtfiles="\$(srcdir)/d/d-tree.h \$(srcdir)/d/d-builtins.cc \$(srcdir)/d/d-lang.cc \$(srcdir)/d/modules.cc \$(srcdir)/d/typeinfo.cc" # Do not build by default. build_by_default="no" ================================================ FILE: gcc/d/d-attribs.cc ================================================ /* d-attribs.c -- D attributes handling. Copyright (C) 2015-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* Implementation of attribute handlers for user defined attributes and internal built-in functions. */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/mtype.h" #include "tree.h" #include "diagnostic.h" #include "tm.h" #include "cgraph.h" #include "toplev.h" #include "target.h" #include "common/common-target.h" #include "stringpool.h" #include "attribs.h" #include "varasm.h" #include "d-tree.h" /* Internal attribute handlers for built-in functions. */ static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); static tree handle_const_attribute (tree *, tree, tree, int, bool *); static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); static tree handle_pure_attribute (tree *, tree, tree, int, bool *); static tree handle_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); /* D attribute handlers for user defined attributes. */ static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *); static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *); static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *); static tree d_handle_target_attribute (tree *, tree, tree, int, bool *); static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *); static tree d_handle_section_attribute (tree *, tree, tree, int, bool *); static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *); static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ; /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ { name, function, type, variable } /* Define attributes that are mutually exclusive with one another. */ static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = { ATTR_EXCL ("const", true, true, true), ATTR_EXCL ("malloc", true, true, true), ATTR_EXCL ("pure", true, true, true), ATTR_EXCL ("returns_twice", true, true, true), ATTR_EXCL (NULL, false, false, false), }; static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = { ATTR_EXCL ("noreturn", true, true, true), ATTR_EXCL (NULL, false, false, false), }; static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { ATTR_EXCL ("const", true, true, true), ATTR_EXCL ("noreturn", true, true, true), ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false) }; static const struct attribute_spec::exclusions attr_inline_exclusions[] = { ATTR_EXCL ("noinline", true, true, true), ATTR_EXCL (NULL, false, false, false), }; static const struct attribute_spec::exclusions attr_noinline_exclusions[] = { ATTR_EXCL ("forceinline", true, true, true), ATTR_EXCL (NULL, false, false, false), }; /* Helper to define an attribute. */ #define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \ affects_type_identity, handler, exclude) \ { name, min_len, max_len, decl_req, type_req, fn_type_req, \ affects_type_identity, handler, exclude } /* Table of machine-independent attributes. For internal use (marking of built-ins) only. */ const attribute_spec d_langhook_common_attribute_table[] = { ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, handle_noreturn_attribute, attr_noreturn_exclusions), ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute, NULL), ATTR_SPEC ("const", 0, 0, true, false, false, false, handle_const_attribute, attr_const_pure_exclusions), ATTR_SPEC ("malloc", 0, 0, true, false, false, false, handle_malloc_attribute, NULL), ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false, handle_returns_twice_attribute, attr_returns_twice_exclusions), ATTR_SPEC ("pure", 0, 0, true, false, false, false, handle_pure_attribute, attr_const_pure_exclusions), ATTR_SPEC ("nonnull", 0, -1, false, true, true, false, handle_nonnull_attribute, NULL), ATTR_SPEC ("nothrow", 0, 0, true, false, false, false, handle_nothrow_attribute, NULL), ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false, handle_transaction_pure_attribute, NULL), ATTR_SPEC ("no vops", 0, 0, true, false, false, false, handle_novops_attribute, NULL), ATTR_SPEC ("type generic", 0, 0, false, true, true, false, handle_type_generic_attribute, NULL), ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, handle_fnspec_attribute, NULL), ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; /* Table of D language attributes exposed by `gcc.attribute' UDAs. */ const attribute_spec d_langhook_attribute_table[] = { ATTR_SPEC ("noinline", 0, 0, true, false, false, false, d_handle_noinline_attribute, attr_noinline_exclusions), ATTR_SPEC ("forceinline", 0, 0, true, false, false, false, d_handle_forceinline_attribute, attr_inline_exclusions), ATTR_SPEC ("flatten", 0, 0, true, false, false, false, d_handle_flatten_attribute, NULL), ATTR_SPEC ("target", 1, -1, true, false, false, false, d_handle_target_attribute, NULL), ATTR_SPEC ("noclone", 0, 0, true, false, false, false, d_handle_noclone_attribute, NULL), ATTR_SPEC ("section", 1, 1, true, false, false, false, d_handle_section_attribute, NULL), ATTR_SPEC ("alias", 1, 1, true, false, false, false, d_handle_alias_attribute, NULL), ATTR_SPEC ("weak", 0, 0, true, false, false, false, d_handle_weak_attribute, NULL), ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; /* Insert the type attribute ATTRNAME with value VALUE into TYPE. Returns a new variant of the original type declaration. */ tree insert_type_attribute (tree type, const char *attrname, tree value) { tree ident = get_identifier (attrname); if (value) value = tree_cons (NULL_TREE, value, NULL_TREE); tree attribs = merge_attributes (TYPE_ATTRIBUTES (type), tree_cons (ident, value, NULL_TREE)); return build_type_attribute_variant (type, attribs); } /* Insert the decl attribute ATTRNAME with value VALUE into DECL. */ tree insert_decl_attribute (tree decl, const char *attrname, tree value) { tree ident = get_identifier (attrname); if (value) value = tree_cons (NULL_TREE, value, NULL_TREE); tree attribs = merge_attributes (DECL_ATTRIBUTES (decl), tree_cons (ident, value, NULL_TREE)); return build_decl_attribute_variant (decl, attribs); } /* Returns TRUE if NAME is an attribute recognized as being handled by the `gcc.attribute' module. */ static bool uda_attribute_p (const char *name) { tree ident = get_identifier (name); /* Search both our language, and target attribute tables. Common and format attributes are kept internal. */ for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++) { if (get_identifier (p->name) == ident) return true; } for (const attribute_spec *p = targetm.attribute_table; p->name; p++) { if (get_identifier (p->name) == ident) return true; } return false; } /* [attribute/uda] User Defined Attributes (UDA) are compile time expressions that can be attached to a declaration. These attributes can then be queried, extracted, and manipulated at compile-time. There is no run-time component to them. Expand and merge all UDAs found in the EATTRS list that are of type `gcc.attribute.Attribute'. This symbol is internally recognized by the compiler and maps them to their equivalent GCC attribute. */ tree build_attributes (Expressions *eattrs) { if (!eattrs) return NULL_TREE; expandTuples (eattrs); tree attribs = NULL_TREE; for (size_t i = 0; i < eattrs->dim; i++) { Expression *attr = (*eattrs)[i]; Dsymbol *sym = attr->type->toDsymbol (0); if (!sym) continue; /* Attribute symbol must come from the `gcc.attribute' module. */ Dsymbol *mod = (Dsymbol*) sym->getModule (); if (!(strcmp (mod->toChars (), "attribute") == 0 && mod->parent != NULL && strcmp (mod->parent->toChars (), "gcc") == 0 && !mod->parent->parent)) continue; /* Get the result of the attribute if it hasn't already been folded. */ if (attr->op == TOKcall) attr = attr->ctfeInterpret (); /* Should now have a struct `Attribute("attrib", "value", ...)' initializer list. */ gcc_assert (attr->op == TOKstructliteral); Expressions *elems = ((StructLiteralExp*) attr)->elements; Expression *e0 = (*elems)[0]; if (e0->op != TOKstring) { error ("expected string attribute, not %qs", e0->toChars ()); return error_mark_node; } StringExp *se = (StringExp*) e0; gcc_assert (se->sz == 1); /* Empty string attribute, just ignore it. */ if (se->len == 0) continue; /* Check if the attribute is recognized and handled. Done here to report the diagnostic at the right location. */ const char *name = (const char *)(se->len ? se->string : ""); if (!uda_attribute_p (name)) { warning_at (make_location_t (e0->loc), OPT_Wattributes, "unknown attribute %qs", name); return error_mark_node; } /* Chain all attribute arguments together. */ tree args = NULL_TREE; for (size_t j = 1; j < elems->dim; j++) { Expression *e = (*elems)[j]; tree t; if (e->op == TOKstring && ((StringExp *) e)->sz == 1) { StringExp *s = (StringExp *) e; const char *string = (const char *)(s->len ? s->string : ""); t = build_string (s->len, string); } else t = build_expr (e); args = chainon (args, build_tree_list (0, t)); } tree list = build_tree_list (get_identifier (name), args); attribs = chainon (attribs, list); } return attribs; } /* Built-in attribute handlers. */ /* Handle a "noreturn" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { tree type = TREE_TYPE (*node); if (TREE_CODE (*node) == FUNCTION_DECL) TREE_THIS_VOLATILE (*node) = 1; else if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) TREE_TYPE (*node) = build_pointer_type (build_type_variant (TREE_TYPE (type), TYPE_READONLY (TREE_TYPE (type)), 1)); else gcc_unreachable (); return NULL_TREE; } /* Handle a "leaf" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_leaf_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { if (TREE_CODE (*node) != FUNCTION_DECL) { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } if (!TREE_PUBLIC (*node)) { warning (OPT_Wattributes, "%qE attribute has no effect", name); *no_add_attrs = true; } return NULL_TREE; } /* Handle a "const" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_const_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { tree type = TREE_TYPE (*node); if (TREE_CODE (*node) == FUNCTION_DECL) TREE_READONLY (*node) = 1; else if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) TREE_TYPE (*node) = build_pointer_type (build_type_variant (TREE_TYPE (type), 1, TREE_THIS_VOLATILE (TREE_TYPE (type)))); else gcc_unreachable (); return NULL_TREE; } /* Handle a "malloc" attribute; arguments as in struct attribute_spec.handler. */ tree handle_malloc_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))); DECL_IS_MALLOC (*node) = 1; return NULL_TREE; } /* Handle a "pure" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_pure_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); DECL_PURE_P (*node) = 1; return NULL_TREE; } /* Handle a "no vops" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_novops_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); DECL_IS_NOVOPS (*node) = 1; return NULL_TREE; } /* Helper for nonnull attribute handling; fetch the operand number from the attribute argument list. */ static bool get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) { /* Verify the arg number is a constant. */ if (!tree_fits_uhwi_p (arg_num_expr)) return false; *valp = TREE_INT_CST_LOW (arg_num_expr); return true; } /* Handle the "nonnull" attribute. */ static tree handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), tree args, int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { tree type = *node; /* If no arguments are specified, all pointer arguments should be non-null. Verify a full prototype is given so that the arguments will have the correct types when we actually check them later. Avoid diagnosing type-generic built-ins since those have no prototype. */ if (!args) { gcc_assert (prototype_p (type) || !TYPE_ATTRIBUTES (type) || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type))); return NULL_TREE; } /* Argument list specified. Verify that each argument number references a pointer argument. */ for (; args; args = TREE_CHAIN (args)) { tree argument; unsigned HOST_WIDE_INT arg_num = 0, ck_num; if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) gcc_unreachable (); argument = TYPE_ARG_TYPES (type); if (argument) { for (ck_num = 1; ; ck_num++) { if (!argument || ck_num == arg_num) break; argument = TREE_CHAIN (argument); } gcc_assert (argument && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE); } } return NULL_TREE; } /* Handle a "nothrow" attribute; arguments as in struct attribute_spec.handler. */ static tree handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); TREE_NOTHROW (*node) = 1; return NULL_TREE; } /* Handle a "type_generic" attribute. */ static tree handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { /* Ensure we have a function type. */ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); /* Ensure we have a variadic function. */ gcc_assert (!prototype_p (*node) || stdarg_p (*node)); return NULL_TREE; } /* Handle a "transaction_pure" attribute. */ static tree handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { /* Ensure we have a function type. */ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); return NULL_TREE; } /* Handle a "returns_twice" attribute. */ static tree handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name), tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); DECL_IS_RETURNS_TWICE (*node) = 1; return NULL_TREE; } /* Handle a "fn spec" attribute; arguments as in struct attribute_spec.handler. */ tree handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name), tree args, int ARG_UNUSED (flags), bool *no_add_attrs ATTRIBUTE_UNUSED) { gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST && !TREE_CHAIN (args)); return NULL_TREE; } /* Language specific attribute handlers. */ /* Handle a "noinline" attribute. */ static tree d_handle_noinline_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); if (t->ty == Tfunction) DECL_UNINLINABLE (*node) = 1; else { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } return NULL_TREE; } /* Handle a "forceinline" attribute. */ static tree d_handle_forceinline_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); if (t->ty == Tfunction) { tree attributes = DECL_ATTRIBUTES (*node); /* Push attribute always_inline. */ if (! lookup_attribute ("always_inline", attributes)) DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"), NULL_TREE, attributes); DECL_DECLARED_INLINE_P (*node) = 1; DECL_NO_INLINE_WARNING_P (*node) = 1; DECL_DISREGARD_INLINE_LIMITS (*node) = 1; } else { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } return NULL_TREE; } /* Handle a "flatten" attribute. */ static tree d_handle_flatten_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) { Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); if (t->ty != Tfunction) { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } return NULL_TREE; } /* Handle a "target" attribute. */ static tree d_handle_target_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) { Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); /* Ensure we have a function type. */ if (t->ty != Tfunction) { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } else if (! targetm.target_option.valid_attribute_p (*node, name, args, flags)) *no_add_attrs = true; return NULL_TREE; } /* Handle a "noclone" attribute. */ static tree d_handle_noclone_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node)); if (t->ty == Tfunction) { tree attributes = DECL_ATTRIBUTES (*node); /* Push attribute noclone. */ if (! lookup_attribute ("noclone", attributes)) DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"), NULL_TREE, attributes); } else { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; } return NULL_TREE; } /* Handle a "section" attribute; arguments as in struct attribute_spec.handler. */ static tree d_handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, int ARG_UNUSED (flags), bool *no_add_attrs) { tree decl = *node; if (targetm_common.have_named_sections) { if (VAR_OR_FUNCTION_DECL_P (decl) && TREE_CODE (TREE_VALUE (args)) == STRING_CST) { if (VAR_P (decl) && current_function_decl != NULL_TREE && !TREE_STATIC (decl)) { error_at (DECL_SOURCE_LOCATION (decl), "section attribute cannot be specified for " "local variables"); *no_add_attrs = true; } /* The decl may have already been given a section attribute from a previous declaration. Ensure they match. */ else if (DECL_SECTION_NAME (decl) != NULL && strcmp (DECL_SECTION_NAME (decl), TREE_STRING_POINTER (TREE_VALUE (args))) != 0) { error ("section of %q+D conflicts with previous declaration", *node); *no_add_attrs = true; } else if (VAR_P (decl) && !targetm.have_tls && targetm.emutls.tmpl_section && DECL_THREAD_LOCAL_P (decl)) { error ("section of %q+D cannot be overridden", *node); *no_add_attrs = true; } else set_decl_section_name (decl, TREE_STRING_POINTER (TREE_VALUE (args))); } else { error ("section attribute not allowed for %q+D", *node); *no_add_attrs = true; } } else { error_at (DECL_SOURCE_LOCATION (*node), "section attributes are not supported for this target"); *no_add_attrs = true; } return NULL_TREE; } /* Handle an "alias" attribute; arguments as in struct attribute_spec.handler. */ static tree d_handle_alias_attribute (tree *node, tree ARG_UNUSED (name), tree args, int ARG_UNUSED (flags), bool *no_add_attrs ATTRIBUTE_UNUSED) { tree decl = *node; if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL) { warning (OPT_Wattributes, "%qE attribute ignored", name); *no_add_attrs = true; return NULL_TREE; } else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) || (TREE_CODE (decl) != FUNCTION_DECL && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl)) /* A static variable declaration is always a tentative definition, but the alias is a non-tentative definition which overrides. */ || (TREE_CODE (decl) != FUNCTION_DECL && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl))) { error ("%q+D defined both normally and as %qE attribute", decl, name); *no_add_attrs = true; return NULL_TREE; } else if (decl_function_context (decl)) { error ("%q+D alias functions must be global", name); *no_add_attrs = true; return NULL_TREE; } else { tree id; id = TREE_VALUE (args); if (TREE_CODE (id) != STRING_CST) { error ("attribute %qE argument not a string", name); *no_add_attrs = true; return NULL_TREE; } id = get_identifier (TREE_STRING_POINTER (id)); /* This counts as a use of the object pointed to. */ TREE_USED (id) = 1; if (TREE_CODE (decl) == FUNCTION_DECL) DECL_INITIAL (decl) = error_mark_node; else TREE_STATIC (decl) = 1; return NULL_TREE; } } /* Handle a "weak" attribute; arguments as in struct attribute_spec.handler. */ static tree d_handle_weak_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool * ARG_UNUSED (no_add_attrs)) { if (TREE_CODE (*node) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (*node)) { warning (OPT_Wattributes, "inline function %q+D declared weak", *node); *no_add_attrs = true; } else if (VAR_OR_FUNCTION_DECL_P (*node)) { struct symtab_node *n = symtab_node::get (*node); if (n && n->refuse_visibility_changes) error ("%q+D declared weak after being used", *node); declare_weak (*node); } else warning (OPT_Wattributes, "%qE attribute ignored", name); return NULL_TREE; } ================================================ FILE: gcc/d/d-builtins.cc ================================================ /* d-builtins.cc -- GCC builtins support for D. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/attrib.h" #include "dmd/aggregate.h" #include "dmd/cond.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/module.h" #include "dmd/mtype.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "target.h" #include "common/common-target.h" #include "stringpool.h" #include "stor-layout.h" #include "d-tree.h" #include "d-target.h" static GTY(()) vec *gcc_builtins_functions = NULL; static GTY(()) vec *gcc_builtins_libfuncs = NULL; static GTY(()) vec *gcc_builtins_types = NULL; /* Record built-in types and their associated decls for re-use when generating the `gcc.builtins' module. */ struct builtin_data { Type *dtype; tree ctype; Dsymbol *dsym; builtin_data (Type *t, tree c, Dsymbol *d = NULL) : dtype(t), ctype(c), dsym(d) { } }; static vec builtin_converted_decls; /* Build D frontend type from tree TYPE type given. This will set the back-end type symbol directly for complex types to save build_ctype() the work. For other types, it is not useful or will cause errors, such as casting from `C char' to `D char', which also means that `char *` needs to be specially handled. */ static Type * build_frontend_type (tree type) { Type *dtype; MOD mod = 0; if (TYPE_READONLY (type)) mod |= MODconst; if (TYPE_VOLATILE (type)) mod |= MODshared; /* If we've seen the type before, re-use the converted decl. */ for (size_t i = 0; i < builtin_converted_decls.length (); ++i) { tree t = builtin_converted_decls[i].ctype; if (TYPE_MAIN_VARIANT (t) == TYPE_MAIN_VARIANT (type)) return builtin_converted_decls[i].dtype; } switch (TREE_CODE (type)) { case POINTER_TYPE: dtype = build_frontend_type (TREE_TYPE (type)); if (dtype) { /* Check for char * first. Needs to be done for chars/string. */ if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node) return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod); if (dtype->ty == Tfunction) return (TypePointer::create (dtype))->addMod (mod); return dtype->pointerTo ()->addMod (mod); } break; case REFERENCE_TYPE: dtype = build_frontend_type (TREE_TYPE (type)); if (dtype) { /* Want to assign ctype directly so that the REFERENCE_TYPE code can be turned into as an `inout' argument. Can't use pointerTo(), because the returned Type is shared. */ dtype = (TypePointer::create (dtype))->addMod (mod); dtype->ctype = type; builtin_converted_decls.safe_push (builtin_data (dtype, type)); return dtype; } break; case BOOLEAN_TYPE: /* Should be no need for size checking. */ return Type::tbool->addMod (mod); case INTEGER_TYPE: { unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)); bool unsignedp = TYPE_UNSIGNED (type); /* For now, skip support for cent/ucent until the frontend has better support for handling it. */ for (size_t i = Tint8; i <= Tuns64; i++) { dtype = Type::basic[i]; /* Search for type matching size and signedness. */ if (unsignedp != dtype->isunsigned () || size != dtype->size ()) continue; return dtype->addMod (mod); } break; } case REAL_TYPE: { unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)); for (size_t i = Tfloat32; i <= Tfloat80; i++) { dtype = Type::basic[i]; /* Search for type matching size. */ if (dtype->size () != size) continue; return dtype->addMod (mod); } break; } case COMPLEX_TYPE: { unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)); for (size_t i = Tcomplex32; i <= Tcomplex80; i++) { dtype = Type::basic[i]; /* Search for type matching size. */ if (dtype->size () != size) continue; return dtype->addMod (mod); } break; } case VOID_TYPE: return Type::tvoid->addMod (mod); case ARRAY_TYPE: dtype = build_frontend_type (TREE_TYPE (type)); if (dtype) { tree index = TYPE_DOMAIN (type); tree ub = TYPE_MAX_VALUE (index); tree lb = TYPE_MIN_VALUE (index); tree length = fold_build2 (MINUS_EXPR, TREE_TYPE (lb), ub, lb); length = size_binop (PLUS_EXPR, size_one_node, convert (sizetype, length)); dtype = dtype->sarrayOf (TREE_INT_CST_LOW (length))->addMod (mod); builtin_converted_decls.safe_push (builtin_data (dtype, type)); return dtype; } break; case VECTOR_TYPE: dtype = build_frontend_type (TREE_TYPE (type)); if (dtype) { poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (type); dtype = dtype->sarrayOf (nunits.to_constant ())->addMod (mod); if (dtype->nextOf ()->isTypeBasic () == NULL) break; dtype = (TypeVector::create (dtype))->addMod (mod); builtin_converted_decls.safe_push (builtin_data (dtype, type)); return dtype; } break; case RECORD_TYPE: if (TYPE_NAME (type)) { tree structname = DECL_NAME (TYPE_NAME (type)); Identifier *ident = Identifier::idPool (IDENTIFIER_POINTER (structname)); /* Neither the `object' and `gcc.builtins' modules will not exist when this is called. Use a stub 'object' module parent in the meantime. If `gcc.builtins' is later imported, the parent will be overridden with the correct module symbol. */ static Identifier *object = Identifier::idPool ("object"); static Module *stubmod = Module::create ("object.d", object, 0, 0); StructDeclaration *sdecl = StructDeclaration::create (Loc (), ident, false); sdecl->parent = stubmod; sdecl->structsize = int_size_in_bytes (type); sdecl->alignsize = TYPE_ALIGN_UNIT (type); sdecl->alignment = STRUCTALIGN_DEFAULT; sdecl->sizeok = SIZEOKdone; sdecl->type = (TypeStruct::create (sdecl))->addMod (mod); sdecl->type->ctype = type; sdecl->type->merge2 (); /* Does not seem necessary to convert fields, but the members field must be non-null for the above size setting to stick. */ sdecl->members = new Dsymbols; dtype = sdecl->type; builtin_converted_decls.safe_push (builtin_data (dtype, type, sdecl)); return dtype; } break; case FUNCTION_TYPE: dtype = build_frontend_type (TREE_TYPE (type)); if (dtype) { tree parms = TYPE_ARG_TYPES (type); int varargs_p = 1; Parameters *args = new Parameters; args->reserve (list_length (parms)); /* Attempt to convert all parameter types. */ for (tree parm = parms; parm != NULL_TREE; parm = TREE_CHAIN (parm)) { tree argtype = TREE_VALUE (parm); if (argtype == void_type_node) { varargs_p = 0; break; } StorageClass sc = STCundefined; if (TREE_CODE (argtype) == REFERENCE_TYPE) { argtype = TREE_TYPE (argtype); sc |= STCref; } Type *targ = build_frontend_type (argtype); if (!targ) { delete args; return NULL; } args->push (Parameter::create (sc, targ, NULL, NULL, NULL)); } /* GCC generic and placeholder built-ins are marked as variadic, yet have no named parameters, and so can't be represented in D. */ if (args->dim != 0 || !varargs_p) { dtype = TypeFunction::create (args, dtype, varargs_p, LINKc); return dtype->addMod (mod); } } break; default: break; } return NULL; } /* Attempt to convert GCC evaluated CST to a D Frontend Expression. This is used for getting the CTFE value out of a const-folded builtin, returns NULL if it cannot convert CST. */ Expression * d_eval_constant_expression (tree cst) { STRIP_TYPE_NOPS (cst); Type *type = build_frontend_type (TREE_TYPE (cst)); if (type) { /* Convert our GCC CST tree into a D Expression. This seems like we are trying too hard, as these will only be converted back to a tree again later in the codegen pass, but satisfies the need to have GCC built-ins CTFE-able in the frontend. */ tree_code code = TREE_CODE (cst); if (code == COMPLEX_CST) { real_value re = TREE_REAL_CST (TREE_REALPART (cst)); real_value im = TREE_REAL_CST (TREE_IMAGPART (cst)); complex_t value = complex_t (ldouble (re), ldouble (im)); return ComplexExp::create (Loc (), value, type); } else if (code == INTEGER_CST) { dinteger_t value = TREE_INT_CST_LOW (cst); return IntegerExp::create (Loc (), value, type); } else if (code == REAL_CST) { real_value value = TREE_REAL_CST (cst); return RealExp::create (Loc (), ldouble (value), type); } else if (code == STRING_CST) { const void *string = TREE_STRING_POINTER (cst); size_t len = TREE_STRING_LENGTH (cst); return StringExp::create (Loc (), CONST_CAST (void *, string), len); } else if (code == VECTOR_CST) { dinteger_t nunits = VECTOR_CST_NELTS (cst).to_constant (); Expressions *elements = new Expressions; elements->setDim (nunits); for (size_t i = 0; i < nunits; i++) { Expression *elem = d_eval_constant_expression (VECTOR_CST_ELT (cst, i)); if (elem == NULL) return NULL; (*elements)[i] = elem; } Expression *e = ArrayLiteralExp::create (Loc (), elements); e->type = ((TypeVector *) type)->basetype; return VectorExp::create (Loc (), e, type); } } return NULL; } /* Callback for TARGET_D_CPU_VERSIONS and TARGET_D_OS_VERSIONS. Adds IDENT to the list of predefined version identifiers. */ void d_add_builtin_version (const char* ident) { /* For now, we need to tell the D frontend what platform is being targeted. This should be removed once the frontend has been fixed. */ if (strcmp (ident, "linux") == 0) global.params.isLinux = true; else if (strcmp (ident, "OSX") == 0) global.params.isOSX = true; else if (strcmp (ident, "Windows") == 0) global.params.isWindows = true; else if (strcmp (ident, "FreeBSD") == 0) global.params.isFreeBSD = true; else if (strcmp (ident, "OpenBSD") == 0) global.params.isOpenBSD = true; else if (strcmp (ident, "Solaris") == 0) global.params.isSolaris = true; /* The is64bit field only refers to x86_64 target. */ else if (strcmp (ident, "X86_64") == 0) global.params.is64bit = true; /* No other fields are required to be set for the frontend. */ VersionCondition::addPredefinedGlobalIdent (ident); } /* Initialize the list of all the predefined version identifiers. */ void d_init_versions (void) { VersionCondition::addPredefinedGlobalIdent ("GNU"); VersionCondition::addPredefinedGlobalIdent ("D_Version2"); if (BYTES_BIG_ENDIAN) VersionCondition::addPredefinedGlobalIdent ("BigEndian"); else VersionCondition::addPredefinedGlobalIdent ("LittleEndian"); if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ) VersionCondition::addPredefinedGlobalIdent ("GNU_SjLj_Exceptions"); else if (targetm_common.except_unwind_info (&global_options) == UI_SEH) VersionCondition::addPredefinedGlobalIdent ("GNU_SEH_Exceptions"); else if (targetm_common.except_unwind_info (&global_options) == UI_DWARF2) VersionCondition::addPredefinedGlobalIdent ("GNU_DWARF2_Exceptions"); if (!targetm.have_tls) VersionCondition::addPredefinedGlobalIdent ("GNU_EMUTLS"); #ifdef STACK_GROWS_DOWNWARD VersionCondition::addPredefinedGlobalIdent ("GNU_StackGrowsDown"); #endif /* Should define this anyway to set us apart from the competition. */ VersionCondition::addPredefinedGlobalIdent ("GNU_InlineAsm"); /* LP64 only means 64bit pointers in D. */ if (global.params.isLP64) VersionCondition::addPredefinedGlobalIdent ("D_LP64"); /* Setting `global.params.cov' forces module info generation which is not needed for the GCC coverage implementation. Instead, just test flag_test_coverage while leaving `global.params.cov' unset. */ if (flag_test_coverage) VersionCondition::addPredefinedGlobalIdent ("D_Coverage"); if (flag_pic) VersionCondition::addPredefinedGlobalIdent ("D_PIC"); if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent ("D_Ddoc"); if (global.params.useUnitTests) VersionCondition::addPredefinedGlobalIdent ("unittest"); if (global.params.useAssert == CHECKENABLEon) VersionCondition::addPredefinedGlobalIdent ("assert"); if (global.params.useArrayBounds == CHECKENABLEoff) VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks"); if (global.params.betterC) VersionCondition::addPredefinedGlobalIdent ("D_BetterC"); else { VersionCondition::addPredefinedGlobalIdent ("D_ModuleInfo"); VersionCondition::addPredefinedGlobalIdent ("D_Exceptions"); VersionCondition::addPredefinedGlobalIdent ("D_TypeInfo"); } VersionCondition::addPredefinedGlobalIdent ("all"); /* Emit all target-specific version identifiers. */ targetdm.d_cpu_versions (); targetdm.d_os_versions (); } /* A helper for d_build_builtins_module. Return a new ALIAS for TYPE. Analogous to `alias ALIAS = TYPE' in D code. */ static AliasDeclaration * build_alias_declaration (const char *alias, Type *type) { return AliasDeclaration::create (Loc (), Identifier::idPool (alias), type); } /* A helper function for Target::loadModule. Generates all code for the `gcc.builtins' module, whose frontend symbol should be M. */ void d_build_builtins_module (Module *m) { Dsymbols *members = new Dsymbols; tree decl; for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i) { const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); TypeFunction *tf = (TypeFunction *) build_frontend_type (TREE_TYPE (decl)); /* Cannot create built-in function type for DECL. */ if (!tf) continue; /* A few notes on D2 attributes applied to builtin functions: - It is assumed that built-ins solely provided by the compiler are considered @safe and pure. - Built-ins that correspond to `extern(C)' functions in the standard library that have `__attribute__(nothrow)' are considered `@trusted'. - The purity of a built-in can vary depending on compiler flags set upon initialization, or by the `-foptions' passed, such as flag_unsafe_math_optimizations. - Built-ins never use the GC or raise a D exception, and so are always marked as `nothrow' and `@nogc'. */ tf->purity = DECL_PURE_P (decl) ? PUREstrong : TREE_READONLY (decl) ? PUREconst : DECL_IS_NOVOPS (decl) ? PUREweak : !DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak : PUREimpure; tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe : TREE_NOTHROW (decl) ? TRUSTtrusted : TRUSTsystem; tf->isnothrow = true; tf->isnogc = true; FuncDeclaration *func = FuncDeclaration::create (Loc (), Loc (), Identifier::idPool (name), STCextern, tf); DECL_LANG_SPECIFIC (decl) = build_lang_decl (func); func->csym = decl; func->builtin = BUILTINyes; members->push (func); } for (size_t i = 0; vec_safe_iterate (gcc_builtins_types, i, &decl); ++i) { const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); Type *t = build_frontend_type (TREE_TYPE (decl)); /* Cannot create built-in type for DECL. */ if (!t) continue; members->push (build_alias_declaration (name, t)); } /* Iterate through the target-specific builtin types for va_list. */ if (targetm.enum_va_list_p) { const char *name; tree type; for (int i = 0; targetm.enum_va_list_p (i, &name, &type); ++i) { Type *t = build_frontend_type (type); /* Cannot create built-in type. */ if (!t) continue; members->push (build_alias_declaration (name, t)); } } /* Push out declarations for any RECORD_TYPE types encountered when building all builtin functions and types. */ for (size_t i = 0; i < builtin_converted_decls.length (); ++i) { /* Currently, there is no need to run semantic, but we do want to output initializers, typeinfo, and others on demand. */ Dsymbol *dsym = builtin_converted_decls[i].dsym; if (dsym != NULL) { dsym->parent = m; members->push (dsym); } } /* va_list should already be built, so no need to convert to D type again. */ members->push (build_alias_declaration ("__builtin_va_list", Type::tvalist)); /* Expose target-specific integer types to the builtins module. */ { Type *t = build_frontend_type (long_integer_type_node); members->push (build_alias_declaration ("__builtin_clong", t)); t = build_frontend_type (long_unsigned_type_node); members->push (build_alias_declaration ("__builtin_culong", t)); t = build_frontend_type (long_long_integer_type_node); members->push (build_alias_declaration ("__builtin_clonglong", t)); t = build_frontend_type (long_long_unsigned_type_node); members->push (build_alias_declaration ("__builtin_culonglong", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 0)); members->push (build_alias_declaration ("__builtin_machine_byte", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 1)); members->push (build_alias_declaration ("__builtin_machine_ubyte", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 0)); members->push (build_alias_declaration ("__builtin_machine_int", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 1)); members->push (build_alias_declaration ("__builtin_machine_uint", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 0)); members->push (build_alias_declaration ("__builtin_pointer_int", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 1)); members->push (build_alias_declaration ("__builtin_pointer_uint", t)); /* _Unwind_Word has its own target specific mode. */ machine_mode mode = targetm.unwind_word_mode (); t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 0)); members->push (build_alias_declaration ("__builtin_unwind_int", t)); t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 1)); members->push (build_alias_declaration ("__builtin_unwind_uint", t)); } m->members->push (LinkDeclaration::create (LINKc, members)); } /* Search for any `extern(C)' functions that match any known GCC library builtin function in D and override its internal back-end symbol. */ static void maybe_set_builtin_1 (Dsymbol *d) { AttribDeclaration *ad = d->isAttribDeclaration (); FuncDeclaration *fd = d->isFuncDeclaration (); if (ad != NULL) { /* Recursively search through attribute decls. */ Dsymbols *decls = ad->include (NULL); if (decls && decls->dim) { for (size_t i = 0; i < decls->dim; i++) { Dsymbol *sym = (*decls)[i]; maybe_set_builtin_1 (sym); } } } else if (fd && !fd->fbody) { tree t; for (size_t i = 0; vec_safe_iterate (gcc_builtins_libfuncs, i, &t); ++i) { gcc_assert (DECL_ASSEMBLER_NAME_SET_P (t)); const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t)); if (fd->ident != Identifier::idPool (name)) continue; /* Found a match, tell the frontend this is a builtin. */ DECL_LANG_SPECIFIC (t) = build_lang_decl (fd); fd->csym = t; fd->builtin = BUILTINyes; return; } } } /* A helper function for Target::loadModule. Traverse all members in module M to search for any functions that can be mapped to any GCC builtin. */ void d_maybe_set_builtin (Module *m) { if (!m || !m->members) return; for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *sym = (*m->members)[i]; maybe_set_builtin_1 (sym); } } /* Used to help initialize the builtin-types.def table. When a type of the correct size doesn't exist, use error_mark_node instead of NULL. The latter results in segfaults even when a decl using the type doesn't get invoked. */ static tree builtin_type_for_size (int size, bool unsignedp) { tree type = lang_hooks.types.type_for_size (size, unsignedp); return type ? type : error_mark_node; } /* Support for DEF_BUILTIN. */ static void do_build_builtin_fn (built_in_function fncode, const char *name, built_in_class fnclass, tree fntype, bool both_p, bool fallback_p, tree fnattrs, bool implicit_p) { tree decl; const char *libname; if (fntype == error_mark_node) return; gcc_assert ((!both_p && !fallback_p) || !strncmp (name, "__builtin_", strlen ("__builtin_"))); libname = name + strlen ("__builtin_"); decl = add_builtin_function (name, fntype, fncode, fnclass, fallback_p ? libname : NULL, fnattrs); set_builtin_decl (fncode, decl, implicit_p); } /* Standard data types to be used in builtin argument declarations. */ static GTY(()) tree string_type_node; static GTY(()) tree const_string_type_node; static GTY(()) tree wint_type_node; static GTY(()) tree intmax_type_node; static GTY(()) tree uintmax_type_node; static GTY(()) tree signed_size_type_node; /* Build nodes that would have been created by the C front-end; necessary for including builtin-types.def and ultimately builtins.def. */ static void d_build_c_type_nodes (void) { void_list_node = build_tree_list (NULL_TREE, void_type_node); string_type_node = build_pointer_type (char_type_node); const_string_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST)); if (strcmp (SIZE_TYPE, "unsigned int") == 0) { intmax_type_node = integer_type_node; uintmax_type_node = unsigned_type_node; signed_size_type_node = integer_type_node; } else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) { intmax_type_node = long_integer_type_node; uintmax_type_node = long_unsigned_type_node; signed_size_type_node = long_integer_type_node; } else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) { intmax_type_node = long_long_integer_type_node; uintmax_type_node = long_long_unsigned_type_node; signed_size_type_node = long_long_integer_type_node; } else gcc_unreachable (); wint_type_node = unsigned_type_node; pid_type_node = integer_type_node; } /* Build nodes that are used by the D front-end. These are distinct from C types. */ static void d_build_d_type_nodes (void) { /* Integral types. */ d_byte_type = make_signed_type (8); d_ubyte_type = make_unsigned_type (8); d_short_type = make_signed_type (16); d_ushort_type = make_unsigned_type (16); d_int_type = make_signed_type (32); d_uint_type = make_unsigned_type (32); d_long_type = make_signed_type (64); d_ulong_type = make_unsigned_type (64); d_cent_type = make_signed_type (128); d_ucent_type = make_unsigned_type (128); { /* Re-define size_t as a D type. */ machine_mode type_mode = TYPE_MODE (size_type_node); size_type_node = lang_hooks.types.type_for_mode (type_mode, 1); } /* Bool and Character types. */ d_bool_type = make_unsigned_type (1); TREE_SET_CODE (d_bool_type, BOOLEAN_TYPE); char8_type_node = make_unsigned_type (8); TYPE_STRING_FLAG (char8_type_node) = 1; char16_type_node = make_unsigned_type (16); TYPE_STRING_FLAG (char16_type_node) = 1; char32_type_node = make_unsigned_type (32); TYPE_STRING_FLAG (char32_type_node) = 1; /* Imaginary types. */ ifloat_type_node = build_distinct_type_copy (float_type_node); TYPE_IMAGINARY_FLOAT (ifloat_type_node) = 1; idouble_type_node = build_distinct_type_copy (double_type_node); TYPE_IMAGINARY_FLOAT (idouble_type_node) = 1; ireal_type_node = build_distinct_type_copy (long_double_type_node); TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1; /* Used for ModuleInfo, ClassInfo, and Interface decls. */ unknown_type_node = make_node (RECORD_TYPE); /* Make sure we get a unique function type, so we can give its pointer type a name. (This wins for gdb). */ { tree vfunc_type = make_node (FUNCTION_TYPE); TREE_TYPE (vfunc_type) = d_int_type; TYPE_ARG_TYPES (vfunc_type) = NULL_TREE; layout_type (vfunc_type); vtable_entry_type = build_pointer_type (vfunc_type); } vtbl_ptr_type_node = build_pointer_type (vtable_entry_type); layout_type (vtbl_ptr_type_node); /* When an object is accessed via an interface, this type appears as the first entry in its vtable. */ { tree domain = build_index_type (size_int (3)); vtbl_interface_type_node = build_array_type (ptr_type_node, domain); } /* Use `void[]' as a generic dynamic array type. */ array_type_node = make_struct_type ("__builtin_void[]", 2, get_identifier ("length"), size_type_node, get_identifier ("ptr"), ptr_type_node); TYPE_DYNAMIC_ARRAY (array_type_node) = 1; null_array_node = d_array_value (array_type_node, size_zero_node, null_pointer_node); } /* Handle default attributes. */ enum built_in_attribute { #define DEF_ATTR_NULL_TREE(ENUM) ENUM, #define DEF_ATTR_INT(ENUM, VALUE) ENUM, #define DEF_ATTR_STRING(ENUM, VALUE) ENUM, #define DEF_ATTR_IDENT(ENUM, STRING) ENUM, #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, #include "builtin-attrs.def" #undef DEF_ATTR_NULL_TREE #undef DEF_ATTR_INT #undef DEF_ATTR_STRING #undef DEF_ATTR_IDENT #undef DEF_ATTR_TREE_LIST ATTR_LAST }; static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; /* Initialize the attribute table for all the supported builtins. */ static void d_init_attributes (void) { /* Fill in the built_in_attributes array. */ #define DEF_ATTR_NULL_TREE(ENUM) \ built_in_attributes[(int) ENUM] = NULL_TREE; # define DEF_ATTR_INT(ENUM, VALUE) \ built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); #define DEF_ATTR_STRING(ENUM, VALUE) \ built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE); #define DEF_ATTR_IDENT(ENUM, STRING) \ built_in_attributes[(int) ENUM] = get_identifier (STRING); #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ built_in_attributes[(int) ENUM] \ = tree_cons (built_in_attributes[(int) PURPOSE], \ built_in_attributes[(int) VALUE], \ built_in_attributes[(int) CHAIN]); #include "builtin-attrs.def" #undef DEF_ATTR_NULL_TREE #undef DEF_ATTR_INT #undef DEF_ATTR_STRING #undef DEF_ATTR_IDENT #undef DEF_ATTR_TREE_LIST } /* Builtin types. */ enum d_builtin_type { #define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, #define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, #define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, #define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, #define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9) NAME, #define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10) NAME, #define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, #define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, #define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, #define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ NAME, #define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) NAME, #define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) NAME, #define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_0 #undef DEF_FUNCTION_TYPE_1 #undef DEF_FUNCTION_TYPE_2 #undef DEF_FUNCTION_TYPE_3 #undef DEF_FUNCTION_TYPE_4 #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_9 #undef DEF_FUNCTION_TYPE_10 #undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 #undef DEF_FUNCTION_TYPE_VAR_11 #undef DEF_POINTER_TYPE BT_LAST }; typedef enum d_builtin_type builtin_type; /* A temporary array used in communication with def_fn_type. */ static GTY(()) tree builtin_types[(int) BT_LAST + 1]; /* A helper function for d_init_builtins. Build function type for DEF with return type RET and N arguments. If VAR is true, then the function should be variadic after those N arguments. Takes special care not to ICE if any of the types involved are error_mark_node, which indicates that said type is not in fact available (see builtin_type_for_size). In which case the function type as a whole should be error_mark_node. */ static void def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) { tree t; tree *args = XALLOCAVEC (tree, n); va_list list; int i; va_start (list, n); for (i = 0; i < n; ++i) { builtin_type a = (builtin_type) va_arg (list, int); t = builtin_types[a]; if (t == error_mark_node) goto egress; args[i] = t; } t = builtin_types[ret]; if (t == error_mark_node) goto egress; if (var) t = build_varargs_function_type_array (t, n, args); else t = build_function_type_array (t, n, args); egress: builtin_types[def] = t; va_end (list); } /* Create builtin types and functions. VA_LIST_REF_TYPE_NODE and VA_LIST_ARG_TYPE_NODE are used in builtin-types.def. */ static void d_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, tree va_list_arg_type_node ATTRIBUTE_UNUSED) { #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ builtin_types[(int) ENUM] = VALUE; #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 0, 0); #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ def_fn_type (ENUM, RETURN, 0, 1, ARG1); #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) \ def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) \ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8); #define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9) \ def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8, ARG9); #define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10) \ def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8, ARG9, ARG10); #define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8, ARG9, ARG10, ARG11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ def_fn_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ def_fn_type (ENUM, RETURN, 1, 1, ARG1); #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); #define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); #define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6) \ def_fn_type (ENUM, RETURN, 1, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); #define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7) \ def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); #define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ ARG7, ARG8, ARG9, ARG10, ARG11); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_1 #undef DEF_FUNCTION_TYPE_2 #undef DEF_FUNCTION_TYPE_3 #undef DEF_FUNCTION_TYPE_4 #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_9 #undef DEF_FUNCTION_TYPE_10 #undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 #undef DEF_FUNCTION_TYPE_VAR_11 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; d_init_attributes (); #define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ NONANSI_P, ATTRS, IMPLICIT, COND) \ if (NAME && COND) \ do_build_builtin_fn (ENUM, NAME, CLASS, \ builtin_types[(int) TYPE], \ BOTH_P, FALLBACK_P, \ built_in_attributes[(int) ATTRS], IMPLICIT); #include "builtins.def" #undef DEF_BUILTIN } /* Build builtin functions and types for the D language frontend. */ void d_init_builtins (void) { /* Build the "standard" abi va_list. */ Type::tvalist = build_frontend_type (va_list_type_node); if (!Type::tvalist) { error ("cannot represent built-in va_list type in D"); gcc_unreachable (); } /* Map the va_list type to the D frontend Type. This is to prevent both errors in gimplification or an ICE in targetm.canonical_va_list_type. */ Type::tvalist->ctype = va_list_type_node; TYPE_LANG_SPECIFIC (va_list_type_node) = build_lang_type (Type::tvalist); d_build_c_type_nodes (); d_build_d_type_nodes (); if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) { /* It might seem natural to make the argument type a pointer, but there is no implicit casting from arrays to pointers in D. */ d_define_builtins (va_list_type_node, va_list_type_node); } else { d_define_builtins (build_reference_type (va_list_type_node), va_list_type_node); } targetm.init_builtins (); build_common_builtin_nodes (); } /* Registration of machine- or os-specific builtin types. Add to builtin types list for maybe processing later if `gcc.builtins' was imported into the current module. */ void d_register_builtin_type (tree type, const char *name) { tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier (name), type); DECL_ARTIFICIAL (decl) = 1; if (!TYPE_NAME (type)) TYPE_NAME (type) = decl; vec_safe_push (gcc_builtins_types, decl); } /* Add DECL to builtin functions list for maybe processing later if `gcc.builtins' was imported into the current module. */ tree d_builtin_function (tree decl) { if (!flag_no_builtin && DECL_ASSEMBLER_NAME_SET_P (decl)) vec_safe_push (gcc_builtins_libfuncs, decl); vec_safe_push (gcc_builtins_functions, decl); return decl; } #include "gt-d-d-builtins.h" ================================================ FILE: gcc/d/d-codegen.cc ================================================ /* d-codegen.cc -- Code generation and routines for manipulation of GCC trees. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/ctfe.h" #include "dmd/declaration.h" #include "dmd/identifier.h" #include "dmd/target.h" #include "dmd/template.h" #include "tree.h" #include "tree-iterator.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "target.h" #include "stringpool.h" #include "varasm.h" #include "stor-layout.h" #include "attribs.h" #include "function.h" #include "d-tree.h" /* Return the GCC location for the D frontend location LOC. */ location_t make_location_t (const Loc& loc) { location_t gcc_location = input_location; if (loc.filename) { linemap_add (line_table, LC_ENTER, 0, loc.filename, loc.linnum); linemap_line_start (line_table, loc.linnum, 0); gcc_location = linemap_position_for_column (line_table, loc.charnum); linemap_add (line_table, LC_LEAVE, 0, NULL, 0); } return gcc_location; } /* Return the DECL_CONTEXT for symbol DSYM. */ tree d_decl_context (Dsymbol *dsym) { Dsymbol *parent = dsym; Declaration *decl = dsym->isDeclaration (); while ((parent = parent->toParent ())) { /* We've reached the top-level module namespace. Set DECL_CONTEXT as the NAMESPACE_DECL of the enclosing module, but only for extern(D) symbols. */ if (parent->isModule ()) { if (decl != NULL && decl->linkage != LINKd) return NULL_TREE; return build_import_decl (parent); } /* Declarations marked as 'static' or '__gshared' are never part of any context except at module level. */ if (decl != NULL && decl->isDataseg ()) continue; /* Nested functions. */ FuncDeclaration *fd = parent->isFuncDeclaration (); if (fd != NULL) return get_symbol_decl (fd); /* Methods of classes or structs. */ AggregateDeclaration *ad = parent->isAggregateDeclaration (); if (ad != NULL) { tree context = build_ctype (ad->type); /* Want the underlying RECORD_TYPE. */ if (ad->isClassDeclaration ()) context = TREE_TYPE (context); return context; } /* Instantiated types are given the context of their template. */ TemplateInstance *ti = parent->isTemplateInstance (); if (ti != NULL && decl == NULL) parent = ti->tempdecl; } return NULL_TREE; } /* Return a copy of record TYPE but safe to modify in any way. */ tree copy_aggregate_type (tree type) { tree newtype = build_distinct_type_copy (type); TYPE_FIELDS (newtype) = copy_list (TYPE_FIELDS (type)); for (tree f = TYPE_FIELDS (newtype); f; f = DECL_CHAIN (f)) DECL_FIELD_CONTEXT (f) = newtype; return newtype; } /* Return TRUE if declaration DECL is a reference type. */ bool declaration_reference_p (Declaration *decl) { Type *tb = decl->type->toBasetype (); /* Declaration is a reference type. */ if (tb->ty == Treference || decl->storage_class & (STCout | STCref)) return true; return false; } /* Returns the real type for declaration DECL. */ tree declaration_type (Declaration *decl) { /* Lazy declarations are converted to delegates. */ if (decl->storage_class & STClazy) { TypeFunction *tf = TypeFunction::create (NULL, decl->type, false, LINKd); TypeDelegate *t = TypeDelegate::create (tf); return build_ctype (t->merge2 ()); } /* Static array va_list have array->pointer conversions applied. */ if (decl->isParameter () && valist_array_p (decl->type)) { Type *valist = decl->type->nextOf ()->pointerTo (); valist = valist->castMod (decl->type->mod); return build_ctype (valist); } tree type = build_ctype (decl->type); /* Parameter is passed by reference. */ if (declaration_reference_p (decl)) return build_reference_type (type); /* The 'this' parameter is always const. */ if (decl->isThisDeclaration ()) return insert_type_modifiers (type, MODconst); return type; } /* These should match the Declaration versions above Return TRUE if parameter ARG is a reference type. */ bool argument_reference_p (Parameter *arg) { Type *tb = arg->type->toBasetype (); /* Parameter is a reference type. */ if (tb->ty == Treference || arg->storageClass & (STCout | STCref)) return true; tree type = build_ctype (arg->type); if (TREE_ADDRESSABLE (type)) return true; return false; } /* Returns the real type for parameter ARG. */ tree type_passed_as (Parameter *arg) { /* Lazy parameters are converted to delegates. */ if (arg->storageClass & STClazy) { TypeFunction *tf = TypeFunction::create (NULL, arg->type, false, LINKd); TypeDelegate *t = TypeDelegate::create (tf); return build_ctype (t->merge2 ()); } /* Static array va_list have array->pointer conversions applied. */ if (valist_array_p (arg->type)) { Type *valist = arg->type->nextOf ()->pointerTo (); valist = valist->castMod (arg->type->mod); return build_ctype (valist); } tree type = build_ctype (arg->type); /* Parameter is passed by reference. */ if (argument_reference_p (arg)) return build_reference_type (type); return type; } /* Build INTEGER_CST of type TYPE with the value VALUE. */ tree build_integer_cst (dinteger_t value, tree type) { /* The type is error_mark_node, we can't do anything. */ if (error_operand_p (type)) return type; return build_int_cst_type (type, value); } /* Build REAL_CST of type TOTYPE with the value VALUE. */ tree build_float_cst (const real_t& value, Type *totype) { real_t new_value; TypeBasic *tb = totype->isTypeBasic (); gcc_assert (tb != NULL); tree type_node = build_ctype (tb); real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ()); return build_real (type_node, new_value.rv ()); } /* Returns the .length component from the D dynamic array EXP. */ tree d_array_length (tree exp) { if (error_operand_p (exp)) return exp; gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp))); /* Get the back-end type for the array and pick out the array length field (assumed to be the first field). */ tree len_field = TYPE_FIELDS (TREE_TYPE (exp)); return component_ref (exp, len_field); } /* Returns the .ptr component from the D dynamic array EXP. */ tree d_array_ptr (tree exp) { if (error_operand_p (exp)) return exp; gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp))); /* Get the back-end type for the array and pick out the array data pointer field (assumed to be the second field). */ tree ptr_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp))); return component_ref (exp, ptr_field); } /* Returns a constructor for D dynamic array type TYPE of .length LEN and .ptr pointing to DATA. */ tree d_array_value (tree type, tree len, tree data) { tree len_field, ptr_field; vec *ce = NULL; gcc_assert (TYPE_DYNAMIC_ARRAY (type)); len_field = TYPE_FIELDS (type); ptr_field = TREE_CHAIN (len_field); len = convert (TREE_TYPE (len_field), len); data = convert (TREE_TYPE (ptr_field), data); CONSTRUCTOR_APPEND_ELT (ce, len_field, len); CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data); return build_constructor (type, ce); } /* Returns value representing the array length of expression EXP. TYPE could be a dynamic or static array. */ tree get_array_length (tree exp, Type *type) { Type *tb = type->toBasetype (); switch (tb->ty) { case Tsarray: return size_int (((TypeSArray *) tb)->dim->toUInteger ()); case Tarray: return d_array_length (exp); default: error ("can't determine the length of a %qs", type->toChars ()); return error_mark_node; } } /* Create BINFO for a ClassDeclaration's inheritance tree. InterfaceDeclaration's are not included. */ tree build_class_binfo (tree super, ClassDeclaration *cd) { tree binfo = make_tree_binfo (1); tree ctype = build_ctype (cd->type); /* Want RECORD_TYPE, not POINTER_TYPE. */ BINFO_TYPE (binfo) = TREE_TYPE (ctype); BINFO_INHERITANCE_CHAIN (binfo) = super; BINFO_OFFSET (binfo) = integer_zero_node; if (cd->baseClass) BINFO_BASE_APPEND (binfo, build_class_binfo (binfo, cd->baseClass)); return binfo; } /* Create BINFO for an InterfaceDeclaration's inheritance tree. In order to access all inherited methods in the debugger, the entire tree must be described. This function makes assumptions about interface layout. */ tree build_interface_binfo (tree super, ClassDeclaration *cd, unsigned& offset) { tree binfo = make_tree_binfo (cd->baseclasses->dim); tree ctype = build_ctype (cd->type); /* Want RECORD_TYPE, not POINTER_TYPE. */ BINFO_TYPE (binfo) = TREE_TYPE (ctype); BINFO_INHERITANCE_CHAIN (binfo) = super; BINFO_OFFSET (binfo) = size_int (offset * Target::ptrsize); BINFO_VIRTUAL_P (binfo) = 1; for (size_t i = 0; i < cd->baseclasses->dim; i++, offset++) { BaseClass *bc = (*cd->baseclasses)[i]; BINFO_BASE_APPEND (binfo, build_interface_binfo (binfo, bc->sym, offset)); } return binfo; } /* Returns the .funcptr component from the D delegate EXP. */ tree delegate_method (tree exp) { /* Get the back-end type for the delegate and pick out the funcptr field (assumed to be the second field). */ gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp))); tree method_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp))); return component_ref (exp, method_field); } /* Returns the .object component from the delegate EXP. */ tree delegate_object (tree exp) { /* Get the back-end type for the delegate and pick out the object field (assumed to be the first field). */ gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp))); tree obj_field = TYPE_FIELDS (TREE_TYPE (exp)); return component_ref (exp, obj_field); } /* Build a delegate literal of type TYPE whose pointer function is METHOD, and hidden object is OBJECT. */ tree build_delegate_cst (tree method, tree object, Type *type) { tree ctor = make_node (CONSTRUCTOR); tree ctype; Type *tb = type->toBasetype (); if (tb->ty == Tdelegate) ctype = build_ctype (type); else { /* Convert a function method into an anonymous delegate. */ ctype = make_struct_type ("delegate()", 2, get_identifier ("object"), TREE_TYPE (object), get_identifier ("func"), TREE_TYPE (method)); TYPE_DELEGATE (ctype) = 1; } vec *ce = NULL; CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (ctype), object); CONSTRUCTOR_APPEND_ELT (ce, TREE_CHAIN (TYPE_FIELDS (ctype)), method); CONSTRUCTOR_ELTS (ctor) = ce; TREE_TYPE (ctor) = ctype; return ctor; } /* Builds a temporary tree to store the CALLEE and OBJECT of a method call expression of type TYPE. */ tree build_method_call (tree callee, tree object, Type *type) { tree t = build_delegate_cst (callee, object, type); METHOD_CALL_EXPR (t) = 1; return t; } /* Extract callee and object from T and return in to CALLEE and OBJECT. */ void extract_from_method_call (tree t, tree& callee, tree& object) { gcc_assert (METHOD_CALL_EXPR (t)); object = CONSTRUCTOR_ELT (t, 0)->value; callee = CONSTRUCTOR_ELT (t, 1)->value; } /* Build a dereference into the virtual table for OBJECT to retrieve a function pointer of type FNTYPE at position INDEX. */ tree build_vindex_ref (tree object, tree fntype, size_t index) { /* The vtable is the first field. Interface methods are also in the class's vtable, so we don't need to convert from a class to an interface. */ tree result = build_deref (object); result = component_ref (result, TYPE_FIELDS (TREE_TYPE (result))); gcc_assert (POINTER_TYPE_P (fntype)); return build_memref (fntype, result, size_int (Target::ptrsize * index)); } /* Return TRUE if EXP is a valid lvalue. Lvalue references cannot be made into temporaries, otherwise any assignments will be lost. */ static bool lvalue_p (tree exp) { const enum tree_code code = TREE_CODE (exp); switch (code) { case SAVE_EXPR: return false; case ARRAY_REF: case INDIRECT_REF: case VAR_DECL: case PARM_DECL: case RESULT_DECL: return !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (exp)); case IMAGPART_EXPR: case REALPART_EXPR: case COMPONENT_REF: CASE_CONVERT: return lvalue_p (TREE_OPERAND (exp, 0)); case COND_EXPR: return (lvalue_p (TREE_OPERAND (exp, 1) ? TREE_OPERAND (exp, 1) : TREE_OPERAND (exp, 0)) && lvalue_p (TREE_OPERAND (exp, 2))); case TARGET_EXPR: return true; case COMPOUND_EXPR: return lvalue_p (TREE_OPERAND (exp, 1)); default: return false; } } /* Create a SAVE_EXPR if EXP might have unwanted side effects if referenced more than once in an expression. */ tree d_save_expr (tree exp) { if (TREE_SIDE_EFFECTS (exp)) { if (lvalue_p (exp)) return stabilize_reference (exp); return save_expr (exp); } return exp; } /* VALUEP is an expression we want to pre-evaluate or perform a computation on. The expression returned by this function is the part whose value we don't care about, storing the value in VALUEP. Callers must ensure that the returned expression is evaluated before VALUEP. */ tree stabilize_expr (tree *valuep) { tree expr = *valuep; const enum tree_code code = TREE_CODE (expr); tree lhs; tree rhs; switch (code) { case COMPOUND_EXPR: /* Given ((e1, ...), eN): Store the last RHS 'eN' expression in VALUEP. */ lhs = TREE_OPERAND (expr, 0); rhs = TREE_OPERAND (expr, 1); lhs = compound_expr (lhs, stabilize_expr (&rhs)); *valuep = rhs; return lhs; default: return NULL_TREE; } } /* Return a TARGET_EXPR, initializing the DECL with EXP. */ tree build_target_expr (tree decl, tree exp) { tree type = TREE_TYPE (decl); tree result = build4 (TARGET_EXPR, type, decl, exp, NULL_TREE, NULL_TREE); if (EXPR_HAS_LOCATION (exp)) SET_EXPR_LOCATION (result, EXPR_LOCATION (exp)); /* If decl must always reside in memory. */ if (TREE_ADDRESSABLE (type)) d_mark_addressable (decl); /* Always set TREE_SIDE_EFFECTS so that expand_expr does not ignore the TARGET_EXPR. If there really turn out to be no side effects, then the optimizer should be able to remove it. */ TREE_SIDE_EFFECTS (result) = 1; return result; } /* Like the above function, but initializes a new temporary. */ tree force_target_expr (tree exp) { tree decl = create_temporary_var (TREE_TYPE (exp)); return build_target_expr (decl, exp); } /* Returns the address of the expression EXP. */ tree build_address (tree exp) { if (error_operand_p (exp)) return exp; tree ptrtype; tree type = TREE_TYPE (exp); if (TREE_CODE (exp) == STRING_CST) { /* Just convert string literals (char[]) to C-style strings (char *), otherwise the latter method (char[]*) causes conversion problems during gimplification. */ ptrtype = build_pointer_type (TREE_TYPE (type)); } else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node) && TREE_CODE (TYPE_MAIN_VARIANT (type)) == ARRAY_TYPE) { /* Special case for va_list, allow arrays to decay to a pointer. */ ptrtype = build_pointer_type (TREE_TYPE (type)); } else ptrtype = build_pointer_type (type); /* Maybe rewrite: &(e1, e2) => (e1, &e2). */ tree init = stabilize_expr (&exp); /* Can't take the address of a manifest constant, instead use its value. */ if (TREE_CODE (exp) == CONST_DECL) exp = DECL_INITIAL (exp); /* Some expression lowering may request an address of a compile-time constant. Make sure it is assigned to a location we can reference. */ if (CONSTANT_CLASS_P (exp) && TREE_CODE (exp) != STRING_CST) exp = force_target_expr (exp); d_mark_addressable (exp); exp = build_fold_addr_expr_with_type_loc (input_location, exp, ptrtype); if (TREE_CODE (exp) == ADDR_EXPR) TREE_NO_TRAMPOLINE (exp) = 1; return compound_expr (init, exp); } /* Mark EXP saying that we need to be able to take the address of it; it should not be allocated in a register. */ tree d_mark_addressable (tree exp) { switch (TREE_CODE (exp)) { case ADDR_EXPR: case COMPONENT_REF: case ARRAY_REF: case REALPART_EXPR: case IMAGPART_EXPR: d_mark_addressable (TREE_OPERAND (exp, 0)); break; case PARM_DECL: case VAR_DECL: case RESULT_DECL: case CONST_DECL: case FUNCTION_DECL: TREE_ADDRESSABLE (exp) = 1; break; case CONSTRUCTOR: TREE_ADDRESSABLE (exp) = 1; break; case TARGET_EXPR: TREE_ADDRESSABLE (exp) = 1; d_mark_addressable (TREE_OPERAND (exp, 0)); break; default: break; } return exp; } /* Mark EXP as "used" in the program for the benefit of -Wunused warning purposes. */ tree d_mark_used (tree exp) { switch (TREE_CODE (exp)) { case VAR_DECL: case CONST_DECL: case PARM_DECL: case RESULT_DECL: case FUNCTION_DECL: TREE_USED (exp) = 1; break; case ARRAY_REF: case COMPONENT_REF: case MODIFY_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: case NOP_EXPR: case CONVERT_EXPR: case ADDR_EXPR: d_mark_used (TREE_OPERAND (exp, 0)); break; case COMPOUND_EXPR: d_mark_used (TREE_OPERAND (exp, 0)); d_mark_used (TREE_OPERAND (exp, 1)); break; default: break; } return exp; } /* Mark EXP as read, not just set, for set but not used -Wunused warning purposes. */ tree d_mark_read (tree exp) { switch (TREE_CODE (exp)) { case VAR_DECL: case PARM_DECL: TREE_USED (exp) = 1; DECL_READ_P (exp) = 1; break; case ARRAY_REF: case COMPONENT_REF: case MODIFY_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: case NOP_EXPR: case CONVERT_EXPR: case ADDR_EXPR: d_mark_read (TREE_OPERAND (exp, 0)); break; case COMPOUND_EXPR: d_mark_read (TREE_OPERAND (exp, 1)); break; default: break; } return exp; } /* Return TRUE if the struct SD is suitable for comparison using memcmp. This is because we don't guarantee that padding is zero-initialized for a stack variable, so we can't use memcmp to compare struct values. */ bool identity_compare_p (StructDeclaration *sd) { if (sd->isUnionDeclaration ()) return true; unsigned offset = 0; for (size_t i = 0; i < sd->fields.dim; i++) { VarDeclaration *vd = sd->fields[i]; /* Check inner data structures. */ if (vd->type->ty == Tstruct) { TypeStruct *ts = (TypeStruct *) vd->type; if (!identity_compare_p (ts->sym)) return false; } if (offset <= vd->offset) { /* There's a hole in the struct. */ if (offset != vd->offset) return false; offset += vd->type->size (); } } /* Any trailing padding may not be zero. */ if (offset < sd->structsize) return false; return true; } /* Lower a field-by-field equality expression between T1 and T2 of type SD. CODE is the EQ_EXPR or NE_EXPR comparison. */ static tree lower_struct_comparison (tree_code code, StructDeclaration *sd, tree t1, tree t2) { tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; tree tmemcmp = NULL_TREE; /* We can skip the compare if the structs are empty. */ if (sd->fields.dim == 0) { tmemcmp = build_boolop (code, integer_zero_node, integer_zero_node); if (TREE_SIDE_EFFECTS (t2)) tmemcmp = compound_expr (t2, tmemcmp); if (TREE_SIDE_EFFECTS (t1)) tmemcmp = compound_expr (t1, tmemcmp); return tmemcmp; } /* Let back-end take care of union comparisons. */ if (sd->isUnionDeclaration ()) { tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3, build_address (t1), build_address (t2), size_int (sd->structsize)); return build_boolop (code, tmemcmp, integer_zero_node); } for (size_t i = 0; i < sd->fields.dim; i++) { VarDeclaration *vd = sd->fields[i]; tree sfield = get_symbol_decl (vd); tree t1ref = component_ref (t1, sfield); tree t2ref = component_ref (t2, sfield); tree tcmp; if (vd->type->ty == Tstruct) { /* Compare inner data structures. */ StructDeclaration *decl = ((TypeStruct *) vd->type)->sym; tcmp = lower_struct_comparison (code, decl, t1ref, t2ref); } else { tree stype = build_ctype (vd->type); opt_scalar_int_mode mode = int_mode_for_mode (TYPE_MODE (stype)); if (vd->type->ty != Tvector && vd->type->isintegral ()) { /* Integer comparison, no special handling required. */ tcmp = build_boolop (code, t1ref, t2ref); } else if (mode.exists ()) { /* Compare field bits as their corresponding integer type. *((T*) &t1) == *((T*) &t2) */ tree tmode = lang_hooks.types.type_for_mode (mode.require (), 1); if (tmode == NULL_TREE) tmode = make_unsigned_type (GET_MODE_BITSIZE (mode.require ())); t1ref = build_vconvert (tmode, t1ref); t2ref = build_vconvert (tmode, t2ref); tcmp = build_boolop (code, t1ref, t2ref); } else { /* Simple memcmp between types. */ tcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3, build_address (t1ref), build_address (t2ref), TYPE_SIZE_UNIT (stype)); tcmp = build_boolop (code, tcmp, integer_zero_node); } } tmemcmp = (tmemcmp) ? build_boolop (tcode, tmemcmp, tcmp) : tcmp; } return tmemcmp; } /* Build an equality expression between two RECORD_TYPES T1 and T2 of type SD. If possible, use memcmp, otherwise field-by-field comparison is done. CODE is the EQ_EXPR or NE_EXPR comparison. */ tree build_struct_comparison (tree_code code, StructDeclaration *sd, tree t1, tree t2) { /* We can skip the compare if the structs are empty. */ if (sd->fields.dim == 0) { tree exp = build_boolop (code, integer_zero_node, integer_zero_node); if (TREE_SIDE_EFFECTS (t2)) exp = compound_expr (t2, exp); if (TREE_SIDE_EFFECTS (t1)) exp = compound_expr (t1, exp); return exp; } /* Make temporaries to prevent multiple evaluations. */ tree t1init = stabilize_expr (&t1); tree t2init = stabilize_expr (&t2); tree result; t1 = d_save_expr (t1); t2 = d_save_expr (t2); /* Bitwise comparison of structs not returned in memory may not work due to data holes loosing its zero padding upon return. As a heuristic, small structs are not compared using memcmp either. */ if (TYPE_MODE (TREE_TYPE (t1)) != BLKmode || !identity_compare_p (sd)) result = lower_struct_comparison (code, sd, t1, t2); else { /* Do bit compare of structs. */ tree size = size_int (sd->structsize); tree tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3, build_address (t1), build_address (t2), size); result = build_boolop (code, tmemcmp, integer_zero_node); } return compound_expr (compound_expr (t1init, t2init), result); } /* Build an equality expression between two ARRAY_TYPES of size LENGTH. The pointer references are T1 and T2, and the element type is SD. CODE is the EQ_EXPR or NE_EXPR comparison. */ tree build_array_struct_comparison (tree_code code, StructDeclaration *sd, tree length, tree t1, tree t2) { tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; /* Build temporary for the result of the comparison. Initialize as either 0 or 1 depending on operation. */ tree result = build_local_temp (d_bool_type); tree init = build_boolop (code, integer_zero_node, integer_zero_node); add_stmt (build_assign (INIT_EXPR, result, init)); /* Cast pointer-to-array to pointer-to-struct. */ tree ptrtype = build_ctype (sd->type->pointerTo ()); tree lentype = TREE_TYPE (length); push_binding_level (level_block); push_stmt_list (); /* Build temporary locals for length and pointers. */ tree t = build_local_temp (size_type_node); add_stmt (build_assign (INIT_EXPR, t, length)); length = t; t = build_local_temp (ptrtype); add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t1))); t1 = t; t = build_local_temp (ptrtype); add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t2))); t2 = t; /* Build loop for comparing each element. */ push_stmt_list (); /* Exit logic for the loop. if (length == 0 || result OP 0) break; */ t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node)); t = build_boolop (TRUTH_ORIF_EXPR, t, build_boolop (code, result, boolean_false_node)); t = build1 (EXIT_EXPR, void_type_node, t); add_stmt (t); /* Do comparison, caching the value. result = result OP (*t1 == *t2); */ t = build_struct_comparison (code, sd, build_deref (t1), build_deref (t2)); t = build_boolop (tcode, result, t); t = modify_expr (result, t); add_stmt (t); /* Move both pointers to next element position. t1++, t2++; */ tree size = d_convert (ptrtype, TYPE_SIZE_UNIT (TREE_TYPE (ptrtype))); t = build2 (POSTINCREMENT_EXPR, ptrtype, t1, size); add_stmt (t); t = build2 (POSTINCREMENT_EXPR, ptrtype, t2, size); add_stmt (t); /* Decrease loop counter. length -= 1; */ t = build2 (POSTDECREMENT_EXPR, lentype, length, d_convert (lentype, integer_one_node)); add_stmt (t); /* Pop statements and finish loop. */ tree body = pop_stmt_list (); add_stmt (build1 (LOOP_EXPR, void_type_node, body)); /* Wrap it up into a bind expression. */ tree stmt_list = pop_stmt_list (); tree block = pop_binding_level (); body = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), stmt_list, block); return compound_expr (body, result); } /* Create an anonymous field of type ubyte[T] at OFFSET to fill the alignment hole between OFFSET and FIELDPOS. */ static tree build_alignment_field (tree type, HOST_WIDE_INT offset, HOST_WIDE_INT fieldpos) { tree atype = make_array_type (Type::tuns8, fieldpos - offset); tree field = create_field_decl (atype, NULL, 1, 1); SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (atype)); DECL_FIELD_OFFSET (field) = size_int (offset); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; DECL_FIELD_CONTEXT (field) = type; DECL_PADDING_P (field) = 1; layout_decl (field, 0); return field; } /* Build a constructor for a variable of aggregate type TYPE using the initializer INIT, an ordered flat list of fields and values provided by the frontend. The returned constructor should be a value that matches the layout of TYPE. */ tree build_struct_literal (tree type, vec *init) { /* If the initializer was empty, use default zero initialization. */ if (vec_safe_is_empty (init)) return build_constructor (type, NULL); vec *ve = NULL; HOST_WIDE_INT offset = 0; bool constant_p = true; bool fillholes = true; bool finished = false; /* Filling alignment holes this only applies to structs. */ if (TREE_CODE (type) != RECORD_TYPE || CLASS_TYPE_P (type) || TYPE_PACKED (type)) fillholes = false; /* Walk through each field, matching our initializer list. */ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { bool is_initialized = false; tree value; if (DECL_NAME (field) == NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && ANON_AGGR_TYPE_P (TREE_TYPE (field))) { /* Search all nesting aggregates, if nothing is found, then this will return an empty initializer to fill the hole. */ value = build_struct_literal (TREE_TYPE (field), init); if (!initializer_zerop (value)) is_initialized = true; } else { /* Search for the value to initialize the next field. Once found, pop it from the init list so we don't look at it again. */ unsigned HOST_WIDE_INT idx; tree index; FOR_EACH_CONSTRUCTOR_ELT (init, idx, index, value) { /* If the index is NULL, then just assign it to the next field. This comes from layout_typeinfo(), which generates a flat list of values that we must shape into the record type. */ if (index == field || index == NULL_TREE) { init->ordered_remove (idx); if (!finished) is_initialized = true; break; } } } if (is_initialized) { HOST_WIDE_INT fieldpos = int_byte_position (field); gcc_assert (value != NULL_TREE); /* Insert anonymous fields in the constructor for padding out alignment holes in-place between fields. */ if (fillholes && offset < fieldpos) { tree pfield = build_alignment_field (type, offset, fieldpos); tree pvalue = build_zero_cst (TREE_TYPE (pfield)); CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue); } /* Must not initialize fields that overlap. */ if (fieldpos < offset) { /* Find the nearest user defined type and field. */ tree vtype = type; while (ANON_AGGR_TYPE_P (vtype)) vtype = TYPE_CONTEXT (vtype); tree vfield = field; if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (vfield)) && ANON_AGGR_TYPE_P (TREE_TYPE (vfield))) vfield = TYPE_FIELDS (TREE_TYPE (vfield)); /* Must not generate errors for compiler generated fields. */ gcc_assert (TYPE_NAME (vtype) && DECL_NAME (vfield)); error ("overlapping initializer for field %qT.%qD", TYPE_NAME (vtype), DECL_NAME (vfield)); } if (!TREE_CONSTANT (value)) constant_p = false; CONSTRUCTOR_APPEND_ELT (ve, field, value); /* For unions, only the first field is initialized, any other field initializers found for this union are drained and ignored. */ if (TREE_CODE (type) == UNION_TYPE) finished = true; } /* Move offset to the next position in the struct. */ if (TREE_CODE (type) == RECORD_TYPE) { offset = int_byte_position (field) + int_size_in_bytes (TREE_TYPE (field)); } /* If all initializers have been assigned, there's nothing else to do. */ if (vec_safe_is_empty (init)) break; } /* Finally pad out the end of the record. */ if (fillholes && offset < int_size_in_bytes (type)) { tree pfield = build_alignment_field (type, offset, int_size_in_bytes (type)); tree pvalue = build_zero_cst (TREE_TYPE (pfield)); CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue); } /* Ensure that we have consumed all values. */ gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type)); tree ctor = build_constructor (type, ve); if (constant_p) TREE_CONSTANT (ctor) = 1; return ctor; } /* Given the TYPE of an anonymous field inside T, return the FIELD_DECL for the field. If not found return NULL_TREE. Because anonymous types can nest, we must also search all anonymous fields that are directly reachable. */ static tree lookup_anon_field (tree t, tree type) { t = TYPE_MAIN_VARIANT (t); for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) { if (DECL_NAME (field) == NULL_TREE) { /* If we find it directly, return the field. */ if (type == TYPE_MAIN_VARIANT (TREE_TYPE (field))) return field; /* Otherwise, it could be nested, search harder. */ if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && ANON_AGGR_TYPE_P (TREE_TYPE (field))) { tree subfield = lookup_anon_field (TREE_TYPE (field), type); if (subfield) return subfield; } } } return NULL_TREE; } /* Builds OBJECT.FIELD component reference. */ tree component_ref (tree object, tree field) { if (error_operand_p (object) || error_operand_p (field)) return error_mark_node; gcc_assert (TREE_CODE (field) == FIELD_DECL); /* Maybe rewrite: (e1, e2).field => (e1, e2.field) */ tree init = stabilize_expr (&object); /* If the FIELD is from an anonymous aggregate, generate a reference to the anonymous data member, and recur to find FIELD. */ if (ANON_AGGR_TYPE_P (DECL_CONTEXT (field))) { tree anonymous_field = lookup_anon_field (TREE_TYPE (object), DECL_CONTEXT (field)); object = component_ref (object, anonymous_field); } tree result = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), object, field, NULL_TREE); return compound_expr (init, result); } /* Build an assignment expression of lvalue LHS from value RHS. CODE is the code for a binary operator that we use to combine the old value of LHS with RHS to get the new value. */ tree build_assign (tree_code code, tree lhs, tree rhs) { tree init = stabilize_expr (&lhs); init = compound_expr (init, stabilize_expr (&rhs)); /* If initializing the LHS using a function that returns via NRVO. */ if (code == INIT_EXPR && TREE_CODE (rhs) == CALL_EXPR && AGGREGATE_TYPE_P (TREE_TYPE (rhs)) && aggregate_value_p (TREE_TYPE (rhs), rhs)) { /* Mark as addressable here, which should ensure the return slot is the address of the LHS expression, taken care of by back-end. */ d_mark_addressable (lhs); CALL_EXPR_RETURN_SLOT_OPT (rhs) = true; } /* The LHS assignment replaces the temporary in TARGET_EXPR_SLOT. */ if (TREE_CODE (rhs) == TARGET_EXPR) { /* If CODE is not INIT_EXPR, can't initialize LHS directly, since that would cause the LHS to be constructed twice. So we force the TARGET_EXPR to be expanded without a target. */ if (code != INIT_EXPR) rhs = compound_expr (rhs, TARGET_EXPR_SLOT (rhs)); else { d_mark_addressable (lhs); rhs = TARGET_EXPR_INITIAL (rhs); } } tree result = fold_build2_loc (input_location, code, TREE_TYPE (lhs), lhs, rhs); return compound_expr (init, result); } /* Build an assignment expression of lvalue LHS from value RHS. */ tree modify_expr (tree lhs, tree rhs) { return build_assign (MODIFY_EXPR, lhs, rhs); } /* Return EXP represented as TYPE. */ tree build_nop (tree type, tree exp) { if (error_operand_p (exp)) return exp; /* Maybe rewrite: cast(TYPE)(e1, e2) => (e1, cast(TYPE) e2) */ tree init = stabilize_expr (&exp); exp = fold_build1_loc (input_location, NOP_EXPR, type, exp); return compound_expr (init, exp); } /* Return EXP to be viewed as being another type TYPE. Same as build_nop, except that EXP is type-punned, rather than a straight-forward cast. */ tree build_vconvert (tree type, tree exp) { /* Building *(cast(TYPE *)&e1) directly rather then using VIEW_CONVERT_EXPR makes sure this works for vector-to-array viewing, or if EXP ends up being used as the LHS of a MODIFY_EXPR. */ return indirect_ref (type, build_address (exp)); } /* Maybe warn about ARG being an address that can never be null. */ static void warn_for_null_address (tree arg) { if (TREE_CODE (arg) == ADDR_EXPR && decl_with_nonnull_addr_p (TREE_OPERAND (arg, 0))) warning (OPT_Waddress, "the address of %qD will never be %", TREE_OPERAND (arg, 0)); } /* Build a boolean ARG0 op ARG1 expression. */ tree build_boolop (tree_code code, tree arg0, tree arg1) { /* Aggregate comparisons may get lowered to a call to builtin memcmp, so need to remove all side effects incase its address is taken. */ if (AGGREGATE_TYPE_P (TREE_TYPE (arg0))) arg0 = d_save_expr (arg0); if (AGGREGATE_TYPE_P (TREE_TYPE (arg1))) arg1 = d_save_expr (arg1); if (VECTOR_TYPE_P (TREE_TYPE (arg0)) && VECTOR_TYPE_P (TREE_TYPE (arg1))) { /* Build a vector comparison. VEC_COND_EXPR ; */ tree type = TREE_TYPE (arg0); tree cmptype = build_same_sized_truth_vector_type (type); tree cmp = fold_build2_loc (input_location, code, cmptype, arg0, arg1); return fold_build3_loc (input_location, VEC_COND_EXPR, type, cmp, build_minus_one_cst (type), build_zero_cst (type)); } if (code == EQ_EXPR || code == NE_EXPR) { /* Check if comparing the address of a variable to null. */ if (POINTER_TYPE_P (TREE_TYPE (arg0)) && integer_zerop (arg1)) warn_for_null_address (arg0); if (POINTER_TYPE_P (TREE_TYPE (arg1)) && integer_zerop (arg0)) warn_for_null_address (arg1); } return fold_build2_loc (input_location, code, d_bool_type, arg0, d_convert (TREE_TYPE (arg0), arg1)); } /* Return a COND_EXPR. ARG0, ARG1, and ARG2 are the three arguments to the conditional expression. */ tree build_condition (tree type, tree arg0, tree arg1, tree arg2) { if (arg1 == void_node) arg1 = build_empty_stmt (input_location); if (arg2 == void_node) arg2 = build_empty_stmt (input_location); return fold_build3_loc (input_location, COND_EXPR, type, arg0, arg1, arg2); } tree build_vcondition (tree arg0, tree arg1, tree arg2) { return build_condition (void_type_node, arg0, arg1, arg2); } /* Build a compound expr to join ARG0 and ARG1 together. */ tree compound_expr (tree arg0, tree arg1) { if (arg1 == NULL_TREE) return arg0; if (arg0 == NULL_TREE || !TREE_SIDE_EFFECTS (arg0)) return arg1; if (TREE_CODE (arg1) == TARGET_EXPR) { /* If the rhs is a TARGET_EXPR, then build the compound expression inside the target_expr's initializer. This helps the compiler to eliminate unnecessary temporaries. */ tree init = compound_expr (arg0, TARGET_EXPR_INITIAL (arg1)); TARGET_EXPR_INITIAL (arg1) = init; return arg1; } return fold_build2_loc (input_location, COMPOUND_EXPR, TREE_TYPE (arg1), arg0, arg1); } /* Build a return expression. */ tree return_expr (tree ret) { return fold_build1_loc (input_location, RETURN_EXPR, void_type_node, ret); } /* Return the product of ARG0 and ARG1 as a size_type_node. */ tree size_mult_expr (tree arg0, tree arg1) { return fold_build2_loc (input_location, MULT_EXPR, size_type_node, d_convert (size_type_node, arg0), d_convert (size_type_node, arg1)); } /* Return the real part of CE, which should be a complex expression. */ tree real_part (tree ce) { return fold_build1_loc (input_location, REALPART_EXPR, TREE_TYPE (TREE_TYPE (ce)), ce); } /* Return the imaginary part of CE, which should be a complex expression. */ tree imaginary_part (tree ce) { return fold_build1_loc (input_location, IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (ce)), ce); } /* Build a complex expression of type TYPE using RE and IM. */ tree complex_expr (tree type, tree re, tree im) { return fold_build2_loc (input_location, COMPLEX_EXPR, type, re, im); } /* Cast EXP (which should be a pointer) to TYPE* and then indirect. The back-end requires this cast in many cases. */ tree indirect_ref (tree type, tree exp) { if (error_operand_p (exp)) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ tree init = stabilize_expr (&exp); if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE) exp = fold_build1 (INDIRECT_REF, type, exp); else { exp = build_nop (build_pointer_type (type), exp); exp = build_deref (exp); } return compound_expr (init, exp); } /* Returns indirect reference of EXP, which must be a pointer type. */ tree build_deref (tree exp) { if (error_operand_p (exp)) return exp; /* Maybe rewrite: *(e1, e2) => (e1, *e2) */ tree init = stabilize_expr (&exp); gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp))); if (TREE_CODE (exp) == ADDR_EXPR) exp = TREE_OPERAND (exp, 0); else exp = build_fold_indirect_ref (exp); return compound_expr (init, exp); } /* Builds pointer offset expression PTR[INDEX]. */ tree build_array_index (tree ptr, tree index) { if (error_operand_p (ptr) || error_operand_p (index)) return error_mark_node; tree ptr_type = TREE_TYPE (ptr); tree target_type = TREE_TYPE (ptr_type); tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype), TYPE_UNSIGNED (sizetype)); /* Array element size. */ tree size_exp = size_in_bytes (target_type); if (integer_zerop (size_exp)) { /* Test for array of void. */ if (TYPE_MODE (target_type) == TYPE_MODE (void_type_node)) index = fold_convert (type, index); else { /* Should catch this earlier. */ error ("invalid use of incomplete type %qD", TYPE_NAME (target_type)); ptr_type = error_mark_node; } } else if (integer_onep (size_exp)) { /* Array of bytes -- No need to multiply. */ index = fold_convert (type, index); } else { index = d_convert (type, index); index = fold_build2 (MULT_EXPR, TREE_TYPE (index), index, d_convert (TREE_TYPE (index), size_exp)); index = fold_convert (type, index); } if (integer_zerop (index)) return ptr; return fold_build2 (POINTER_PLUS_EXPR, ptr_type, ptr, index); } /* Builds pointer offset expression *(PTR OP OFFSET) OP could be a plus or minus expression. */ tree build_offset_op (tree_code op, tree ptr, tree offset) { gcc_assert (op == MINUS_EXPR || op == PLUS_EXPR); tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype), TYPE_UNSIGNED (sizetype)); offset = fold_convert (type, offset); if (op == MINUS_EXPR) offset = fold_build1 (NEGATE_EXPR, type, offset); return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, offset); } /* Builds pointer offset expression *(PTR + OFFSET). */ tree build_offset (tree ptr, tree offset) { return build_offset_op (PLUS_EXPR, ptr, offset); } tree build_memref (tree type, tree ptr, tree offset) { return fold_build2 (MEM_REF, type, ptr, fold_convert (type, offset)); } /* Create a tree node to set multiple elements to a single value. */ tree build_array_set (tree ptr, tree length, tree value) { tree ptrtype = TREE_TYPE (ptr); tree lentype = TREE_TYPE (length); push_binding_level (level_block); push_stmt_list (); /* Build temporary locals for length and ptr, and maybe value. */ tree t = build_local_temp (size_type_node); add_stmt (build_assign (INIT_EXPR, t, length)); length = t; t = build_local_temp (ptrtype); add_stmt (build_assign (INIT_EXPR, t, ptr)); ptr = t; if (TREE_SIDE_EFFECTS (value)) { t = build_local_temp (TREE_TYPE (value)); add_stmt (build_assign (INIT_EXPR, t, value)); value = t; } /* Build loop to initialize { .length=length, .ptr=ptr } with value. */ push_stmt_list (); /* Exit logic for the loop. if (length == 0) break; */ t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node)); t = build1 (EXIT_EXPR, void_type_node, t); add_stmt (t); /* Assign value to the current pointer position. *ptr = value; */ t = modify_expr (build_deref (ptr), value); add_stmt (t); /* Move pointer to next element position. ptr++; */ tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptrtype)); t = build2 (POSTINCREMENT_EXPR, ptrtype, ptr, d_convert (ptrtype, size)); add_stmt (t); /* Decrease loop counter. length -= 1; */ t = build2 (POSTDECREMENT_EXPR, lentype, length, d_convert (lentype, integer_one_node)); add_stmt (t); /* Pop statements and finish loop. */ tree loop_body = pop_stmt_list (); add_stmt (build1 (LOOP_EXPR, void_type_node, loop_body)); /* Wrap it up into a bind expression. */ tree stmt_list = pop_stmt_list (); tree block = pop_binding_level (); return build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), stmt_list, block); } /* Build an array of type TYPE where all the elements are VAL. */ tree build_array_from_val (Type *type, tree val) { gcc_assert (type->ty == Tsarray); tree etype = build_ctype (type->nextOf ()); /* Initializing a multidimensional array. */ if (TREE_CODE (etype) == ARRAY_TYPE && TREE_TYPE (val) != etype) val = build_array_from_val (type->nextOf (), val); size_t dims = ((TypeSArray *) type)->dim->toInteger (); vec *elms = NULL; vec_safe_reserve (elms, dims); val = d_convert (etype, val); for (size_t i = 0; i < dims; i++) CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val); return build_constructor (build_ctype (type), elms); } /* Implicitly converts void* T to byte* as D allows { void[] a; &a[3]; } */ tree void_okay_p (tree t) { tree type = TREE_TYPE (t); if (VOID_TYPE_P (TREE_TYPE (type))) { tree totype = build_ctype (Type::tuns8->pointerTo ()); return fold_convert (totype, t); } return t; } /* Builds a bounds condition checking that INDEX is between 0 and LEN. The condition returns the INDEX if true, or throws a RangeError. If INCLUSIVE, we allow INDEX == LEN to return true also. */ tree build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive) { if (!array_bounds_check ()) return index; /* Prevent multiple evaluations of the index. */ index = d_save_expr (index); /* Generate INDEX >= LEN && throw RangeError. No need to check whether INDEX >= 0 as the front-end should have already taken care of implicit casts to unsigned. */ tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR, d_bool_type, index, len); /* Terminate the program with a trap if no D runtime present. */ tree boundserr = (global.params.checkAction == CHECKACTION_C) ? build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0) : d_assert_call (loc, LIBCALL_ARRAY_BOUNDS); return build_condition (TREE_TYPE (index), condition, boundserr, index); } /* Returns TRUE if array bounds checking code generation is turned on. */ bool array_bounds_check (void) { FuncDeclaration *fd; switch (global.params.useArrayBounds) { case CHECKENABLEoff: return false; case CHECKENABLEon: return true; case CHECKENABLEsafeonly: /* For D2 safe functions only. */ fd = d_function_chain->function; if (fd && fd->type->ty == Tfunction) { TypeFunction *tf = (TypeFunction *) fd->type; if (tf->trust == TRUSTsafe) return true; } return false; default: gcc_unreachable (); } } /* Return an undeclared local temporary of type TYPE for use with BIND_EXPR. */ tree create_temporary_var (tree type) { tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type); DECL_CONTEXT (decl) = current_function_decl; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; layout_decl (decl, 0); return decl; } /* Return an undeclared local temporary OUT_VAR initialized with result of expression EXP. */ tree maybe_temporary_var (tree exp, tree *out_var) { tree t = exp; /* Get the base component. */ while (TREE_CODE (t) == COMPONENT_REF) t = TREE_OPERAND (t, 0); if (!DECL_P (t) && !REFERENCE_CLASS_P (t)) { *out_var = create_temporary_var (TREE_TYPE (exp)); DECL_INITIAL (*out_var) = exp; return *out_var; } else { *out_var = NULL_TREE; return exp; } } /* Builds a BIND_EXPR around BODY for the variables VAR_CHAIN. */ tree bind_expr (tree var_chain, tree body) { /* Only handles one var. */ gcc_assert (TREE_CHAIN (var_chain) == NULL_TREE); if (DECL_INITIAL (var_chain)) { tree ini = build_assign (INIT_EXPR, var_chain, DECL_INITIAL (var_chain)); DECL_INITIAL (var_chain) = NULL_TREE; body = compound_expr (ini, body); } return d_save_expr (build3 (BIND_EXPR, TREE_TYPE (body), var_chain, body, NULL_TREE)); } /* Returns the TypeFunction class for Type T. Assumes T is already ->toBasetype(). */ TypeFunction * get_function_type (Type *t) { TypeFunction *tf = NULL; if (t->ty == Tpointer) t = t->nextOf ()->toBasetype (); if (t->ty == Tfunction) tf = (TypeFunction *) t; else if (t->ty == Tdelegate) tf = (TypeFunction *) ((TypeDelegate *) t)->next; return tf; } /* Returns TRUE if CALLEE is a plain nested function outside the scope of CALLER. In which case, CALLEE is being called through an alias that was passed to CALLER. */ bool call_by_alias_p (FuncDeclaration *caller, FuncDeclaration *callee) { if (!callee->isNested ()) return false; if (caller->toParent () == callee->toParent ()) return false; Dsymbol *dsym = callee; while (dsym) { if (dsym->isTemplateInstance ()) return false; else if (dsym->isFuncDeclaration () == caller) return false; dsym = dsym->toParent (); } return true; } /* Entry point for call routines. Builds a function call to FD. OBJECT is the 'this' reference passed and ARGS are the arguments to FD. */ tree d_build_call_expr (FuncDeclaration *fd, tree object, Expressions *arguments) { return d_build_call (get_function_type (fd->type), build_address (get_symbol_decl (fd)), object, arguments); } /* Builds a CALL_EXPR of type TF to CALLABLE. OBJECT holds the 'this' pointer, ARGUMENTS are evaluated in left to right order, saved and promoted before passing. */ tree d_build_call (TypeFunction *tf, tree callable, tree object, Expressions *arguments) { tree ctype = TREE_TYPE (callable); tree callee = callable; if (POINTER_TYPE_P (ctype)) ctype = TREE_TYPE (ctype); else callee = build_address (callable); gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype)); gcc_assert (tf != NULL); gcc_assert (tf->ty == Tfunction); if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE) { /* Front-end apparently doesn't check this. */ if (TREE_CODE (callable) == FUNCTION_DECL) { error ("need % to access member %qE", DECL_NAME (callable)); return error_mark_node; } /* Probably an internal error. */ gcc_unreachable (); } /* Build the argument list for the call. */ vec *args = NULL; tree saved_args = NULL_TREE; /* If this is a delegate call or a nested function being called as a delegate, the object should not be NULL. */ if (object != NULL_TREE) vec_safe_push (args, object); if (arguments) { /* First pass, evaluated expanded tuples in function arguments. */ for (size_t i = 0; i < arguments->dim; ++i) { Lagain: Expression *arg = (*arguments)[i]; gcc_assert (arg->op != TOKtuple); if (arg->op == TOKcomma) { CommaExp *ce = (CommaExp *) arg; tree tce = build_expr (ce->e1); saved_args = compound_expr (saved_args, tce); (*arguments)[i] = ce->e2; goto Lagain; } } size_t nparams = Parameter::dim (tf->parameters); /* if _arguments[] is the first argument. */ size_t varargs = (tf->linkage == LINKd && tf->varargs == 1); /* Assumes arguments->dim <= formal_args->dim if (!tf->varargs). */ for (size_t i = 0; i < arguments->dim; ++i) { Expression *arg = (*arguments)[i]; tree targ = build_expr (arg); if (i - varargs < nparams && i >= varargs) { /* Actual arguments for declared formal arguments. */ Parameter *parg = Parameter::getNth (tf->parameters, i - varargs); targ = convert_for_argument (targ, parg); } /* Don't pass empty aggregates by value. */ if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ) && TREE_CODE (targ) != CONSTRUCTOR) { tree t = build_constructor (TREE_TYPE (targ), NULL); targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t); } vec_safe_push (args, targ); } } /* Evaluate the callee before calling it. */ if (TREE_SIDE_EFFECTS (callee)) { callee = d_save_expr (callee); saved_args = compound_expr (callee, saved_args); } tree result = build_call_vec (TREE_TYPE (ctype), callee, args); /* Enforce left to right evaluation. */ if (tf->linkage == LINKd) CALL_EXPR_ARGS_ORDERED (result) = 1; result = maybe_expand_intrinsic (result); /* Return the value in a temporary slot so that it can be evaluated multiple times by the caller. */ if (TREE_CODE (result) == CALL_EXPR && AGGREGATE_TYPE_P (TREE_TYPE (result)) && TREE_ADDRESSABLE (TREE_TYPE (result))) { CALL_EXPR_RETURN_SLOT_OPT (result) = true; result = force_target_expr (result); } return compound_expr (saved_args, result); } /* Builds a call to AssertError or AssertErrorMsg. */ tree d_assert_call (const Loc& loc, libcall_fn libcall, tree msg) { tree file; tree line = size_int (loc.linnum); /* File location is passed as a D string. */ if (loc.filename) { unsigned len = strlen (loc.filename); tree str = build_string (len, loc.filename); TREE_TYPE (str) = make_array_type (Type::tchar, len); file = d_array_value (build_ctype (Type::tchar->arrayOf ()), size_int (len), build_address (str)); } else file = null_array_node; if (msg != NULL) return build_libcall (libcall, Type::tvoid, 3, msg, file, line); else return build_libcall (libcall, Type::tvoid, 2, file, line); } /* Build and return the correct call to fmod depending on TYPE. ARG0 and ARG1 are the arguments pass to the function. */ tree build_float_modulus (tree type, tree arg0, tree arg1) { tree fmodfn = NULL_TREE; tree basetype = type; if (COMPLEX_FLOAT_TYPE_P (basetype)) basetype = TREE_TYPE (basetype); if (TYPE_MAIN_VARIANT (basetype) == double_type_node || TYPE_MAIN_VARIANT (basetype) == idouble_type_node) fmodfn = builtin_decl_explicit (BUILT_IN_FMOD); else if (TYPE_MAIN_VARIANT (basetype) == float_type_node || TYPE_MAIN_VARIANT (basetype) == ifloat_type_node) fmodfn = builtin_decl_explicit (BUILT_IN_FMODF); else if (TYPE_MAIN_VARIANT (basetype) == long_double_type_node || TYPE_MAIN_VARIANT (basetype) == ireal_type_node) fmodfn = builtin_decl_explicit (BUILT_IN_FMODL); if (!fmodfn) { error ("tried to perform floating-point modulo division on %qT", type); return error_mark_node; } if (COMPLEX_FLOAT_TYPE_P (type)) { tree re = build_call_expr (fmodfn, 2, real_part (arg0), arg1); tree im = build_call_expr (fmodfn, 2, imaginary_part (arg0), arg1); return complex_expr (type, re, im); } if (SCALAR_FLOAT_TYPE_P (type)) return build_call_expr (fmodfn, 2, arg0, arg1); /* Should have caught this above. */ gcc_unreachable (); } /* Build a function type whose first argument is a pointer to BASETYPE, which is to be used for the 'vthis' context parameter for TYPE. The base type may be a record for member functions, or a void for nested functions and delegates. */ tree build_vthis_function (tree basetype, tree type) { gcc_assert (TREE_CODE (type) == FUNCTION_TYPE); tree argtypes = tree_cons (NULL_TREE, build_pointer_type (basetype), TYPE_ARG_TYPES (type)); tree fntype = build_function_type (TREE_TYPE (type), argtypes); if (RECORD_OR_UNION_TYPE_P (basetype)) TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype); else gcc_assert (VOID_TYPE_P (basetype)); return fntype; } /* If SYM is a nested function, return the static chain to be used when calling that function from the current function. If SYM is a nested class or struct, return the static chain to be used when creating an instance of the class from CFUN. */ tree get_frame_for_symbol (Dsymbol *sym) { FuncDeclaration *thisfd = d_function_chain ? d_function_chain->function : NULL; FuncDeclaration *fd = sym->isFuncDeclaration (); FuncDeclaration *fdparent = NULL; FuncDeclaration *fdoverride = NULL; if (fd != NULL) { /* Check that the nested function is properly defined. */ if (!fd->fbody) { /* Should instead error on line that references 'fd'. */ error_at (make_location_t (fd->loc), "nested function missing body"); return null_pointer_node; } fdparent = fd->toParent2 ()->isFuncDeclaration (); /* Special case for __ensure and __require. */ if ((fd->ident == Identifier::idPool ("__ensure") || fd->ident == Identifier::idPool ("__require")) && fdparent != thisfd) { fdoverride = fdparent; fdparent = thisfd; } } else { /* It's a class (or struct). NewExp codegen has already determined its outer scope is not another class, so it must be a function. */ while (sym && !sym->isFuncDeclaration ()) sym = sym->toParent2 (); fdparent = (FuncDeclaration *) sym; } gcc_assert (fdparent != NULL); if (thisfd != fdparent) { /* If no frame pointer for this function. */ if (!thisfd->vthis) { error_at (make_location_t (sym->loc), "is a nested function and cannot be accessed from %qs", thisfd->toChars ()); return null_pointer_node; } /* Make sure we can get the frame pointer to the outer function. Go up each nesting level until we find the enclosing function. */ Dsymbol *dsym = thisfd; while (fd != dsym) { /* Check if enclosing function is a function. */ FuncDeclaration *fd = dsym->isFuncDeclaration (); if (fd != NULL) { if (fdparent == fd->toParent2 ()) break; gcc_assert (fd->isNested () || fd->vthis); dsym = dsym->toParent2 (); continue; } /* Check if enclosed by an aggregate. That means the current function must be a member function of that aggregate. */ AggregateDeclaration *ad = dsym->isAggregateDeclaration (); if (ad == NULL) goto Lnoframe; if (ad->isClassDeclaration () && fdparent == ad->toParent2 ()) break; if (ad->isStructDeclaration () && fdparent == ad->toParent2 ()) break; if (!ad->isNested () || !ad->vthis) { Lnoframe: error_at (make_location_t (thisfd->loc), "cannot get frame pointer to %qs", sym->toPrettyChars ()); return null_pointer_node; } dsym = dsym->toParent2 (); } } tree ffo = get_frameinfo (fdparent); if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo)) { tree frame_ref = get_framedecl (thisfd, fdparent); /* If 'thisfd' is a derived member function, then 'fdparent' is the overridden member function in the base class. Even if there's a closure environment, we should give the original stack data as the nested function frame. */ if (fdoverride) { ClassDeclaration *cdo = fdoverride->isThis ()->isClassDeclaration (); ClassDeclaration *cd = thisfd->isThis ()->isClassDeclaration (); gcc_assert (cdo && cd); int offset; if (cdo->isBaseOf (cd, &offset) && offset != 0) { /* Generate a new frame to pass to the overriden function that has the 'this' pointer adjusted. */ gcc_assert (offset != OFFSET_RUNTIME); tree type = FRAMEINFO_TYPE (get_frameinfo (fdoverride)); tree fields = TYPE_FIELDS (type); /* The 'this' field comes immediately after the '__chain'. */ tree thisfield = chain_index (1, fields); vec *ve = NULL; tree framefields = TYPE_FIELDS (FRAMEINFO_TYPE (ffo)); frame_ref = build_deref (frame_ref); for (tree field = fields; field; field = DECL_CHAIN (field)) { tree value = component_ref (frame_ref, framefields); if (field == thisfield) value = build_offset (value, size_int (offset)); CONSTRUCTOR_APPEND_ELT (ve, field, value); framefields = DECL_CHAIN (framefields); } frame_ref = build_address (build_constructor (type, ve)); } } return frame_ref; } return null_pointer_node; } /* Return the parent function of a nested class CD. */ static FuncDeclaration * d_nested_class (ClassDeclaration *cd) { FuncDeclaration *fd = NULL; while (cd && cd->isNested ()) { Dsymbol *dsym = cd->toParent2 (); if ((fd = dsym->isFuncDeclaration ())) return fd; else cd = dsym->isClassDeclaration (); } return NULL; } /* Return the parent function of a nested struct SD. */ static FuncDeclaration * d_nested_struct (StructDeclaration *sd) { FuncDeclaration *fd = NULL; while (sd && sd->isNested ()) { Dsymbol *dsym = sd->toParent2 (); if ((fd = dsym->isFuncDeclaration ())) return fd; else sd = dsym->isStructDeclaration (); } return NULL; } /* Starting from the current function FD, try to find a suitable value of 'this' in nested function instances. A suitable 'this' value is an instance of OCD or a class that has OCD as a base. */ static tree find_this_tree (ClassDeclaration *ocd) { FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL; while (fd) { AggregateDeclaration *ad = fd->isThis (); ClassDeclaration *cd = ad ? ad->isClassDeclaration () : NULL; if (cd != NULL) { if (ocd == cd) return get_decl_tree (fd->vthis); else if (ocd->isBaseOf (cd, NULL)) return convert_expr (get_decl_tree (fd->vthis), cd->type, ocd->type); fd = d_nested_class (cd); } else { if (fd->isNested ()) { fd = fd->toParent2 ()->isFuncDeclaration (); continue; } fd = NULL; } } return NULL_TREE; } /* Retrieve the outer class/struct 'this' value of DECL from the current function. */ tree build_vthis (AggregateDeclaration *decl) { ClassDeclaration *cd = decl->isClassDeclaration (); StructDeclaration *sd = decl->isStructDeclaration (); /* If an aggregate nested in a function has no methods and there are no other nested functions, any static chain created here will never be translated. Use a null pointer for the link in this case. */ tree vthis_value = null_pointer_node; if (cd != NULL || sd != NULL) { Dsymbol *outer = decl->toParent2 (); /* If the parent is a templated struct, the outer context is instead the enclosing symbol of where the instantiation happened. */ if (outer->isStructDeclaration ()) { gcc_assert (outer->parent && outer->parent->isTemplateInstance ()); outer = ((TemplateInstance *) outer->parent)->enclosing; } /* For outer classes, get a suitable 'this' value. For outer functions, get a suitable frame/closure pointer. */ ClassDeclaration *cdo = outer->isClassDeclaration (); FuncDeclaration *fdo = outer->isFuncDeclaration (); if (cdo) { vthis_value = find_this_tree (cdo); gcc_assert (vthis_value != NULL_TREE); } else if (fdo) { tree ffo = get_frameinfo (fdo); if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo) || fdo->hasNestedFrameRefs ()) vthis_value = get_frame_for_symbol (decl); else if (cd != NULL) { /* Classes nested in methods are allowed to access any outer class fields, use the function chain in this case. */ if (fdo->vthis && fdo->vthis->type != Type::tvoidptr) vthis_value = get_decl_tree (fdo->vthis); } } else gcc_unreachable (); } return vthis_value; } /* Build the RECORD_TYPE that describes the function frame or closure type for the function FD. FFI is the tree holding all frame information. */ static tree build_frame_type (tree ffi, FuncDeclaration *fd) { if (FRAMEINFO_TYPE (ffi)) return FRAMEINFO_TYPE (ffi); tree frame_rec_type = make_node (RECORD_TYPE); char *name = concat (FRAMEINFO_IS_CLOSURE (ffi) ? "CLOSURE." : "FRAME.", fd->toPrettyChars (), NULL); TYPE_NAME (frame_rec_type) = get_identifier (name); free (name); tree fields = NULL_TREE; /* Function is a member or nested, so must have field for outer context. */ if (fd->vthis) { tree ptr_field = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("__chain"), ptr_type_node); DECL_FIELD_CONTEXT (ptr_field) = frame_rec_type; fields = chainon (NULL_TREE, ptr_field); DECL_NONADDRESSABLE_P (ptr_field) = 1; } /* The __ensure and __require are called directly, so never make the outer functions closure, but nevertheless could still be referencing parameters of the calling function non-locally. So we add all parameters with nested refs to the function frame, this should also mean overriding methods will have the same frame layout when inheriting a contract. */ if ((global.params.useIn && fd->frequire) || (global.params.useOut && fd->fensure)) { if (fd->parameters) { for (size_t i = 0; fd->parameters && i < fd->parameters->dim; i++) { VarDeclaration *v = (*fd->parameters)[i]; /* Remove if already in closureVars so can push to front. */ for (size_t j = i; j < fd->closureVars.dim; j++) { Dsymbol *s = fd->closureVars[j]; if (s == v) { fd->closureVars.remove (j); break; } } fd->closureVars.insert (i, v); } } /* Also add hidden 'this' to outer context. */ if (fd->vthis) { for (size_t i = 0; i < fd->closureVars.dim; i++) { Dsymbol *s = fd->closureVars[i]; if (s == fd->vthis) { fd->closureVars.remove (i); break; } } fd->closureVars.insert (0, fd->vthis); } } for (size_t i = 0; i < fd->closureVars.dim; i++) { VarDeclaration *v = fd->closureVars[i]; tree vsym = get_symbol_decl (v); tree ident = v->ident ? get_identifier (v->ident->toChars ()) : NULL_TREE; tree field = build_decl (make_location_t (v->loc), FIELD_DECL, ident, TREE_TYPE (vsym)); SET_DECL_LANG_FRAME_FIELD (vsym, field); DECL_FIELD_CONTEXT (field) = frame_rec_type; fields = chainon (fields, field); TREE_USED (vsym) = 1; TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (vsym); DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym); TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym); /* Can't do nrvo if the variable is put in a frame. */ if (fd->nrvo_can && fd->nrvo_var == v) fd->nrvo_can = 0; if (FRAMEINFO_IS_CLOSURE (ffi)) { /* Because the value needs to survive the end of the scope. */ if ((v->edtor && (v->storage_class & STCparameter)) || v->needsScopeDtor ()) error_at (make_location_t (v->loc), "has scoped destruction, cannot build closure"); } } TYPE_FIELDS (frame_rec_type) = fields; TYPE_READONLY (frame_rec_type) = 1; layout_type (frame_rec_type); d_keep (frame_rec_type); return frame_rec_type; } /* Closures are implemented by taking the local variables that need to survive the scope of the function, and copying them into a GC allocated chuck of memory. That chunk, called the closure here, is inserted into the linked list of stack frames instead of the usual stack frame. If a closure is not required, but FD still needs a frame to lower nested refs, then instead build custom static chain decl on stack. */ void build_closure (FuncDeclaration *fd) { tree ffi = get_frameinfo (fd); if (!FRAMEINFO_CREATES_FRAME (ffi)) return; tree type = FRAMEINFO_TYPE (ffi); gcc_assert (COMPLETE_TYPE_P (type)); tree decl, decl_ref; if (FRAMEINFO_IS_CLOSURE (ffi)) { decl = build_local_temp (build_pointer_type (type)); DECL_NAME (decl) = get_identifier ("__closptr"); decl_ref = build_deref (decl); /* Allocate memory for closure. */ tree arg = convert (build_ctype (Type::tsize_t), TYPE_SIZE_UNIT (type)); tree init = build_libcall (LIBCALL_ALLOCMEMORY, Type::tvoidptr, 1, arg); tree init_exp = build_assign (INIT_EXPR, decl, build_nop (TREE_TYPE (decl), init)); add_stmt (init_exp); } else { decl = build_local_temp (type); DECL_NAME (decl) = get_identifier ("__frame"); decl_ref = decl; } /* Set the first entry to the parent closure/frame, if any. */ if (fd->vthis) { tree chain_field = component_ref (decl_ref, TYPE_FIELDS (type)); tree chain_expr = modify_expr (chain_field, d_function_chain->static_chain); add_stmt (chain_expr); } /* Copy parameters that are referenced nonlocally. */ for (size_t i = 0; i < fd->closureVars.dim; i++) { VarDeclaration *v = fd->closureVars[i]; if (!v->isParameter ()) continue; tree vsym = get_symbol_decl (v); tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym)); tree expr = modify_expr (field, vsym); add_stmt (expr); } if (!FRAMEINFO_IS_CLOSURE (ffi)) decl = build_address (decl); d_function_chain->static_chain = decl; } /* Return the frame of FD. This could be a static chain or a closure passed via the hidden 'this' pointer. */ tree get_frameinfo (FuncDeclaration *fd) { tree fds = get_symbol_decl (fd); if (DECL_LANG_FRAMEINFO (fds)) return DECL_LANG_FRAMEINFO (fds); tree ffi = make_node (FUNCFRAME_INFO); DECL_LANG_FRAMEINFO (fds) = ffi; if (fd->needsClosure ()) { /* Set-up a closure frame, this will be allocated on the heap. */ FRAMEINFO_CREATES_FRAME (ffi) = 1; FRAMEINFO_IS_CLOSURE (ffi) = 1; } else if (fd->hasNestedFrameRefs ()) { /* Functions with nested refs must create a static frame for local variables to be referenced from. */ FRAMEINFO_CREATES_FRAME (ffi) = 1; } else { /* For nested functions, default to creating a frame. Even if there are no fields to populate the frame, create it anyway, as this will be used as the record type instead of `void*` for the this parameter. */ if (fd->vthis && fd->vthis->type == Type::tvoidptr) FRAMEINFO_CREATES_FRAME (ffi) = 1; /* In checkNestedReference, references from contracts are not added to the closureVars array, so assume all parameters referenced. */ if ((global.params.useIn && fd->frequire) || (global.params.useOut && fd->fensure)) FRAMEINFO_CREATES_FRAME (ffi) = 1; /* If however `fd` is nested (deeply) in a function that creates a closure, then `fd` instead inherits that closure via hidden vthis pointer, and doesn't create a stack frame at all. */ FuncDeclaration *ff = fd; while (ff) { tree ffo = get_frameinfo (ff); if (ff != fd && FRAMEINFO_CREATES_FRAME (ffo)) { gcc_assert (FRAMEINFO_TYPE (ffo)); FRAMEINFO_CREATES_FRAME (ffi) = 0; FRAMEINFO_STATIC_CHAIN (ffi) = 1; FRAMEINFO_IS_CLOSURE (ffi) = FRAMEINFO_IS_CLOSURE (ffo); gcc_assert (COMPLETE_TYPE_P (FRAMEINFO_TYPE (ffo))); FRAMEINFO_TYPE (ffi) = FRAMEINFO_TYPE (ffo); break; } /* Stop looking if no frame pointer for this function. */ if (ff->vthis == NULL) break; AggregateDeclaration *ad = ff->isThis (); if (ad && ad->isNested ()) { while (ad->isNested ()) { Dsymbol *d = ad->toParent2 (); ad = d->isAggregateDeclaration (); ff = d->isFuncDeclaration (); if (ad == NULL) break; } } else ff = ff->toParent2 ()->isFuncDeclaration (); } } /* Build type now as may be referenced from another module. */ if (FRAMEINFO_CREATES_FRAME (ffi)) FRAMEINFO_TYPE (ffi) = build_frame_type (ffi, fd); return ffi; } /* Return a pointer to the frame/closure block of OUTER so can be accessed from the function INNER. */ tree get_framedecl (FuncDeclaration *inner, FuncDeclaration *outer) { tree result = d_function_chain->static_chain; FuncDeclaration *fd = inner; while (fd && fd != outer) { AggregateDeclaration *ad; ClassDeclaration *cd; StructDeclaration *sd; /* Parent frame link is the first field. */ if (FRAMEINFO_CREATES_FRAME (get_frameinfo (fd))) result = indirect_ref (ptr_type_node, result); if (fd->isNested ()) fd = fd->toParent2 ()->isFuncDeclaration (); /* The frame/closure record always points to the outer function's frame, even if there are intervening nested classes or structs. So, we can just skip over these. */ else if ((ad = fd->isThis ()) && (cd = ad->isClassDeclaration ())) fd = d_nested_class (cd); else if ((ad = fd->isThis ()) && (sd = ad->isStructDeclaration ())) fd = d_nested_struct (sd); else break; } /* Go get our frame record. */ gcc_assert (fd == outer); tree frame_type = FRAMEINFO_TYPE (get_frameinfo (outer)); if (frame_type != NULL_TREE) { result = build_nop (build_pointer_type (frame_type), result); return result; } else { error_at (make_location_t (inner->loc), "forward reference to frame of %qs", outer->toChars ()); return null_pointer_node; } } ================================================ FILE: gcc/d/d-convert.cc ================================================ /* d-convert.cc -- Data type conversion routines. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/mtype.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "target.h" #include "convert.h" #include "stor-layout.h" #include "d-tree.h" /* Build CODE expression with operands OP0 and OP1. Helper function for d_truthvalue_conversion, so assumes bool result. */ static tree d_build_truthvalue_op (tree_code code, tree op0, tree op1) { tree type0, type1; tree result_type = NULL_TREE; type0 = TREE_TYPE (op0); type1 = TREE_TYPE (op1); /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */ STRIP_TYPE_NOPS (op0); STRIP_TYPE_NOPS (op1); /* Also need to convert pointer/int comparison. */ if (POINTER_TYPE_P (type0) && TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1)) { result_type = type0; } else if (POINTER_TYPE_P (type1) && TREE_CODE (op0) == INTEGER_CST && integer_zerop (op0)) { result_type = type1; } /* If integral, need to convert unsigned/signed comparison. Will also need to convert if type precisions differ. */ else if (INTEGRAL_TYPE_P (type0) && INTEGRAL_TYPE_P (type1)) { if (TYPE_PRECISION (type0) > TYPE_PRECISION (type1)) result_type = type0; else if (TYPE_PRECISION (type0) < TYPE_PRECISION (type1)) result_type = type1; else if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1)) result_type = TYPE_UNSIGNED (type0) ? type0 : type1; } if (result_type) { if (TREE_TYPE (op0) != result_type) op0 = convert (result_type, op0); if (TREE_TYPE (op1) != result_type) op1 = convert (result_type, op1); } return fold_build2 (code, d_bool_type, op0, op1); } /* Return whether EXPR is a declaration whose address can never be NULL. */ bool decl_with_nonnull_addr_p (const_tree expr) { return (DECL_P (expr) && (TREE_CODE (expr) == PARM_DECL || TREE_CODE (expr) == LABEL_DECL || !DECL_WEAK (expr))); } /* Convert EXPR to be a truth-value, validating its type for this purpose. */ tree d_truthvalue_conversion (tree expr) { switch (TREE_CODE (expr)) { case EQ_EXPR: case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: if (TREE_TYPE (expr) == d_bool_type) return expr; return build2 (TREE_CODE (expr), d_bool_type, TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1)); case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: if (TREE_TYPE (expr) == d_bool_type) return expr; return build2 (TREE_CODE (expr), d_bool_type, d_truthvalue_conversion (TREE_OPERAND (expr, 0)), d_truthvalue_conversion (TREE_OPERAND (expr, 1))); case TRUTH_NOT_EXPR: if (TREE_TYPE (expr) == d_bool_type) return expr; return build1 (TREE_CODE (expr), d_bool_type, d_truthvalue_conversion (TREE_OPERAND (expr, 0))); case ERROR_MARK: return expr; case INTEGER_CST: return integer_zerop (expr) ? boolean_false_node : boolean_true_node; case REAL_CST: return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0) ? boolean_true_node : boolean_false_node; case ADDR_EXPR: /* If we are taking the address of a decl that can never be null, then the return result is always true. */ if (decl_with_nonnull_addr_p (TREE_OPERAND (expr, 0))) { warning (OPT_Waddress, "the address of %qD will always evaluate as %", TREE_OPERAND (expr, 0)); return boolean_true_node; } break; case COMPLEX_EXPR: return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), d_truthvalue_conversion (TREE_OPERAND (expr, 0)), d_truthvalue_conversion (TREE_OPERAND (expr, 1))); case NEGATE_EXPR: case ABS_EXPR: case FLOAT_EXPR: /* These don't change whether an object is nonzero or zero. */ return d_truthvalue_conversion (TREE_OPERAND (expr, 0)); case LROTATE_EXPR: case RROTATE_EXPR: /* These don't change whether an object is zero or nonzero, but we can't ignore them if their second arg has side-effects. */ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) { return build2 (COMPOUND_EXPR, d_bool_type, TREE_OPERAND (expr, 1), d_truthvalue_conversion (TREE_OPERAND (expr, 0))); } else return d_truthvalue_conversion (TREE_OPERAND (expr, 0)); case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ return fold_build3 (COND_EXPR, d_bool_type, TREE_OPERAND (expr, 0), d_truthvalue_conversion (TREE_OPERAND (expr, 1)), d_truthvalue_conversion (TREE_OPERAND (expr, 2))); case CONVERT_EXPR: /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, since that affects how `default_conversion' will behave. */ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) break; /* Fall through. */ case NOP_EXPR: /* If this isn't narrowing the argument, we can ignore it. */ if (TYPE_PRECISION (TREE_TYPE (expr)) >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) return d_truthvalue_conversion (TREE_OPERAND (expr, 0)); break; default: break; } if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) { tree t = save_expr (expr); return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (expr) ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), d_truthvalue_conversion (real_part (t)), d_truthvalue_conversion (imaginary_part (t))); } else return d_build_truthvalue_op (NE_EXPR, expr, build_zero_cst (TREE_TYPE (expr))); } /* Creates an expression whose value is that of EXPR, converted to type TYPE. This function implements all reasonable scalar conversions. */ tree convert (tree type, tree expr) { tree e = expr; tree_code code = TREE_CODE (type); if (type == error_mark_node || expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; const char *invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type); if (invalid_conv_diag) { error ("%s", invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; if (TREE_CODE (type) == ARRAY_TYPE && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && TYPE_DOMAIN (type) == TYPE_DOMAIN (TREE_TYPE (expr))) return expr; tree ret = targetm.convert_to_type (type, expr); if (ret) return ret; STRIP_TYPE_NOPS (e); tree etype = TREE_TYPE (e); if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) return fold_convert (type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } switch (code) { case VOID_TYPE: return fold_convert (type, e); case INTEGER_TYPE: case ENUMERAL_TYPE: if (TREE_CODE (etype) == POINTER_TYPE || TREE_CODE (etype) == REFERENCE_TYPE) { if (integer_zerop (e)) return build_int_cst (type, 0); /* Convert to an unsigned integer of the correct width first, and from there widen/truncate to the required type. */ tree utype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), 1); ret = fold_build1 (CONVERT_EXPR, utype, e); return fold_convert (type, ret); } return fold (convert_to_integer (type, e)); case BOOLEAN_TYPE: return fold_convert (type, d_truthvalue_conversion (expr)); case POINTER_TYPE: case REFERENCE_TYPE: return fold (convert_to_pointer (type, e)); case REAL_TYPE: if (TREE_CODE (etype) == COMPLEX_TYPE && TYPE_IMAGINARY_FLOAT (type)) e = build1 (IMAGPART_EXPR, TREE_TYPE (etype), e); return fold (convert_to_real (type, e)); case COMPLEX_TYPE: if (TREE_CODE (etype) == REAL_TYPE && TYPE_IMAGINARY_FLOAT (etype)) return fold_build2 (COMPLEX_EXPR, type, build_zero_cst (TREE_TYPE (type)), convert (TREE_TYPE (type), expr)); return fold (convert_to_complex (type, e)); case VECTOR_TYPE: return fold (convert_to_vector (type, e)); case RECORD_TYPE: case UNION_TYPE: if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return fold_build1 (VIEW_CONVERT_EXPR, type, expr); break; default: break; } error ("conversion to non-scalar type requested"); return error_mark_node; } /* Return expression EXP, whose type has been converted to TYPE. */ tree d_convert (tree type, tree exp) { /* Check this first before retrieving frontend type. */ if (error_operand_p (type) || error_operand_p (exp)) return error_mark_node; Type *totype = TYPE_LANG_FRONTEND (type); Type *etype = TYPE_LANG_FRONTEND (TREE_TYPE (exp)); if (totype && etype) return convert_expr (exp, etype, totype); return convert (type, exp); } /* Return expression EXP, whose type has been convert from ETYPE to TOTYPE. */ tree convert_expr (tree exp, Type *etype, Type *totype) { tree result = NULL_TREE; gcc_assert (etype && totype); Type *ebtype = etype->toBasetype (); Type *tbtype = totype->toBasetype (); if (same_type_p (etype, totype)) return exp; if (error_operand_p (exp)) return exp; switch (ebtype->ty) { case Tdelegate: if (tbtype->ty == Tdelegate) { exp = d_save_expr (exp); return build_delegate_cst (delegate_method (exp), delegate_object (exp), totype); } else if (tbtype->ty == Tpointer) { /* The front-end converts .ptr to cast (void *). Maybe should only allow void* ? */ exp = delegate_object (exp); } else { error ("can't convert a delegate expression to %qs", totype->toChars ()); return error_mark_node; } break; case Tstruct: if (tbtype->ty == Tstruct) { if (totype->size () == etype->size ()) { /* Allowed to cast to structs with same type size. */ result = build_vconvert (build_ctype (totype), exp); } else { error ("can't convert struct %qs to %qs", etype->toChars (), totype->toChars ()); return error_mark_node; } } /* else, default conversion, which should produce an error. */ break; case Tclass: if (tbtype->ty == Tclass) { ClassDeclaration *cdfrom = ebtype->isClassHandle (); ClassDeclaration *cdto = tbtype->isClassHandle (); int offset; if (cdto->isBaseOf (cdfrom, &offset) && offset != OFFSET_RUNTIME) { /* Casting up the inheritance tree: Don't do anything special. Cast to an implemented interface: Handle at compile-time. */ if (offset) { /* Forward references should not leak from the frontend. */ gcc_assert (offset != OFFSET_FWDREF); tree type = build_ctype (totype); exp = d_save_expr (exp); tree cond = build_boolop (NE_EXPR, exp, null_pointer_node); tree object = build_offset (exp, size_int (offset)); return build_condition (build_ctype (totype), cond, build_nop (type, object), build_nop (type, null_pointer_node)); } /* d_convert will make a no-op cast. */ break; } else if (cdfrom->isCPPclass ()) { /* Downcasting in C++ is a no-op. */ if (cdto->isCPPclass ()) break; /* Casting from a C++ interface to a class/non-C++ interface always results in null as there is no run-time information, and no way one can derive from the other. */ warning (OPT_Wcast_result, "cast to %qs will produce null result", totype->toChars ()); result = d_convert (build_ctype (totype), null_pointer_node); /* Make sure the expression is still evaluated if necessary. */ if (TREE_SIDE_EFFECTS (exp)) result = compound_expr (exp, result); break; } /* The offset can only be determined at run-time, do dynamic cast. */ libcall_fn libcall = cdfrom->isInterfaceDeclaration () ? LIBCALL_INTERFACE_CAST : LIBCALL_DYNAMIC_CAST; return build_libcall (libcall, totype, 2, exp, build_address (get_classinfo_decl (cdto))); } /* else default conversion. */ break; case Tsarray: if (tbtype->ty == Tpointer) { result = build_nop (build_ctype (totype), build_address (exp)); } else if (tbtype->ty == Tarray) { dinteger_t dim = ((TypeSArray *) ebtype)->dim->toInteger (); dinteger_t esize = ebtype->nextOf ()->size (); dinteger_t tsize = tbtype->nextOf ()->size (); tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ()); if ((dim * esize) % tsize != 0) { error ("cannot cast %qs to %qs since sizes don't line up", etype->toChars (), totype->toChars ()); return error_mark_node; } dim = (dim * esize) / tsize; /* Assumes casting to dynamic array of same type or void. */ return d_array_value (build_ctype (totype), size_int (dim), build_nop (ptrtype, build_address (exp))); } else if (tbtype->ty == Tsarray) { /* D allows casting a static array to any static array type. */ return build_nop (build_ctype (totype), exp); } else if (tbtype->ty == Tstruct) { /* And allows casting a static array to any struct type too. Type sizes should have already been checked by the frontend. */ gcc_assert (totype->size () == etype->size ()); result = build_vconvert (build_ctype (totype), exp); } else { error ("cannot cast expression of type %qs to type %qs", etype->toChars (), totype->toChars ()); return error_mark_node; } break; case Tarray: if (tbtype->ty == Tpointer) { return d_convert (build_ctype (totype), d_array_ptr (exp)); } else if (tbtype->ty == Tarray) { /* Assume tvoid->size() == 1. */ d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size (); d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size (); if (fsize != tsize) { /* Conversion requires a reinterpret cast of array. */ return build_libcall (LIBCALL_ARRAYCAST, totype, 3, size_int (tsize), size_int (fsize), exp); } else { /* Convert from void[] or elements are the same size -- don't change length. */ return build_vconvert (build_ctype (totype), exp); } } else if (tbtype->ty == Tsarray) { /* Strings are treated as dynamic arrays in D2. */ if (ebtype->isString () && tbtype->isString ()) return indirect_ref (build_ctype (totype), d_array_ptr (exp)); } else { error ("cannot cast expression of type %qs to %qs", etype->toChars (), totype->toChars ()); return error_mark_node; } break; case Taarray: if (tbtype->ty == Taarray) return build_vconvert (build_ctype (totype), exp); /* Can convert associative arrays to void pointers. */ else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid) return build_vconvert (build_ctype (totype), exp); /* Else, default conversion, which should product an error. */ break; case Tpointer: /* Can convert void pointers to associative arrays too. */ if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid) return build_vconvert (build_ctype (totype), exp); break; case Tnull: /* Casting from typeof(null) is represented as all zeros. */ if (tbtype->ty == Tarray) { tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ()); return d_array_value (build_ctype (totype), size_int (0), build_nop (ptrtype, exp)); } else if (tbtype->ty == Taarray) return build_constructor (build_ctype (totype), NULL); else if (tbtype->ty == Tdelegate) return build_delegate_cst (exp, null_pointer_node, totype); return build_zero_cst (build_ctype (totype)); case Tvector: if (tbtype->ty == Tsarray) { if (tbtype->size () == ebtype->size ()) return build_vconvert (build_ctype (totype), exp); } break; default: /* All casts between imaginary and non-imaginary result in 0.0, except for casts between complex and imaginary types. */ if (!ebtype->iscomplex () && !tbtype->iscomplex () && (ebtype->isimaginary () != tbtype->isimaginary ())) { warning (OPT_Wcast_result, "cast from %qs to %qs will produce zero result", ebtype->toChars (), tbtype->toChars ()); return compound_expr (exp, build_zero_cst (build_ctype (tbtype))); } exp = fold_convert (build_ctype (etype), exp); gcc_assert (TREE_CODE (exp) != STRING_CST); break; } return result ? result : convert (build_ctype (totype), exp); } /* Apply semantics of assignment to a value of type TOTYPE to EXPR (e.g., pointer = array -> pointer = &array[0]) Return a TREE representation of EXPR implicitly converted to TOTYPE for use in assignment expressions MODIFY_EXPR, INIT_EXPR. */ tree convert_for_assignment (tree expr, Type *etype, Type *totype) { Type *ebtype = etype->toBasetype (); Type *tbtype = totype->toBasetype (); /* Assuming this only has to handle converting a non Tsarray type to arbitrarily dimensioned Tsarrays. */ if (tbtype->ty == Tsarray) { Type *telem = tbtype->nextOf ()->baseElemOf (); if (same_type_p (telem, ebtype)) { TypeSArray *sa_type = (TypeSArray *) tbtype; uinteger_t count = sa_type->dim->toUInteger (); tree ctor = build_constructor (build_ctype (totype), NULL); if (count) { vec *ce = NULL; tree index = build2 (RANGE_EXPR, build_ctype (Type::tsize_t), size_zero_node, size_int (count - 1)); tree value = convert_for_assignment (expr, etype, sa_type->next); /* Can't use VAR_DECLs in CONSTRUCTORS. */ if (VAR_P (value)) { value = DECL_INITIAL (value); gcc_assert (value); } CONSTRUCTOR_APPEND_ELT (ce, index, value); CONSTRUCTOR_ELTS (ctor) = ce; } TREE_READONLY (ctor) = 1; TREE_CONSTANT (ctor) = 1; return ctor; } } /* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */ if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct) && ebtype->isintegral ()) { if (!integer_zerop (expr)) gcc_unreachable (); return expr; } return convert_expr (expr, etype, totype); } /* Return a TREE representation of EXPR converted to represent the parameter type ARG. */ tree convert_for_argument (tree expr, Parameter *arg) { /* Lazy arguments: expr should already be a delegate. */ if (arg->storageClass & STClazy) return expr; if (valist_array_p (arg->type)) { /* Do nothing if the va_list has already been decayed to a pointer. */ if (!POINTER_TYPE_P (TREE_TYPE (expr))) return build_address (expr); } else if (argument_reference_p (arg)) { /* Front-end shouldn't automatically take the address. */ return convert (type_passed_as (arg), build_address (expr)); } return expr; } /* Perform default promotions for data used in expressions. Arrays and functions are converted to pointers; enumeral types or short or char, to int. In addition, manifest constants symbols are replaced by their values. Return truth-value conversion of expression EXPR from value type TYPE. */ tree convert_for_condition (tree expr, Type *type) { tree result = NULL_TREE; switch (type->toBasetype ()->ty) { case Taarray: /* Checks that aa.ptr !is null. */ result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr))); break; case Tarray: { /* Checks (arr.length || arr.ptr) (i.e arr !is null). */ expr = d_save_expr (expr); tree len = d_array_length (expr); tree ptr = d_array_ptr (expr); if (TYPE_MODE (TREE_TYPE (len)) == TYPE_MODE (TREE_TYPE (ptr))) { result = build2 (BIT_IOR_EXPR, TREE_TYPE (len), len, d_convert (TREE_TYPE (len), ptr)); } else { len = d_truthvalue_conversion (len); ptr = d_truthvalue_conversion (ptr); /* Probably not worth using TRUTH_OROR here. */ result = build2 (TRUTH_OR_EXPR, TREE_TYPE (len), len, ptr); } break; } case Tdelegate: { /* Checks (function || object), but what good is it if there is a null function pointer? */ tree obj, func; if (METHOD_CALL_EXPR (expr)) extract_from_method_call (expr, obj, func); else { expr = d_save_expr (expr); obj = delegate_object (expr); func = delegate_method (expr); } obj = d_truthvalue_conversion (obj); func = d_truthvalue_conversion (func); /* Probably not worth using TRUTH_ORIF here. */ result = build2 (BIT_IOR_EXPR, TREE_TYPE (obj), obj, func); break; } default: result = expr; break; } return d_truthvalue_conversion (result); } /* Convert EXP to a dynamic array. EXP must be a static array or dynamic array. */ tree d_array_convert (Expression *exp) { Type *tb = exp->type->toBasetype (); if (tb->ty == Tarray) return build_expr (exp); if (tb->ty == Tsarray) { Type *totype = tb->nextOf ()->arrayOf (); return convert_expr (build_expr (exp), exp->type, totype); } /* Invalid type passed. */ gcc_unreachable (); } /* Convert EXP to a dynamic array, where ETYPE is the element type. Similar to above, except that EXP is allowed to be an element of an array. Temporary variables that need some kind of BIND_EXPR are pushed to VARS. */ tree d_array_convert (Type *etype, Expression *exp, vec **vars) { Type *tb = exp->type->toBasetype (); if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype)) { /* Convert single element to an array. */ tree var = NULL_TREE; tree expr = maybe_temporary_var (build_expr (exp), &var); if (var != NULL_TREE) vec_safe_push (*vars, var); return d_array_value (build_ctype (exp->type->arrayOf ()), size_int (1), build_address (expr)); } else return d_array_convert (exp); } ================================================ FILE: gcc/d/d-diagnostic.cc ================================================ /* d-diagnostics.cc -- D frontend interface to gcc diagnostics. Copyright (C) 2017-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/globals.h" #include "dmd/errors.h" #include "tree.h" #include "options.h" #include "diagnostic.h" #include "d-tree.h" /* Rewrite the format string FORMAT to deal with any format extensions not supported by pp_format(). The following format specifiers are handled: `...`: text within backticks gets quoted as '%<...%>'. %-10s: left-justify format flag is removed leaving '%s' remaining. %02x: zero-padding format flag is removed leaving '%x' remaining. %X: uppercase unsigned hexadecimals are rewritten as '%x'. The result should be freed by the caller. */ static char * expand_d_format (const char *format) { OutBuffer buf; bool inbacktick = false; for (const char *p = format; *p;) { while (*p != '\0' && *p != '%' && *p != '`') { buf.writeByte (*p); p++; } if (*p == '\0') break; if (*p == '`') { /* Text enclosed by `...` are translated as a quoted string. */ if (inbacktick) { buf.writestring ("%>"); inbacktick = false; } else { buf.writestring ("%<"); inbacktick = true; } p++; continue; } /* Check the conversion specification for unhandled flags. */ buf.writeByte (*p); p++; Lagain: switch (*p) { case '\0': /* Malformed format string. */ gcc_unreachable (); case '-': /* Remove whitespace formatting. */ p++; while (ISDIGIT (*p)) p++; goto Lagain; case '0': /* Remove zero padding from format string. */ while (ISDIGIT (*p)) p++; goto Lagain; case 'X': /* Hex format only supports lower-case. */ buf.writeByte ('x'); p++; break; default: break; } } gcc_assert (!inbacktick); return buf.extractString (); } /* Helper routine for all error routines. Reports a diagnostic specified by KIND at the explicit location LOC. The message FORMAT comes from the dmd front-end, which does not get translated by the gcc diagnostic routines. */ static void ATTRIBUTE_GCC_DIAG(3,0) d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format, va_list ap, diagnostic_t kind, bool verbatim) { va_list argp; va_copy (argp, ap); if (loc.filename || !verbatim) { rich_location rich_loc (line_table, make_location_t (loc)); diagnostic_info diagnostic; char *xformat = expand_d_format (format); diagnostic_set_info_translated (&diagnostic, xformat, &argp, &rich_loc, kind); if (opt != 0) diagnostic.option_index = opt; diagnostic_report_diagnostic (global_dc, &diagnostic); free (xformat); } else { /* Write verbatim messages with no location direct to stream. */ text_info text; text.err_no = errno; text.args_ptr = &argp; text.format_spec = expand_d_format (format); text.x_data = NULL; pp_format_verbatim (global_dc->printer, &text); pp_newline_and_flush (global_dc->printer); } va_end (argp); } /* Print a hard error message with explicit location LOC with an optional message prefix PREFIX1 and PREFIX2, increasing the global or gagged error count. */ void ATTRIBUTE_GCC_DIAG(2,0) verror (const Loc& loc, const char *format, va_list ap, const char *prefix1, const char *prefix2, const char *) { if (!global.gag || global.params.showGaggedErrors) { char *xformat; /* Build string and emit. */ if (prefix2 != NULL) xformat = xasprintf ("%s %s %s", prefix1, prefix2, format); else if (prefix1 != NULL) xformat = xasprintf ("%s %s", prefix1, format); else xformat = xasprintf ("%s", format); d_diagnostic_report_diagnostic (loc, 0, xformat, ap, global.gag ? DK_ANACHRONISM : DK_ERROR, false); free (xformat); } if (global.gag) global.gaggedErrors++; global.errors++; } /* Print supplementary message about the last error with explicit location LOC. This doesn't increase the global error count. */ void ATTRIBUTE_GCC_DIAG(2,0) verrorSupplemental (const Loc& loc, const char *format, va_list ap) { if (global.gag && !global.params.showGaggedErrors) return; d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); } /* Print a warning message with explicit location LOC, increasing the global warning count. */ void ATTRIBUTE_GCC_DIAG(2,0) vwarning (const Loc& loc, const char *format, va_list ap) { if (!global.gag && global.params.warnings != DIAGNOSTICoff) { /* Warnings don't count if not treated as errors. */ if (global.params.warnings == DIAGNOSTICerror) global.warnings++; d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false); } else if (global.gag) global.gaggedWarnings++; } /* Print supplementary message about the last warning with explicit location LOC. This doesn't increase the global warning count. */ void ATTRIBUTE_GCC_DIAG(2,0) vwarningSupplemental (const Loc& loc, const char *format, va_list ap) { if (global.params.warnings == DIAGNOSTICoff || global.gag) return; d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); } /* Print a deprecation message with explicit location LOC with an optional message prefix PREFIX1 and PREFIX2, increasing the global warning or error count depending on how deprecations are treated. */ void ATTRIBUTE_GCC_DIAG(2,0) vdeprecation (const Loc& loc, const char *format, va_list ap, const char *prefix1, const char *prefix2) { if (global.params.useDeprecated == DIAGNOSTICerror) verror (loc, format, ap, prefix1, prefix2); else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) { char *xformat; /* Build string and emit. */ if (prefix2 != NULL) xformat = xasprintf ("%s %s %s", prefix1, prefix2, format); else if (prefix1 != NULL) xformat = xasprintf ("%s %s", prefix1, format); else xformat = xasprintf ("%s", format); d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap, DK_WARNING, false); free (xformat); } else if (global.gag) global.gaggedWarnings++; } /* Print supplementary message about the last deprecation with explicit location LOC. This does not increase the global error count. */ void ATTRIBUTE_GCC_DIAG(2,0) vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap) { if (global.params.useDeprecated == DIAGNOSTICerror) verrorSupplemental (loc, format, ap); else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); } /* Print a verbose message with explicit location LOC. */ void ATTRIBUTE_GCC_DIAG(2,0) vmessage (const Loc& loc, const char *format, va_list ap) { d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true); } /* Call this after printing out fatal error messages to clean up and exit the compiler. */ void fatal (void) { exit (FATAL_EXIT_CODE); } ================================================ FILE: gcc/d/d-frontend.cc ================================================ /* d-frontend.cc -- D frontend interface to the gcc back-end. Copyright (C) 2013-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/compiler.h" #include "dmd/declaration.h" #include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/module.h" #include "dmd/mtype.h" #include "dmd/scope.h" #include "dmd/statement.h" #include "dmd/target.h" #include "tree.h" #include "options.h" #include "fold-const.h" #include "diagnostic.h" #include "stor-layout.h" #include "d-tree.h" /* Implements the Global interface defined by the frontend. Used for managing the state of the current compilation. */ void Global::_init (void) { this->obj_ext = "o"; this->run_noext = true; this->version = "v" #include "verstr.h" ; } /* Implements the Loc interface defined by the frontend. Used for keeping track of current file/line position in code. */ Loc::Loc (const char *filename, unsigned linnum, unsigned charnum) { this->linnum = linnum; this->charnum = charnum; this->filename = filename; } const char * Loc::toChars (void) const { OutBuffer buf; if (this->filename) buf.printf ("%s", this->filename); if (this->linnum) { buf.printf (":%u", this->linnum); if (this->charnum) buf.printf (":%u", this->charnum); } return buf.extractString (); } /* Implements the Port interface defined by the frontend. A mini library for doing compiler/system specific things. */ /* Compare the first N bytes of S1 and S2 without regard to the case. */ int Port::memicmp (const char *s1, const char *s2, size_t n) { int result = 0; for (size_t i = 0; i < n; i++) { char c1 = s1[i]; char c2 = s2[i]; result = c1 - c2; if (result) { result = TOUPPER (c1) - TOUPPER (c2); if (result) break; } } return result; } /* Convert all characters in S to uppercase. */ char * Port::strupr (char *s) { char *t = s; while (*s) { *s = TOUPPER (*s); s++; } return t; } /* Return true if the real_t value from string BUFFER overflows as a result of rounding down to float mode. */ bool Port::isFloat32LiteralOutOfRange (const char *buffer) { real_t r; real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node)); return r == Target::RealProperties::infinity; } /* Return true if the real_t value from string BUFFER overflows as a result of rounding down to double mode. */ bool Port::isFloat64LiteralOutOfRange (const char *buffer) { real_t r; real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node)); return r == Target::RealProperties::infinity; } /* Fetch a little-endian 16-bit value from BUFFER. */ unsigned Port::readwordLE (void *buffer) { unsigned char *p = (unsigned char*) buffer; return ((unsigned) p[1] << 8) | (unsigned) p[0]; } /* Fetch a big-endian 16-bit value from BUFFER. */ unsigned Port::readwordBE (void *buffer) { unsigned char *p = (unsigned char*) buffer; return ((unsigned) p[0] << 8) | (unsigned) p[1]; } /* Fetch a little-endian 32-bit value from BUFFER. */ unsigned Port::readlongLE (void *buffer) { unsigned char *p = (unsigned char*) buffer; return (((unsigned) p[3] << 24) | ((unsigned) p[2] << 16) | ((unsigned) p[1] << 8) | (unsigned) p[0]); } /* Fetch a big-endian 32-bit value from BUFFER. */ unsigned Port::readlongBE (void *buffer) { unsigned char *p = (unsigned char*) buffer; return (((unsigned) p[0] << 24) | ((unsigned) p[1] << 16) | ((unsigned) p[2] << 8) | (unsigned) p[3]); } /* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */ void Port::valcpy (void *buffer, uint64_t value, size_t sz) { switch (sz) { case 1: *(uint8_t *) buffer = (uint8_t) value; break; case 2: *(uint16_t *) buffer = (uint16_t) value; break; case 4: *(uint32_t *) buffer = (uint32_t) value; break; case 8: *(uint64_t *) buffer = (uint64_t) value; break; default: gcc_unreachable (); } } /* Implements the CTFloat interface defined by the frontend. Compile-time floating-pointer helper functions. */ /* Return the absolute value of R. */ real_t CTFloat::fabs (real_t r) { real_t x; real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL); return x.normalize (); } /* Return the value of R * 2 ^^ EXP. */ real_t CTFloat::ldexp (real_t r, int exp) { real_t x; real_ldexp (&x.rv (), &r.rv (), exp); return x.normalize (); } /* Return true if longdouble value X is identical to Y. */ bool CTFloat::isIdentical (real_t x, real_t y) { real_value rx = x.rv (); real_value ry = y.rv (); return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry)) || real_identical (&rx, &ry); } /* Return true if real_t value R is NaN. */ bool CTFloat::isNaN (real_t r) { return REAL_VALUE_ISNAN (r.rv ()); } /* Same as isNaN, but also check if is signalling. */ bool CTFloat::isSNaN (real_t r) { return REAL_VALUE_ISSIGNALING_NAN (r.rv ()); } /* Return true if real_t value is +Inf. */ bool CTFloat::isInfinity (real_t r) { return REAL_VALUE_ISINF (r.rv ()); } /* Return a real_t value from string BUFFER rounded to long double mode. */ real_t CTFloat::parse (const char *buffer, bool *overflow) { real_t r; real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node)); /* Front-end checks overflow to see if the value is representable. */ if (overflow && r == Target::RealProperties::infinity) *overflow = true; return r; } /* Format the real_t value R to string BUFFER as a decimal or hexadecimal, converting the result to uppercase if FMT requests it. */ int CTFloat::sprint (char *buffer, char fmt, real_t r) { if (fmt == 'a' || fmt == 'A') { /* Converting to a hexadecimal string. */ real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1); int buflen; switch (fmt) { case 'A': buflen = strlen (buffer); for (int i = 0; i < buflen; i++) buffer[i] = TOUPPER (buffer[i]); return buflen; case 'a': return strlen (buffer); default: gcc_unreachable (); } } else { /* Note: restricting the precision of significant digits to 18. */ real_to_decimal (buffer, &r.rv (), 32, 18, 1); return strlen (buffer); } } /* Return a hash value for real_t value R. */ size_t CTFloat::hash (real_t r) { return real_hash (&r.rv ()); } /* Implements the Compiler interface used by the frontend. */ /* Generate C main() in response to seeing D main(). This used to be in libdruntime, but contained a reference to _Dmain which didn't work when druntime was made into a shared library and was linked to a program, such as a C++ program, that didn't have a _Dmain. */ void Compiler::genCmain (Scope *sc) { static bool initialized = false; if (initialized) return; /* The D code to be generated is provided by __entrypoint.di, try to load it, but don't fail if unfound. */ unsigned errors = global.startGagging (); Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint")); if (global.endGagging (errors)) m = NULL; if (m != NULL) { m->importedFrom = m; m->importAll (NULL); dsymbolSemantic (m, NULL); semantic2 (m, NULL); semantic3 (m, NULL); d_add_entrypoint_module (m, sc->_module); } initialized = true; } /* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE. The front end should have already ensured that EXPR is a constant, so we just lower the value to GCC and return the converted CST. */ Expression * Compiler::paintAsType (Expression *expr, Type *type) { /* We support up to 512-bit values. */ unsigned char buffer[64]; tree cst; Type *tb = type->toBasetype (); if (expr->type->isintegral ()) cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type)); else if (expr->type->isfloating ()) cst = build_float_cst (expr->toReal (), expr->type); else if (expr->op == TOKarrayliteral) { /* Build array as VECTOR_CST, assumes EXPR is constant. */ Expressions *elements = ((ArrayLiteralExp *) expr)->elements; vec *elms = NULL; vec_safe_reserve (elms, elements->dim); for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; if (e->type->isintegral ()) { tree value = build_integer_cst (e->toInteger (), build_ctype (e->type)); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } else if (e->type->isfloating ()) { tree value = build_float_cst (e->toReal (), e->type); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } else gcc_unreachable (); } /* Build vector type. */ int nunits = ((TypeSArray *) expr->type)->dim->toUInteger (); Type *telem = expr->type->nextOf (); tree vectype = build_vector_type (build_ctype (telem), nunits); cst = build_vector_from_ctor (vectype, elms); } else gcc_unreachable (); /* Encode CST to buffer. */ int len = native_encode_expr (cst, buffer, sizeof (buffer)); if (tb->ty == Tsarray) { /* Interpret value as a vector of the same size, then return the array literal. */ int nunits = ((TypeSArray *) type)->dim->toUInteger (); Type *elem = type->nextOf (); tree vectype = build_vector_type (build_ctype (elem), nunits); cst = native_interpret_expr (vectype, buffer, len); Expression *e = d_eval_constant_expression (cst); gcc_assert (e != NULL && e->op == TOKvector); return ((VectorExp *) e)->e1; } else { /* Normal interpret cast. */ cst = native_interpret_expr (build_ctype (type), buffer, len); Expression *e = d_eval_constant_expression (cst); gcc_assert (e != NULL); return e; } } /* Check imported module M for any special processing. Modules we look out for are: - object: For D runtime type information. - gcc.builtins: For all gcc builtins. - core.stdc.*: For all gcc library builtins. */ void Compiler::loadModule (Module *m) { ModuleDeclaration *md = m->md; if (!md || !md->id || !md->packages) { Identifier *id = (md && md->id) ? md->id : m->ident; if (!strcmp (id->toChars (), "object")) create_tinfo_types (m); } else if (md->packages->dim == 1) { if (!strcmp ((*md->packages)[0]->toChars (), "gcc") && !strcmp (md->id->toChars (), "builtins")) d_build_builtins_module (m); } else if (md->packages->dim == 2) { if (!strcmp ((*md->packages)[0]->toChars (), "core") && !strcmp ((*md->packages)[1]->toChars (), "stdc")) d_add_builtin_module (m); } } /* A callback function that is called once an imported module is parsed. If the callback returns true, then it tells the front-end that the driver intends on compiling the import. */ bool Compiler::onImport (Module *) { return false; } /* Implements back-end specific interfaces used by the frontend. */ /* Determine if function FD is a builtin one that we can evaluate in CTFE. */ BUILTIN isBuiltin (FuncDeclaration *fd) { if (fd->builtin != BUILTINunknown) return fd->builtin; maybe_set_intrinsic (fd); return fd->builtin; } /* Evaluate builtin D function FD whose argument list is ARGUMENTS. Return result; NULL if cannot evaluate it. */ Expression * eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments) { if (fd->builtin != BUILTINyes) return NULL; tree decl = get_symbol_decl (fd); gcc_assert (fndecl_built_in_p (decl) || DECL_INTRINSIC_CODE (decl) != INTRINSIC_NONE); TypeFunction *tf = (TypeFunction *) fd->type; Expression *e = NULL; input_location = make_location_t (loc); tree result = d_build_call (tf, decl, NULL, arguments); result = fold (result); /* Builtin should be successfully evaluated. Will only return NULL if we can't convert it. */ if (TREE_CONSTANT (result) && TREE_CODE (result) != CALL_EXPR) e = d_eval_constant_expression (result); return e; } /* Build and return typeinfo type for TYPE. */ Type * getTypeInfoType (Loc loc, Type *type, Scope *sc) { if (!global.params.useTypeInfo) { /* Even when compiling without RTTI we should still be able to evaluate TypeInfo at compile-time, just not at run-time. */ if (!sc || !(sc->flags & SCOPEctfe)) { static int warned = 0; if (!warned) { error_at (make_location_t (loc), "% cannot be used with -fno-rtti"); warned = 1; } } } if (Type::dtypeinfo == NULL || (Type::dtypeinfo->storage_class & STCtemp)) { /* If TypeInfo has not been declared, warn about each location once. */ static Loc warnloc; if (!loc.equals (warnloc)) { error_at (make_location_t (loc), "% could not be found, " "but is implicitly used"); warnloc = loc; } } gcc_assert (type->ty != Terror); create_typeinfo (type, sc ? sc->_module->importedFrom : NULL); return type->vtinfo->type; } ================================================ FILE: gcc/d/d-incpath.cc ================================================ /* d-incpath.cc -- Set up combined import paths for the D frontend. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/globals.h" #include "cppdefault.h" /* Look for directories that start with the standard prefix. "Translate" them, i.e: replace /usr/local/lib/gcc with IPREFIX and search them first. Based on incpath.c. */ static char * prefixed_path (const char *path, const char *iprefix) { size_t len; if (cpp_relocated () && (len = cpp_PREFIX_len) != 0) { if (!strncmp (path, cpp_PREFIX, len)) { static const char *relocated_prefix; /* If this path starts with the configure-time prefix, but the compiler has been relocated, replace it with the run-time prefix. */ if (!relocated_prefix) { /* Make relative prefix expects the first argument to be a program, not a directory. */ char *dummy = concat (gcc_exec_prefix, "dummy", NULL); relocated_prefix = make_relative_prefix (dummy, cpp_EXEC_PREFIX, cpp_PREFIX); free (dummy); } return concat (relocated_prefix, path + len, NULL); } } if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0) { if (!strncmp (path, cpp_GCC_INCLUDE_DIR, len)) return concat (iprefix, path + len, NULL); } return xstrdup (path); } /* Add PATHS to the global import lookup path. */ static void add_globalpaths (Strings *paths) { if (paths) { if (!global.path) global.path = new Strings (); for (size_t i = 0; i < paths->dim; i++) { const char *path = (*paths)[i]; const char *target = FileName::canonicalName (path); if (target == NULL || !FileName::exists (target)) { if (target) free (CONST_CAST (char *, target)); continue; } global.path->push (target); } } } /* Add PATHS to the global file import lookup path. */ static void add_filepaths (Strings *paths) { if (paths) { if (!global.filePath) global.filePath = new Strings (); for (size_t i = 0; i < paths->dim; i++) { const char *path = (*paths)[i]; const char *target = FileName::canonicalName (path); if (!FileName::exists (target)) { free (CONST_CAST (char *, target)); continue; } global.filePath->push (target); } } } /* Add all search directories to compiler runtime. if STDINC, also include standard library paths. */ void add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) { if (stdinc) { for (const default_include *p = cpp_include_defaults; p->fname; p++) { char *path; /* Ignore C++ paths. */ if (p->cplusplus) continue; if (!p->add_sysroot) path = prefixed_path (p->fname, iprefix); else path = xstrdup (p->fname); /* Add D-specific suffix. */ path = concat (path, "/d", NULL); /* Ignore duplicate entries. */ bool found = false; for (size_t i = 0; i < global.params.imppath->dim; i++) { if (strcmp (path, (*global.params.imppath)[i]) == 0) { found = true; break; } } if (found) { free (path); continue; } /* Multilib support. */ if (imultilib) { char *target_path = concat (path, "/", imultilib, NULL); global.params.imppath->shift (target_path); } global.params.imppath->shift (path); } } /* Add import search paths. */ if (global.params.imppath) { for (size_t i = 0; i < global.params.imppath->dim; i++) { const char *path = (*global.params.imppath)[i]; if (path) add_globalpaths (FileName::splitPath (path)); } } /* Add string import search paths. */ if (global.params.fileImppath) { for (size_t i = 0; i < global.params.fileImppath->dim; i++) { const char *path = (*global.params.fileImppath)[i]; if (path) add_filepaths (FileName::splitPath (path)); } } } ================================================ FILE: gcc/d/d-lang.cc ================================================ /* d-lang.cc -- Language-dependent hooks for D. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/cond.h" #include "dmd/declaration.h" #include "dmd/doc.h" #include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/hdrgen.h" #include "dmd/id.h" #include "dmd/identifier.h" #include "dmd/json.h" #include "dmd/mangle.h" #include "dmd/mars.h" #include "dmd/module.h" #include "dmd/mtype.h" #include "dmd/target.h" #include "opts.h" #include "alias.h" #include "tree.h" #include "diagnostic.h" #include "fold-const.h" #include "toplev.h" #include "langhooks.h" #include "langhooks-def.h" #include "target.h" #include "stringpool.h" #include "stor-layout.h" #include "varasm.h" #include "output.h" #include "print-tree.h" #include "gimple-expr.h" #include "gimplify.h" #include "debug.h" #include "d-tree.h" /* Array of D frontend type/decl nodes. */ tree d_global_trees[DTI_MAX]; /* True if compilation is currently inside the D frontend semantic passes. */ bool doing_semantic_analysis_p = false; /* Options handled by the compiler that are separate from the frontend. */ struct d_option_data { const char *fonly; /* -fonly= */ const char *multilib; /* -imultilib */ const char *prefix; /* -iprefix */ bool deps; /* -M */ bool deps_skip_system; /* -MM */ const char *deps_filename; /* -M[M]D */ const char *deps_filename_user; /* -MF */ OutBuffer *deps_target; /* -M[QT] */ bool deps_phony; /* -MP */ bool stdinc; /* -nostdinc */ } d_option; /* List of modules being compiled. */ static Modules builtin_modules; /* Module where `C main' is defined, compiled in if needed. */ static Module *entrypoint_module = NULL; static Module *entrypoint_root_module = NULL; /* The current and global binding level in effect. */ struct binding_level *current_binding_level; struct binding_level *global_binding_level; /* The context to be used for global declarations. */ static GTY(()) tree global_context; /* Array of all global declarations to pass back to the middle-end. */ static GTY(()) vec *global_declarations; /* Support for GCC-style command-line make dependency generation. Adds TARGET to the make dependencies target buffer. QUOTED is true if the string should be quoted. */ static void deps_add_target (const char *target, bool quoted) { if (!d_option.deps_target) d_option.deps_target = new OutBuffer (); else d_option.deps_target->writeByte (' '); d_option.deps_target->reserve (strlen (target)); if (!quoted) { d_option.deps_target->writestring (target); return; } /* Quote characters in target which are significant to Make. */ for (const char *p = target; *p != '\0'; p++) { switch (*p) { case ' ': case '\t': for (const char *q = p - 1; target <= q && *q == '\\'; q--) d_option.deps_target->writeByte ('\\'); d_option.deps_target->writeByte ('\\'); break; case '$': d_option.deps_target->writeByte ('$'); break; case '#': d_option.deps_target->writeByte ('\\'); break; default: break; } d_option.deps_target->writeByte (*p); } } /* Write out all dependencies of a given MODULE to the specified BUFFER. COLMAX is the number of columns to word-wrap at (0 means don't wrap). */ static void deps_write (Module *module, OutBuffer *buffer, unsigned colmax = 72) { hash_set dependencies; Modules modlist; modlist.push (module); Modules phonylist; const char *str; unsigned size; unsigned column = 0; /* Write out make target module name. */ if (d_option.deps_target) { size = d_option.deps_target->offset; str = d_option.deps_target->extractString (); } else { str = module->objfile->name.toChars (); size = strlen (str); } buffer->writestring (str); column = size; buffer->writestring (":"); column++; /* Write out all make dependencies. */ while (modlist.dim > 0) { Module *depmod = modlist.pop (); str = depmod->srcfile->name.toChars (); size = strlen (str); /* Skip dependencies that have already been written. */ if (dependencies.add (str)) continue; column += size; if (colmax && column > colmax) { buffer->writestring (" \\\n "); column = size + 1; } else { buffer->writestring (" "); column++; } buffer->writestring (str); /* Add to list of phony targets if is not being compile. */ if (d_option.deps_phony && !depmod->isRoot ()) phonylist.push (depmod); /* Search all imports of the written dependency. */ for (size_t i = 0; i < depmod->aimports.dim; i++) { Module *m = depmod->aimports[i]; /* Ignore compiler-generated modules. */ if ((m->ident == Identifier::idPool ("__entrypoint") || m->ident == Identifier::idPool ("__main")) && m->parent == NULL) continue; /* Don't search system installed modules, this includes object, core.*, std.*, and gcc.* packages. */ if (d_option.deps_skip_system) { if (m->ident == Identifier::idPool ("object") && m->parent == NULL) continue; if (m->md && m->md->packages) { Identifier *package = (*m->md->packages)[0]; if (package == Identifier::idPool ("core") || package == Identifier::idPool ("std") || package == Identifier::idPool ("gcc")) continue; } } modlist.push (m); } } buffer->writenl (); /* Write out all phony targets. */ for (size_t i = 0; i < phonylist.dim; i++) { Module *m = phonylist[i]; buffer->writenl (); buffer->writestring (m->srcfile->name.toChars ()); buffer->writestring (":\n"); } } /* These functions are defined in D runtime. */ extern "C" int rt_init (void); extern "C" void gc_disable (void); /* Implements the lang_hooks.init_options routine for language D. This initializes the global state for the D frontend before calling the option handlers. */ static void d_init_options (unsigned int, cl_decoded_option *decoded_options) { /* Initialize the D runtime. */ rt_init (); gc_disable (); /* Set default values. */ global._init (); global.vendor = lang_hooks.name; global.params.argv0.ptr = xstrdup (decoded_options[0].arg); global.params.argv0.length = strlen (decoded_options[0].arg); global.params.errorLimit = flag_max_errors; /* Warnings and deprecations are disabled by default. */ global.params.useDeprecated = DIAGNOSTICoff; global.params.warnings = DIAGNOSTICoff; global.params.imppath = new Strings (); global.params.fileImppath = new Strings (); global.params.modFileAliasStrings = new Strings (); /* Extra GDC-specific options. */ d_option.fonly = NULL; d_option.multilib = NULL; d_option.prefix = NULL; d_option.deps = false; d_option.deps_skip_system = false; d_option.deps_filename = NULL; d_option.deps_filename_user = NULL; d_option.deps_target = NULL; d_option.deps_phony = false; d_option.stdinc = true; } /* Implements the lang_hooks.init_options_struct routine for language D. Initializes the options structure OPTS. */ static void d_init_options_struct (gcc_options *opts) { /* GCC options. */ opts->x_flag_exceptions = 1; /* Avoid range issues for complex multiply and divide. */ opts->x_flag_complex_method = 2; /* Unlike C, there is no global 'errno' variable. */ opts->x_flag_errno_math = 0; opts->frontend_set_flag_errno_math = true; /* Keep in sync with existing -fbounds-check flag. */ opts->x_flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon); /* D says that signed overflow is precisely defined. */ opts->x_flag_wrapv = 1; } /* Implements the lang_hooks.lang_mask routine for language D. Returns language mask for option parsing. */ static unsigned int d_option_lang_mask (void) { return CL_D; } /* Implements the lang_hooks.init routine for language D. */ static bool d_init (void) { Type::_init (); Id::initialize (); Module::_init (); Expression::_init (); Objc::_init (); /* Back-end init. */ global_binding_level = ggc_cleared_alloc (); current_binding_level = global_binding_level; /* This allows the code in d-builtins.cc to not have to worry about converting (C signed char *) to (D char *) for string arguments of built-in functions. The parameter (signed_char = false) specifies whether char is signed. */ build_common_tree_nodes (false); d_init_builtins (); if (global.params.useExceptions) using_eh_for_cleanups (); if (!supports_one_only ()) flag_weak = 0; /* This is the C main, not the D main. */ main_identifier_node = get_identifier ("main"); Target::_init (); d_init_versions (); /* Insert all library-configured identifiers and import paths. */ add_import_paths (d_option.prefix, d_option.multilib, d_option.stdinc); return 1; } /* Implements the lang_hooks.init_ts routine for language D. */ static void d_init_ts (void) { MARK_TS_TYPED (FLOAT_MOD_EXPR); MARK_TS_TYPED (UNSIGNED_RSHIFT_EXPR); } /* Implements the lang_hooks.handle_option routine for language D. Handles D specific options. Return false if we didn't do anything. */ static bool d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED, const cl_option_handlers *handlers ATTRIBUTE_UNUSED) { opt_code code = (opt_code) scode; bool result = true; switch (code) { case OPT_fall_instantiations: global.params.allInst = value; break; case OPT_fassert: global.params.useAssert = value ? CHECKENABLEon : CHECKENABLEoff; break; case OPT_fbounds_check: global.params.useArrayBounds = value ? CHECKENABLEon : CHECKENABLEoff; break; case OPT_fbounds_check_: global.params.useArrayBounds = (value == 2) ? CHECKENABLEon : (value == 1) ? CHECKENABLEsafeonly : CHECKENABLEoff; break; case OPT_fdebug: global.params.debuglevel = value ? 1 : 0; break; case OPT_fdebug_: if (ISDIGIT (arg[0])) { int level = integral_argument (arg); if (level != -1) { global.params.debuglevel = level; break; } } if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.debugids) global.params.debugids = new Strings (); global.params.debugids->push (arg); break; } error ("bad argument for -fdebug %qs", arg); break; case OPT_fdoc: global.params.doDocComments = value; break; case OPT_fdoc_dir_: global.params.doDocComments = true; global.params.docdir = arg; break; case OPT_fdoc_file_: global.params.doDocComments = true; global.params.docname = arg; break; case OPT_fdoc_inc_: global.params.ddocfiles.push (arg); break; case OPT_fdruntime: global.params.betterC = !value; break; case OPT_fdump_d_original: global.params.vcg_ast = value; break; case OPT_fexceptions: global.params.useExceptions = value; break; case OPT_fignore_unknown_pragmas: global.params.ignoreUnsupportedPragmas = value; break; case OPT_finvariants: global.params.useInvariants = value; break; case OPT_fmain: global.params.addMain = value; break; case OPT_fmodule_file_: global.params.modFileAliasStrings->push (arg); if (!strchr (arg, '=')) error ("bad argument for -fmodule-file %qs", arg); break; case OPT_fmoduleinfo: global.params.useModuleInfo = value; break; case OPT_fonly_: d_option.fonly = arg; break; case OPT_fpostconditions: global.params.useOut = value; break; case OPT_fpreconditions: global.params.useIn = value; break; case OPT_frelease: global.params.release = value; break; case OPT_frtti: global.params.useTypeInfo = value; break; case OPT_fswitch_errors: global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff; break; case OPT_ftransition_all: global.params.vtls = value; global.params.vfield = value; global.params.vcomplex = value; break; case OPT_ftransition_checkimports: global.params.check10378 = value; break; case OPT_ftransition_complex: global.params.vcomplex = value; break; case OPT_ftransition_dip1000: global.params.vsafe = value; global.params.useDIP25 = value; break; case OPT_ftransition_dip1008: global.params.ehnogc = value; break; case OPT_ftransition_dip25: global.params.useDIP25 = value; break; case OPT_ftransition_dtorfields: global.params.dtorFields = value; break; case OPT_ftransition_field: global.params.vfield = value; break; case OPT_ftransition_import: global.params.bug10378 = value; break; case OPT_ftransition_intpromote: global.params.fix16997 = value; break; case OPT_ftransition_nogc: global.params.vgc = value; break; case OPT_ftransition_tls: global.params.vtls = value; break; case OPT_funittest: global.params.useUnitTests = value; break; case OPT_fversion_: if (ISDIGIT (arg[0])) { int level = integral_argument (arg); if (level != -1) { global.params.versionlevel = level; break; } } if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.versionids) global.params.versionids = new Strings (); global.params.versionids->push (arg); break; } error ("bad argument for -fversion %qs", arg); break; case OPT_H: global.params.doHdrGeneration = true; break; case OPT_Hd: global.params.doHdrGeneration = true; global.params.hdrdir = arg; break; case OPT_Hf: global.params.doHdrGeneration = true; global.params.hdrname = arg; break; case OPT_imultilib: d_option.multilib = arg; break; case OPT_iprefix: d_option.prefix = arg; break; case OPT_I: global.params.imppath->push (arg); break; case OPT_J: global.params.fileImppath->push (arg); break; case OPT_MM: d_option.deps_skip_system = true; /* Fall through. */ case OPT_M: d_option.deps = true; break; case OPT_MMD: d_option.deps_skip_system = true; /* Fall through. */ case OPT_MD: d_option.deps = true; d_option.deps_filename = arg; break; case OPT_MF: /* If specified multiple times, last one wins. */ d_option.deps_filename_user = arg; break; case OPT_MP: d_option.deps_phony = true; break; case OPT_MQ: deps_add_target (arg, true); break; case OPT_MT: deps_add_target (arg, false); break; case OPT_nostdinc: d_option.stdinc = false; break; case OPT_v: global.params.verbose = value; break; case OPT_Wall: if (value) global.params.warnings = DIAGNOSTICinform; break; case OPT_Wdeprecated: global.params.useDeprecated = value ? DIAGNOSTICinform : DIAGNOSTICoff; break; case OPT_Werror: if (value) global.params.warnings = DIAGNOSTICerror; break; case OPT_Wspeculative: if (value) global.params.showGaggedErrors = 1; break; case OPT_Xf: global.params.jsonfilename = arg; /* Fall through. */ case OPT_X: global.params.doJsonGeneration = true; break; default: break; } D_handle_option_auto (&global_options, &global_options_set, scode, arg, value, d_option_lang_mask (), kind, loc, handlers, global_dc); return result; } /* Implements the lang_hooks.post_options routine for language D. Deal with any options that imply the turning on/off of features. FN is the main input filename passed on the command line. */ static bool d_post_options (const char ** fn) { /* Verify the input file name. */ const char *filename = *fn; if (!filename || strcmp (filename, "-") == 0) filename = ""; /* The front end considers the first input file to be the main one. */ *fn = filename; /* Release mode doesn't turn off bounds checking for safe functions. */ if (global.params.useArrayBounds == CHECKENABLEdefault) { global.params.useArrayBounds = global.params.release ? CHECKENABLEsafeonly : CHECKENABLEon; flag_bounds_check = !global.params.release; } /* Assert code is generated if unittests are being compiled also, even if release mode is turned on. */ if (global.params.useAssert == CHECKENABLEdefault) { if (global.params.useUnitTests || !global.params.release) global.params.useAssert = CHECKENABLEon; else global.params.useAssert = CHECKENABLEoff; } /* Checks for switches without a default are turned off in release mode. */ if (global.params.useSwitchError == CHECKENABLEdefault) { global.params.useSwitchError = global.params.release ? CHECKENABLEoff : CHECKENABLEon; } if (global.params.release) { if (!global_options_set.x_flag_invariants) global.params.useInvariants = false; if (!global_options_set.x_flag_preconditions) global.params.useIn = false; if (!global_options_set.x_flag_postconditions) global.params.useOut = false; } if (global.params.betterC) { if (!global_options_set.x_flag_moduleinfo) global.params.useModuleInfo = false; if (!global_options_set.x_flag_rtti) global.params.useTypeInfo = false; if (!global_options_set.x_flag_exceptions) global.params.useExceptions = false; global.params.checkAction = CHECKACTION_C; } /* Error about use of deprecated features. */ if (global.params.useDeprecated == DIAGNOSTICinform && global.params.warnings == DIAGNOSTICerror) global.params.useDeprecated = DIAGNOSTICerror; /* Make -fmax-errors visible to frontend's diagnostic machinery. */ if (global_options_set.x_flag_max_errors) global.params.errorLimit = flag_max_errors; if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; global.params.symdebug = write_symbols != NO_DEBUG; global.params.useInline = flag_inline_functions; global.params.showColumns = flag_show_column; if (global.params.useInline) global.params.hdrStripPlainFunctions = false; global.params.obj = !flag_syntax_only; /* Has no effect yet. */ global.params.pic = flag_pic != 0; /* Add in versions given on the command line. */ if (global.params.versionids) { for (size_t i = 0; i < global.params.versionids->dim; i++) { const char *s = (*global.params.versionids)[i]; VersionCondition::addGlobalIdent (s); } } if (global.params.debugids) { for (size_t i = 0; i < global.params.debugids->dim; i++) { const char *s = (*global.params.debugids)[i]; DebugCondition::addGlobalIdent (s); } } if (warn_return_type == -1) warn_return_type = 0; return false; } /* Return TRUE if an operand OP of a given TYPE being copied has no data. The middle-end does a similar check with zero sized types. */ static bool empty_modify_p (tree type, tree op) { tree_code code = TREE_CODE (op); switch (code) { case COMPOUND_EXPR: return empty_modify_p (type, TREE_OPERAND (op, 1)); case CONSTRUCTOR: /* Non-empty construcors are valid. */ if (CONSTRUCTOR_NELTS (op) != 0 || TREE_CLOBBER_P (op)) return false; break; case CALL_EXPR: /* Leave nrvo alone because it isn't a copy. */ if (CALL_EXPR_RETURN_SLOT_OPT (op)) return false; break; default: /* If the operand doesn't have a simple form. */ if (!is_gimple_lvalue (op) && !INDIRECT_REF_P (op)) return false; break; } return empty_aggregate_p (type); } /* Implements the lang_hooks.gimplify_expr routine for language D. Do gimplification of D specific expression trees in EXPR_P. */ int d_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p ATTRIBUTE_UNUSED) { tree_code code = TREE_CODE (*expr_p); enum gimplify_status ret = GS_UNHANDLED; tree op0, op1; tree type; switch (code) { case INIT_EXPR: case MODIFY_EXPR: op0 = TREE_OPERAND (*expr_p, 0); op1 = TREE_OPERAND (*expr_p, 1); if (!error_operand_p (op0) && !error_operand_p (op1) && (AGGREGATE_TYPE_P (TREE_TYPE (op0)) || AGGREGATE_TYPE_P (TREE_TYPE (op1))) && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0))) { /* If the back end isn't clever enough to know that the lhs and rhs types are the same, add an explicit conversion. */ TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (op0), op1); ret = GS_OK; } else if (empty_modify_p (TREE_TYPE (op0), op1)) { /* Remove any copies of empty aggregates. */ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_gimple_lvalue, fb_lvalue); if (TREE_SIDE_EFFECTS (op1)) gimplify_and_add (op1, pre_p); *expr_p = TREE_OPERAND (*expr_p, 0); ret = GS_OK; } break; case ADDR_EXPR: op0 = TREE_OPERAND (*expr_p, 0); /* Constructors are not lvalues, so make them one. */ if (TREE_CODE (op0) == CONSTRUCTOR) { TREE_OPERAND (*expr_p, 0) = force_target_expr (op0); ret = GS_OK; } break; case CALL_EXPR: if (CALL_EXPR_ARGS_ORDERED (*expr_p)) { /* Strictly evaluate all arguments from left to right. */ int nargs = call_expr_nargs (*expr_p); location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location); /* No need to enforce evaluation order if only one argument. */ if (nargs < 2) break; /* Or if all arguments are already free of side-effects. */ bool has_side_effects = false; for (int i = 0; i < nargs; i++) { if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i))) { has_side_effects = true; break; } } if (!has_side_effects) break; /* Leave the last argument for gimplify_call_expr. */ for (int i = 0; i < nargs - 1; i++) { tree new_arg = CALL_EXPR_ARG (*expr_p, i); /* If argument has a side-effect, gimplify_arg will handle it. */ if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR) ret = GS_ERROR; /* Even if an argument itself doesn't have any side-effects, it might be altered by another argument in the list. */ if (new_arg == CALL_EXPR_ARG (*expr_p, i) && !really_constant_p (new_arg)) new_arg = get_formal_tmp_var (new_arg, pre_p); CALL_EXPR_ARG (*expr_p, i) = new_arg; } if (ret != GS_ERROR) ret = GS_OK; } break; case UNSIGNED_RSHIFT_EXPR: /* Convert op0 to an unsigned type. */ op0 = TREE_OPERAND (*expr_p, 0); op1 = TREE_OPERAND (*expr_p, 1); type = d_unsigned_type (TREE_TYPE (op0)); *expr_p = convert (TREE_TYPE (*expr_p), build2 (RSHIFT_EXPR, type, convert (type, op0), op1)); ret = GS_OK; break; case FLOAT_MOD_EXPR: gcc_unreachable (); default: break; } return ret; } /* Add the module M to the list of modules that may declare GCC builtins. These are scanned after first semantic and before codegen passes. See d_maybe_set_builtin() for the implementation. */ void d_add_builtin_module (Module *m) { builtin_modules.push (m); } /* Record the entrypoint module ENTRY which will be compiled in the current compilation. ROOT is the module scope where this was requested from. */ void d_add_entrypoint_module (Module *entry, Module *root) { /* We are emitting this straight to object file. */ entrypoint_module = entry; entrypoint_root_module = root; } /* Implements the lang_hooks.parse_file routine for language D. */ void d_parse_file (void) { if (global.params.verbose) { message ("binary %s", global.params.argv0.ptr); message ("version %s", global.version); if (global.versionids) { OutBuffer buf; buf.writestring ("predefs "); for (size_t i = 0; i < global.versionids->dim; i++) { Identifier *id = (*global.versionids)[i]; buf.writestring (" "); buf.writestring (id->toChars ()); } message ("%.*s", (int) buf.offset, (char *) buf.data); } } /* Start the main input file, if the debug writer wants it. */ if (debug_hooks->start_end_main_source_file) debug_hooks->start_source_file (0, main_input_filename); /* Create Module's for all sources we will load. */ Modules modules; modules.reserve (num_in_fnames); /* In this mode, the first file name is supposed to be a duplicate of one of the input files. */ if (d_option.fonly && strcmp (d_option.fonly, main_input_filename) != 0) error ("-fonly= argument is different from first input file name"); for (size_t i = 0; i < num_in_fnames; i++) { if (strcmp (in_fnames[i], "-") == 0) { /* Handling stdin, generate a unique name for the module. */ obstack buffer; gcc_obstack_init (&buffer); int c; Module *m = Module::create (in_fnames[i], Identifier::generateId ("__stdin"), global.params.doDocComments, global.params.doHdrGeneration); modules.push (m); /* Load the entire contents of stdin into memory. */ while ((c = getc (stdin)) != EOF) obstack_1grow (&buffer, c); if (!obstack_object_size (&buffer)) obstack_1grow (&buffer, '\0'); /* Overwrite the source file for the module, the one created by Module::create would have a forced a `.d' suffix. */ m->srcfile = File::create (""); m->srcfile->len = obstack_object_size (&buffer); m->srcfile->buffer = (unsigned char *) obstack_finish (&buffer); /* Tell the front-end not to free the buffer after parsing. */ m->srcfile->ref = 1; } else { /* Handling a D source file, strip off the path and extension. */ const char *basename = FileName::name (in_fnames[i]); const char *name = FileName::removeExt (basename); Module *m = Module::create (in_fnames[i], Identifier::idPool (name), global.params.doDocComments, global.params.doHdrGeneration); modules.push (m); FileName::free (name); } } /* Read all D source files. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; m->read (Loc ()); } /* Parse all D source files. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) message ("parse %s", m->toChars ()); if (!Module::rootModule) Module::rootModule = m; m->importedFrom = m; m->parse (); Compiler::loadModule (m); if (m->isDocFile) { gendocfile (m); /* Remove M from list of modules. */ modules.remove (i); i--; } } /* Load the module containing D main. */ if (global.params.addMain) { unsigned errors = global.startGagging (); Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main")); if (! global.endGagging (errors)) { m->importedFrom = m; modules.push (m); } } if (global.errors) goto had_errors; if (global.params.doHdrGeneration) { /* Generate 'header' import files. Since 'header' import files must be independent of command line switches and what else is imported, they are generated before any semantic analysis. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (d_option.fonly && m != Module::rootModule) continue; if (global.params.verbose) message ("import %s", m->toChars ()); genhdrfile (m); } } if (global.errors) goto had_errors; /* Load all unconditional imports for better symbol resolving. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) message ("importall %s", m->toChars ()); m->importAll (NULL); } if (global.errors) goto had_errors; /* Do semantic analysis. */ doing_semantic_analysis_p = true; for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) message ("semantic %s", m->toChars ()); dsymbolSemantic (m, NULL); } /* Do deferred semantic analysis. */ Module::dprogress = 1; Module::runDeferredSemantic (); if (Module::deferred.dim) { for (size_t i = 0; i < Module::deferred.dim; i++) { Dsymbol *sd = Module::deferred[i]; error_at (make_location_t (sd->loc), "unable to resolve forward reference in definition"); } } /* Process all built-in modules or functions now for CTFE. */ while (builtin_modules.dim != 0) { Module *m = builtin_modules.pop (); d_maybe_set_builtin (m); } /* Do pass 2 semantic analysis. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) message ("semantic2 %s", m->toChars ()); semantic2 (m, NULL); } Module::runDeferredSemantic2 (); if (global.errors) goto had_errors; /* Do pass 3 semantic analysis. */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) message ("semantic3 %s", m->toChars ()); semantic3 (m, NULL); } Module::runDeferredSemantic3 (); /* Check again, incase semantic3 pass loaded any more modules. */ while (builtin_modules.dim != 0) { Module *m = builtin_modules.pop (); d_maybe_set_builtin (m); } /* Do not attempt to generate output files if errors or warnings occurred. */ if (global.errors || global.warnings) goto had_errors; /* Generate output files. */ doing_semantic_analysis_p = false; if (Module::rootModule) { /* Declare the name of the root module as the first global name in order to make the middle-end fully deterministic. */ OutBuffer buf; mangleToBuffer (Module::rootModule, &buf); first_global_object_name = buf.extractString (); } /* Make dependencies. */ if (d_option.deps) { OutBuffer buf; for (size_t i = 0; i < modules.dim; i++) deps_write (modules[i], &buf); /* -MF overrides -M[M]D. */ if (d_option.deps_filename_user) d_option.deps_filename = d_option.deps_filename_user; if (d_option.deps_filename) { File *fdeps = File::create (d_option.deps_filename); fdeps->setbuffer ((void *) buf.data, buf.offset); fdeps->ref = 1; writeFile (Loc (), fdeps); } else message ("%.*s", (int) buf.offset, (char *) buf.data); } /* Generate JSON files. */ if (global.params.doJsonGeneration) { OutBuffer buf; json_generate (&buf, &modules); const char *name = global.params.jsonfilename; if (name && (name[0] != '-' || name[1] != '\0')) { const char *nameext = FileName::defaultExt (name, global.json_ext); File *fjson = File::create (nameext); fjson->setbuffer ((void *) buf.data, buf.offset); fjson->ref = 1; writeFile (Loc (), fjson); } else message ("%.*s", (int) buf.offset, (char *) buf.data); } /* Generate Ddoc files. */ if (global.params.doDocComments && !global.errors && !errorcount) { for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; gendocfile (m); } } /* Handle -fdump-d-original. */ if (global.params.vcg_ast) { for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; OutBuffer buf; buf.doindent = 1; moduleToBuffer (&buf, m); message ("%.*s", (int) buf.offset, (char *) buf.data); } } for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (d_option.fonly && m != Module::rootModule) continue; if (global.params.verbose) message ("code %s", m->toChars ()); if (!flag_syntax_only) { if ((entrypoint_module != NULL) && (m == entrypoint_root_module)) build_decl_tree (entrypoint_module); build_decl_tree (m); } } /* And end the main input file, if the debug writer wants it. */ if (debug_hooks->start_end_main_source_file) debug_hooks->end_source_file (0); had_errors: /* Add the D frontend error count to the GCC error count to correctly exit with an error status. */ errorcount += (global.errors + global.warnings); /* Write out globals. */ d_finish_compilation (vec_safe_address (global_declarations), vec_safe_length (global_declarations)); } /* Implements the lang_hooks.types.type_for_mode routine for language D. */ static tree d_type_for_mode (machine_mode mode, int unsignedp) { if (mode == QImode) return unsignedp ? d_ubyte_type : d_byte_type; if (mode == HImode) return unsignedp ? d_ushort_type : d_short_type; if (mode == SImode) return unsignedp ? d_uint_type : d_int_type; if (mode == DImode) return unsignedp ? d_ulong_type : d_long_type; if (mode == TYPE_MODE (d_cent_type)) return unsignedp ? d_ucent_type : d_cent_type; if (mode == TYPE_MODE (float_type_node)) return float_type_node; if (mode == TYPE_MODE (double_type_node)) return double_type_node; if (mode == TYPE_MODE (long_double_type_node)) return long_double_type_node; if (mode == TYPE_MODE (build_pointer_type (char8_type_node))) return build_pointer_type (char8_type_node); if (mode == TYPE_MODE (build_pointer_type (d_int_type))) return build_pointer_type (d_int_type); if (COMPLEX_MODE_P (mode)) { machine_mode inner_mode; tree inner_type; if (mode == TYPE_MODE (complex_float_type_node)) return complex_float_type_node; if (mode == TYPE_MODE (complex_double_type_node)) return complex_double_type_node; if (mode == TYPE_MODE (complex_long_double_type_node)) return complex_long_double_type_node; inner_mode = (machine_mode) GET_MODE_INNER (mode); inner_type = d_type_for_mode (inner_mode, unsignedp); if (inner_type != NULL_TREE) return build_complex_type (inner_type); } else if (VECTOR_MODE_P (mode)) { machine_mode inner_mode = (machine_mode) GET_MODE_INNER (mode); tree inner_type = d_type_for_mode (inner_mode, unsignedp); if (inner_type != NULL_TREE) return build_vector_type_for_mode (inner_type, mode); } return 0; } /* Implements the lang_hooks.types.type_for_size routine for language D. */ static tree d_type_for_size (unsigned bits, int unsignedp) { if (bits <= TYPE_PRECISION (d_byte_type)) return unsignedp ? d_ubyte_type : d_byte_type; if (bits <= TYPE_PRECISION (d_short_type)) return unsignedp ? d_ushort_type : d_short_type; if (bits <= TYPE_PRECISION (d_int_type)) return unsignedp ? d_uint_type : d_int_type; if (bits <= TYPE_PRECISION (d_long_type)) return unsignedp ? d_ulong_type : d_long_type; if (bits <= TYPE_PRECISION (d_cent_type)) return unsignedp ? d_ucent_type : d_cent_type; return 0; } /* Return the signed or unsigned version of TYPE, an integral type, the signedness being specified by UNSIGNEDP. */ static tree d_signed_or_unsigned_type (int unsignedp, tree type) { if (TYPE_UNSIGNED (type) == (unsigned) unsignedp) return type; if (TYPE_PRECISION (type) == TYPE_PRECISION (d_cent_type)) return unsignedp ? d_ucent_type : d_cent_type; if (TYPE_PRECISION (type) == TYPE_PRECISION (d_long_type)) return unsignedp ? d_ulong_type : d_long_type; if (TYPE_PRECISION (type) == TYPE_PRECISION (d_int_type)) return unsignedp ? d_uint_type : d_int_type; if (TYPE_PRECISION (type) == TYPE_PRECISION (d_short_type)) return unsignedp ? d_ushort_type : d_short_type; if (TYPE_PRECISION (type) == TYPE_PRECISION (d_byte_type)) return unsignedp ? d_ubyte_type : d_byte_type; return signed_or_unsigned_type_for (unsignedp, type); } /* Return the unsigned version of TYPE, an integral type. */ tree d_unsigned_type (tree type) { return d_signed_or_unsigned_type (1, type); } /* Return the signed version of TYPE, an integral type. */ tree d_signed_type (tree type) { return d_signed_or_unsigned_type (0, type); } /* Implements the lang_hooks.types.type_promotes_to routine for language D. All promotions for variable arguments are handled by the D frontend. */ static tree d_type_promotes_to (tree type) { return type; } /* Implements the lang_hooks.decls.global_bindings_p routine for language D. Return true if we are in the global binding level. */ static bool d_global_bindings_p (void) { return (current_binding_level == global_binding_level); } /* Return global_context, but create it first if need be. */ static tree get_global_context (void) { if (!global_context) { global_context = build_translation_unit_decl (NULL_TREE); debug_hooks->register_main_translation_unit (global_context); } return global_context; } /* Implements the lang_hooks.decls.pushdecl routine for language D. Record DECL as belonging to the current lexical scope. */ tree d_pushdecl (tree decl) { /* Set the context of the decl. If current_function_decl did not help in determining the context, use global scope. */ if (!DECL_CONTEXT (decl)) { if (current_function_decl) DECL_CONTEXT (decl) = current_function_decl; else DECL_CONTEXT (decl) = get_global_context (); } /* Put decls on list in reverse order. */ if (TREE_STATIC (decl) || d_global_bindings_p ()) vec_safe_push (global_declarations, decl); else { TREE_CHAIN (decl) = current_binding_level->names; current_binding_level->names = decl; } return decl; } /* Implements the lang_hooks.decls.getdecls routine for language D. Return the list of declarations of the current level. */ static tree d_getdecls (void) { if (current_binding_level) return current_binding_level->names; return NULL_TREE; } /* Implements the lang_hooks.get_alias_set routine for language D. Get the alias set corresponding to type or expression T. Return -1 if we don't do anything special. */ static alias_set_type d_get_alias_set (tree) { /* For now in D, assume everything aliases everything else, until we define some solid rules backed by a specification. There are also some parts of code generation routines that don't adhere to C alias rules, such as build_vconvert. In any case, a lot of user code already assumes there is no strict aliasing and will break if we were to change that. */ return 0; } /* Implements the lang_hooks.types_compatible_p routine for language D. Compares two types for equivalence in the D programming language. This routine should only return 1 if it is sure, even though the frontend should have already ensured that all types are compatible before handing over the parsed ASTs to the code generator. */ static int d_types_compatible_p (tree x, tree y) { Type *tx = TYPE_LANG_FRONTEND (x); Type *ty = TYPE_LANG_FRONTEND (y); /* Try validating the types in the frontend. */ if (tx != NULL && ty != NULL) { /* Types are equivalent. */ if (same_type_p (tx, ty)) return true; /* Type system allows implicit conversion between. */ if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx)) return true; } /* Fallback on using type flags for comparison. E.g: all dynamic arrays are distinct types in D, but are VIEW_CONVERT compatible. */ if (TREE_CODE (x) == RECORD_TYPE && TREE_CODE (y) == RECORD_TYPE) { if (TYPE_DYNAMIC_ARRAY (x) && TYPE_DYNAMIC_ARRAY (y)) return true; if (TYPE_DELEGATE (x) && TYPE_DELEGATE (y)) return true; if (TYPE_ASSOCIATIVE_ARRAY (x) && TYPE_ASSOCIATIVE_ARRAY (y)) return true; } return false; } /* Implements the lang_hooks.finish_incomplete_decl routine for language D. */ static void d_finish_incomplete_decl (tree decl) { if (VAR_P (decl)) { /* D allows zero-length declarations. Such a declaration ends up with DECL_SIZE (t) == NULL_TREE which is what the back-end function assembler_variable checks. This could change in later versions, or maybe all of these variables should be aliased to one symbol. */ if (DECL_SIZE (decl) == 0) { DECL_SIZE (decl) = bitsize_zero_node; DECL_SIZE_UNIT (decl) = size_zero_node; } } } /* Implements the lang_hooks.types.classify_record routine for language D. Return the true debug type for TYPE. */ static classify_record d_classify_record (tree type) { Type *t = TYPE_LANG_FRONTEND (type); if (t && t->ty == Tclass) { TypeClass *tc = (TypeClass *) t; /* extern(C++) interfaces get emitted as classes. */ if (tc->sym->isInterfaceDeclaration () && !tc->sym->isCPPinterface ()) return RECORD_IS_INTERFACE; return RECORD_IS_CLASS; } return RECORD_IS_STRUCT; } /* Implements the lang_hooks.tree_size routine for language D. Determine the size of our tcc_constant or tcc_exceptional nodes. */ static size_t d_tree_size (tree_code code) { switch (code) { case FUNCFRAME_INFO: return sizeof (tree_frame_info); default: gcc_unreachable (); } } /* Implements the lang_hooks.print_xnode routine for language D. */ static void d_print_xnode (FILE *file, tree node, int indent) { switch (TREE_CODE (node)) { case FUNCFRAME_INFO: print_node (file, "frame_type", FRAMEINFO_TYPE (node), indent + 4); break; default: break; } } /* Return which tree structure is used by NODE, or TS_D_GENERIC if NODE is one of the language-independent trees. */ d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *t) { switch (TREE_CODE (&t->generic)) { case IDENTIFIER_NODE: return TS_D_IDENTIFIER; case FUNCFRAME_INFO: return TS_D_FRAMEINFO; default: return TS_D_GENERIC; } } /* Allocate and return a lang specific structure for the frontend type. */ struct lang_type * build_lang_type (Type *t) { struct lang_type *lt = ggc_cleared_alloc (); lt->type = t; return lt; } /* Allocate and return a lang specific structure for the frontend decl. */ struct lang_decl * build_lang_decl (Declaration *d) { /* For compiler generated run-time typeinfo, a lang_decl is allocated even if there's no associated frontend symbol to refer to (yet). If the symbol appears later in the compilation, then the slot will be re-used. */ if (d == NULL) return ggc_cleared_alloc (); struct lang_decl *ld = (d->csym) ? DECL_LANG_SPECIFIC (d->csym) : NULL; if (ld == NULL) ld = ggc_cleared_alloc (); if (ld->decl == NULL) ld->decl = d; return ld; } /* Implements the lang_hooks.dup_lang_specific_decl routine for language D. Replace the DECL_LANG_SPECIFIC field of NODE with a copy. */ static void d_dup_lang_specific_decl (tree node) { if (! DECL_LANG_SPECIFIC (node)) return; struct lang_decl *ld = ggc_alloc (); memcpy (ld, DECL_LANG_SPECIFIC (node), sizeof (struct lang_decl)); DECL_LANG_SPECIFIC (node) = ld; } /* This preserves trees we create from the garbage collector. */ static GTY(()) tree d_keep_list = NULL_TREE; void d_keep (tree t) { d_keep_list = tree_cons (NULL_TREE, t, d_keep_list); } /* Implements the lang_hooks.eh_personality routine for language D. Return the GDC personality function decl. */ static GTY(()) tree d_eh_personality_decl; static tree d_eh_personality (void) { if (!d_eh_personality_decl) d_eh_personality_decl = build_personality_function ("gdc"); return d_eh_personality_decl; } /* Implements the lang_hooks.eh_runtime_type routine for language D. */ static tree d_build_eh_runtime_type (tree type) { Type *t = TYPE_LANG_FRONTEND (type); if (t != NULL) t = t->toBasetype (); gcc_assert (t != NULL && t->ty == Tclass); ClassDeclaration *cd = ((TypeClass *) t)->sym; tree decl; if (cd->isCPPclass ()) decl = get_cpp_typeinfo_decl (cd); else decl = get_classinfo_decl (cd); return convert (ptr_type_node, build_address (decl)); } /* Definitions for our language-specific hooks. */ #undef LANG_HOOKS_NAME #undef LANG_HOOKS_INIT #undef LANG_HOOKS_INIT_TS #undef LANG_HOOKS_INIT_OPTIONS #undef LANG_HOOKS_INIT_OPTIONS_STRUCT #undef LANG_HOOKS_OPTION_LANG_MASK #undef LANG_HOOKS_HANDLE_OPTION #undef LANG_HOOKS_POST_OPTIONS #undef LANG_HOOKS_PARSE_FILE #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE #undef LANG_HOOKS_ATTRIBUTE_TABLE #undef LANG_HOOKS_GET_ALIAS_SET #undef LANG_HOOKS_TYPES_COMPATIBLE_P #undef LANG_HOOKS_BUILTIN_FUNCTION #undef LANG_HOOKS_REGISTER_BUILTIN_TYPE #undef LANG_HOOKS_FINISH_INCOMPLETE_DECL #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_CLASSIFY_RECORD #undef LANG_HOOKS_TREE_SIZE #undef LANG_HOOKS_PRINT_XNODE #undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL #undef LANG_HOOKS_EH_PERSONALITY #undef LANG_HOOKS_EH_RUNTIME_TYPE #undef LANG_HOOKS_PUSHDECL #undef LANG_HOOKS_GETDECLS #undef LANG_HOOKS_GLOBAL_BINDINGS_P #undef LANG_HOOKS_TYPE_FOR_MODE #undef LANG_HOOKS_TYPE_FOR_SIZE #undef LANG_HOOKS_TYPE_PROMOTES_TO #define LANG_HOOKS_NAME "GNU D" #define LANG_HOOKS_INIT d_init #define LANG_HOOKS_INIT_TS d_init_ts #define LANG_HOOKS_INIT_OPTIONS d_init_options #define LANG_HOOKS_INIT_OPTIONS_STRUCT d_init_options_struct #define LANG_HOOKS_OPTION_LANG_MASK d_option_lang_mask #define LANG_HOOKS_HANDLE_OPTION d_handle_option #define LANG_HOOKS_POST_OPTIONS d_post_options #define LANG_HOOKS_PARSE_FILE d_parse_file #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE d_langhook_common_attribute_table #define LANG_HOOKS_ATTRIBUTE_TABLE d_langhook_attribute_table #define LANG_HOOKS_GET_ALIAS_SET d_get_alias_set #define LANG_HOOKS_TYPES_COMPATIBLE_P d_types_compatible_p #define LANG_HOOKS_BUILTIN_FUNCTION d_builtin_function #define LANG_HOOKS_REGISTER_BUILTIN_TYPE d_register_builtin_type #define LANG_HOOKS_FINISH_INCOMPLETE_DECL d_finish_incomplete_decl #define LANG_HOOKS_GIMPLIFY_EXPR d_gimplify_expr #define LANG_HOOKS_CLASSIFY_RECORD d_classify_record #define LANG_HOOKS_TREE_SIZE d_tree_size #define LANG_HOOKS_PRINT_XNODE d_print_xnode #define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL d_dup_lang_specific_decl #define LANG_HOOKS_EH_PERSONALITY d_eh_personality #define LANG_HOOKS_EH_RUNTIME_TYPE d_build_eh_runtime_type #define LANG_HOOKS_PUSHDECL d_pushdecl #define LANG_HOOKS_GETDECLS d_getdecls #define LANG_HOOKS_GLOBAL_BINDINGS_P d_global_bindings_p #define LANG_HOOKS_TYPE_FOR_MODE d_type_for_mode #define LANG_HOOKS_TYPE_FOR_SIZE d_type_for_size #define LANG_HOOKS_TYPE_PROMOTES_TO d_type_promotes_to struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; #include "gt-d-d-lang.h" #include "gtype-d.h" ================================================ FILE: gcc/d/d-longdouble.cc ================================================ /* d-longdouble.cc -- Software floating-point emulation for the frontend. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/mtype.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "stor-layout.h" #include "d-tree.h" #include "longdouble.h" /* Truncate longdouble to the highest precision supported by target. */ longdouble longdouble::normalize (void) { const machine_mode mode = TYPE_MODE (long_double_type_node); real_convert (&this->rv (), mode, &this->rv ()); return *this; } /* Assign a real_value to a longdouble type. */ void longdouble::set (real_value& d) { real_convert (&this->rv (), TYPE_MODE (long_double_type_node), &d); } /* Conversion routines between longdouble and integer types. */ void longdouble::set (int32_t d) { real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, SIGNED); } void longdouble::set (int64_t d) { real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d, SIGNED); } int64_t longdouble::to_int (void) const { bool overflow; wide_int wi = real_to_integer (&this->rv (), &overflow, 64); return wi.to_shwi (); } /* Unsigned variants of the same conversion routines. */ void longdouble::set (uint32_t d) { real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, UNSIGNED); } void longdouble::set (uint64_t d) { real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d, UNSIGNED); } uint64_t longdouble::to_uint (void) const { bool overflow; wide_int wi = real_to_integer (&this->rv (), &overflow, 64); return wi.to_uhwi (); } /* For conversion between boolean, only need to check if is zero. */ void longdouble::set (bool d) { this->rv () = (d == false) ? dconst0 : dconst1; } bool longdouble::to_bool (void) const { return this->rv ().cl != rvc_zero; } /* Overload numeric operators for longdouble types. */ longdouble longdouble::add (const longdouble& r) const { longdouble x; real_arithmetic (&x.rv (), PLUS_EXPR, &this->rv (), &r.rv ()); return x.normalize (); } longdouble longdouble::sub (const longdouble& r) const { longdouble x; real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &r.rv ()); return x.normalize (); } longdouble longdouble::mul (const longdouble& r) const { longdouble x; real_arithmetic (&x.rv (), MULT_EXPR, &this->rv (), &r.rv ()); return x.normalize (); } longdouble longdouble::div (const longdouble& r) const { longdouble x; real_arithmetic (&x.rv (), RDIV_EXPR, &this->rv (), &r.rv ()); return x.normalize (); } longdouble longdouble::mod (const longdouble& r) const { longdouble x; real_value q; if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ())) { real_nan (&x.rv (), "", 1, TYPE_MODE (long_double_type_node)); return x; } if (this->rv ().cl == rvc_zero) return *this; if (REAL_VALUE_ISINF (r.rv ())) return *this; /* Need to check for NaN? */ real_arithmetic (&q, RDIV_EXPR, &this->rv (), &r.rv ()); real_arithmetic (&q, FIX_TRUNC_EXPR, &q, NULL); real_arithmetic (&q, MULT_EXPR, &q, &r.rv ()); real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &q); return x.normalize (); } longdouble longdouble::neg (void) const { longdouble x; real_arithmetic (&x.rv (), NEGATE_EXPR, &this->rv (), NULL); return x.normalize (); } /* Overload equality operators for longdouble types. */ int longdouble::cmp (const longdouble& r) const { if (real_compare (LT_EXPR, &this->rv (), &r.rv ())) return -1; if (real_compare (GT_EXPR, &this->rv (), &r.rv ())) return 1; return 0; } int longdouble::equals (const longdouble& r) const { return real_compare (EQ_EXPR, &this->rv (), &r.rv ()); } ================================================ FILE: gcc/d/d-spec.cc ================================================ /* d-spec.c -- Specific flags and argument handling of the D front end. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "opt-suggestions.h" #include "gcc.h" #include "tm.h" #include "opts.h" /* This bit is set if the arguments is a D source file. */ #define DSOURCE (1<<1) /* This bit is set if they did `-lstdc++'. */ #define WITHLIBCXX (1<<2) /* Skip this option. */ #define SKIPOPT (1<<3) #ifndef LIBSTDCXX #define LIBSTDCXX "stdc++" #endif #ifndef LIBSTDCXX_PROFILE #define LIBSTDCXX_PROFILE LIBSTDCXX #endif #ifndef LIBPHOBOS #define LIBPHOBOS "gphobos" #endif #ifndef LIBPHOBOS_PROFILE #define LIBPHOBOS_PROFILE LIBPHOBOS #endif #ifndef LIBDRUNTIME #define LIBDRUNTIME "gdruntime" #endif #ifndef LIBDRUNTIME_PROFILE #define LIBDRUNTIME_PROFILE LIBDRUNTIME #endif /* What do with libgphobos. */ enum phobos_action { /* libgphobos should not be linked in. */ PHOBOS_NOLINK = -1, /* libgphobos should be linked in if it is needed. */ PHOBOS_DEFAULT = 0, /* libgphobos is needed and should be linked in. */ PHOBOS_LINK, /* libgphobos is needed and should be linked statically. */ PHOBOS_STATIC, /* libgphobos is needed and should be linked dynamically. */ PHOBOS_DYNAMIC, }; static phobos_action phobos_library = PHOBOS_DEFAULT; /* If true, use the standard D runtime library when linking with standard libraries. */ static bool need_phobos = true; void lang_specific_driver (cl_decoded_option **in_decoded_options, unsigned int *in_decoded_options_count, int *in_added_libraries) { unsigned int i, j; /* If nonzero, the user gave us the `-p' or `-pg' flag. */ int saw_profile_flag = 0; /* If true, the user gave `-g'. Used by -debuglib. */ bool saw_debug_flag = false; /* The new argument list will be contained in this. */ cl_decoded_option *new_decoded_options; /* "-lstdc++" if it appears on the command line. */ const cl_decoded_option *saw_libcxx = 0; /* Whether we need the C++ STD library. */ bool need_stdcxx = false; /* True if we saw -static. */ bool static_link = false; /* True if we should add -shared-libgcc to the command-line. */ bool shared_libgcc = true; /* What default library to use instead of phobos. */ const char *defaultlib = NULL; /* What debug library to use instead of phobos. */ const char *debuglib = NULL; /* The total number of arguments with the new stuff. */ unsigned int num_args = 1; /* "-fonly" if it appears on the command line. */ const char *only_source_option = 0; /* Whether the -o option was used. */ bool saw_opt_o = false; /* Whether the -c option was used. Also used for -E, -fsyntax-only, in general anything which implies only compilation and not linking. */ bool saw_opt_c = false; /* Whether the -S option was used. */ bool saw_opt_S = false; /* The first input file with an extension of .d. */ const char *first_d_file = NULL; /* The total number of arguments with the new stuff. */ unsigned int argc = *in_decoded_options_count; /* The argument list. */ cl_decoded_option *decoded_options = *in_decoded_options; /* The number of libraries added in. */ int added_libraries = *in_added_libraries; /* An array used to flag each argument that needs a bit set for DSOURCE, MATHLIB, WITHTHREAD, WITHLIBC or WITHLIBCXX. */ int *args = XCNEWVEC (int, argc); for (i = 1; i < argc; i++) { const char *arg = decoded_options[i].arg; switch (decoded_options[i].opt_index) { case OPT_nostdlib: case OPT_nodefaultlibs: phobos_library = PHOBOS_NOLINK; break; case OPT_nophoboslib: need_phobos = false; args[i] |= SKIPOPT; break; case OPT_defaultlib_: if (defaultlib != NULL) free (CONST_CAST (char *, defaultlib)); if (arg != NULL) { need_phobos = false; args[i] |= SKIPOPT; defaultlib = XNEWVEC (char, strlen (arg)); strcpy (CONST_CAST (char *, defaultlib), arg); } break; case OPT_debuglib_: if (debuglib != NULL) free (CONST_CAST (char *, debuglib)); if (arg != NULL) { need_phobos = false; args[i] |= SKIPOPT; debuglib = XNEWVEC (char, strlen (arg)); strcpy (CONST_CAST (char *, debuglib), arg); } break; case OPT_l: if ((strcmp (arg, LIBSTDCXX) == 0) || (strcmp (arg, LIBSTDCXX_PROFILE) == 0)) { args[i] |= WITHLIBCXX; need_stdcxx = false; } /* Unrecognized libraries (e.g. -ltango) may require libphobos. */ else if (phobos_library == PHOBOS_DEFAULT) phobos_library = PHOBOS_LINK; break; case OPT_pg: case OPT_p: saw_profile_flag++; break; case OPT_g: saw_debug_flag = true; break; case OPT_v: /* If they only gave us `-v', don't try to link in libphobos. */ if (argc == 2) phobos_library = PHOBOS_NOLINK; break; case OPT_x: if (phobos_library == PHOBOS_DEFAULT && (strcmp (arg, "d") == 0)) phobos_library = PHOBOS_LINK; break; case OPT_Xlinker: case OPT_Wl_: /* Arguments that go directly to the linker might be .o files or something, and so might cause libphobos to be needed. */ if (phobos_library == PHOBOS_DEFAULT) phobos_library = PHOBOS_LINK; break; case OPT_c: case OPT_E: case OPT_M: case OPT_MM: case OPT_fsyntax_only: /* Don't specify libaries if we won't link, since that would cause a warning. */ saw_opt_c = true; phobos_library = PHOBOS_NOLINK; break; case OPT_S: saw_opt_S = true; phobos_library = PHOBOS_NOLINK; break; case OPT_o: saw_opt_o = true; break; case OPT_static: static_link = true; break; case OPT_static_libgcc: shared_libgcc = false; break; case OPT_static_libphobos: if (phobos_library != PHOBOS_NOLINK) phobos_library = PHOBOS_STATIC; args[i] |= SKIPOPT; break; case OPT_shared_libphobos: if (phobos_library != PHOBOS_NOLINK) phobos_library = PHOBOS_DYNAMIC; args[i] |= SKIPOPT; break; case OPT_fonly_: args[i] |= SKIPOPT; only_source_option = decoded_options[i].orig_option_with_args_text; if (arg != NULL) { const char *suffix = strrchr (only_source_option, '.'); if (suffix == NULL || strcmp (suffix, ".d") != 0) only_source_option = concat (only_source_option, ".d", NULL); } break; case OPT_SPECIAL_input_file: { if (arg[0] == '\0' || arg[1] == '\0') continue; if (phobos_library == PHOBOS_DEFAULT) phobos_library = PHOBOS_LINK; /* Record that this is a D source file. */ const char *suffix = strrchr (arg, '.'); if (suffix != NULL && strcmp (suffix, ".d") == 0) { if (first_d_file == NULL) first_d_file = arg; args[i] |= DSOURCE; } /* If this is a C++ source file, we'll need to link against libstdc++ library. */ if (suffix != NULL && (strcmp (suffix, ".cc") == 0 || (strcmp (suffix, ".cpp") == 0) || (strcmp (suffix, ".c++") == 0))) need_stdcxx = true; break; } } } /* There's no point adding -shared-libgcc if we don't have a shared libgcc. */ #ifndef ENABLE_SHARED_LIBGCC shared_libgcc = false; #endif /* Make sure to have room for the trailing NULL argument. - needstdcxx might add `-lstdcxx' - libphobos adds `-Bstatic -lphobos -ldruntime -Bdynamic' - only_source adds 1 more arg, also maybe add `-o'. */ num_args = argc + need_stdcxx + shared_libgcc + need_phobos * 4 + 2; new_decoded_options = XNEWVEC (cl_decoded_option, num_args); i = 0; j = 0; /* Copy the 0th argument, i.e., the name of the program itself. */ new_decoded_options[j++] = decoded_options[i++]; /* NOTE: We start at 1 now, not 0. */ while (i < argc) { if (args[i] & SKIPOPT) { ++i; continue; } new_decoded_options[j] = decoded_options[i]; if (!saw_libcxx && (args[i] & WITHLIBCXX)) { --j; saw_libcxx = &decoded_options[i]; } if (args[i] & DSOURCE) { if (only_source_option) --j; } i++; j++; } if (only_source_option) { const char *only_source_arg = only_source_option + 7; generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER, &new_decoded_options[j]); j++; generate_option_input_file (only_source_arg, &new_decoded_options[j++]); } /* If no reason to link against libphobos library, then don't add it. */ if (phobos_library == PHOBOS_DEFAULT) phobos_library = PHOBOS_NOLINK; /* If we didn't see a -o option, add one. This is because we need the driver to pass all .d files to the D compiler. Without a -o option the driver will invoke the compiler separately for each input file. */ if (first_d_file != NULL && !saw_opt_o) { if (saw_opt_c || saw_opt_S) { const char *base = lbasename (first_d_file); int baselen = strlen (base) - 2; char *out = XNEWVEC (char, baselen + 3); memcpy (out, base, baselen); /* The driver will convert .o to some other suffix if appropriate. */ out[baselen] = '.'; if (saw_opt_S) out[baselen + 1] = 's'; else out[baselen + 1] = 'o'; out[baselen + 2] = '\0'; generate_option (OPT_o, out, 1, CL_DRIVER, &new_decoded_options[j]); } else { /* Wouldn't be necessary if the driver converted .out also. */ const char *out = NULL; #ifdef TARGET_EXECUTABLE_SUFFIX if (TARGET_EXECUTABLE_SUFFIX[0] != 0) out = "a" TARGET_EXECUTABLE_SUFFIX; #endif if (out == NULL) out = "a.out"; generate_option (OPT_o, out, 1, CL_DRIVER, &new_decoded_options[j]); } j++; } /* Add `-lgphobos' if we haven't already done so. */ if (phobos_library != PHOBOS_NOLINK && need_phobos) { /* Default to static linking. */ if (phobos_library != PHOBOS_DYNAMIC) phobos_library = PHOBOS_STATIC; #ifdef HAVE_LD_STATIC_DYNAMIC if (phobos_library == PHOBOS_DYNAMIC && static_link) { generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER, &new_decoded_options[j]); j++; } else if (phobos_library == PHOBOS_STATIC && !static_link) { generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER, &new_decoded_options[j]); j++; } #endif generate_option (OPT_l, saw_profile_flag ? LIBPHOBOS_PROFILE : LIBPHOBOS, 1, CL_DRIVER, &new_decoded_options[j]); added_libraries++; j++; generate_option (OPT_l, saw_profile_flag ? LIBDRUNTIME_PROFILE : LIBDRUNTIME, 1, CL_DRIVER, &new_decoded_options[j]); added_libraries++; j++; #ifdef HAVE_LD_STATIC_DYNAMIC if (phobos_library == PHOBOS_DYNAMIC && static_link) { generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER, &new_decoded_options[j]); j++; } else if (phobos_library == PHOBOS_STATIC && !static_link) { generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER, &new_decoded_options[j]); j++; } #endif } else if (saw_debug_flag && debuglib) { generate_option (OPT_l, debuglib, 1, CL_DRIVER, &new_decoded_options[j++]); added_libraries++; } else if (defaultlib) { generate_option (OPT_l, defaultlib, 1, CL_DRIVER, &new_decoded_options[j++]); added_libraries++; } if (saw_libcxx) new_decoded_options[j++] = *saw_libcxx; else if (need_stdcxx) { generate_option (OPT_l, (saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX), 1, CL_DRIVER, &new_decoded_options[j++]); added_libraries++; } if (shared_libgcc && !static_link) { generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, &new_decoded_options[j++]); } *in_decoded_options_count = j; *in_decoded_options = new_decoded_options; *in_added_libraries = added_libraries; } /* Called before linking. Returns 0 on success and -1 on failure. */ int lang_specific_pre_link (void) { if (phobos_library != PHOBOS_NOLINK && need_phobos) do_spec ("%:include(libgphobos.spec)"); return 0; } /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for D. */ ================================================ FILE: gcc/d/d-target-def.h ================================================ /* d-target-def.h -- Default initializers for D target hooks. Copyright (C) 2017-2018 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not see . */ #include "d/d-target-hooks-def.h" #include "tree.h" #include "hooks.h" ================================================ FILE: gcc/d/d-target.cc ================================================ /* d-target.cc -- Target interface for the D front end. Copyright (C) 2013-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/mangle.h" #include "dmd/mtype.h" #include "dmd/tokens.h" #include "dmd/target.h" #include "tree.h" #include "memmodel.h" #include "fold-const.h" #include "stor-layout.h" #include "tm.h" #include "tm_p.h" #include "target.h" #include "d-tree.h" #include "d-target.h" /* Implements the Target interface defined by the front end. Used for retrieving target-specific information. */ /* Floating-point constants for for .max, .min, and other properties. */ template real_t Target::FPTypeProperties::max; template real_t Target::FPTypeProperties::min_normal; template real_t Target::FPTypeProperties::nan; template real_t Target::FPTypeProperties::snan; template real_t Target::FPTypeProperties::infinity; template real_t Target::FPTypeProperties::epsilon; template d_int64 Target::FPTypeProperties::dig; template d_int64 Target::FPTypeProperties::mant_dig; template d_int64 Target::FPTypeProperties::max_exp; template d_int64 Target::FPTypeProperties::min_exp; template d_int64 Target::FPTypeProperties::max_10_exp; template d_int64 Target::FPTypeProperties::min_10_exp; /* Initialize the floating-point constants for TYPE. */ template static void define_float_constants (tree type) { const double log10_2 = 0.30102999566398119521; char buf[128]; /* Get back-end real mode format. */ const machine_mode mode = TYPE_MODE (type); const real_format *fmt = REAL_MODE_FORMAT (mode); /* The largest representable value that's not infinity. */ get_max_float (fmt, buf, sizeof (buf)); real_from_string (&T::max.rv (), buf); /* The smallest representable normalized value that's not 0. */ snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - 1); real_from_string (&T::min_normal.rv (), buf); /* Floating-point NaN. */ real_nan (&T::nan.rv (), "", 1, mode); /* Signalling floating-point NaN. */ real_nan (&T::snan.rv (), "", 0, mode); /* Floating-point +Infinity if the target supports infinities. */ real_inf (&T::infinity.rv ()); /* The smallest increment to the value 1. */ if (fmt->pnan < fmt->p) snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - fmt->p); else snprintf (buf, sizeof (buf), "0x1p%d", 1 - fmt->p); real_from_string (&T::epsilon.rv (), buf); /* The number of decimal digits of precision. */ T::dig = (fmt->p - 1) * log10_2; /* The number of bits in mantissa. */ T::mant_dig = fmt->p; /* The maximum int value such that 2** (value-1) is representable. */ T::max_exp = fmt->emax; /* The minimum int value such that 2** (value-1) is representable as a normalized value. */ T::min_exp = fmt->emin; /* The maximum int value such that 10**value is representable. */ T::max_10_exp = fmt->emax * log10_2; /* The minimum int value such that 10**value is representable as a normalized value. */ T::min_10_exp = (fmt->emin - 1) * log10_2; } /* Initialize all variables of the Target structure. */ void Target::_init (void) { /* Map D frontend type and sizes to GCC back-end types. */ Target::ptrsize = (POINTER_SIZE / BITS_PER_UNIT); Target::realsize = int_size_in_bytes (long_double_type_node); Target::realpad = (Target::realsize - (TYPE_PRECISION (long_double_type_node) / BITS_PER_UNIT)); Target::realalignsize = TYPE_ALIGN_UNIT (long_double_type_node); /* Size of run-time TypeInfo object. */ Target::classinfosize = 19 * Target::ptrsize; /* Allow data sizes up to half of the address space. */ Target::maxStaticDataSize = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); /* Define what type to use for size_t, ptrdiff_t. */ if (POINTER_SIZE == 64) { global.params.isLP64 = true; Tsize_t = Tuns64; Tptrdiff_t = Tint64; } else { Tsize_t = Tuns32; Tptrdiff_t = Tint32; } Type::tsize_t = Type::basic[Tsize_t]; Type::tptrdiff_t = Type::basic[Tptrdiff_t]; Type::thash_t = Type::tsize_t; /* Set-up target C ABI. */ Target::c_longsize = int_size_in_bytes (long_integer_type_node); Target::c_long_doublesize = int_size_in_bytes (long_double_type_node); /* Set-up target C++ ABI. */ Target::reverseCppOverloads = false; Target::cppExceptions = true; Target::twoDtorInVtable = true; /* Initialize all compile-time properties for floating-point types. Should ensure that our real_t type is able to represent real_value. */ gcc_assert (sizeof (real_t) >= sizeof (real_value)); define_float_constants (float_type_node); define_float_constants (double_type_node); define_float_constants (long_double_type_node); /* Commonly used floating-point constants. */ const machine_mode mode = TYPE_MODE (long_double_type_node); real_convert (&CTFloat::zero.rv (), mode, &dconst0); real_convert (&CTFloat::one.rv (), mode, &dconst1); real_convert (&CTFloat::minusone.rv (), mode, &dconstm1); real_convert (&CTFloat::half.rv (), mode, &dconsthalf); } /* Return GCC memory alignment size for type TYPE. */ unsigned Target::alignsize (Type *type) { gcc_assert (type->isTypeBasic ()); return TYPE_ALIGN_UNIT (build_ctype (type)); } /* Return GCC field alignment size for type TYPE. */ unsigned Target::fieldalign (Type *type) { /* Work out the correct alignment for the field decl. */ unsigned int align = type->alignsize () * BITS_PER_UNIT; #ifdef BIGGEST_FIELD_ALIGNMENT align = MIN (align, (unsigned) BIGGEST_FIELD_ALIGNMENT); #endif #ifdef ADJUST_FIELD_ALIGN if (type->isTypeBasic ()) align = ADJUST_FIELD_ALIGN (NULL_TREE, build_ctype (type), align); #endif /* Also controlled by -fpack-struct= */ if (maximum_field_alignment) align = MIN (align, maximum_field_alignment); return align / BITS_PER_UNIT; } /* Return size of OS critical section. Can't use the sizeof () calls directly since cross compiling is supported and would end up using the host sizes rather than the target sizes. */ unsigned Target::critsecsize (void) { return targetdm.d_critsec_size (); } /* Returns a Type for the va_list type of the target. */ Type * Target::va_listType (void) { return Type::tvalist; } /* Checks whether the target supports a vector type with total size SZ (in bytes) and element type TYPE. */ int Target::isVectorTypeSupported (int sz, Type *type) { /* Size must be greater than zero, and a power of two. */ if (sz <= 0 || sz & (sz - 1)) return 2; /* __vector(void[]) is treated same as __vector(ubyte[]) */ if (type == Type::tvoid) type = Type::tuns8; /* No support for non-trivial types. */ if (!type->isTypeBasic ()) return 3; /* If there is no hardware support, check if we can safely emulate it. */ tree ctype = build_ctype (type); machine_mode mode = TYPE_MODE (ctype); if (!targetm.vector_mode_supported_p (mode) && !targetm.scalar_mode_supported_p (as_a (mode))) return 3; return 0; } /* Checks whether the target supports operation OP for vectors of type TYPE. For binary ops T2 is the type of the right-hand operand. Returns true if the operation is supported or type is not a vector. */ bool Target::isVectorOpSupported (Type *type, TOK op, Type *) { if (type->ty != Tvector) return true; /* Don't support if type is non-scalar, such as __vector(void[]). */ if (!type->isscalar ()) return false; /* Don't support if expression cannot be represented. */ switch (op) { case TOKpow: case TOKpowass: /* pow() is lowered as a function call. */ return false; case TOKmod: case TOKmodass: /* fmod() is lowered as a function call. */ if (type->isfloating ()) return false; break; case TOKandand: case TOKoror: /* Logical operators must have a result type of bool. */ return false; case TOKle: case TOKlt: case TOKge: case TOKgt: case TOKequal: case TOKnotequal: case TOKidentity: case TOKnotidentity: /* Comparison operators must have a result type of bool. */ return false; default: break; } return true; } /* Return the symbol mangling of S for C++ linkage. */ const char * Target::toCppMangle (Dsymbol *s) { return toCppMangleItanium (s); } /* Return the symbol mangling of CD for C++ linkage. */ const char * Target::cppTypeInfoMangle (ClassDeclaration *cd) { return cppTypeInfoMangleItanium (cd); } /* For a vendor-specific type, return a string containing the C++ mangling. In all other cases, return NULL. */ const char * Target::cppTypeMangle (Type *type) { if (type->isTypeBasic () || type->ty == Tvector || type->ty == Tstruct) { tree ctype = build_ctype (type); return targetm.mangle_type (ctype); } return NULL; } /* Return the type that will really be used for passing the given parameter ARG to an extern(C++) function. */ Type * Target::cppParameterType (Parameter *arg) { Type *t = arg->type->merge2 (); if (arg->storageClass & (STCout | STCref)) t = t->referenceTo (); else if (arg->storageClass & STClazy) { /* Mangle as delegate. */ Type *td = TypeFunction::create (NULL, t, 0, LINKd); td = TypeDelegate::create (td); t = t->merge2 (); } /* Could be a va_list, which we mangle as a pointer. */ if (t->ty == Tsarray && Type::tvalist->ty == Tsarray) { Type *tb = t->toBasetype ()->mutableOf (); if (tb == Type::tvalist) { tb = t->nextOf ()->pointerTo (); t = tb->castMod (t->mod); } } return t; } /* Return the default system linkage for the target. */ LINK Target::systemLinkage (void) { return LINKc; } /* Determine return style of function, whether in registers or through a hidden pointer to the caller's stack. */ bool Target::isReturnOnStack (TypeFunction *, bool) { /* Need the back-end type to determine this, but this is called from the frontend before semantic processing is finished. An accurate value is not currently needed anyway. */ return true; } /* Return the result of a __traits(getTargetInfo) query or NULL if it is not information that's known at compile-time. */ Expression * Target::getTargetInfo (const char *name, const Loc& loc) { const char *result = NULL; switch (strlen (name)) { case 8: if (strcmp (name, "floatAbi") == 0) result = targetdm.d_float_abi_type (); break; case 12: if (strcmp (name, "objectFormat") == 0) result = targetdm.d_object_format (); break; case 17: /* The driver only ever optionally links to libstdc++. */ if (strcmp (name, "cppRuntimeLibrary") == 0) result = "libstdc++"; break; } if (result != NULL) return StringExp::create (loc, CONST_CAST (char *, result), strlen (result)); return NULL; } ================================================ FILE: gcc/d/d-target.def ================================================ /* d-target.def -- Target hook definitions for the D front end. Copyright (C) 2017-2018 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not see . */ /* See target-hooks-macros.h for details of macros that should be provided by the including file, and how to use them here. */ #include "target-hooks-macros.h" #undef HOOK_TYPE #define HOOK_TYPE "D Target Hook" HOOK_VECTOR (TARGETDM_INITIALIZER, gcc_targetdm) #undef HOOK_PREFIX #define HOOK_PREFIX "TARGET_" /* Environmental version identifiers relating to the target CPU. */ DEFHOOK (d_cpu_versions, "Declare all environmental version identifiers relating to the target CPU\n\ using the function @code{builtin_version}, which takes a string representing\n\ the name of the version. Version identifiers predefined by this hook apply\n\ to all modules that are being compiled and imported.", void, (void), hook_void_void) /* Environmental version identifiers relating to the target OS. */ DEFHOOK (d_os_versions, "Similarly to @code{TARGET_D_CPU_VERSIONS}, but is used for versions\n\ relating to the target operating system.", void, (void), hook_void_void) /* The sizeof CRITICAL_SECTION or pthread_mutex_t. */ DEFHOOK (d_critsec_size, "Returns the size of the data structure used by the target operating system\n\ for critical sections and monitors. For example, on Microsoft Windows this\n\ would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that\n\ implement pthreads would return @code{sizeof(pthread_mutex_t)}.", unsigned, (void), hook_uint_void_0) /* The floating point ABI, may be "hard" or "soft". */ DEFHOOK (d_float_abi_type, "Returns a string specifying which floating-point ABI is in use, or whether\n\ floating-point value types are passed in FPU registers. For most targets,\n\ this would be described as either \"hard\" or \"soft\".", const char *, (void), hook_constcharptr_void_null) /* The target object format. */ DEFHOOK (d_object_format, "Returns a string specifying the executable object format of the platform\n\ the compiler is generating code for.", const char *, (void), hook_constcharptr_void_null) /* Close the 'struct gcc_targetdm' definition. */ HOOK_VECTOR_END (C90_EMPTY_HACK) ================================================ FILE: gcc/d/d-target.h ================================================ /* d-target.h -- Data structure definitions for target-specific D behavior. Copyright (C) 2017-2018 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not see . */ #ifndef GCC_D_TARGET_H #define GCC_D_TARGET_H #define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME; #define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS; #define DEFHOOK_UNDOC DEFHOOK #define HOOKSTRUCT(FRAGMENT) FRAGMENT #include "d-target.def" /* Each target can provide their own. */ extern struct gcc_targetdm targetdm; /* Used by target to add predefined version idenditiers. */ extern void d_add_builtin_version (const char *); #endif /* GCC_D_TARGET_H */ ================================================ FILE: gcc/d/d-tree.def ================================================ /* d-tree.def -- Definitions and documentation for additional tree codes used in the D compiler (see tree.def for standard codes). Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* Logical shift done on an unsigned type. If the first operand is signed, it will be converted to the unsigned equivalent. The second operand is the number of bits to shift by; it need not be the same type as the first operand and result. */ DEFTREECODE (UNSIGNED_RSHIFT_EXPR, "unsigned_rshift_expr", tcc_binary, 2) /* Floating point modulus that expands to a call to fmod. */ DEFTREECODE (FLOAT_MOD_EXPR, "float_mod_expr", tcc_binary, 2) /* Used to represent information associated with a function closure. */ DEFTREECODE (FUNCFRAME_INFO, "funcframe_info", tcc_exceptional, 0) ================================================ FILE: gcc/d/d-tree.h ================================================ /* d-tree.h -- Definitions and declarations for code generation. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #ifndef GCC_D_TREE_H #define GCC_D_TREE_H /* Forward type declarations to avoid including unnecessary headers. */ class Dsymbol; class Declaration; class AggregateDeclaration; class ClassDeclaration; class EnumDeclaration; class FuncDeclaration; class StructDeclaration; class TypeInfoDeclaration; class VarDeclaration; class UserAttributeDeclaration; class Expression; class ClassReferenceExp; class Module; class Statement; class Type; class TypeFunction; class Parameter; struct BaseClass; struct Scope; struct Loc; template struct Array; typedef Array Expressions; /* Usage of TREE_LANG_FLAG_?: 0: METHOD_CALL_EXPR 1: CALL_EXPR_ARGS_ORDERED (in CALL_EXPR). Usage of TYPE_LANG_FLAG_?: 0: TYPE_SHARED 1: TYPE_IMAGINARY_FLOAT (in REAL_TYPE). ANON_AGGR_TYPE_P (in RECORD_TYPE, UNION_TYPE). 2: CLASS_TYPE_P (in RECORD_TYPE). 3: TYPE_DYNAMIC_ARRAY (in RECORD_TYPE). 4: TYPE_DELEGATE (in RECORD_TYPE). 5: TYPE_ASSOCIATIVE_ARRAY (in RECORD_TYPE). Usage of DECL_LANG_FLAG_?: 0: LABEL_VARIABLE_CASE (in LABEL_DECL). DECL_BUILT_IN_CTFE (in FUNCTION_DECL). */ /* The kinds of scopes we recognize. */ enum level_kind { level_block, /* An ordinary block scope. */ level_try, /* A try-block. */ level_catch, /* A catch-block. */ level_finally, /* A finally-block. */ level_cond, /* The scope for an if condition. */ level_switch, /* The scope for a switch statement. */ level_loop, /* A for, do-while, or unrolled-loop block. */ level_with, /* The scope for a with statement. */ level_function /* The block representing an entire function. */ }; /* List of codes for internally recognised compiler intrinsics. */ enum intrinsic_code { #define DEF_D_INTRINSIC(CODE, A, N, M, D, C) INTRINSIC_ ## CODE, #include "intrinsics.def" #undef DEF_D_INTRINSIC INTRINSIC_LAST }; /* For use with break and continue statements. */ enum bc_kind { bc_break = 0, bc_continue = 1 }; /* The datatype used to implement D scope. It is needed primarily to support the back-end, but also helps debugging information for local variables. */ struct GTY((chain_next ("%h.level_chain"))) binding_level { /* A chain of declarations for all variables, constants and functions. These are in the reverse of the order supplied. */ tree names; /* For each level (except the global one), a chain of BLOCK nodes for all the levels that were entered and exited one level down. */ tree blocks; /* The binding level this one is contained in. */ binding_level *level_chain; /* The kind of scope this object represents. */ ENUM_BITFIELD (level_kind) kind : 4; }; /* The binding level currently in effect. */ extern GTY(()) binding_level *current_binding_level; extern GTY(()) binding_level *global_binding_level; /* Used only for jumps to as-yet undefined labels, since jumps to defined labels can have their validity checked immediately. */ struct GTY((chain_next ("%h.next"))) d_label_use_entry { d_label_use_entry *next; /* The frontend Statement associated with the jump. */ Statement * GTY((skip)) statement; /* The binding level to which this entry is *currently* attached. This is initially the binding level in which the goto appeared, but is modified as scopes are closed. */ binding_level *level; }; /* A list of all LABEL_DECLs in the function that have names. Here so we can clear out their names' definitions at the end of the function, and so we can check the validity of jumps to these labels. */ struct GTY(()) d_label_entry { /* The label decl itself. */ tree label; /* The frontend Statement associated with the label. */ Statement * GTY((skip)) statement; /* The binding level to which the label is *currently* attached. This is initially set to the binding level in which the label is defined, but is modified as scopes are closed. */ binding_level *level; /* A list of forward references of the label. */ d_label_use_entry *fwdrefs; /* The following bits are set after the label is defined, and are updated as scopes are popped. They indicate that a backward jump to the label will illegally enter a scope of the given flavor. */ bool in_try_scope; bool in_catch_scope; /* If set, the label we reference represents a break/continue pair. */ bool bc_label; }; /* Frame information for a function declaration. */ struct GTY(()) tree_frame_info { struct tree_common common; tree frame_type; }; /* True if the function creates a nested frame. */ #define FRAMEINFO_CREATES_FRAME(NODE) \ (TREE_LANG_FLAG_0 (FUNCFRAME_INFO_CHECK (NODE))) /* True if the function has a static chain passed in its DECL_ARGUMENTS. */ #define FRAMEINFO_STATIC_CHAIN(NODE) \ (TREE_LANG_FLAG_1 (FUNCFRAME_INFO_CHECK (NODE))) /* True if the function frame is a closure (initialized on the heap). */ #define FRAMEINFO_IS_CLOSURE(NODE) \ (TREE_LANG_FLAG_2 (FUNCFRAME_INFO_CHECK (NODE))) #define FRAMEINFO_TYPE(NODE) \ (((tree_frame_info *) FUNCFRAME_INFO_CHECK (NODE))->frame_type) /* Language-dependent contents of an identifier. */ struct GTY(()) lang_identifier { struct tree_identifier common; /* The identifier as the user sees it. */ tree pretty_ident; /* The back-end tree associated with this identifier. */ tree decl_tree; /* The frontend Declaration associated with this identifier. */ Declaration * GTY((skip)) dsymbol; AggregateDeclaration * GTY((skip)) daggregate; }; #define IDENTIFIER_LANG_SPECIFIC(NODE) \ ((struct lang_identifier *) IDENTIFIER_NODE_CHECK (NODE)) #define IDENTIFIER_PRETTY_NAME(NODE) \ (IDENTIFIER_LANG_SPECIFIC (NODE)->pretty_ident) #define IDENTIFIER_DECL_TREE(NODE) \ (IDENTIFIER_LANG_SPECIFIC (NODE)->decl_tree) #define IDENTIFIER_DSYMBOL(NODE) \ (IDENTIFIER_LANG_SPECIFIC (NODE)->dsymbol) #define IDENTIFIER_DAGGREGATE(NODE) \ (IDENTIFIER_LANG_SPECIFIC (NODE)->daggregate) /* Global state pertinent to the current function. */ struct GTY(()) language_function { /* Our function and enclosing module. */ FuncDeclaration * GTY((skip)) function; Module * GTY((skip)) module; /* Static chain of function, for D2, this is a closure. */ tree static_chain; /* Stack of statement lists being collected while we are compiling the function. */ vec *stmt_list; /* Variables that are in scope that will need destruction later. */ vec *vars_in_scope; /* Table of all used or defined labels in the function. */ hash_map *labels; }; /* The D front end types have not been integrated into the GCC garbage collection system. Handle this by using the "skip" attribute. */ struct GTY(()) lang_decl { Declaration * GTY((skip)) decl; /* FIELD_DECL in frame struct that this variable is allocated in. */ tree frame_field; /* RESULT_DECL in a function that returns by nrvo. */ tree named_result; /* Chain of DECL_LANG_THUNKS in a function. */ tree thunks; /* In a FUNCTION_DECL, this is the THUNK_LANG_OFFSET. */ int offset; /* In a FUNCTION_DECL, if this is an intrinsic, the code for it. */ enum intrinsic_code intrinsic; /* FUNCFRAME_INFO in a function that has non-local references. */ tree frame_info; }; /* The current D per-function global variables. */ #define d_function_chain (cfun ? cfun->language : NULL) /* The D frontend Declaration AST for GCC decl NODE. */ #define DECL_LANG_FRONTEND(NODE) \ (DECL_LANG_SPECIFIC (NODE) \ ? DECL_LANG_SPECIFIC (NODE)->decl : NULL) #define SET_DECL_LANG_FRAME_FIELD(NODE, VAL) \ DECL_LANG_SPECIFIC (NODE)->frame_field = VAL #define DECL_LANG_FRAME_FIELD(NODE) \ (DECL_P (NODE) \ ? DECL_LANG_SPECIFIC (NODE)->frame_field : NULL) #define SET_DECL_LANG_NRVO(NODE, VAL) \ DECL_LANG_SPECIFIC (NODE)->named_result = VAL #define DECL_LANG_NRVO(NODE) \ (DECL_P (NODE) \ ? DECL_LANG_SPECIFIC (NODE)->named_result : NULL) #define DECL_LANG_THUNKS(NODE) \ DECL_LANG_SPECIFIC (NODE)->thunks #define THUNK_LANG_OFFSET(NODE) \ DECL_LANG_SPECIFIC (NODE)->offset #define DECL_INTRINSIC_CODE(NODE) \ DECL_LANG_SPECIFIC (NODE)->intrinsic #define DECL_LANG_FRAMEINFO(NODE) \ DECL_LANG_SPECIFIC (NODE)->frame_info /* The lang_type field is not set for every GCC type. */ struct GTY(()) lang_type { Type * GTY((skip)) type; }; /* The D frontend Type AST for GCC type NODE. */ #define TYPE_LANG_FRONTEND(NODE) \ (TYPE_LANG_SPECIFIC (NODE) \ ? TYPE_LANG_SPECIFIC (NODE)->type : NULL) enum d_tree_node_structure_enum { TS_D_GENERIC, TS_D_IDENTIFIER, TS_D_FRAMEINFO, LAST_TS_D_ENUM }; /* The resulting tree type. */ union GTY((desc ("d_tree_node_structure (&%h)"), chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON)" " ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) lang_tree_node { union tree_node GTY ((tag ("TS_D_GENERIC"), desc ("tree_node_structure (&%h)"))) generic; lang_identifier GTY ((tag ("TS_D_IDENTIFIER"))) identifier; tree_frame_info GTY ((tag ("TS_D_FRAMEINFO"))) frameinfo; }; /* True if the Tdelegate typed expression is not really a variable, but a literal function / method reference. */ #define METHOD_CALL_EXPR(NODE) \ (TREE_LANG_FLAG_0 (NODE)) /* True if all arguments in a call expression should be evaluated in the order they are given (left to right). */ #define CALL_EXPR_ARGS_ORDERED(NODE) \ (TREE_LANG_FLAG_1 (CALL_EXPR_CHECK (NODE))) /* True if the type was declared 'shared'. */ #define TYPE_SHARED(NODE) \ (TYPE_LANG_FLAG_0 (NODE)) /* True if the type is an imaginary float type. */ #define TYPE_IMAGINARY_FLOAT(NODE) \ (TYPE_LANG_FLAG_1 (REAL_TYPE_CHECK (NODE))) /* True if the type is an anonymous record or union. */ #define ANON_AGGR_TYPE_P(NODE) \ (TYPE_LANG_FLAG_1 (RECORD_OR_UNION_CHECK (NODE))) /* True if the type is the underlying record for a class. */ #define CLASS_TYPE_P(NODE) \ (TYPE_LANG_FLAG_2 (RECORD_TYPE_CHECK (NODE))) /* True if the type is a D dynamic array. */ #define TYPE_DYNAMIC_ARRAY(NODE) \ (TYPE_LANG_FLAG_3 (RECORD_TYPE_CHECK (NODE))) /* True if the type is a D delegate. */ #define TYPE_DELEGATE(NODE) \ (TYPE_LANG_FLAG_4 (RECORD_TYPE_CHECK (NODE))) /* True if the type is a D associative array. */ #define TYPE_ASSOCIATIVE_ARRAY(NODE) \ (TYPE_LANG_FLAG_5 (RECORD_TYPE_CHECK (NODE))) /* True if the decl is a variable case label decl. */ #define LABEL_VARIABLE_CASE(NODE) \ (DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE))) /* True if the decl is a CTFE built-in. */ #define DECL_BUILT_IN_CTFE(NODE) \ (DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE))) enum d_tree_index { DTI_VTABLE_ENTRY_TYPE, DTI_VTBL_PTR_TYPE, DTI_VTBL_INTERFACE_TYPE, DTI_BOOL_TYPE, DTI_CHAR_TYPE, DTI_WCHAR_TYPE, DTI_DCHAR_TYPE, DTI_BYTE_TYPE, DTI_UBYTE_TYPE, DTI_SHORT_TYPE, DTI_USHORT_TYPE, DTI_INT_TYPE, DTI_UINT_TYPE, DTI_LONG_TYPE, DTI_ULONG_TYPE, DTI_CENT_TYPE, DTI_UCENT_TYPE, DTI_IFLOAT_TYPE, DTI_IDOUBLE_TYPE, DTI_IREAL_TYPE, DTI_UNKNOWN_TYPE, DTI_ARRAY_TYPE, DTI_NULL_ARRAY, DTI_MAX }; extern GTY(()) tree d_global_trees[DTI_MAX]; #define vtable_entry_type d_global_trees[DTI_VTABLE_ENTRY_TYPE] #define vtbl_ptr_type_node d_global_trees[DTI_VTBL_PTR_TYPE] #define vtbl_interface_type_node d_global_trees[DTI_VTBL_INTERFACE_TYPE] /* D built-in language types. */ #define d_bool_type d_global_trees[DTI_BOOL_TYPE] #define d_byte_type d_global_trees[DTI_BYTE_TYPE] #define d_ubyte_type d_global_trees[DTI_UBYTE_TYPE] #define d_short_type d_global_trees[DTI_SHORT_TYPE] #define d_ushort_type d_global_trees[DTI_USHORT_TYPE] #define d_int_type d_global_trees[DTI_INT_TYPE] #define d_uint_type d_global_trees[DTI_UINT_TYPE] #define d_long_type d_global_trees[DTI_LONG_TYPE] #define d_ulong_type d_global_trees[DTI_ULONG_TYPE] #define d_cent_type d_global_trees[DTI_CENT_TYPE] #define d_ucent_type d_global_trees[DTI_UCENT_TYPE] /* Imaginary floating-point types. */ #define ifloat_type_node d_global_trees[DTI_IFLOAT_TYPE] #define idouble_type_node d_global_trees[DTI_IDOUBLE_TYPE] #define ireal_type_node d_global_trees[DTI_IREAL_TYPE] /* UTF-8, 16 and 32 types. */ #define char8_type_node d_global_trees[DTI_CHAR_TYPE] #define char16_type_node d_global_trees[DTI_DCHAR_TYPE] #define char32_type_node d_global_trees[DTI_WCHAR_TYPE] /* Empty record type used as placeholder when real type is unknown. */ #define unknown_type_node d_global_trees[DTI_UNKNOWN_TYPE] /* Generic dynamic array type void[]. */ #define array_type_node d_global_trees[DTI_ARRAY_TYPE] /* Null initializer for dynamic arrays. */ #define null_array_node d_global_trees[DTI_NULL_ARRAY] /* A prefix for internal variables, which are not user-visible. */ #if !defined (NO_DOT_IN_LABEL) # define GDC_PREFIX(x) "gdc." x #elif !defined (NO_DOLLAR_IN_LABEL) # define GDC_PREFIX(x) "gdc$" x #else # define GDC_PREFIX(x) "gdc_" x #endif /* Internally recognised D runtime library functions. */ enum libcall_fn { #define DEF_D_RUNTIME(CODE, N, T, P, F) LIBCALL_ ## CODE, #include "runtime.def" #undef DEF_D_RUNTIME LIBCALL_LAST }; /* Gate for when the D frontend makes an early call into the codegen pass, such as when it requires target information or CTFE evaluation. As full semantic may not be completed, we only want to build the superficial tree structure without finishing any decls or types. */ extern bool doing_semantic_analysis_p; /* In d-attribs.c. */ extern tree insert_type_attribute (tree, const char *, tree = NULL_TREE); extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE); extern tree build_attributes (Expressions *); /* In d-builtins.cc. */ extern const attribute_spec d_langhook_attribute_table[]; extern const attribute_spec d_langhook_common_attribute_table[]; extern tree d_builtin_function (tree); extern void d_init_builtins (void); extern void d_register_builtin_type (tree, const char *); extern void d_build_builtins_module (Module *); extern void d_maybe_set_builtin (Module *); extern Expression *d_eval_constant_expression (tree); extern void d_init_versions (void); /* In d-codegen.cc. */ extern location_t make_location_t (const Loc &); extern tree d_decl_context (Dsymbol *); extern tree copy_aggregate_type (tree); extern bool declaration_reference_p (Declaration *); extern tree declaration_type (Declaration *); extern bool argument_reference_p (Parameter *); extern tree type_passed_as (Parameter *); extern tree build_integer_cst (dinteger_t, tree = d_int_type); extern tree build_float_cst (const real_t &, Type *); extern tree d_array_length (tree); extern tree d_array_ptr (tree); extern tree d_array_value (tree, tree, tree); extern tree get_array_length (tree, Type *); extern tree build_class_binfo (tree, ClassDeclaration *); extern tree build_interface_binfo (tree, ClassDeclaration *, unsigned &); extern tree delegate_method (tree); extern tree delegate_object (tree); extern tree build_delegate_cst (tree, tree, Type *); extern tree build_method_call (tree, tree, Type *); extern void extract_from_method_call (tree, tree &, tree &); extern tree build_vindex_ref (tree, tree, size_t); extern tree d_save_expr (tree); extern tree stabilize_expr (tree *); extern tree build_target_expr (tree, tree); extern tree force_target_expr (tree); extern tree build_address (tree); extern tree d_mark_addressable (tree); extern tree d_mark_used (tree); extern tree d_mark_read (tree); extern bool identity_compare_p (StructDeclaration *); extern tree build_struct_comparison (tree_code, StructDeclaration *, tree, tree); extern tree build_array_struct_comparison (tree_code, StructDeclaration *, tree, tree, tree); extern tree build_struct_literal (tree, vec *); extern tree component_ref (tree, tree); extern tree build_assign (tree_code, tree, tree); extern tree modify_expr (tree, tree); extern tree build_nop (tree, tree); extern tree build_vconvert (tree, tree); extern tree build_boolop (tree_code, tree, tree); extern tree build_condition (tree, tree, tree, tree); extern tree build_vcondition (tree, tree, tree); extern tree compound_expr (tree, tree); extern tree return_expr (tree); extern tree size_mult_expr (tree, tree); extern tree real_part (tree); extern tree imaginary_part (tree); extern tree complex_expr (tree, tree, tree); extern tree indirect_ref (tree, tree); extern tree build_deref (tree); extern tree build_array_index (tree, tree); extern tree build_offset_op (tree_code, tree, tree); extern tree build_offset (tree, tree); extern tree build_memref (tree, tree, tree); extern tree build_array_set (tree, tree, tree); extern tree build_array_from_val (Type *, tree); extern tree void_okay_p (tree); extern tree build_bounds_condition (const Loc &, tree, tree, bool); extern bool array_bounds_check (void); extern tree create_temporary_var (tree); extern tree maybe_temporary_var (tree, tree *); extern tree bind_expr (tree, tree); extern TypeFunction *get_function_type (Type *); extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *); extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *); extern tree d_build_call (TypeFunction *, tree, tree, Expressions *); extern tree d_assert_call (const Loc &, libcall_fn, tree = NULL_TREE); extern tree build_float_modulus (tree, tree, tree); extern tree build_vthis_function (tree, tree); extern tree get_frame_for_symbol (Dsymbol *); extern tree build_vthis (AggregateDeclaration *); extern void build_closure (FuncDeclaration *); extern tree get_frameinfo (FuncDeclaration *); extern tree get_framedecl (FuncDeclaration *, FuncDeclaration *); /* In d-convert.cc. */ extern bool decl_with_nonnull_addr_p (const_tree); extern tree d_truthvalue_conversion (tree); extern tree d_convert (tree, tree); extern tree convert_expr (tree, Type *, Type *); extern tree convert_for_assignment (tree, Type *, Type *); extern tree convert_for_argument (tree, Parameter *); extern tree convert_for_condition (tree, Type *); extern tree d_array_convert (Expression *); extern tree d_array_convert (Type *, Expression *, vec **); /* In d-incpath.cc. */ extern void add_import_paths (const char *, const char *, bool); /* In d-lang.cc. */ extern void d_add_builtin_module (Module *); extern void d_add_entrypoint_module (Module *, Module *); extern d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *); extern struct lang_type *build_lang_type (Type *); extern struct lang_decl *build_lang_decl (Declaration *); extern tree d_pushdecl (tree); extern tree d_unsigned_type (tree); extern tree d_signed_type (tree); extern void d_keep (tree); /* In decl.cc. */ const char *mangle_decl (Dsymbol *); extern tree mangle_internal_decl (Dsymbol *, const char *, const char *); extern void build_decl_tree (Dsymbol *); extern tree get_symbol_decl (Declaration *); extern tree declare_extern_var (tree, tree); extern void declare_local_var (VarDeclaration *); extern tree build_local_temp (tree); extern tree get_decl_tree (Declaration *); extern void d_finish_decl (tree); extern tree make_thunk (FuncDeclaration *, int); extern tree start_function (FuncDeclaration *); extern void finish_function (tree); extern void mark_needed (tree); extern unsigned base_vtable_offset (ClassDeclaration *, BaseClass *); extern tree get_vtable_decl (ClassDeclaration *); extern tree build_new_class_expr (ClassReferenceExp *); extern tree aggregate_initializer_decl (AggregateDeclaration *); extern tree layout_struct_initializer (StructDeclaration *); extern tree layout_class_initializer (ClassDeclaration *); extern tree enum_initializer_decl (EnumDeclaration *); extern tree build_artificial_decl (tree, tree, const char * = NULL); extern tree create_field_decl (tree, const char *, int, int); extern void build_type_decl (tree, Dsymbol *); extern void d_comdat_linkage (tree); extern void d_linkonce_linkage (tree); /* In expr.cc. */ extern tree build_expr (Expression *, bool = false); extern tree build_expr_dtor (Expression *); extern tree build_return_dtor (Expression *, Type *, TypeFunction *); /* In imports.cc. */ extern tree build_import_decl (Dsymbol *); /* In intrinsics.cc. */ extern void maybe_set_intrinsic (FuncDeclaration *); extern tree maybe_expand_intrinsic (tree); /* In modules.cc. */ extern void build_module_tree (Module *); extern tree d_module_context (void); extern void register_module_decl (Declaration *); extern void d_finish_compilation (tree *, int); /* In runtime.cc. */ extern tree build_libcall (libcall_fn, Type *, int ...); /* In typeinfo.cc. */ extern bool have_typeinfo_p (ClassDeclaration *); extern tree layout_typeinfo (TypeInfoDeclaration *); extern tree layout_classinfo (ClassDeclaration *); extern tree get_typeinfo_decl (TypeInfoDeclaration *); extern tree get_classinfo_decl (ClassDeclaration *); extern tree build_typeinfo (const Loc &, Type *); extern void create_typeinfo (Type *, Module *); extern void create_tinfo_types (Module *); extern void layout_cpp_typeinfo (ClassDeclaration *); extern tree get_cpp_typeinfo_decl (ClassDeclaration *); extern bool speculative_type_p (Type *); /* In toir.cc. */ extern void push_binding_level (level_kind); extern tree pop_binding_level (void); extern void push_stmt_list (void); extern tree pop_stmt_list (void); extern void add_stmt (tree); extern void build_function_body (FuncDeclaration *); /* In types.cc. */ extern bool valist_array_p (Type *); extern bool empty_aggregate_p (tree); extern bool same_type_p (Type *, Type *); extern Type *get_object_type (void); extern tree make_array_type (Type *, unsigned HOST_WIDE_INT); extern tree make_struct_type (const char *, int n, ...); extern tree insert_type_modifiers (tree, unsigned); extern void insert_aggregate_field (tree, tree, size_t); extern void finish_aggregate_type (unsigned, unsigned, tree, UserAttributeDeclaration *); extern tree build_ctype (Type *); #endif /* GCC_D_TREE_H */ ================================================ FILE: gcc/d/decl.cc ================================================ /* decl.cc -- Lower D frontend declarations to GCC trees. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/attrib.h" #include "dmd/ctfe.h" #include "dmd/declaration.h" #include "dmd/enum.h" #include "dmd/errors.h" #include "dmd/globals.h" #include "dmd/hdrgen.h" #include "dmd/identifier.h" #include "dmd/import.h" #include "dmd/init.h" #include "dmd/mangle.h" #include "dmd/module.h" #include "dmd/nspace.h" #include "dmd/target.h" #include "dmd/template.h" #include "tree.h" #include "tree-iterator.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "target.h" #include "common/common-target.h" #include "cgraph.h" #include "toplev.h" #include "stringpool.h" #include "varasm.h" #include "stor-layout.h" #include "attribs.h" #include "function.h" #include "debug.h" #include "tree-pretty-print.h" #include "d-tree.h" /* Return identifier for the external mangled name of DECL. */ const char * mangle_decl (Dsymbol *decl) { if (decl->isFuncDeclaration ()) return mangleExact ((FuncDeclaration *)decl); else { OutBuffer buf; mangleToBuffer (decl, &buf); return buf.extractString (); } } /* Generate a mangled identifier using NAME and SUFFIX, prefixed by the assembler name for DECL. */ tree mangle_internal_decl (Dsymbol *decl, const char *name, const char *suffix) { const char *prefix = mangle_decl (decl); unsigned namelen = strlen (name); unsigned buflen = (2 + strlen (prefix) + namelen + strlen (suffix)) * 2; char *buf = (char *) alloca (buflen); snprintf (buf, buflen, "_D%s%u%s%s", prefix, namelen, name, suffix); tree ident = get_identifier (buf); /* Symbol is not found in user code, but generate a readable name for it anyway for debug and diagnostic reporting. */ snprintf (buf, buflen, "%s.%s", decl->toPrettyChars (), name); IDENTIFIER_PRETTY_NAME (ident) = get_identifier (buf); return ident; } /* Returns true if DECL is from the gcc.attribute module. */ static bool gcc_attribute_p (Dsymbol *decl) { ModuleDeclaration *md = decl->getModule ()->md; if (md && md->packages && md->packages->dim == 1) { if (!strcmp ((*md->packages)[0]->toChars (), "gcc") && !strcmp (md->id->toChars (), "attribute")) return true; } return false; } /* Subroutine of pragma declaration visitor for marking the function in the defined in SYM as a global constructor or destructor. If ISCTOR is true, then we're applying pragma(crt_constructor). */ static int apply_pragma_crt (Dsymbol *sym, bool isctor) { AttribDeclaration *ad = sym->isAttribDeclaration (); if (ad != NULL) { int nested = 0; /* Walk all declarations of the attribute scope. */ Dsymbols *ds = ad->include (NULL); if (ds) { for (size_t i = 0; i < ds->dim; i++) nested += apply_pragma_crt ((*ds)[i], isctor); } return nested; } FuncDeclaration *fd = sym->isFuncDeclaration (); if (fd != NULL) { tree decl = get_decl_tree (fd); /* Apply flags to the function. */ if (isctor) { DECL_STATIC_CONSTRUCTOR (decl) = 1; decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY); } else { DECL_STATIC_DESTRUCTOR (decl) = 1; decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY); } if (fd->linkage != LINKc) { error_at (make_location_t (fd->loc), "must be % for %", isctor ? "crt_constructor" : "crt_destructor"); } return 1; } return 0; } /* Implements the visitor interface to lower all Declaration AST classes emitted from the D Front-end to GCC trees. All visit methods accept one parameter D, which holds the frontend AST of the declaration to compile. These also don't return any value, instead generated code are appened to global_declarations or added to the current_binding_level by d_pushdecl(). */ class DeclVisitor : public Visitor { using Visitor::visit; public: DeclVisitor (void) { } /* This should be overridden by each declaration class. */ void visit (Dsymbol *) { } /* Compile a D module, and all members of it. */ void visit (Module *d) { if (d->semanticRun >= PASSobj) return; build_module_tree (d); d->semanticRun = PASSobj; } /* Write the imported symbol to debug. */ void visit (Import *d) { /* Implements import declarations by telling the debug back-end we are importing the NAMESPACE_DECL of the module or IMPORTED_DECL of the declaration into the current lexical scope CONTEXT. NAME is set if this is a renamed import. */ if (d->isstatic) return; /* Get the context of this import, this should never be null. */ tree context = d_module_context (); if (d->ident == NULL) { /* Importing declaration list. */ for (size_t i = 0; i < d->names.dim; i++) { AliasDeclaration *aliasdecl = d->aliasdecls[i]; tree decl = build_import_decl (aliasdecl); /* Skip over unhandled imports. */ if (decl == NULL_TREE) continue; Identifier *alias = d->aliases[i]; tree name = (alias != NULL) ? get_identifier (alias->toChars ()) : NULL_TREE; debug_hooks->imported_module_or_decl (decl, name, context, false, false); } } else { /* Importing the entire module. */ tree decl = build_import_decl (d->mod); tree name = (d->aliasId != NULL) ? get_identifier (d->aliasId->toChars ()) : NULL_TREE; debug_hooks->imported_module_or_decl (decl, name, context, false, false); } } /* Expand any local variables found in tuples. */ void visit (TupleDeclaration *d) { for (size_t i = 0; i < d->objects->dim; i++) { RootObject *o = (*d->objects)[i]; if ((o->dyncast () == DYNCAST_EXPRESSION) && ((Expression *) o)->op == TOKdsymbol) { Declaration *d = ((DsymbolExp *) o)->s->isDeclaration (); if (d) d->accept (this); } } } /* Walk over all declarations in the attribute scope. */ void visit (AttribDeclaration *d) { Dsymbols *ds = d->include (NULL); if (!ds) return; for (size_t i = 0; i < ds->dim; i++) { Dsymbol *s = (*ds)[i]; s->accept (this); } } /* Pragmas are a way to pass special information to the compiler and to add vendor specific extensions to D. */ void visit (PragmaDeclaration *d) { if (!global.params.ignoreUnsupportedPragmas) { if (d->ident == Identifier::idPool ("lib") || d->ident == Identifier::idPool ("startaddress")) { warning_at (make_location_t (d->loc), OPT_Wunknown_pragmas, "pragma(%s) not implemented", d->ident->toChars ()); } } visit ((AttribDeclaration *) d); /* Handle pragma(crt_constructor) and pragma(crt_destructor). Apply flag to indicate that the functions enclosed should run automatically at the beginning or end of execution. */ if (d->ident == Identifier::idPool ("crt_constructor") || d->ident == Identifier::idPool ("crt_destructor")) { bool isctor = (d->ident == Identifier::idPool ("crt_constructor")); if (apply_pragma_crt (d, isctor) > 1) error_at (make_location_t (d->loc), "can only apply to a single declaration"); } } /* Walk over all members in the namespace scope. */ void visit (Nspace *d) { if (isError (d) || !d->members) return; for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *s = (*d->members)[i]; s->accept (this); } } /* Walk over all members in the instantiated template. */ void visit (TemplateInstance *d) { if (isError (d)|| !d->members) return; if (!d->needsCodegen ()) return; for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *s = (*d->members)[i]; s->accept (this); } } /* Walk over all members in the mixin template scope. */ void visit (TemplateMixin *d) { if (isError (d)|| !d->members) return; for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *s = (*d->members)[i]; s->accept (this); } } /* Write out compiler generated TypeInfo, initializer and functions for the given struct declaration, walking over all static members. */ void visit (StructDeclaration *d) { if (d->type->ty == Terror) { error_at (make_location_t (d->loc), "had semantic errors when compiling"); return; } /* Add this decl to the current binding level. */ tree ctype = build_ctype (d->type); if (TYPE_NAME (ctype)) d_pushdecl (TYPE_NAME (ctype)); /* Anonymous structs/unions only exist as part of others, do not output forward referenced structs. */ if (d->isAnonymous () || !d->members) return; /* Don't emit any symbols from gcc.attribute module. */ if (gcc_attribute_p (d)) return; /* Generate TypeInfo. */ if (have_typeinfo_p (Type::dtypeinfo)) create_typeinfo (d->type, NULL); /* Generate static initializer. */ d->sinit = aggregate_initializer_decl (d); DECL_INITIAL (d->sinit) = layout_struct_initializer (d); if (d->isInstantiated ()) d_linkonce_linkage (d->sinit); d_finish_decl (d->sinit); /* Put out the members. */ for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *member = (*d->members)[i]; /* There might be static ctors in the members, and they cannot be put in separate object files. */ member->accept (this); } /* Put out xopEquals, xopCmp and xopHash. */ if (d->xeq && d->xeq != d->xerreq) d->xeq->accept (this); if (d->xcmp && d->xcmp != d->xerrcmp) d->xcmp->accept (this); if (d->xhash) d->xhash->accept (this); } /* Finish semantic analysis of functions in vtbl for class CD. */ bool finish_vtable (ClassDeclaration *d) { bool has_errors = false; /* Finish semantic analysis of functions in vtbl[]. */ for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++) { FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration (); if (!fd || (!fd->fbody && d->isAbstract ())) continue; /* Ensure function has a return value. */ if (!fd->functionSemantic ()) has_errors = true; /* No name hiding to check for. */ if (!d->isFuncHidden (fd) || fd->isFuture ()) continue; /* The function fd is hidden from the view of the class. If it overlaps with any function in the vtbl[], then issue an error. */ for (size_t j = 1; j < d->vtbl.dim; j++) { if (j == i) continue; FuncDeclaration *fd2 = d->vtbl[j]->isFuncDeclaration (); if (!fd2->ident->equals (fd->ident)) continue; /* The function is marked as @__future, a deprecation has already been given by the frontend. */ if (fd2->isFuture ()) continue; if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd)) { TypeFunction *tf = (TypeFunction *) fd->type; if (tf->ty == Tfunction) { error_at (make_location_t (fd->loc), "use of %qs", fd->toPrettyChars ()); inform (make_location_t (fd2->loc), "is hidden by %qs", fd2->toPrettyChars ()); inform (make_location_t (d->loc), "use % to introduce base class " "overload set.", fd->toChars (), fd->parent->toChars (), fd->toChars ()); } else { error_at (make_location_t (fd->loc), "use of %qs", fd->toPrettyChars ()); inform (make_location_t (fd2->loc), "is hidden by %qs", fd2->toPrettyChars ()); } has_errors = true; break; } } } return !has_errors; } /* Write out compiler generated TypeInfo, initializer and vtables for the given class declaration, walking over all static members. */ void visit (ClassDeclaration *d) { if (d->type->ty == Terror) { error_at (make_location_t (d->loc), "had semantic errors when compiling"); return; } if (!d->members) return; /* Put out the members. */ for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *member = (*d->members)[i]; member->accept (this); } /* If something goes wrong during final semantic pass, don't bother with the rest as we may have incomplete info. */ if (!this->finish_vtable (d)) return; /* Generate C symbols. */ d->csym = get_classinfo_decl (d); Dsymbol *vtblsym = d->vtblSymbol (); vtblsym->csym = get_vtable_decl (d); d->sinit = aggregate_initializer_decl (d); /* Generate static initializer. */ DECL_INITIAL (d->sinit) = layout_class_initializer (d); d_linkonce_linkage (d->sinit); d_finish_decl (d->sinit); /* Put out the TypeInfo. */ if (have_typeinfo_p (Type::dtypeinfo)) create_typeinfo (d->type, NULL); DECL_INITIAL (d->csym) = layout_classinfo (d); d_linkonce_linkage (d->csym); d_finish_decl (d->csym); /* Put out the vtbl[]. */ vec *elms = NULL; /* First entry is ClassInfo reference. */ if (d->vtblOffset ()) CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, build_address (d->csym)); for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++) { FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration (); if (fd && (fd->fbody || !d->isAbstract ())) { CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_address (get_symbol_decl (fd))); } } DECL_INITIAL (vtblsym->csym) = build_constructor (TREE_TYPE (vtblsym->csym), elms); d_comdat_linkage (vtblsym->csym); d_finish_decl (vtblsym->csym); /* Add this decl to the current binding level. */ tree ctype = TREE_TYPE (build_ctype (d->type)); if (TYPE_NAME (ctype)) d_pushdecl (TYPE_NAME (ctype)); } /* Write out compiler generated TypeInfo and vtables for the given interface declaration, walking over all static members. */ void visit (InterfaceDeclaration *d) { if (d->type->ty == Terror) { error_at (make_location_t (d->loc), "had semantic errors when compiling"); return; } if (!d->members) return; /* Put out the members. */ for (size_t i = 0; i < d->members->dim; i++) { Dsymbol *member = (*d->members)[i]; member->accept (this); } /* Generate C symbols. */ d->csym = get_classinfo_decl (d); /* Put out the TypeInfo. */ if (have_typeinfo_p (Type::dtypeinfo)) { create_typeinfo (d->type, NULL); d->type->vtinfo->accept (this); } DECL_INITIAL (d->csym) = layout_classinfo (d); d_linkonce_linkage (d->csym); d_finish_decl (d->csym); /* Add this decl to the current binding level. */ tree ctype = TREE_TYPE (build_ctype (d->type)); if (TYPE_NAME (ctype)) d_pushdecl (TYPE_NAME (ctype)); } /* Write out compiler generated TypeInfo and initializer for the given enum declaration. */ void visit (EnumDeclaration *d) { if (d->semanticRun >= PASSobj) return; if (d->errors || d->type->ty == Terror) { error_at (make_location_t (d->loc), "had semantic errors when compiling"); return; } if (d->isAnonymous ()) return; /* Generate TypeInfo. */ if (have_typeinfo_p (Type::dtypeinfo)) create_typeinfo (d->type, NULL); TypeEnum *tc = (TypeEnum *) d->type; if (tc->sym->members && !d->type->isZeroInit ()) { /* Generate static initializer. */ d->sinit = enum_initializer_decl (d); DECL_INITIAL (d->sinit) = build_expr (tc->sym->defaultval, true); if (d->isInstantiated ()) d_linkonce_linkage (d->sinit); d_finish_decl (d->sinit); /* Add this decl to the current binding level. */ tree ctype = build_ctype (d->type); if (TREE_CODE (ctype) == ENUMERAL_TYPE && TYPE_NAME (ctype)) d_pushdecl (TYPE_NAME (ctype)); } d->semanticRun = PASSobj; } /* Finish up a variable declaration and push it into the current scope. This can either be a static, local or manifest constant. */ void visit (VarDeclaration *d) { if (d->type->ty == Terror) { error_at (make_location_t (d->loc), "had semantic errors when compiling"); return; } if (d->aliassym) { d->toAlias ()->accept (this); return; } /* Do not store variables we cannot take the address of, but keep the values for purposes of debugging. */ if (!d->canTakeAddressOf ()) { /* Don't know if there is a good way to handle instantiations. */ if (d->isInstantiated ()) return; tree decl = get_symbol_decl (d); gcc_assert (d->_init && !d->_init->isVoidInitializer ()); Expression *ie = initializerToExpression (d->_init); /* CONST_DECL was initially intended for enumerals and may be used for scalars in general, but not for aggregates. Here a non-constant value is generated anyway so as the CONST_DECL only serves as a placeholder for the value, however the DECL itself should never be referenced in any generated code, or passed to the back-end. */ if (!d->type->isscalar ()) DECL_INITIAL (decl) = build_expr (ie, false); else { DECL_INITIAL (decl) = build_expr (ie, true); d_pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } } else if (d->isDataseg () && !(d->storage_class & STCextern)) { tree decl = get_symbol_decl (d); /* Duplicated VarDeclarations map to the same symbol. Check if this is the one declaration which will be emitted. */ tree ident = DECL_ASSEMBLER_NAME (decl); if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d) return; /* How big a symbol can be should depend on back-end. */ tree size = build_integer_cst (d->type->size (d->loc), build_ctype (Type::tsize_t)); if (!valid_constant_size_p (size)) { error_at (make_location_t (d->loc), "size is too large"); return; } if (d->_init && !d->_init->isVoidInitializer ()) { Expression *e = initializerToExpression (d->_init, d->type); DECL_INITIAL (decl) = build_expr (e, true); } else { if (d->type->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *) d->type)->sym; DECL_INITIAL (decl) = layout_struct_initializer (sd); } else { Expression *e = d->type->defaultInitLiteral (d->loc); DECL_INITIAL (decl) = build_expr (e, true); } } /* Frontend should have already caught this. */ gcc_assert (!integer_zerop (size) || d->type->toBasetype ()->ty == Tsarray); d_finish_decl (decl); /* Maybe record the var against the current module. */ register_module_decl (d); } else if (!d->isDataseg () && !d->isMember ()) { /* This is needed for VarDeclarations in mixins that are to be local variables of a function. Otherwise, it would be enough to make a check for isVarDeclaration() in DeclarationExp codegen. */ declare_local_var (d); if (d->_init) { tree decl = get_symbol_decl (d); if (!d->_init->isVoidInitializer ()) { ExpInitializer *vinit = d->_init->isExpInitializer (); Expression *ie = initializerToExpression (vinit); tree exp = build_expr (ie); /* Maybe put variable on list of things needing destruction. */ if (d->needsScopeDtor ()) { vec_safe_push (d_function_chain->vars_in_scope, decl); /* Force a TARGET_EXPR to add the corresponding cleanup. */ exp = force_target_expr (compound_expr (exp, decl)); TARGET_EXPR_CLEANUP (exp) = build_expr (d->edtor); } add_stmt (exp); } else if (d->size (d->loc) != 0) { /* Zero-length arrays do not have an initializer. */ warning (OPT_Wuninitialized, "uninitialized variable '%s'", d->ident ? d->ident->toChars () : "(no name)"); } } } } /* Generate and compile a static TypeInfo declaration, but only if it is needed in the current compilation. */ void visit (TypeInfoDeclaration *d) { if (speculative_type_p (d->tinfo)) return; tree t = get_typeinfo_decl (d); DECL_INITIAL (t) = layout_typeinfo (d); d_finish_decl (t); } /* Finish up a function declaration and compile it all the way down to assembler language output. */ void visit (FuncDeclaration *d) { /* Already generated the function. */ if (d->semanticRun >= PASSobj) return; /* Don't emit any symbols from gcc.attribute module. */ if (gcc_attribute_p (d)) return; /* Not emitting unittest functions. */ if (!global.params.useUnitTests && d->isUnitTestDeclaration ()) return; /* Check if any errors occurred when running semantic. */ if (d->type->ty == Tfunction) { TypeFunction *tf = (TypeFunction *) d->type; if (tf->next == NULL || tf->next->ty == Terror) return; } if (d->semantic3Errors) return; if (d->isNested ()) { FuncDeclaration *fdp = d; while (fdp && fdp->isNested ()) { fdp = fdp->toParent2 ()->isFuncDeclaration (); if (fdp == NULL) break; /* Parent failed to compile, but errors were gagged. */ if (fdp->semantic3Errors) return; } } /* Ensure all semantic passes have run. */ if (d->semanticRun < PASSsemantic3) { d->functionSemantic3 (); Module::runDeferredSemantic3 (); } if (global.errors) return; /* Duplicated FuncDeclarations map to the same symbol. Check if this is the one declaration which will be emitted. */ tree fndecl = get_symbol_decl (d); tree ident = DECL_ASSEMBLER_NAME (fndecl); if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d) return; if (!d->fbody) { rest_of_decl_compilation (fndecl, 1, 0); return; } if (global.params.verbose) message ("function %s", d->toPrettyChars ()); /* Start generating code for this function. */ gcc_assert (d->semanticRun == PASSsemantic3done); d->semanticRun = PASSobj; tree old_context = start_function (d); tree parm_decl = NULL_TREE; tree param_list = NULL_TREE; /* Special arguments... */ /* 'this' parameter: For nested functions, D still generates a vthis, but it should not be referenced in any expression. */ if (d->vthis) { parm_decl = get_symbol_decl (d->vthis); DECL_ARTIFICIAL (parm_decl) = 1; TREE_READONLY (parm_decl) = 1; if (d->vthis->type == Type::tvoidptr) { /* Replace generic pointer with back-end closure type (this wins for gdb). */ tree frame_type = FRAMEINFO_TYPE (get_frameinfo (d)); gcc_assert (frame_type != NULL_TREE); TREE_TYPE (parm_decl) = build_pointer_type (frame_type); } param_list = chainon (param_list, parm_decl); d_function_chain->static_chain = parm_decl; } /* _arguments parameter. */ if (d->v_arguments) { parm_decl = get_symbol_decl (d->v_arguments); param_list = chainon (param_list, parm_decl); } /* formal function parameters. */ size_t n_parameters = d->parameters ? d->parameters->dim : 0; for (size_t i = 0; i < n_parameters; i++) { VarDeclaration *param = (*d->parameters)[i]; parm_decl = get_symbol_decl (param); /* Chain them in the correct order. */ param_list = chainon (param_list, parm_decl); } DECL_ARGUMENTS (fndecl) = param_list; rest_of_decl_compilation (fndecl, 1, 0); /* If this is a member function that nested (possibly indirectly) in another function, construct an expession for this member function's static chain by going through parent link of nested classes. */ if (d->isThis ()) { AggregateDeclaration *ad = d->isThis (); tree this_tree = get_symbol_decl (d->vthis); while (ad->isNested ()) { Dsymbol *pd = ad->toParent2 (); tree vthis_field = get_symbol_decl (ad->vthis); this_tree = component_ref (build_deref (this_tree), vthis_field); ad = pd->isAggregateDeclaration (); if (ad == NULL) { cfun->language->static_chain = this_tree; break; } } } /* May change cfun->static_chain. */ build_closure (d); if (d->vresult) declare_local_var (d->vresult); if (d->v_argptr) push_stmt_list (); /* Named return value optimisation support for D. Implemented by overriding all the RETURN_EXPRs and replacing all occurrences of VAR with the RESULT_DECL for the function. This is only worth doing for functions that can return in memory. */ if (d->nrvo_can) { tree restype = TREE_TYPE (DECL_RESULT (fndecl)); if (!AGGREGATE_TYPE_P (restype)) d->nrvo_can = 0; else d->nrvo_can = aggregate_value_p (restype, fndecl); } if (d->nrvo_can) { tree resdecl = DECL_RESULT (fndecl); TREE_TYPE (resdecl) = build_reference_type (TREE_TYPE (resdecl)); DECL_BY_REFERENCE (resdecl) = 1; TREE_ADDRESSABLE (resdecl) = 0; relayout_decl (resdecl); if (d->nrvo_var) { tree var = get_symbol_decl (d->nrvo_var); /* Copy name from VAR to RESULT. */ DECL_NAME (resdecl) = DECL_NAME (var); /* Don't forget that we take its address. */ TREE_ADDRESSABLE (var) = 1; resdecl = build_deref (resdecl); SET_DECL_VALUE_EXPR (var, resdecl); DECL_HAS_VALUE_EXPR_P (var) = 1; SET_DECL_LANG_NRVO (var, resdecl); } } build_function_body (d); /* Initialize the _argptr variable. */ if (d->v_argptr) { tree body = pop_stmt_list (); tree var = get_decl_tree (d->v_argptr); var = build_address (var); tree init = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_START), 2, var, parm_decl); declare_local_var (d->v_argptr); add_stmt (init); tree cleanup = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_END), 1, var); add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup)); } finish_function (old_context); /* Maybe record the function against the current module. */ register_module_decl (d); } }; /* Main entry point for the DeclVisitor interface to send the Declaration AST class D to GCC back-end. */ void build_decl_tree (Dsymbol *d) { location_t saved_location = input_location; /* Set input location, empty DECL_SOURCE_FILE can crash debug generator. */ if (d->loc.filename) input_location = make_location_t (d->loc); else input_location = make_location_t (Loc ("", 1, 0)); DeclVisitor v = DeclVisitor (); d->accept (&v); input_location = saved_location; } /* Return the decl for the symbol, create it if it doesn't already exist. */ tree get_symbol_decl (Declaration *decl) { if (decl->csym) return decl->csym; /* Deal with placeholder symbols immediately: SymbolDeclaration is used as a shell around an initializer symbol. */ SymbolDeclaration *sd = decl->isSymbolDeclaration (); if (sd) { decl->csym = aggregate_initializer_decl (sd->dsym); return decl->csym; } /* Global static TypeInfo declaration. */ if (decl->isTypeInfoDeclaration ()) return get_typeinfo_decl ((TypeInfoDeclaration *) decl); /* FuncAliasDeclaration is used to import functions from another scope. */ FuncAliasDeclaration *fad = decl->isFuncAliasDeclaration (); if (fad) { decl->csym = get_symbol_decl (fad->funcalias); return decl->csym; } /* It is possible for a field declaration symbol to be requested before the parent type has been built. */ if (decl->isField ()) { AggregateDeclaration *ad = decl->toParent ()->isAggregateDeclaration (); gcc_assert (ad != NULL); /* Finishing off the type should create the associated FIELD_DECL. */ build_ctype (ad->type); gcc_assert (decl->csym != NULL); return decl->csym; } /* Build the tree for the symbol. */ FuncDeclaration *fd = decl->isFuncDeclaration (); if (fd) { /* Run full semantic on functions we need to know about. */ if (!fd->functionSemantic ()) { decl->csym = error_mark_node; return decl->csym; } decl->csym = build_decl (make_location_t (decl->loc), FUNCTION_DECL, get_identifier (decl->ident->toChars ()), NULL_TREE); /* Set function type afterwards as there could be self references. */ TREE_TYPE (decl->csym) = build_ctype (fd->type); if (!fd->fbody) DECL_EXTERNAL (decl->csym) = 1; } else { /* Build the variable declaration. */ VarDeclaration *vd = decl->isVarDeclaration (); gcc_assert (vd != NULL); tree_code code = vd->isParameter () ? PARM_DECL : !vd->canTakeAddressOf () ? CONST_DECL : VAR_DECL; decl->csym = build_decl (make_location_t (decl->loc), code, get_identifier (decl->ident->toChars ()), declaration_type (vd)); /* If any alignment was set on the declaration. */ if (vd->alignment != STRUCTALIGN_DEFAULT) { SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT); DECL_USER_ALIGN (decl->csym) = 1; } if (vd->storage_class & STCextern) DECL_EXTERNAL (decl->csym) = 1; } /* Set the declaration mangled identifier if static. */ if (decl->isCodeseg () || decl->isDataseg ()) { tree mangled_name; if (decl->mangleOverride.length) { mangled_name = get_identifier_with_length (decl->mangleOverride.ptr, decl->mangleOverride.length); } else mangled_name = get_identifier (mangle_decl (decl)); mangled_name = targetm.mangle_decl_assembler_name (decl->csym, mangled_name); /* The frontend doesn't handle duplicate definitions of unused symbols with the same mangle. So a check is done here instead. */ if (!DECL_EXTERNAL (decl->csym)) { if (IDENTIFIER_DSYMBOL (mangled_name)) { Declaration *other = IDENTIFIER_DSYMBOL (mangled_name); /* Non-templated variables shouldn't be defined twice. */ if (!decl->isInstantiated ()) ScopeDsymbol::multiplyDefined (decl->loc, decl, other); decl->csym = get_symbol_decl (other); return decl->csym; } IDENTIFIER_PRETTY_NAME (mangled_name) = get_identifier (decl->toPrettyChars (true)); IDENTIFIER_DSYMBOL (mangled_name) = decl; } SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name); } DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl); DECL_CONTEXT (decl->csym) = d_decl_context (decl); if (TREE_CODE (decl->csym) == PARM_DECL) { /* Pass non-trivial structs by invisible reference. */ if (TREE_ADDRESSABLE (TREE_TYPE (decl->csym))) { tree argtype = build_reference_type (TREE_TYPE (decl->csym)); argtype = build_qualified_type (argtype, TYPE_QUAL_RESTRICT); gcc_assert (!DECL_BY_REFERENCE (decl->csym)); TREE_TYPE (decl->csym) = argtype; DECL_BY_REFERENCE (decl->csym) = 1; TREE_ADDRESSABLE (decl->csym) = 0; relayout_decl (decl->csym); decl->storage_class |= STCref; } DECL_ARG_TYPE (decl->csym) = TREE_TYPE (decl->csym); gcc_assert (TREE_CODE (DECL_CONTEXT (decl->csym)) == FUNCTION_DECL); } else if (TREE_CODE (decl->csym) == CONST_DECL) { /* Manifest constants have no address in memory. */ TREE_CONSTANT (decl->csym) = 1; TREE_READONLY (decl->csym) = 1; } else if (TREE_CODE (decl->csym) == FUNCTION_DECL) { /* The real function type may differ from its declaration. */ tree fntype = TREE_TYPE (decl->csym); tree newfntype = NULL_TREE; if (fd->isNested ()) { /* Add an extra argument for the frame/closure pointer, this is also required to be compatible with D delegates. */ newfntype = build_vthis_function (void_type_node, fntype); } else if (fd->isThis ()) { /* Add an extra argument for the 'this' parameter. The handle type is used even if there is no debug info. It is needed to make sure virtual member functions are not called statically. */ AggregateDeclaration *ad = fd->isMember2 (); tree handle = build_ctype (ad->handleType ()); /* If handle is a pointer type, get record type. */ if (!ad->isStructDeclaration ()) handle = TREE_TYPE (handle); newfntype = build_vthis_function (handle, fntype); /* Set the vindex on virtual functions. */ if (fd->isVirtual () && fd->vtblIndex != -1) { DECL_VINDEX (decl->csym) = size_int (fd->vtblIndex); DECL_VIRTUAL_P (decl->csym) = 1; } } else if (fd->isMain () || fd->isCMain ()) { /* The main function is named 'D main' to distinguish from C main. */ if (fd->isMain ()) DECL_NAME (decl->csym) = get_identifier (fd->toPrettyChars (true)); /* 'void main' is implicitly converted to returning an int. */ newfntype = build_function_type (d_int_type, TYPE_ARG_TYPES (fntype)); } if (newfntype != NULL_TREE) { /* Copy the old attributes from the original type. */ TYPE_ATTRIBUTES (newfntype) = TYPE_ATTRIBUTES (fntype); TYPE_LANG_SPECIFIC (newfntype) = TYPE_LANG_SPECIFIC (fntype); TREE_ADDRESSABLE (newfntype) = TREE_ADDRESSABLE (fntype); TREE_TYPE (decl->csym) = newfntype; d_keep (newfntype); } /* Miscellaneous function flags. */ if (fd->isMember2 () || fd->isFuncLiteralDeclaration ()) { /* See grokmethod in cp/decl.c. Maybe we shouldn't be setting inline flags without reason or proper handling. */ DECL_DECLARED_INLINE_P (decl->csym) = 1; DECL_NO_INLINE_WARNING_P (decl->csym) = 1; } /* Function was declared 'naked'. */ if (fd->naked) { insert_decl_attribute (decl->csym, "naked"); DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1; } /* Vector array operations are always compiler generated. */ if (fd->isArrayOp) { TREE_PUBLIC (decl->csym) = 1; DECL_ARTIFICIAL (decl->csym) = 1; DECL_DECLARED_INLINE_P (decl->csym) = 1; d_comdat_linkage (decl->csym); } /* And so are ensure and require contracts. */ if (fd->ident == Identifier::idPool ("ensure") || fd->ident == Identifier::idPool ("require")) { DECL_ARTIFICIAL (decl->csym) = 1; TREE_PUBLIC (decl->csym) = 1; } if (decl->storage_class & STCfinal) DECL_FINAL_P (decl->csym) = 1; /* Check whether this function is expanded by the frontend. */ DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE; maybe_set_intrinsic (fd); /* For nested functions in particular, unnest fndecl in the cgraph, as all static chain passing is handled by the front-end. Do this even if we are not emitting the body. */ struct cgraph_node *node = cgraph_node::get_create (decl->csym); if (node->origin) node->unnest (); } /* Mark compiler generated temporaries as artificial. */ if (decl->storage_class & STCtemp) DECL_ARTIFICIAL (decl->csym) = 1; /* Propagate shared on the decl. */ if (TYPE_SHARED (TREE_TYPE (decl->csym))) TREE_ADDRESSABLE (decl->csym) = 1; /* Symbol was marked volatile. */ if (decl->storage_class & STCvolatile) TREE_THIS_VOLATILE (decl->csym) = 1; /* Protection attributes are used by the debugger. */ if (decl->protection.kind == Prot::private_) TREE_PRIVATE (decl->csym) = 1; else if (decl->protection.kind == Prot::protected_) TREE_PROTECTED (decl->csym) = 1; /* Likewise, so could the deprecated attribute. */ if (decl->storage_class & STCdeprecated) TREE_DEPRECATED (decl->csym) = 1; #if TARGET_DLLIMPORT_DECL_ATTRIBUTES /* Have to test for import first. */ if (decl->isImportedSymbol ()) { insert_decl_attribute (decl->csym, "dllimport"); DECL_DLLIMPORT_P (decl->csym) = 1; } else if (decl->isExport ()) insert_decl_attribute (decl->csym, "dllexport"); #endif if (decl->isDataseg () || decl->isCodeseg () || decl->isThreadlocal ()) { /* Set TREE_PUBLIC by default, but allow private template to override. */ if (!fd || !fd->isNested ()) TREE_PUBLIC (decl->csym) = 1; TREE_STATIC (decl->csym) = 1; /* The decl has not been defined -- yet. */ DECL_EXTERNAL (decl->csym) = 1; if (decl->isInstantiated ()) d_linkonce_linkage (decl->csym); } /* Symbol is going in thread local storage. */ if (decl->isThreadlocal () && !DECL_ARTIFICIAL (decl->csym)) { if (global.params.vtls) message (decl->loc, "`%s` is thread local", decl->toChars ()); set_decl_tls_model (decl->csym, decl_default_tls_model (decl->csym)); } /* Apply any user attributes that may affect semantic meaning. */ if (decl->userAttribDecl) { Expressions *attrs = decl->userAttribDecl->getAttributes (); decl_attributes (&decl->csym, build_attributes (attrs), 0); } else if (DECL_ATTRIBUTES (decl->csym) != NULL) decl_attributes (&decl->csym, DECL_ATTRIBUTES (decl->csym), 0); /* %% Probably should be a little more intelligent about setting this. */ TREE_USED (decl->csym) = 1; d_keep (decl->csym); return decl->csym; } /* Returns a declaration for a VAR_DECL. Used to create compiler-generated global variables. */ tree declare_extern_var (tree ident, tree type) { /* If the VAR_DECL has already been declared, return it. */ if (IDENTIFIER_DECL_TREE (ident)) return IDENTIFIER_DECL_TREE (ident); tree name = IDENTIFIER_PRETTY_NAME (ident) ? IDENTIFIER_PRETTY_NAME (ident) : ident; tree decl = build_decl (input_location, VAR_DECL, name, type); IDENTIFIER_DECL_TREE (ident) = decl; d_keep (decl); SET_DECL_ASSEMBLER_NAME (decl, ident); DECL_ARTIFICIAL (decl) = 1; TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 1; /* The decl has not been defined -- yet. */ DECL_EXTERNAL (decl) = 1; return decl; } /* Add local variable VAR into the current function body. */ void declare_local_var (VarDeclaration *var) { gcc_assert (!var->isDataseg () && !var->isMember ()); gcc_assert (current_function_decl != NULL_TREE); FuncDeclaration *fd = cfun->language->function; tree decl = get_symbol_decl (var); gcc_assert (!TREE_STATIC (decl)); d_pushdecl (decl); DECL_CONTEXT (decl) = current_function_decl; /* Compiler generated symbols. */ if (var == fd->vresult || var == fd->v_argptr) DECL_ARTIFICIAL (decl) = 1; if (DECL_LANG_FRAME_FIELD (decl)) { /* Fixes debugging local variables. */ SET_DECL_VALUE_EXPR (decl, get_decl_tree (var)); DECL_HAS_VALUE_EXPR_P (decl) = 1; } } /* Return an unnamed local temporary of type TYPE. */ tree build_local_temp (tree type) { tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type); DECL_CONTEXT (decl) = current_function_decl; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; d_pushdecl (decl); return decl; } /* Return the correct decl to be used for DECL. For VAR_DECLs, this could instead be a FIELD_DECL from a closure, or a RESULT_DECL from a named return value. For PARM_DECLs, this could be a FIELD_DECL for a non-local `this'. For all other kinds of decls, this just returns the result of get_symbol_decl(). */ tree get_decl_tree (Declaration *decl) { tree t = get_symbol_decl (decl); FuncDeclaration *fd = cfun ? cfun->language->function : NULL; VarDeclaration *vd = decl->isVarDeclaration (); /* If cfun is NULL, then this is a global static. */ if (vd == NULL || fd == NULL) return t; /* Get the named return value. */ if (DECL_LANG_NRVO (t)) return DECL_LANG_NRVO (t); /* Get the closure holding the var decl. */ if (DECL_LANG_FRAME_FIELD (t)) { FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration (); tree frame_ref = get_framedecl (fd, parent); return component_ref (build_deref (frame_ref), DECL_LANG_FRAME_FIELD (t)); } /* Get the non-local 'this' value by going through parent link of nested classes, this routine pretty much undoes what getRightThis in the frontend removes from codegen. */ if (vd->parent != fd && vd->isThisDeclaration ()) { /* Find the first parent that is a member function. */ while (!fd->isMember2 ()) { gcc_assert (fd->vthis); fd = fd->toParent2 ()->isFuncDeclaration (); gcc_assert (fd != NULL); } AggregateDeclaration *ad = fd->isThis (); gcc_assert (ad != NULL); t = get_decl_tree (fd->vthis); Dsymbol *outer = fd; while (outer != vd->parent) { gcc_assert (ad != NULL); outer = ad->toParent2 (); /* Get the this->this parent link. */ tree vfield = get_symbol_decl (ad->vthis); t = component_ref (build_deref (t), vfield); ad = outer->isAggregateDeclaration (); if (ad != NULL) continue; fd = outer->isFuncDeclaration (); while (fd != NULL) { /* If outer function creates a closure, then the 'this' value would be the closure pointer, and the real 'this' the first field of that closure. */ tree ff = get_frameinfo (fd); if (FRAMEINFO_CREATES_FRAME (ff)) { t = build_nop (build_pointer_type (FRAMEINFO_TYPE (ff)), t); t = indirect_ref (build_ctype (fd->vthis->type), t); } if (fd == vd->parent) break; /* Continue looking for the right `this'. */ outer = outer->toParent2 (); fd = outer->isFuncDeclaration (); } ad = outer->isAggregateDeclaration (); } return t; } /* Auto variable that the back end will handle for us. */ return t; } /* Update the TLS model on variable DECL, typically after the linkage has been modified. */ static void reset_decl_tls_model (tree decl) { if (DECL_THREAD_LOCAL_P (decl)) set_decl_tls_model (decl, decl_default_tls_model (decl)); } /* Finish up a variable declaration and compile it all the way to the assembler language output. */ void d_finish_decl (tree decl) { gcc_assert (!error_operand_p (decl)); /* We are sending this symbol to object file, can't be extern. */ TREE_STATIC (decl) = 1; DECL_EXTERNAL (decl) = 0; reset_decl_tls_model (decl); relayout_decl (decl); if (flag_checking && DECL_INITIAL (decl)) { /* Initializer must never be bigger than symbol size. */ dinteger_t tsize = int_size_in_bytes (TREE_TYPE (decl)); dinteger_t dtsize = int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl))); if (tsize < dtsize) { tree name = DECL_ASSEMBLER_NAME (decl); internal_error ("Mismatch between declaration %qE size (%wd) and " "its initializer size (%wd).", IDENTIFIER_PRETTY_NAME (name) ? IDENTIFIER_PRETTY_NAME (name) : name, tsize, dtsize); } } /* Without weak symbols, symbol should be put in .common, but that can't be done if there is a nonzero initializer. */ if (DECL_COMDAT (decl) && DECL_COMMON (decl) && initializer_zerop (DECL_INITIAL (decl))) DECL_INITIAL (decl) = error_mark_node; /* Add this decl to the current binding level. */ d_pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } /* Thunk code is based on g++. */ static int thunk_labelno; /* Create a static alias to function. */ static tree make_alias_for_thunk (tree function) { tree alias; char buf[256]; /* Thunks may reference extern functions which cannot be aliased. */ if (DECL_EXTERNAL (function)) return function; targetm.asm_out.generate_internal_label (buf, "LTHUNK", thunk_labelno); thunk_labelno++; alias = build_decl (DECL_SOURCE_LOCATION (function), FUNCTION_DECL, get_identifier (buf), TREE_TYPE (function)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); lang_hooks.dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL_TREE; TREE_READONLY (alias) = TREE_READONLY (function); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); TREE_PUBLIC (alias) = 0; DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_DECLARED_INLINE_P (alias) = 0; DECL_INITIAL (alias) = error_mark_node; DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (function)); TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); if (!flag_syntax_only) { cgraph_node *aliasn; aliasn = cgraph_node::create_same_body_alias (alias, function); gcc_assert (aliasn != NULL); } return alias; } /* Emit the definition of a D vtable thunk. */ static void finish_thunk (tree thunk, tree function) { /* Setup how D thunks are outputted. */ int fixed_offset = -THUNK_LANG_OFFSET (thunk); bool this_adjusting = true; tree alias; if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)) alias = make_alias_for_thunk (function); else alias = function; TREE_ADDRESSABLE (function) = 1; TREE_USED (function) = 1; if (flag_syntax_only) { TREE_ASM_WRITTEN (thunk) = 1; return; } if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function) && targetm_common.have_named_sections) { tree fn = function; symtab_node *symbol = symtab_node::get (function); if (symbol != NULL && symbol->alias) { if (symbol->analyzed) fn = symtab_node::get (function)->ultimate_alias_target ()->decl; else fn = symtab_node::get (function)->alias_target; } resolve_unique_section (fn, 0, flag_function_sections); if (DECL_SECTION_NAME (fn) != NULL && DECL_ONE_ONLY (fn)) { resolve_unique_section (thunk, 0, flag_function_sections); /* Output the thunk into the same section as function. */ set_decl_section_name (thunk, DECL_SECTION_NAME (fn)); symtab_node::get (thunk)->implicit_section = symtab_node::get (fn)->implicit_section; } } /* Set up cloned argument trees for the thunk. */ tree t = NULL_TREE; for (tree a = DECL_ARGUMENTS (function); a; a = DECL_CHAIN (a)) { tree x = copy_node (a); DECL_CHAIN (x) = t; DECL_CONTEXT (x) = thunk; SET_DECL_RTL (x, NULL); DECL_HAS_VALUE_EXPR_P (x) = 0; TREE_ADDRESSABLE (x) = 0; t = x; } DECL_ARGUMENTS (thunk) = nreverse (t); TREE_ASM_WRITTEN (thunk) = 1; cgraph_node *funcn, *thunk_node; funcn = cgraph_node::get_create (function); gcc_assert (funcn); thunk_node = funcn->create_thunk (thunk, thunk, this_adjusting, fixed_offset, 0, 0, 0, alias); if (DECL_ONE_ONLY (function)) thunk_node->add_to_same_comdat_group (funcn); /* Target assemble_mi_thunk doesn't work across section boundaries on many targets, instead force thunk to be expanded in gimple. */ if (DECL_EXTERNAL (function)) { /* cgraph::expand_thunk writes over current_function_decl, so if this could ever be in use by the codegen pass, we want to know about it. */ gcc_assert (current_function_decl == NULL_TREE); if (!stdarg_p (TREE_TYPE (thunk))) { thunk_node->create_edge (funcn, NULL, thunk_node->count); thunk_node->expand_thunk (false, true); } /* Tell the back-end to not bother inlining the function, this is assumed not to work as it could be referencing symbols outside of the current compilation unit. */ DECL_UNINLINABLE (function) = 1; } } /* Return a thunk to DECL. Thunks adjust the incoming `this' pointer by OFFSET. Adjustor thunks are created and pointers to them stored in the method entries in the vtable in order to set the this pointer to the start of the object instance corresponding to the implementing method. */ tree make_thunk (FuncDeclaration *decl, int offset) { tree function = get_symbol_decl (decl); if (!DECL_ARGUMENTS (function) || !DECL_RESULT (function)) { /* Compile the function body before generating the thunk, this is done even if the decl is external to the current module. */ if (decl->fbody) build_decl_tree (decl); else { /* Build parameters for functions that are not being compiled, so that they can be correctly cloned in finish_thunk. */ tree fntype = TREE_TYPE (function); tree params = NULL_TREE; for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) { if (t == void_list_node) break; tree param = build_decl (DECL_SOURCE_LOCATION (function), PARM_DECL, NULL_TREE, TREE_VALUE (t)); DECL_ARG_TYPE (param) = TREE_TYPE (param); DECL_ARTIFICIAL (param) = 1; DECL_IGNORED_P (param) = 1; DECL_CONTEXT (param) = function; params = chainon (params, param); } DECL_ARGUMENTS (function) = params; /* Also build the result decl, which is needed when force creating the thunk in gimple inside cgraph_node::expand_thunk. */ tree resdecl = build_decl (DECL_SOURCE_LOCATION (function), RESULT_DECL, NULL_TREE, TREE_TYPE (fntype)); DECL_ARTIFICIAL (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1; DECL_CONTEXT (resdecl) = function; DECL_RESULT (function) = resdecl; } } /* Don't build the thunk if the compilation step failed. */ if (global.errors) return error_mark_node; /* See if we already have the thunk in question. */ for (tree t = DECL_LANG_THUNKS (function); t; t = DECL_CHAIN (t)) { if (THUNK_LANG_OFFSET (t) == offset) return t; } tree thunk = build_decl (DECL_SOURCE_LOCATION (function), FUNCTION_DECL, NULL_TREE, TREE_TYPE (function)); DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); lang_hooks.dup_lang_specific_decl (thunk); THUNK_LANG_OFFSET (thunk) = offset; TREE_READONLY (thunk) = TREE_READONLY (function); TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); TREE_NOTHROW (thunk) = TREE_NOTHROW (function); DECL_CONTEXT (thunk) = d_decl_context (decl); /* Thunks inherit the public access of the function they are targetting. */ TREE_PUBLIC (thunk) = TREE_PUBLIC (function); DECL_EXTERNAL (thunk) = 0; /* Thunks are always addressable. */ TREE_ADDRESSABLE (thunk) = 1; TREE_USED (thunk) = 1; DECL_ARTIFICIAL (thunk) = 1; DECL_DECLARED_INLINE_P (thunk) = 0; DECL_VISIBILITY (thunk) = DECL_VISIBILITY (function); DECL_COMDAT (thunk) = DECL_COMDAT (function); DECL_WEAK (thunk) = DECL_WEAK (function); tree target_name = DECL_ASSEMBLER_NAME (function); unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14; const char *ident = XNEWVEC (const char, identlen); snprintf (CONST_CAST (char *, ident), identlen, "_DT%u%s", offset, IDENTIFIER_POINTER (target_name)); DECL_NAME (thunk) = get_identifier (ident); SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk)); d_keep (thunk); finish_thunk (thunk, function); /* Add it to the list of thunks associated with the function. */ DECL_LANG_THUNKS (thunk) = NULL_TREE; DECL_CHAIN (thunk) = DECL_LANG_THUNKS (function); DECL_LANG_THUNKS (function) = thunk; return thunk; } /* Create the FUNCTION_DECL for a function definition. This function creates a binding context for the function body as well as setting up the FUNCTION_DECL in current_function_decl. Returns the previous function context if it was already set. */ tree start_function (FuncDeclaration *fd) { tree fndecl = get_symbol_decl (fd); /* Function has been defined, check now whether we intend to send it to object file, or it really is extern. Such as inlinable functions from modules not in this compilation, or thunk aliases. */ TemplateInstance *ti = fd->isInstantiated (); if (ti && ti->needsCodegen ()) { /* Warn about templates instantiated in this compilation. */ if (ti == fd->parent) { warning (OPT_Wtemplates, "%s %qs instantiated", ti->kind (), ti->toPrettyChars (false)); } DECL_EXTERNAL (fndecl) = 0; } else { Module *md = fd->getModule (); if (md && md->isRoot ()) DECL_EXTERNAL (fndecl) = 0; } DECL_INITIAL (fndecl) = error_mark_node; /* Add this decl to the current binding level. */ d_pushdecl (fndecl); /* Save the current function context. */ tree old_context = current_function_decl; if (old_context) push_function_context (); /* Let GCC know the current scope is this function. */ current_function_decl = fndecl; tree restype = TREE_TYPE (TREE_TYPE (fndecl)); tree resdecl = build_decl (make_location_t (fd->loc), RESULT_DECL, NULL_TREE, restype); DECL_RESULT (fndecl) = resdecl; DECL_CONTEXT (resdecl) = fndecl; DECL_ARTIFICIAL (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1; /* Initialize the RTL code for the function. */ allocate_struct_function (fndecl, false); /* Store the end of the function. */ if (fd->endloc.filename) cfun->function_end_locus = make_location_t (fd->endloc); else cfun->function_end_locus = DECL_SOURCE_LOCATION (fndecl); cfun->language = ggc_cleared_alloc (); cfun->language->function = fd; /* Default chain value is 'null' unless parent found. */ cfun->language->static_chain = null_pointer_node; /* Find module for this function. */ for (Dsymbol *p = fd->parent; p != NULL; p = p->parent) { cfun->language->module = p->isModule (); if (cfun->language->module) break; } gcc_assert (cfun->language->module != NULL); /* Begin the statement tree for this function. */ push_stmt_list (); push_binding_level (level_function); return old_context; } /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage for the function definition. Restores the previous function context. */ void finish_function (tree old_context) { tree fndecl = current_function_decl; /* Tie off the statement tree for this function. */ tree block = pop_binding_level (); tree body = pop_stmt_list (); tree bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), body, block); gcc_assert (vec_safe_is_empty (d_function_chain->stmt_list)); /* Back-end expects a statement list to come from somewhere, however pop_stmt_list returns expressions when there is a single statement. So here we create a statement list unconditionally. */ if (TREE_CODE (body) != STATEMENT_LIST) { tree stmtlist = alloc_stmt_list (); append_to_statement_list_force (body, &stmtlist); BIND_EXPR_BODY (bind) = stmtlist; } else if (!STATEMENT_LIST_HEAD (body)) { /* For empty functions add a void return. */ append_to_statement_list_force (return_expr (NULL_TREE), &body); } DECL_SAVED_TREE (fndecl) = bind; if (!errorcount && !global.errors) { /* Dump the D-specific tree IR. */ dump_function (TDI_original, fndecl); cgraph_node::finalize_function (fndecl, true); } /* We're leaving the context of this function, so free it. */ ggc_free (cfun->language); cfun->language = NULL; set_cfun (NULL); if (old_context) pop_function_context (); current_function_decl = old_context; } /* Mark DECL, which is a VAR_DECL or FUNCTION_DECL as a symbol that must be emitted in this, output module. */ void mark_needed (tree decl) { TREE_USED (decl) = 1; if (TREE_CODE (decl) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_node::get_create (decl); node->forced_by_abi = true; } else if (VAR_P (decl)) { struct varpool_node *node = varpool_node::get_create (decl); node->forced_by_abi = true; } } /* Get the offset to the BC's vtbl[] initializer from the start of CD. Returns "~0u" if the base class is not found in any vtable interfaces. */ unsigned base_vtable_offset (ClassDeclaration *cd, BaseClass *bc) { unsigned csymoffset = Target::classinfosize; unsigned interfacesize = int_size_in_bytes (vtbl_interface_type_node); csymoffset += cd->vtblInterfaces->dim * interfacesize; for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; if (b == bc) return csymoffset; csymoffset += b->sym->vtbl.dim * Target::ptrsize; } /* Check all overriding interface vtbl[]s. */ for (ClassDeclaration *cd2 = cd->baseClass; cd2; cd2 = cd2->baseClass) { for (size_t k = 0; k < cd2->vtblInterfaces->dim; k++) { BaseClass *bs = (*cd2->vtblInterfaces)[k]; if (bs->fillVtbl (cd, NULL, 0)) { if (bc == bs) return csymoffset; csymoffset += bs->sym->vtbl.dim * Target::ptrsize; } } } return ~0u; } /* Get the VAR_DECL of the vtable symbol for DECL. If this does not yet exist, create it. The vtable is accessible via ClassInfo, but since it is needed frequently (like for rtti comparisons), make it directly accessible. */ tree get_vtable_decl (ClassDeclaration *decl) { if (decl->vtblsym && decl->vtblsym->csym) return decl->vtblsym->csym; tree ident = mangle_internal_decl (decl, "__vtbl", "Z"); /* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value will have a different type. However the back-end seems to accept this. */ tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.dim)); Dsymbol *vtblsym = decl->vtblSymbol (); vtblsym->csym = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (vtblsym->csym) = build_lang_decl (NULL); /* Class is a reference, want the record type. */ DECL_CONTEXT (vtblsym->csym) = TREE_TYPE (build_ctype (decl->type)); TREE_READONLY (vtblsym->csym) = 1; DECL_VIRTUAL_P (vtblsym->csym) = 1; SET_DECL_ALIGN (vtblsym->csym, TARGET_VTABLE_ENTRY_ALIGN); DECL_USER_ALIGN (vtblsym->csym) = true; return vtblsym->csym; } /* Helper function of build_class_instance. Find the field inside aggregate TYPE identified by IDENT at field OFFSET. */ static tree find_aggregate_field (tree type, tree ident, tree offset) { tree fields = TYPE_FIELDS (type); for (tree field = fields; field != NULL_TREE; field = TREE_CHAIN (field)) { if (DECL_NAME (field) == NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && ANON_AGGR_TYPE_P (TREE_TYPE (field))) { /* Search nesting anonymous structs and unions. */ tree vfield = find_aggregate_field (TREE_TYPE (field), ident, offset); if (vfield != NULL_TREE) return vfield; } else if (DECL_NAME (field) == ident && (offset == NULL_TREE || DECL_FIELD_OFFSET (field) == offset)) { /* Found matching field at offset. */ return field; } } return NULL_TREE; } /* Helper function of build_new_class_expr. Return a constructor that matches the layout of the class expression EXP. */ static tree build_class_instance (ClassReferenceExp *exp) { ClassDeclaration *cd = exp->originalClass (); tree type = TREE_TYPE (build_ctype (exp->value->stype)); vec *ve = NULL; /* The set base vtable field. */ tree vptr = build_address (get_vtable_decl (cd)); CONSTRUCTOR_APPEND_ELT (ve, TYPE_FIELDS (type), vptr); /* Go through the inheritance graph from top to bottom. This will add all values to the constructor out of order, however build_struct_literal will re-order all values before returning the finished literal. */ for (ClassDeclaration *bcd = cd; bcd != NULL; bcd = bcd->baseClass) { /* Anonymous vtable interface fields are laid out before the fields of each class. The interface offset is used to determine where to put the classinfo offset reference. */ for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++) { BaseClass *bc = (*bcd->vtblInterfaces)[i]; for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass) { gcc_assert (cd2 != NULL); unsigned csymoffset = base_vtable_offset (cd2, bc); /* If the base class vtable was found. */ if (csymoffset != ~0u) { tree csym = build_address (get_classinfo_decl (cd2)); csym = build_offset (csym, size_int (csymoffset)); tree field = find_aggregate_field (type, NULL_TREE, size_int (bc->offset)); gcc_assert (field != NULL_TREE); CONSTRUCTOR_APPEND_ELT (ve, field, csym); break; } } } /* Generate initial values of all fields owned by current class. Use both the name and offset to find the right field. */ for (size_t i = 0; i < bcd->fields.dim; i++) { VarDeclaration *vfield = bcd->fields[i]; int index = exp->findFieldIndexByName (vfield); gcc_assert (index != -1); Expression *value = (*exp->value->elements)[index]; if (!value) continue; /* Use find_aggregate_field to get the overridden field decl, instead of the field associated with the base class. */ tree field = get_symbol_decl (bcd->fields[i]); field = find_aggregate_field (type, DECL_NAME (field), DECL_FIELD_OFFSET (field)); gcc_assert (field != NULL_TREE); CONSTRUCTOR_APPEND_ELT (ve, field, build_expr (value, true)); } } return build_struct_literal (type, ve); } /* Get the VAR_DECL of a class instance representing EXPR as static data. If this does not yet exist, create it. This is used to support initializing a static variable that is of a class type using values known during CTFE. In user code, it is analogous to the following code snippet. enum E = new C(1, 2, 3); That we write the contents of `C(1, 2, 3)' to static data is only a compiler implementation detail. The initialization of these symbols could be done at run-time using during as part of the module initialization or shared static constructors phase of run-time start-up - whichever comes after `gc_init()'. And infact that would be the better thing to do here eventually. */ tree build_new_class_expr (ClassReferenceExp *expr) { if (expr->value->sym) return expr->value->sym; /* Build the reference symbol. */ tree type = build_ctype (expr->value->stype); expr->value->sym = build_artificial_decl (TREE_TYPE (type), NULL_TREE, "C"); DECL_INITIAL (expr->value->sym) = build_class_instance (expr); d_pushdecl (expr->value->sym); rest_of_decl_compilation (expr->value->sym, 1, 0); return expr->value->sym; } /* Get the VAR_DECL of the static initializer symbol for the struct/class DECL. If this does not yet exist, create it. The static initializer data is accessible via TypeInfo, and is also used in 'new class' and default initializing struct literals. */ tree aggregate_initializer_decl (AggregateDeclaration *decl) { if (decl->sinit) return decl->sinit; /* Class is a reference, want the record type. */ tree type = build_ctype (decl->type); StructDeclaration *sd = decl->isStructDeclaration (); if (!sd) type = TREE_TYPE (type); tree ident = mangle_internal_decl (decl, "__init", "Z"); decl->sinit = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL); DECL_CONTEXT (decl->sinit) = type; TREE_READONLY (decl->sinit) = 1; /* Honor struct alignment set by user. */ if (sd && sd->alignment != STRUCTALIGN_DEFAULT) { SET_DECL_ALIGN (decl->sinit, sd->alignment * BITS_PER_UNIT); DECL_USER_ALIGN (decl->sinit) = true; } return decl->sinit; } /* Generate the data for the static initializer. */ tree layout_class_initializer (ClassDeclaration *cd) { NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL); ne->type = cd->type; Expression *e = ne->ctfeInterpret (); gcc_assert (e->op == TOKclassreference); return build_class_instance ((ClassReferenceExp *) e); } tree layout_struct_initializer (StructDeclaration *sd) { StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL); if (!sd->fill (sd->loc, sle->elements, true)) gcc_unreachable (); sle->type = sd->type; return build_expr (sle, true); } /* Get the VAR_DECL of the static initializer symbol for the enum DECL. If this does not yet exist, create it. The static initializer data is accessible via TypeInfo_Enum, but the field member type is a byte[] that requires a pointer to a symbol reference. */ tree enum_initializer_decl (EnumDeclaration *decl) { if (decl->sinit) return decl->sinit; tree type = build_ctype (decl->type); Identifier *ident_save = decl->ident; if (!decl->ident) decl->ident = Identifier::generateId ("__enum"); tree ident = mangle_internal_decl (decl, "__init", "Z"); decl->ident = ident_save; decl->sinit = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL); DECL_CONTEXT (decl->sinit) = d_decl_context (decl); TREE_READONLY (decl->sinit) = 1; return decl->sinit; } /* Return an anonymous static variable of type TYPE, initialized with INIT, and optionally prefixing the name with PREFIX. */ tree build_artificial_decl (tree type, tree init, const char *prefix) { tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE, type); const char *name = prefix ? prefix : "___s"; char *label; ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl)); SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label)); DECL_NAME (decl) = DECL_ASSEMBLER_NAME (decl); TREE_PUBLIC (decl) = 0; TREE_STATIC (decl) = 1; TREE_USED (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_ARTIFICIAL (decl) = 1; /* Perhaps at some point the initializer constant should be hashed to remove duplicates. */ DECL_INITIAL (decl) = init; return decl; } /* Build TYPE_DECL for the declaration DSYM. */ void build_type_decl (tree type, Dsymbol *dsym) { if (TYPE_STUB_DECL (type)) return; gcc_assert (!POINTER_TYPE_P (type)); tree decl = build_decl (make_location_t (dsym->loc), TYPE_DECL, get_identifier (dsym->ident->toChars ()), type); SET_DECL_ASSEMBLER_NAME (decl, get_identifier (mangle_decl (dsym))); TREE_PUBLIC (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_CONTEXT (decl) = d_decl_context (dsym); TYPE_CONTEXT (type) = DECL_CONTEXT (decl); TYPE_NAME (type) = decl; /* Not sure if there is a need for separate TYPE_DECLs in TYPE_NAME and TYPE_STUB_DECL. */ if (TREE_CODE (type) == ENUMERAL_TYPE || RECORD_OR_UNION_TYPE_P (type)) TYPE_STUB_DECL (type) = decl; rest_of_decl_compilation (decl, SCOPE_FILE_SCOPE_P (decl), 0); } /* Create a declaration for field NAME of a given TYPE, setting the flags for whether the field is ARTIFICIAL and/or IGNORED. */ tree create_field_decl (tree type, const char *name, int artificial, int ignored) { tree decl = build_decl (input_location, FIELD_DECL, name ? get_identifier (name) : NULL_TREE, type); DECL_ARTIFICIAL (decl) = artificial; DECL_IGNORED_P (decl) = ignored; return decl; } /* Return the COMDAT group into which DECL should be placed. */ static tree d_comdat_group (tree decl) { /* If already part of a comdat group, use that. */ if (DECL_COMDAT_GROUP (decl)) return DECL_COMDAT_GROUP (decl); return DECL_ASSEMBLER_NAME (decl); } /* Set DECL up to have the closest approximation of "initialized common" linkage available. */ void d_comdat_linkage (tree decl) { if (flag_weak) make_decl_one_only (decl, d_comdat_group (decl)); else if (TREE_CODE (decl) == FUNCTION_DECL || (VAR_P (decl) && DECL_ARTIFICIAL (decl))) /* We can just emit function and compiler-generated variables statically; having multiple copies is (for the most part) only a waste of space. */ TREE_PUBLIC (decl) = 0; else if (DECL_INITIAL (decl) == NULL_TREE || DECL_INITIAL (decl) == error_mark_node) /* Fallback, cannot have multiple copies. */ DECL_COMMON (decl) = 1; if (TREE_PUBLIC (decl)) DECL_COMDAT (decl) = 1; } /* Set DECL up to have the closest approximation of "linkonce" linkage. */ void d_linkonce_linkage (tree decl) { /* Weak definitions have to be public. */ if (!TREE_PUBLIC (decl)) return; /* Necessary to allow DECL_ONE_ONLY or DECL_WEAK functions to be inlined. */ if (TREE_CODE (decl) == FUNCTION_DECL) DECL_DECLARED_INLINE_P (decl) = 1; /* No weak support, fallback to COMDAT linkage. */ if (!flag_weak) return d_comdat_linkage (decl); make_decl_one_only (decl, d_comdat_group (decl)); } ================================================ FILE: gcc/d/dmd/MERGE ================================================ 76d619c28590c632d01e8b0840b358acdf141357 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. ================================================ FILE: gcc/d/dmd/access.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/access.d, _access.d) * Documentation: https://dlang.org/phobos/dmd_access.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/access.d */ module dmd.access; import dmd.aggregate; import dmd.dclass; import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.mtype; import dmd.tokens; private enum LOG = false; /**************************************** * Return Prot access for Dsymbol smember in this declaration. */ private Prot getAccess(AggregateDeclaration ad, Dsymbol smember) { Prot access_ret = Prot(Prot.Kind.none); static if (LOG) { printf("+AggregateDeclaration::getAccess(this = '%s', smember = '%s')\n", ad.toChars(), smember.toChars()); } assert(ad.isStructDeclaration() || ad.isClassDeclaration()); if (smember.toParent() == ad) { access_ret = smember.prot(); } else if (smember.isDeclaration().isStatic()) { access_ret = smember.prot(); } if (ClassDeclaration cd = ad.isClassDeclaration()) { foreach (b; *cd.baseclasses) { Prot access = getAccess(b.sym, smember); final switch (access.kind) { case Prot.Kind.none: case Prot.Kind.undefined: break; case Prot.Kind.private_: access_ret = Prot(Prot.Kind.none); // private members of base class not accessible break; case Prot.Kind.package_: case Prot.Kind.protected_: case Prot.Kind.public_: case Prot.Kind.export_: // If access is to be tightened if (Prot.Kind.public_ < access.kind) access = Prot(Prot.Kind.public_); // Pick path with loosest access if (access_ret.isMoreRestrictiveThan(access)) access_ret = access; break; } } } static if (LOG) { printf("-AggregateDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", ad.toChars(), smember.toChars(), access_ret); } return access_ret; } /******************************************************** * Helper function for checkAccess() * Returns: * false is not accessible * true is accessible */ private bool isAccessible(Dsymbol smember, Dsymbol sfunc, AggregateDeclaration dthis, AggregateDeclaration cdscope) { assert(dthis); version (none) { printf("isAccessible for %s.%s in function %s() in scope %s\n", dthis.toChars(), smember.toChars(), sfunc ? sfunc.toChars() : "NULL", cdscope ? cdscope.toChars() : "NULL"); } if (hasPrivateAccess(dthis, sfunc) || isFriendOf(dthis, cdscope)) { if (smember.toParent() == dthis) return true; if (ClassDeclaration cdthis = dthis.isClassDeclaration()) { foreach (b; *cdthis.baseclasses) { const Prot access = getAccess(b.sym, smember); if (access.kind >= Prot.Kind.protected_ || isAccessible(smember, sfunc, b.sym, cdscope)) { return true; } } } } else { if (smember.toParent() != dthis) { if (ClassDeclaration cdthis = dthis.isClassDeclaration()) { foreach (b; *cdthis.baseclasses) if (isAccessible(smember, sfunc, b.sym, cdscope)) return true; } } } return false; } /******************************* * Do access check for member of this class, this class being the * type of the 'this' pointer used to access smember. * Returns true if the member is not accessible. */ bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember) { FuncDeclaration f = sc.func; AggregateDeclaration cdscope = sc.getStructClassScope(); static if (LOG) { printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n", ad.toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null); } Dsymbol smemberparent = smember.toParent(); if (!smemberparent || !smemberparent.isAggregateDeclaration()) { static if (LOG) { printf("not an aggregate member\n"); } return false; // then it is accessible } // BUG: should enable this check //assert(smember.parent.isBaseOf(this, NULL)); bool result; Prot access; if (smemberparent == ad) { access = smember.prot(); result = access.kind >= Prot.Kind.public_ || hasPrivateAccess(ad, f) || isFriendOf(ad, cdscope) || (access.kind == Prot.Kind.package_ && hasPackageAccess(sc, smember)) || ad.getAccessModule() == sc._module; static if (LOG) { printf("result1 = %d\n", result); } } else if ((access = getAccess(ad, smember)).kind >= Prot.Kind.public_) { result = true; static if (LOG) { printf("result2 = %d\n", result); } } else if (access.kind == Prot.Kind.package_ && hasPackageAccess(sc, ad)) { result = true; static if (LOG) { printf("result3 = %d\n", result); } } else { result = isAccessible(smember, f, ad, cdscope); static if (LOG) { printf("result4 = %d\n", result); } } if (!result && (!(sc.flags & SCOPE.onlysafeaccess) || sc.func.setUnsafe())) { ad.error(loc, "member `%s` is not accessible%s", smember.toChars(), (sc.flags & SCOPE.onlysafeaccess) ? " from `@safe` code".ptr : "".ptr); //printf("smember = %s %s, prot = %d, semanticRun = %d\n", // smember.kind(), smember.toPrettyChars(), smember.prot(), smember.semanticRun); return true; } return false; } /**************************************** * Determine if this is the same or friend of cd. */ private bool isFriendOf(AggregateDeclaration ad, AggregateDeclaration cd) { static if (LOG) { printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", ad.toChars(), cd ? cd.toChars() : "null"); } if (ad == cd) return true; // Friends if both are in the same module //if (toParent() == cd.toParent()) if (cd && ad.getAccessModule() == cd.getAccessModule()) { static if (LOG) { printf("\tin same module\n"); } return true; } static if (LOG) { printf("\tnot friend\n"); } return false; } /**************************************** * Determine if scope sc has package level access to s. */ private bool hasPackageAccess(Scope* sc, Dsymbol s) { return hasPackageAccess(sc._module, s); } private bool hasPackageAccess(Module mod, Dsymbol s) { static if (LOG) { printf("hasPackageAccess(s = '%s', mod = '%s', s.protection.pkg = '%s')\n", s.toChars(), mod.toChars(), s.prot().pkg ? s.prot().pkg.toChars() : "NULL"); } Package pkg = null; if (s.prot().pkg) pkg = s.prot().pkg; else { // no explicit package for protection, inferring most qualified one for (; s; s = s.parent) { if (Module m = s.isModule()) { DsymbolTable dst = Package.resolve(m.md ? m.md.packages : null, null, null); assert(dst); Dsymbol s2 = dst.lookup(m.ident); assert(s2); Package p = s2.isPackage(); if (p && p.isPackageMod()) { pkg = p; break; } } else if ((pkg = s.isPackage()) !is null) break; } } static if (LOG) { if (pkg) printf("\tsymbol access binds to package '%s'\n", pkg.toChars()); } if (pkg) { if (pkg == mod.parent) { static if (LOG) { printf("\tsc is in permitted package for s\n"); } return true; } if (pkg.isPackageMod() == mod) { static if (LOG) { printf("\ts is in same package.d module as sc\n"); } return true; } Dsymbol ancestor = mod.parent; for (; ancestor; ancestor = ancestor.parent) { if (ancestor == pkg) { static if (LOG) { printf("\tsc is in permitted ancestor package for s\n"); } return true; } } } static if (LOG) { printf("\tno package access\n"); } return false; } /**************************************** * Determine if scope sc has protected level access to cd. */ private bool hasProtectedAccess(Scope *sc, Dsymbol s) { if (auto cd = s.isClassMember()) // also includes interfaces { for (auto scx = sc; scx; scx = scx.enclosing) { if (!scx.scopesym) continue; auto cd2 = scx.scopesym.isClassDeclaration(); if (cd2 && cd.isBaseOf(cd2, null)) return true; } } return sc._module == s.getAccessModule(); } /********************************** * Determine if smember has access to private members of this declaration. */ private bool hasPrivateAccess(AggregateDeclaration ad, Dsymbol smember) { if (smember) { AggregateDeclaration cd = null; Dsymbol smemberparent = smember.toParent(); if (smemberparent) cd = smemberparent.isAggregateDeclaration(); static if (LOG) { printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", ad.toChars(), smember.toChars()); } if (ad == cd) // smember is a member of this class { static if (LOG) { printf("\tyes 1\n"); } return true; // so we get private access } // If both are members of the same module, grant access while (1) { Dsymbol sp = smember.toParent(); if (sp.isFuncDeclaration() && smember.isFuncDeclaration()) smember = sp; else break; } if (!cd && ad.toParent() == smember.toParent()) { static if (LOG) { printf("\tyes 2\n"); } return true; } if (!cd && ad.getAccessModule() == smember.getAccessModule()) { static if (LOG) { printf("\tyes 3\n"); } return true; } } static if (LOG) { printf("\tno\n"); } return false; } /**************************************** * Check access to d for expression e.d * Returns true if the declaration is not accessible. */ bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) { if (sc.flags & SCOPE.noaccesscheck) return false; static if (LOG) { if (e) { printf("checkAccess(%s . %s)\n", e.toChars(), d.toChars()); printf("\te.type = %s\n", e.type.toChars()); } else { printf("checkAccess(%s)\n", d.toPrettyChars()); } } if (d.isUnitTestDeclaration()) { // Unittests are always accessible. return false; } if (!e) { if (d.prot().kind == Prot.Kind.private_ && d.getAccessModule() != sc._module || d.prot().kind == Prot.Kind.package_ && !hasPackageAccess(sc, d)) { error(loc, "%s `%s` is not accessible from module `%s`", d.kind(), d.toPrettyChars(), sc._module.toChars()); return true; } } else if (e.type.ty == Tclass) { // Do access check ClassDeclaration cd = (cast(TypeClass)e.type).sym; if (e.op == TOK.super_) { if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration()) cd = cd2; } return checkAccess(cd, loc, sc, d); } else if (e.type.ty == Tstruct) { // Do access check StructDeclaration cd = (cast(TypeStruct)e.type).sym; return checkAccess(cd, loc, sc, d); } return false; } /**************************************** * Check access to package/module `p` from scope `sc`. * * Params: * loc = source location for issued error message * sc = scope from which to access to a fully qualified package name * p = the package/module to check access for * Returns: true if the package is not accessible. * * Because a global symbol table tree is used for imported packages/modules, * access to them needs to be checked based on the imports in the scope chain * (see https://issues.dlang.org/show_bug.cgi?id=313). * */ bool checkAccess(Loc loc, Scope* sc, Package p) { if (sc._module == p) return false; for (; sc; sc = sc.enclosing) { if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Prot(Prot.Kind.private_))) return false; } auto name = p.toPrettyChars(); if (p.isPkgMod == PKG.module_ || p.isModule()) error(loc, "%s `%s` is not accessible here, perhaps add `static import %s;`", p.kind(), name, name); else error(loc, "%s `%s` is not accessible here", p.kind(), name); return true; } /** * Check whether symbols `s` is visible in `mod`. * * Params: * mod = lookup origin * s = symbol to check for visibility * Returns: true if s is visible in mod */ bool symbolIsVisible(Module mod, Dsymbol s) { // should sort overloads by ascending protection instead of iterating here s = mostVisibleOverload(s); final switch (s.prot().kind) { case Prot.Kind.undefined: return true; case Prot.Kind.none: return false; // no access case Prot.Kind.private_: return s.getAccessModule() == mod; case Prot.Kind.package_: return s.getAccessModule() == mod || hasPackageAccess(mod, s); case Prot.Kind.protected_: return s.getAccessModule() == mod; case Prot.Kind.public_, Prot.Kind.export_: return true; } } /** * Same as above, but determines the lookup module from symbols `origin`. */ bool symbolIsVisible(Dsymbol origin, Dsymbol s) { return symbolIsVisible(origin.getAccessModule(), s); } /** * Same as above but also checks for protected symbols visible from scope `sc`. * Used for qualified name lookup. * * Params: * sc = lookup scope * s = symbol to check for visibility * Returns: true if s is visible by origin */ bool symbolIsVisible(Scope *sc, Dsymbol s) { s = mostVisibleOverload(s); return checkSymbolAccess(sc, s); } /** * Check if a symbol is visible from a given scope without taking * into account the most visible overload. * * Params: * sc = lookup scope * s = symbol to check for visibility * Returns: true if s is visible by origin */ bool checkSymbolAccess(Scope *sc, Dsymbol s) { final switch (s.prot().kind) { case Prot.Kind.undefined: return true; case Prot.Kind.none: return false; // no access case Prot.Kind.private_: return sc._module == s.getAccessModule(); case Prot.Kind.package_: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s); case Prot.Kind.protected_: return hasProtectedAccess(sc, s); case Prot.Kind.public_, Prot.Kind.export_: return true; } } /** * Use the most visible overload to check visibility. Later perform an access * check on the resolved overload. This function is similar to overloadApply, * but doesn't recurse nor resolve aliases because protection/visibility is an * attribute of the alias not the aliasee. */ public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null) { if (!s.isOverloadable()) return s; Dsymbol next, fstart = s, mostVisible = s; for (; s; s = next) { // void func() {} // private void func(int) {} if (auto fd = s.isFuncDeclaration()) next = fd.overnext; // template temp(T) {} // private template temp(T:int) {} else if (auto td = s.isTemplateDeclaration()) next = td.overnext; // alias common = mod1.func1; // alias common = mod2.func2; else if (auto fa = s.isFuncAliasDeclaration()) next = fa.overnext; // alias common = mod1.templ1; // alias common = mod2.templ2; else if (auto od = s.isOverDeclaration()) next = od.overnext; // alias name = sym; // private void name(int) {} else if (auto ad = s.isAliasDeclaration()) { assert(ad.isOverloadable || ad.type && ad.type.ty == Terror, "Non overloadable Aliasee in overload list"); // Yet unresolved aliases store overloads in overnext. if (ad.semanticRun < PASS.semanticdone) next = ad.overnext; else { /* This is a bit messy due to the complicated implementation of * alias. Aliases aren't overloadable themselves, but if their * Aliasee is overloadable they can be converted to an overloadable * alias. * * This is done by replacing the Aliasee w/ FuncAliasDeclaration * (for functions) or OverDeclaration (for templates) which are * simply overloadable aliases w/ weird names. * * Usually aliases should not be resolved for visibility checking * b/c public aliases to private symbols are public. But for the * overloadable alias situation, the Alias (_ad_) has been moved * into it's own Aliasee, leaving a shell that we peel away here. */ auto aliasee = ad.toAlias(); if (aliasee.isFuncAliasDeclaration || aliasee.isOverDeclaration) next = aliasee; else { /* A simple alias can be at the end of a function or template overload chain. * It can't have further overloads b/c it would have been * converted to an overloadable alias. */ assert(ad.overnext is null, "Unresolved overload of alias"); break; } } // handled by dmd.func.overloadApply for unknown reason assert(next !is ad); // should not alias itself assert(next !is fstart); // should not alias the overload list itself } else break; /** * Return the "effective" protection attribute of a symbol when accessed in a module. * The effective protection attribute is the same as the regular protection attribute, * except package() is "private" if the module is outside the package; * otherwise, "public". */ static Prot protectionSeenFromModule(Dsymbol d, Module mod = null) { Prot prot = d.prot(); if (mod && prot.kind == Prot.Kind.package_) { return hasPackageAccess(mod, d) ? Prot(Prot.Kind.public_) : Prot(Prot.Kind.private_); } return prot; } if (next && protectionSeenFromModule(mostVisible, mod).isMoreRestrictiveThan(protectionSeenFromModule(next, mod))) mostVisible = next; } return mostVisible; } ================================================ FILE: gcc/d/dmd/aggregate.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/aggregate.d, _aggregate.d) * Documentation: https://dlang.org/phobos/dmd_aggregate.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aggregate.d */ module dmd.aggregate; import core.stdc.stdio; import core.checkedint; import dmd.arraytypes; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.semantic2; import dmd.semantic3; import dmd.tokens; import dmd.typesem; import dmd.visitor; enum Sizeok : int { none, // size of aggregate is not yet able to compute fwd, // size of aggregate is ready to compute done, // size of aggregate is set correctly } enum Baseok : int { none, // base classes not computed yet start, // in process of resolving base classes done, // all base classes are resolved semanticdone, // all base classes semantic done } /** * The ClassKind enum is used in AggregateDeclaration AST nodes to * specify the linkage type of the struct/class/interface or if it * is an anonymous class. If the class is anonymous it is also * considered to be a D class. */ enum ClassKind : int { /// the aggregate is a d(efault) class d, /// the aggregate is a C++ struct/class/interface cpp, /// the aggregate is an Objective-C class/interface objc, } /*********************************************************** */ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol { Type type; StorageClass storage_class; Prot protection; uint structsize; // size of struct uint alignsize; // size of struct for alignment purposes VarDeclarations fields; // VarDeclaration fields Sizeok sizeok; // set when structsize contains valid data Dsymbol deferred; // any deferred semantic2() or semantic3() symbol bool isdeprecated; // true if deprecated /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface ClassKind classKind; /* !=null if is nested * pointing to the dsymbol that directly enclosing it. * 1. The function that enclosing it (nested struct and class) * 2. The class that enclosing it (nested class only) * 3. If enclosing aggregate is template, its enclosing dsymbol. * See AggregateDeclaraton::makeNested for the details. */ Dsymbol enclosing; VarDeclaration vthis; // 'this' parameter if this aggregate is nested // Special member functions FuncDeclarations invs; // Array of invariants FuncDeclaration inv; // invariant NewDeclaration aggNew; // allocator DeleteDeclaration aggDelete; // deallocator // CtorDeclaration or TemplateDeclaration Dsymbol ctor; // default constructor - should have no arguments, because // it would be stored in TypeInfo_Class.defaultConstructor CtorDeclaration defaultCtor; Dsymbol aliasthis; // forward unresolved lookups to aliasthis bool noDefaultCtor; // no default construction DtorDeclarations dtors; // Array of destructors DtorDeclaration dtor; // aggregate destructor DtorDeclaration primaryDtor; // non-deleting C++ destructor, same as dtor for D DtorDeclaration tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI) FuncDeclaration fieldDtor; // aggregate destructor for just the fields Expression getRTInfo; // pointer to GC info generated by object.RTInfo(this) final extern (D) this(const ref Loc loc, Identifier id) { super(id); this.loc = loc; protection = Prot(Prot.Kind.public_); sizeok = Sizeok.none; // size not determined yet } /*************************************** * Create a new scope from sc. * semantic, semantic2 and semantic3 will use this for aggregate members. */ Scope* newScope(Scope* sc) { auto sc2 = sc.push(this); sc2.stc &= STC.safe | STC.trusted | STC.system; sc2.parent = this; if (isUnionDeclaration()) sc2.inunion = true; sc2.protection = Prot(Prot.Kind.public_); sc2.explicitProtection = 0; sc2.aligndecl = null; sc2.userAttribDecl = null; return sc2; } override final void setScope(Scope* sc) { // Might need a scope to resolve forward references. The check for // semanticRun prevents unnecessary setting of _scope during deferred // setScope phases for aggregates which already finished semantic(). // See https://issues.dlang.org/show_bug.cgi?id=16607 if (semanticRun < PASS.semanticdone) ScopeDsymbol.setScope(sc); } /*************************************** * Find all instance fields, then push them into `fields`. * * Runs semantic() for all instance field variables, but also * the field types can remain yet not resolved forward references, * except direct recursive definitions. * After the process sizeok is set to Sizeok.fwd. * * Returns: * false if any errors occur. */ final bool determineFields() { if (_scope) dsymbolSemantic(this, null); if (sizeok != Sizeok.none) return true; //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim); // determineFields can be called recursively from one of the fields's v.semantic fields.setDim(0); extern (C++) static int func(Dsymbol s, void* param) { auto v = s.isVarDeclaration(); if (!v) return 0; if (v.storage_class & STC.manifest) return 0; auto ad = cast(AggregateDeclaration)param; if (v.semanticRun < PASS.semanticdone) v.dsymbolSemantic(null); // Return in case a recursive determineFields triggered by v.semantic already finished if (ad.sizeok != Sizeok.none) return 1; if (v.aliassym) return 0; // If this variable was really a tuple, skip it. if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) return 0; if (!v.isField() || v.semanticRun < PASS.semanticdone) return 1; // unresolvable forward reference ad.fields.push(v); if (v.storage_class & STC.ref_) return 0; auto tv = v.type.baseElemOf(); if (tv.ty != Tstruct) return 0; if (ad == (cast(TypeStruct)tv).sym) { const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : ""; ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz); ad.type = Type.terror; ad.errors = true; return 1; } return 0; } for (size_t i = 0; i < members.dim; i++) { auto s = (*members)[i]; if (s.apply(&func, cast(void*)this)) { if (sizeok != Sizeok.none) { // recursive determineFields already finished return true; } return false; } } if (sizeok != Sizeok.done) sizeok = Sizeok.fwd; return true; } /*************************************** * Collect all instance fields, then determine instance size. * Returns: * false if failed to determine the size. */ final bool determineSize(Loc loc) { //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok); // The previous instance size finalizing had: if (type.ty == Terror) return false; // failed already if (sizeok == Sizeok.done) return true; // succeeded if (!members) { error(loc, "unknown size"); return false; } if (_scope) dsymbolSemantic(this, null); // Determine the instance size of base class first. if (auto cd = isClassDeclaration()) { cd = cd.baseClass; if (cd && !cd.determineSize(loc)) goto Lfail; } // Determine instance fields when sizeok == Sizeok.none if (!determineFields()) goto Lfail; if (sizeok != Sizeok.done) finalizeSize(); // this aggregate type has: if (type.ty == Terror) return false; // marked as invalid during the finalizing. if (sizeok == Sizeok.done) return true; // succeeded to calculate instance size. Lfail: // There's unresolvable forward reference. if (type != Type.terror) error(loc, "no size because of forward reference"); // Don't cache errors from speculative semantic, might be resolvable later. // https://issues.dlang.org/show_bug.cgi?id=16574 if (!global.gag) { type = Type.terror; errors = true; } return false; } abstract void finalizeSize(); override final d_uns64 size(const ref Loc loc) { //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); bool ok = determineSize(loc); //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok); return ok ? structsize : SIZE_INVALID; } /*************************************** * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit * field initializers have unique memory space on instance. * Returns: * true if any errors happen. */ extern (D) final bool checkOverlappedFields() { //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars()); assert(sizeok == Sizeok.done); size_t nfields = fields.dim; if (isNested()) { auto cd = isClassDeclaration(); if (!cd || !cd.baseClass || !cd.baseClass.isNested()) nfields--; } bool errors = false; // Fill in missing any elements with default initializers foreach (i; 0 .. nfields) { auto vd = fields[i]; if (vd.errors) { errors = true; continue; } auto vx = vd; if (vd._init && vd._init.isVoidInitializer()) vx = null; // Find overlapped fields with the hole [vd.offset .. vd.offset.size()]. foreach (j; 0 .. nfields) { if (i == j) continue; auto v2 = fields[j]; if (v2.errors) { errors = true; continue; } if (!vd.isOverlappedWith(v2)) continue; // vd and v2 are overlapping. vd.overlapped = true; v2.overlapped = true; if (!MODimplicitConv(vd.type.mod, v2.type.mod)) v2.overlapUnsafe = true; if (!MODimplicitConv(v2.type.mod, vd.type.mod)) vd.overlapUnsafe = true; if (!vx) continue; if (v2._init && v2._init.isVoidInitializer()) continue; if (vx._init && v2._init) { .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } } } return errors; } /*************************************** * Fill out remainder of elements[] with default initializers for fields[]. * Params: * loc = location * elements = explicit arguments which given to construct object. * ctorinit = true if the elements will be used for default initialization. * Returns: * false if any errors occur. * Otherwise, returns true and the missing arguments will be pushed in elements[]. */ final bool fill(Loc loc, Expressions* elements, bool ctorinit) { //printf("AggregateDeclaration::fill() %s\n", toChars()); assert(sizeok == Sizeok.done); assert(elements); size_t nfields = fields.dim - isNested(); bool errors = false; size_t dim = elements.dim; elements.setDim(nfields); foreach (size_t i; dim .. nfields) (*elements)[i] = null; // Fill in missing any elements with default initializers foreach (i; 0 .. nfields) { if ((*elements)[i]) continue; auto vd = fields[i]; auto vx = vd; if (vd._init && vd._init.isVoidInitializer()) vx = null; // Find overlapped fields with the hole [vd.offset .. vd.offset.size()]. size_t fieldi = i; foreach (j; 0 .. nfields) { if (i == j) continue; auto v2 = fields[j]; if (!vd.isOverlappedWith(v2)) continue; if ((*elements)[j]) { vx = null; break; } if (v2._init && v2._init.isVoidInitializer()) continue; version (all) { /* Prefer first found non-void-initialized field * union U { int a; int b = 2; } * U u; // Error: overlapping initialization for field a and b */ if (!vx) { vx = v2; fieldi = j; } else if (v2._init) { .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } } else { // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always /* Prefer explicitly initialized field * union U { int a; int b = 2; } * U u; // OK (u.b == 2) */ if (!vx || !vx._init && v2._init) { vx = v2; fieldi = j; } else if (vx != vd && !vx.isOverlappedWith(v2)) { // Both vx and v2 fills vd, but vx and v2 does not overlap } else if (vx._init && v2._init) { .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } else assert(vx._init || !vx._init && !v2._init); } } if (vx) { Expression e; if (vx.type.size() == 0) { e = null; } else if (vx._init) { assert(!vx._init.isVoidInitializer()); if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057 { vx.error(loc, "recursive initialization of field"); errors = true; } else e = vx.getConstInitializer(false); } else { if ((vx.storage_class & STC.nodefaultctor) && !ctorinit) { .error(loc, "field `%s.%s` must be initialized because it has no default constructor", type.toChars(), vx.toChars()); errors = true; } /* https://issues.dlang.org/show_bug.cgi?id=12509 * Get the element of static array type. */ Type telem = vx.type; if (telem.ty == Tsarray) { /* We cannot use Type::baseElemOf() here. * If the bottom of the Tsarray is an enum type, baseElemOf() * will return the base of the enum, and its default initializer * would be different from the enum's. */ while (telem.toBasetype().ty == Tsarray) telem = (cast(TypeSArray)telem.toBasetype()).next; if (telem.ty == Tvoid) telem = Type.tuns8.addMod(telem.mod); } if (telem.needsNested() && ctorinit) e = telem.defaultInit(loc); else e = telem.defaultInitLiteral(loc); } (*elements)[fieldi] = e; } } foreach (e; *elements) { if (e && e.op == TOK.error) return false; } return !errors; } /**************************** * Do byte or word alignment as necessary. * Align sizes of 0, as we may not know array sizes yet. * Params: * alignment = struct alignment that is in effect * size = alignment requirement of field * poffset = pointer to offset to be aligned */ extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe { //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); switch (alignment) { case cast(structalign_t)1: // No alignment break; case cast(structalign_t)STRUCTALIGN_DEFAULT: // Alignment in Target::fieldalignsize must match what the // corresponding C compiler's default alignment behavior is. assert(size > 0 && !(size & (size - 1))); *poffset = (*poffset + size - 1) & ~(size - 1); break; default: // Align on alignment boundary, which must be a positive power of 2 assert(alignment > 0 && !(alignment & (alignment - 1))); *poffset = (*poffset + alignment - 1) & ~(alignment - 1); break; } } /**************************************** * Place a member (mem) into an aggregate (agg), which can be a struct, union or class * Returns: * offset to place field at * * nextoffset: next location in aggregate * memsize: size of member * memalignsize: natural alignment of member * alignment: alignment in effect for this member * paggsize: size of aggregate (updated) * paggalignsize: alignment of aggregate (updated) * isunion: the aggregate is a union */ extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize, structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion) { uint ofs = *nextoffset; const uint actualAlignment = alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment; // Ensure no overflow bool overflow; const sz = addu(memsize, actualAlignment, overflow); const sum = addu(ofs, sz, overflow); if (overflow) assert(0); alignmember(alignment, memalignsize, &ofs); uint memoffset = ofs; ofs += memsize; if (ofs > *paggsize) *paggsize = ofs; if (!isunion) *nextoffset = ofs; if (*paggalignsize < actualAlignment) *paggalignsize = actualAlignment; return memoffset; } override final Type getType() { return type; } // is aggregate deprecated? override final bool isDeprecated() { return isdeprecated; } /**************************************** * Returns true if there's an extra member which is the 'this' * pointer to the enclosing context (enclosing aggregate or function) */ final bool isNested() { return enclosing !is null; } /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested. */ final void makeNested() { if (enclosing) // if already nested return; if (sizeok == Sizeok.done) return; if (isUnionDeclaration() || isInterfaceDeclaration()) return; if (storage_class & STC.static_) return; // If nested struct, add in hidden 'this' pointer to outer scope auto s = toParent2(); if (!s) return; Type t = null; if (auto fd = s.isFuncDeclaration()) { enclosing = fd; /* https://issues.dlang.org/show_bug.cgi?id=14422 * If a nested class parent is a function, its * context pointer (== `outer`) should be void* always. */ t = Type.tvoidptr; } else if (auto ad = s.isAggregateDeclaration()) { if (isClassDeclaration() && ad.isClassDeclaration()) { enclosing = ad; } else if (isStructDeclaration()) { if (auto ti = ad.parent.isTemplateInstance()) { enclosing = ti.enclosing; } } t = ad.handleType(); } if (enclosing) { //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars()); assert(t); if (t.ty == Tstruct) t = Type.tvoidptr; // t should not be a ref type assert(!vthis); vthis = new ThisDeclaration(loc, t); //vthis.storage_class |= STC.ref_; // Emulate vthis.addMember() members.push(vthis); // Emulate vthis.dsymbolSemantic() vthis.storage_class |= STC.field; vthis.parent = this; vthis.protection = Prot(Prot.Kind.public_); vthis.alignment = t.alignment(); vthis.semanticRun = PASS.semanticdone; if (sizeok == Sizeok.fwd) fields.push(vthis); } } override final bool isExport() const { return protection.kind == Prot.Kind.export_; } /******************************************* * Look for constructor declaration. */ final Dsymbol searchCtor() { auto s = search(Loc.initial, Id.ctor); if (s) { if (!(s.isCtorDeclaration() || s.isTemplateDeclaration() || s.isOverloadSet())) { s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation"); errors = true; s = null; } } if (s && s.toParent() != this) s = null; // search() looks through ancestor classes if (s) { // Finish all constructors semantics to determine this.noDefaultCtor. struct SearchCtor { extern (C++) static int fp(Dsymbol s, void* ctxt) { auto f = s.isCtorDeclaration(); if (f && f.semanticRun == PASS.init) f.dsymbolSemantic(null); return 0; } } for (size_t i = 0; i < members.dim; i++) { auto sm = (*members)[i]; sm.apply(&SearchCtor.fp, null); } } return s; } override final Prot prot() { return protection; } // 'this' type final Type handleType() { return type; } // Back end Symbol* stag; // tag symbol for debug data Symbol* sinit; override final inout(AggregateDeclaration) isAggregateDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/aggregate.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.h */ #pragma once #include "dsymbol.h" #include "objc.h" class Identifier; class Type; class TypeFunction; class Expression; class FuncDeclaration; class CtorDeclaration; class DtorDeclaration; class NewDeclaration; class DeleteDeclaration; class InterfaceDeclaration; class TypeInfoClassDeclaration; class VarDeclaration; enum Sizeok { SIZEOKnone, // size of aggregate is not yet able to compute SIZEOKfwd, // size of aggregate is ready to compute SIZEOKdone // size of aggregate is set correctly }; enum Baseok { BASEOKnone, // base classes not computed yet BASEOKin, // in process of resolving base classes BASEOKdone, // all base classes are resolved BASEOKsemanticdone // all base classes semantic done }; enum StructPOD { ISPODno, // struct is not POD ISPODyes, // struct is POD ISPODfwd // POD not yet computed }; enum Abstract { ABSfwdref = 0, // whether an abstract class is not yet computed ABSyes, // is abstract class ABSno // is not abstract class }; FuncDeclaration *search_toString(StructDeclaration *sd); struct ClassKind { enum Type { /// the aggregate is a d(efault) struct/class/interface d, /// the aggregate is a C++ struct/class/interface cpp, /// the aggregate is an Objective-C class/interface objc }; }; class AggregateDeclaration : public ScopeDsymbol { public: Type *type; StorageClass storage_class; Prot protection; unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes VarDeclarations fields; // VarDeclaration fields Sizeok sizeok; // set when structsize contains valid data Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol bool isdeprecated; // true if deprecated ClassKind::Type classKind; // specifies the linkage type /* !=NULL if is nested * pointing to the dsymbol that directly enclosing it. * 1. The function that enclosing it (nested struct and class) * 2. The class that enclosing it (nested class only) * 3. If enclosing aggregate is template, its enclosing dsymbol. * See AggregateDeclaraton::makeNested for the details. */ Dsymbol *enclosing; VarDeclaration *vthis; // 'this' parameter if this aggregate is nested // Special member functions FuncDeclarations invs; // Array of invariants FuncDeclaration *inv; // invariant NewDeclaration *aggNew; // allocator DeleteDeclaration *aggDelete; // deallocator Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration // default constructor - should have no arguments, because // it would be stored in TypeInfo_Class.defaultConstructor CtorDeclaration *defaultCtor; Dsymbol *aliasthis; // forward unresolved lookups to aliasthis bool noDefaultCtor; // no default construction DtorDeclarations dtors; // Array of destructors DtorDeclaration *dtor; // aggregate destructor DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI) FuncDeclaration *fieldDtor; // aggregate destructor for just the fields Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) virtual Scope *newScope(Scope *sc); void setScope(Scope *sc); bool determineFields(); bool determineSize(Loc loc); virtual void finalizeSize() = 0; d_uns64 size(const Loc &loc); bool fill(Loc loc, Expressions *elements, bool ctorinit); Type *getType(); bool isDeprecated(); // is aggregate deprecated? bool isNested(); void makeNested(); bool isExport() const; Dsymbol *searchCtor(); Prot prot(); // 'this' type Type *handleType() { return type; } // Back end Symbol *stag; // tag symbol for debug data Symbol *sinit; AggregateDeclaration *isAggregateDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; struct StructFlags { enum Type { none = 0x0, hasPointers = 0x1 // NB: should use noPointers as in ClassFlags }; }; class StructDeclaration : public AggregateDeclaration { public: bool zeroInit; // !=0 if initialize with 0 fill bool hasIdentityAssign; // true if has identity opAssign bool hasIdentityEquals; // true if has identity opEquals bool hasNoFields; // has no fields FuncDeclarations postblits; // Array of postblit functions FuncDeclaration *postblit; // aggregate postblit FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals FuncDeclaration *xcmp; // TypeInfo_Struct.xopCmp FuncDeclaration *xhash; // TypeInfo_Struct.xtoHash static FuncDeclaration *xerreq; // object.xopEquals static FuncDeclaration *xerrcmp; // object.xopCmp structalign_t alignment; // alignment applied outside of the struct StructPOD ispod; // if struct is POD // For 64 bit Efl function call/return ABI Type *arg1type; Type *arg2type; // Even if struct is defined as non-root symbol, some built-in operations // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo. // For those, today TypeInfo_Struct is generated in COMDAT. bool requestTypeInfo; static StructDeclaration *create(Loc loc, Identifier *id, bool inObject); Dsymbol *syntaxCopy(Dsymbol *s); void semanticTypeInfoMembers(); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); const char *kind() const; void finalizeSize(); bool fit(const Loc &loc, Scope *sc, Expressions *elements, Type *stype); bool isPOD(); StructDeclaration *isStructDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class UnionDeclaration : public StructDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *s); const char *kind() const; UnionDeclaration *isUnionDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; struct BaseClass { Type *type; // (before semantic processing) ClassDeclaration *sym; unsigned offset; // 'this' pointer offset // for interfaces: Array of FuncDeclaration's // making up the vtbl[] FuncDeclarations vtbl; DArray baseInterfaces; // if BaseClass is an interface, these // are a copy of the InterfaceDeclaration::interfaces BaseClass(); BaseClass(Type *type); bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); void copyBaseInterfaces(BaseClasses *); }; struct ClassFlags { enum Type { none = 0x0, isCOMclass = 0x1, noPointers = 0x2, hasOffTi = 0x4, hasCtor = 0x8, hasGetMembers = 0x10, hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100 }; }; class ClassDeclaration : public AggregateDeclaration { public: static ClassDeclaration *object; static ClassDeclaration *throwable; static ClassDeclaration *exception; static ClassDeclaration *errorException; static ClassDeclaration *cpp_type_info_ptr; ClassDeclaration *baseClass; // NULL only if this is Object FuncDeclaration *staticCtor; FuncDeclaration *staticDtor; Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] BaseClasses *baseclasses; // Array of BaseClass's; first is super, // rest are Interface's DArray interfaces; // interfaces[interfaces_dim] for this class // (does not include baseClass) BaseClasses *vtblInterfaces; // array of base interfaces that have // their own vtbl[] TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration bool com; // true if this is a COM class (meaning it derives from IUnknown) bool stack; // true if this is a scope class int cppDtorVtblIndex; // slot reserved for the virtual destructor [extern(C++)] bool inuse; // to prevent recursive attempts bool isActuallyAnonymous; // true if this class has an identifier, but was originally declared anonymous // used in support of https://issues.dlang.org/show_bug.cgi?id=17371 Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract Baseok baseok; // set the progress of base classes resolving ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); bool isBaseOf2(ClassDeclaration *cd); #define OFFSET_RUNTIME 0x76543210 #define OFFSET_FWDREF 0x76543211 virtual bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isAnonymous(); bool isBaseInfoComplete(); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); ClassDeclaration *searchBase(Identifier *ident); void finalizeSize(); bool isFuncHidden(FuncDeclaration *fd); FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); bool isCOMclass() const; virtual bool isCOMinterface() const; bool isCPPclass() const; virtual bool isCPPinterface() const; bool isAbstract(); virtual int vtblOffset() const; const char *kind() const; void addLocalClass(ClassDeclarations *); // Back end Dsymbol *vtblsym; Dsymbol *vtblSymbol(); ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } void accept(Visitor *v) { v->visit(this); } }; class InterfaceDeclaration : public ClassDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseOf(BaseClass *bc, int *poffset); const char *kind() const; int vtblOffset() const; bool isCPPinterface() const; bool isCOMinterface() const; InterfaceDeclaration *isInterfaceDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/aliasthis.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/aliasthis.d, _aliasthis.d) * Documentation: https://dlang.org/phobos/dmd_aliasthis.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aliasthis.d */ module dmd.aliasthis; import core.stdc.stdio; import dmd.aggregate; import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.expressionsem; import dmd.globals; import dmd.identifier; import dmd.mtype; import dmd.opover; import dmd.tokens; import dmd.visitor; /*********************************************************** * alias ident this; */ extern (C++) final class AliasThis : Dsymbol { Identifier ident; extern (D) this(const ref Loc loc, Identifier ident) { super(null); // it's anonymous (no identifier) this.loc = loc; this.ident = ident; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new AliasThis(loc, ident); } override const(char)* kind() const { return "alias this"; } AliasThis isAliasThis() { return this; } override void accept(Visitor v) { v.visit(this); } } Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false) { for (AggregateDeclaration ad = isAggregate(e.type); ad;) { if (ad.aliasthis) { uint olderrors = gag ? global.startGagging() : 0; Loc loc = e.loc; Type tthis = (e.op == TOK.type ? e.type : null); e = new DotIdExp(loc, e, ad.aliasthis.ident); e = e.expressionSemantic(sc); if (tthis && ad.aliasthis.needThis()) { if (e.op == TOK.variable) { if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) { // https://issues.dlang.org/show_bug.cgi?id=13009 // Support better match for the overloaded alias this. bool hasOverloads; if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) { if (!hasOverloads) fd = f; // use exact match e = new VarExp(loc, fd, hasOverloads); e.type = f.type; e = new CallExp(loc, e); goto L1; } } } /* non-@property function is not called inside typeof(), * so resolve it ahead. */ { int save = sc.intypeof; sc.intypeof = 1; // bypass "need this" error check e = resolveProperties(sc, e); sc.intypeof = save; } L1: e = new TypeExp(loc, new TypeTypeof(loc, e)); e = e.expressionSemantic(sc); } e = resolveProperties(sc, e); if (gag && global.endGagging(olderrors)) e = null; } import dmd.dclass : ClassDeclaration; auto cd = ad.isClassDeclaration(); if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) { ad = cd.baseClass; continue; } break; } return e; } ================================================ FILE: gcc/d/dmd/apply.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/apply.d, _apply.d) * Documentation: https://dlang.org/phobos/dmd_apply.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d */ module dmd.apply; import dmd.arraytypes; import dmd.dtemplate; import dmd.expression; import dmd.visitor; /************************************** * An Expression tree walker that will visit each Expression e in the tree, * in depth-first evaluation order, and call fp(e,param) on it. * fp() signals whether the walking continues with its return value: * Returns: * 0 continue * 1 done * It's a bit slower than using virtual functions, but more encapsulated and less brittle. * Creating an iterator for this would be much more complex. */ private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor { alias visit = typeof(super).visit; public: StoppableVisitor v; extern (D) this(StoppableVisitor v) { this.v = v; } bool doCond(Expression e) { if (!stop && e) e.accept(this); return stop; } bool doCond(Expressions* e) { if (!e) return false; for (size_t i = 0; i < e.dim && !stop; i++) doCond((*e)[i]); return stop; } bool applyTo(Expression e) { e.accept(v); stop = v.stop; return true; } override void visit(Expression e) { applyTo(e); } override void visit(NewExp e) { //printf("NewExp::apply(): %s\n", toChars()); doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); } override void visit(NewAnonClassExp e) { //printf("NewAnonClassExp::apply(): %s\n", toChars()); doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e); } override void visit(TypeidExp e) { doCond(isExpression(e.obj)) || applyTo(e); } override void visit(UnaExp e) { doCond(e.e1) || applyTo(e); } override void visit(BinExp e) { doCond(e.e1) || doCond(e.e2) || applyTo(e); } override void visit(AssertExp e) { //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); doCond(e.e1) || doCond(e.msg) || applyTo(e); } override void visit(CallExp e) { //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); doCond(e.e1) || doCond(e.arguments) || applyTo(e); } override void visit(ArrayExp e) { //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); doCond(e.e1) || doCond(e.arguments) || applyTo(e); } override void visit(SliceExp e) { doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e); } override void visit(ArrayLiteralExp e) { doCond(e.basis) || doCond(e.elements) || applyTo(e); } override void visit(AssocArrayLiteralExp e) { doCond(e.keys) || doCond(e.values) || applyTo(e); } override void visit(StructLiteralExp e) { if (e.stageflags & stageApply) return; int old = e.stageflags; e.stageflags |= stageApply; doCond(e.elements) || applyTo(e); e.stageflags = old; } override void visit(TupleExp e) { doCond(e.e0) || doCond(e.exps) || applyTo(e); } override void visit(CondExp e) { doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e); } } bool walkPostorder(Expression e, StoppableVisitor v) { scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v); e.accept(pv); return v.stop; } ================================================ FILE: gcc/d/dmd/argtypes.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/argtypes.d, _argtypes.d) * Documentation: https://dlang.org/phobos/dmd_argtypes.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/argtypes.d */ module dmd.argtypes; import core.stdc.stdio; import core.checkedint; import dmd.declaration; import dmd.globals; import dmd.mtype; import dmd.visitor; /**************************************************** * This breaks a type down into 'simpler' types that can be passed to a function * in registers, and returned in registers. * It's highly platform dependent. * Params: * t = type to break down * Returns: * tuple of types, each element can be passed in a register. * A tuple of zero length means the type cannot be passed/returned in registers. * null indicates a `void`. * References: * For 64 bit code, follows Itanium C++ ABI 1.86 Chapter 3 * http://refspecs.linux-foundation.org/cxxabi-1.86.html#calls */ TypeTuple toArgTypes(Type t) { extern (C++) final class ToArgTypes : Visitor { alias visit = Visitor.visit; public: TypeTuple result; /***** * Pass type in memory (i.e. on the stack), a tuple of one type, or a tuple of 2 types */ void memory() { //printf("\ttoArgTypes() %s => [ ]\n", t.toChars()); result = new TypeTuple(); // pass on the stack } /// void oneType(Type t) { result = new TypeTuple(t); } /// void twoTypes(Type t1, Type t2) { result = new TypeTuple(t1, t2); } override void visit(Type) { // not valid for a parameter } override void visit(TypeError) { result = new TypeTuple(Type.terror); } override void visit(TypeBasic t) { Type t1 = null; Type t2 = null; switch (t.ty) { case Tvoid: return; case Tbool: case Tint8: case Tuns8: case Tint16: case Tuns16: case Tint32: case Tuns32: case Tfloat32: case Tint64: case Tuns64: case Tint128: case Tuns128: case Tfloat64: case Tfloat80: t1 = t; break; case Timaginary32: t1 = Type.tfloat32; break; case Timaginary64: t1 = Type.tfloat64; break; case Timaginary80: t1 = Type.tfloat80; break; case Tcomplex32: if (global.params.is64bit) t1 = Type.tfloat64; else { t1 = Type.tfloat64; t2 = Type.tfloat64; } break; case Tcomplex64: t1 = Type.tfloat64; t2 = Type.tfloat64; break; case Tcomplex80: t1 = Type.tfloat80; t2 = Type.tfloat80; break; case Tchar: t1 = Type.tuns8; break; case Twchar: t1 = Type.tuns16; break; case Tdchar: t1 = Type.tuns32; break; default: assert(0); } if (t1) { if (t2) return twoTypes(t1, t2); else return oneType(t1); } else return memory(); } override void visit(TypeVector t) { return oneType(t); } override void visit(TypeAArray) { return oneType(Type.tvoidptr); } override void visit(TypePointer) { return oneType(Type.tvoidptr); } /************************************* * Convert a floating point type into the equivalent integral type. */ static Type mergeFloatToInt(Type t) { switch (t.ty) { case Tfloat32: case Timaginary32: t = Type.tint32; break; case Tfloat64: case Timaginary64: case Tcomplex32: t = Type.tint64; break; default: debug { printf("mergeFloatToInt() %s\n", t.toChars()); } assert(0); } return t; } /************************************* * This merges two types into an 8byte type. * Params: * t1 = first type (can be null) * t2 = second type (can be null) * offset2 = offset of t2 from start of t1 * Returns: * type that encompasses both t1 and t2, null if cannot be done */ static Type argtypemerge(Type t1, Type t2, uint offset2) { //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1.toChars() : "", t2 ? t2.toChars() : "", offset2); if (!t1) { assert(!t2 || offset2 == 0); return t2; } if (!t2) return t1; const sz1 = t1.size(Loc.initial); const sz2 = t2.size(Loc.initial); assert(sz1 != SIZE_INVALID && sz2 != SIZE_INVALID); if (t1.ty != t2.ty && (t1.ty == Tfloat80 || t2.ty == Tfloat80)) return null; // [float,float] => [cfloat] if (t1.ty == Tfloat32 && t2.ty == Tfloat32 && offset2 == 4) return Type.tfloat64; // Merging floating and non-floating types produces the non-floating type if (t1.isfloating()) { if (!t2.isfloating()) t1 = mergeFloatToInt(t1); } else if (t2.isfloating()) t2 = mergeFloatToInt(t2); Type t; // Pick type with larger size if (sz1 < sz2) t = t2; else t = t1; // If t2 does not lie within t1, need to increase the size of t to enclose both bool overflow; const offset3 = addu(offset2, sz2, overflow); assert(!overflow); if (offset2 && sz1 < offset3) { switch (offset3) { case 2: t = Type.tint16; break; case 3: case 4: t = Type.tint32; break; default: t = Type.tint64; break; } } return t; } override void visit(TypeDArray) { /* Should be done as if it were: * struct S { size_t length; void* ptr; } */ if (global.params.is64bit && !global.params.isLP64) { // For AMD64 ILP32 ABI, D arrays fit into a single integer register. const offset = cast(uint)Type.tsize_t.size(Loc.initial); Type t = argtypemerge(Type.tsize_t, Type.tvoidptr, offset); if (t) { return oneType(t); } } return twoTypes(Type.tsize_t, Type.tvoidptr); } override void visit(TypeDelegate) { /* Should be done as if it were: * struct S { void* funcptr; void* ptr; } */ if (global.params.is64bit && !global.params.isLP64) { // For AMD64 ILP32 ABI, delegates fit into a single integer register. const offset = cast(uint)Type.tsize_t.size(Loc.initial); Type t = argtypemerge(Type.tvoidptr, Type.tvoidptr, offset); if (t) { return oneType(t); } } return twoTypes(Type.tvoidptr, Type.tvoidptr); } override void visit(TypeSArray t) { const sz = t.size(Loc.initial); if (sz > 16) return memory(); const dim = t.dim.toInteger(); Type tn = t.next; const tnsize = tn.size(); const tnalignsize = tn.alignsize(); /***** * Get the nth element of this array. * Params: * n = element number, from 0..dim * offset = set to offset of the element from the start of the array * alignsize = set to the aligned size of the element * Returns: * type of the element */ extern (D) Type getNthElement(size_t n, out uint offset, out uint alignsize) { offset = cast(uint)(n * tnsize); alignsize = tnalignsize; return tn; } aggregate(sz, cast(size_t)dim, &getNthElement); } override void visit(TypeStruct t) { //printf("TypeStruct.toArgTypes() %s\n", t.toChars()); if (!t.sym.isPOD()) return memory(); /***** * Get the nth field of this struct. * Params: * n = field number, from 0..nfields * offset = set to offset of the field from the start of the type * alignsize = set to the aligned size of the field * Returns: * type of the field */ extern (D) Type getNthField(size_t n, out uint offset, out uint alignsize) { auto field = t.sym.fields[n]; offset = field.offset; alignsize = field.type.alignsize(); return field.type; } aggregate(t.size(Loc.initial), t.sym.fields.dim, &getNthField); } /******************* * Handle aggregates (struct, union, and static array) and set `result` * Params: * sz = total size of aggregate * nfields = number of fields in the aggregate (dimension for static arrays) * getFieldInfo = get information about the nth field in the aggregate */ extern (D) void aggregate(d_uns64 sz, size_t nfields, Type delegate(size_t, out uint, out uint) getFieldInfo) { if (nfields == 0) return memory(); if (global.params.is64bit) { if (sz == 0 || sz > 16) return memory(); Type t1 = null; Type t2 = null; foreach (n; 0 .. nfields) { uint foffset; uint falignsize; Type ftype = getFieldInfo(n, foffset, falignsize); //printf(" [%u] ftype = %s\n", n, ftype.toChars()); TypeTuple tup = toArgTypes(ftype); if (!tup) return memory(); const dim = tup.arguments.dim; Type ft1 = null; Type ft2 = null; switch (dim) { case 2: ft1 = (*tup.arguments)[0].type; ft2 = (*tup.arguments)[1].type; break; case 1: if (foffset < 8) ft1 = (*tup.arguments)[0].type; else ft2 = (*tup.arguments)[0].type; break; default: return memory(); } if (foffset & 7) { // Misaligned fields goto Lmemory if (foffset & (falignsize - 1)) return memory(); // Fields that overlap the 8byte boundary goto memory const fieldsz = ftype.size(Loc.initial); bool overflow; const nextOffset = addu(foffset, fieldsz, overflow); assert(!overflow); if (foffset < 8 && nextOffset > 8) return memory(); } // First field in 8byte must be at start of 8byte assert(t1 || foffset == 0); //printf("ft1 = %s\n", ft1 ? ft1.toChars() : "null"); //printf("ft2 = %s\n", ft2 ? ft2.toChars() : "null"); if (ft1) { t1 = argtypemerge(t1, ft1, foffset); if (!t1) return memory(); } if (ft2) { const off2 = ft1 ? 8 : foffset; if (!t2 && off2 != 8) return memory(); assert(t2 || off2 == 8); t2 = argtypemerge(t2, ft2, off2 - 8); if (!t2) return memory(); } } if (t2) { if (t1.isfloating() && t2.isfloating()) { if ((t1.ty == Tfloat32 || t1.ty == Tfloat64) && (t2.ty == Tfloat32 || t2.ty == Tfloat64)) { } else return memory(); } else if (t1.isfloating() || t2.isfloating()) return memory(); return twoTypes(t1, t2); } //printf("\ttoArgTypes() %s => [%s,%s]\n", t.toChars(), t1 ? t1.toChars() : "", t2 ? t2.toChars() : ""); if (t1) return oneType(t1); else return memory(); } else { Type t1 = null; switch (cast(uint)sz) { case 1: t1 = Type.tint8; break; case 2: t1 = Type.tint16; break; case 4: t1 = Type.tint32; break; case 8: t1 = Type.tint64; break; case 16: t1 = null; // could be a TypeVector break; default: return memory(); } if (global.params.isFreeBSD && nfields == 1 && (sz == 4 || sz == 8)) { /* FreeBSD changed their 32 bit ABI at some point before 10.3 for the following: * struct { float f; } => arg1type is float * struct { double d; } => arg1type is double * Cannot find any documentation on it. */ uint foffset; uint falignsize; Type ftype = getFieldInfo(0, foffset, falignsize); TypeTuple tup = toArgTypes(ftype); if (tup && tup.arguments.dim == 1) { Type ft1 = (*tup.arguments)[0].type; if (ft1.ty == Tfloat32 || ft1.ty == Tfloat64) return oneType(ft1); } } if (t1) return oneType(t1); else return memory(); } } override void visit(TypeEnum t) { t.toBasetype().accept(this); } override void visit(TypeClass) { result = new TypeTuple(Type.tvoidptr); } } scope ToArgTypes v = new ToArgTypes(); t.accept(v); return v.result; } ================================================ FILE: gcc/d/dmd/arrayop.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/arrayop.d, _arrayop.d) * Documentation: https://dlang.org/phobos/dmd_arrayop.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arrayop.d */ module dmd.arrayop; import core.stdc.stdio; import dmd.arraytypes; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.statement; import dmd.tokens; import dmd.visitor; /********************************************** * Check that there are no uses of arrays without []. */ bool isArrayOpValid(Expression e) { if (e.op == TOK.slice) return true; if (e.op == TOK.arrayLiteral) { Type t = e.type.toBasetype(); while (t.ty == Tarray || t.ty == Tsarray) t = t.nextOf().toBasetype(); return (t.ty != Tvoid); } Type tb = e.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (isUnaArrayOp(e.op)) { return isArrayOpValid((cast(UnaExp)e).e1); } if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign) { BinExp be = cast(BinExp)e; return isArrayOpValid(be.e1) && isArrayOpValid(be.e2); } if (e.op == TOK.construct) { BinExp be = cast(BinExp)e; return be.e1.op == TOK.slice && isArrayOpValid(be.e2); } // if (e.op == TOK.call) // { // TODO: Decide if [] is required after arrayop calls. // } return false; } return true; } bool isNonAssignmentArrayOp(Expression e) { if (e.op == TOK.slice) return isNonAssignmentArrayOp((cast(SliceExp)e).e1); Type tb = e.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { return (isUnaArrayOp(e.op) || isBinArrayOp(e.op)); } return false; } bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false) { if (isNonAssignmentArrayOp(e)) { const(char)* s = ""; if (suggestion) s = " (possible missing [])"; e.error("array operation `%s` without destination memory not allowed%s", e.toChars(), s); return true; } return false; } /*********************************** * Construct the array operation expression, call object._arrayOp!(tiargs)(args). * Encode operand types and operations into tiargs using reverse polish notation (RPN) to preserve precedence. * Unary operations are prefixed with "u" (e.g. "u~"). * Pass operand values (slices or scalars) as args. * * Scalar expression sub-trees of `e` are evaluated before calling * into druntime to hoist them out of the loop. This is a valid * evaluation order as the actual array operations have no * side-effect. */ Expression arrayOp(BinExp e, Scope* sc) { //printf("BinExp.arrayOp() %s\n", toChars()); Type tb = e.type.toBasetype(); assert(tb.ty == Tarray || tb.ty == Tsarray); Type tbn = tb.nextOf().toBasetype(); if (tbn.ty == Tvoid) { e.error("cannot perform array operations on `void[]` arrays"); return new ErrorExp(); } if (!isArrayOpValid(e)) return arrayOpInvalidError(e); auto tiargs = new Objects(); auto args = new Expressions(); buildArrayOp(sc, e, tiargs, args); import dmd.dtemplate : TemplateDeclaration; __gshared TemplateDeclaration arrayOp; if (arrayOp is null) { Expression id = new IdentifierExp(e.loc, Id.empty); id = new DotIdExp(e.loc, id, Id.object); id = new DotIdExp(e.loc, id, Identifier.idPool("_arrayOp")); id = id.expressionSemantic(sc); if (id.op != TOK.template_) ObjectNotFound(Identifier.idPool("_arrayOp")); arrayOp = (cast(TemplateExp)id).td; } auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, args); if (!fd || fd.errors) return new ErrorExp(); return new CallExp(e.loc, new VarExp(e.loc, fd, false), args).expressionSemantic(sc); } /// ditto Expression arrayOp(BinAssignExp e, Scope* sc) { //printf("BinAssignExp.arrayOp() %s\n", toChars()); /* Check that the elements of e1 can be assigned to */ Type tn = e.e1.type.toBasetype().nextOf(); if (tn && (!tn.isMutable() || !tn.isAssignable())) { e.error("slice `%s` is not mutable", e.e1.toChars()); return new ErrorExp(); } if (e.e1.op == TOK.arrayLiteral) { return e.e1.modifiableLvalue(sc, e.e1); } return arrayOp(cast(BinExp)e, sc); } /****************************************** * Convert the expression tree e to template and function arguments, * using reverse polish notation (RPN) to encode order of operations. * Encode operations as string arguments, using a "u" prefix for unary operations. */ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* args) { extern (C++) final class BuildArrayOpVisitor : Visitor { alias visit = Visitor.visit; Scope* sc; Objects* tiargs; Expressions* args; public: extern (D) this(Scope* sc, Objects* tiargs, Expressions* args) { this.sc = sc; this.tiargs = tiargs; this.args = args; } override void visit(Expression e) { tiargs.push(e.type); args.push(e); } override void visit(SliceExp e) { visit(cast(Expression) e); } override void visit(CastExp e) { visit(cast(Expression) e); } override void visit(UnaExp e) { Type tb = e.type.toBasetype(); if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions { visit(cast(Expression) e); } else { // RPN, prefix unary ops with u OutBuffer buf; buf.writestring("u"); buf.writestring(Token.toString(e.op)); e.e1.accept(this); tiargs.push(new StringExp(Loc.initial, buf.extractString()).expressionSemantic(sc)); } } override void visit(BinExp e) { Type tb = e.type.toBasetype(); if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions { visit(cast(Expression) e); } else { // RPN e.e1.accept(this); e.e2.accept(this); tiargs.push(new StringExp(Loc.initial, cast(char*) Token.toChars(e.op)).expressionSemantic(sc)); } } } scope v = new BuildArrayOpVisitor(sc, tiargs, args); e.accept(v); } /*********************************************** * Test if expression is a unary array op. */ bool isUnaArrayOp(TOK op) { switch (op) { case TOK.negate: case TOK.tilde: return true; default: break; } return false; } /*********************************************** * Test if expression is a binary array op. */ bool isBinArrayOp(TOK op) { switch (op) { case TOK.add: case TOK.min: case TOK.mul: case TOK.div: case TOK.mod: case TOK.xor: case TOK.and: case TOK.or: case TOK.pow: return true; default: break; } return false; } /*********************************************** * Test if expression is a binary assignment array op. */ bool isBinAssignArrayOp(TOK op) { switch (op) { case TOK.addAssign: case TOK.minAssign: case TOK.mulAssign: case TOK.divAssign: case TOK.modAssign: case TOK.xorAssign: case TOK.andAssign: case TOK.orAssign: case TOK.powAssign: return true; default: break; } return false; } /*********************************************** * Test if operand is a valid array op operand. */ bool isArrayOpOperand(Expression e) { //printf("Expression.isArrayOpOperand() %s\n", e.toChars()); if (e.op == TOK.slice) return true; if (e.op == TOK.arrayLiteral) { Type t = e.type.toBasetype(); while (t.ty == Tarray || t.ty == Tsarray) t = t.nextOf().toBasetype(); return (t.ty != Tvoid); } Type tb = e.type.toBasetype(); if (tb.ty == Tarray) { return (isUnaArrayOp(e.op) || isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign); } return false; } /*************************************************** * Print error message about invalid array operation. * Params: * e = expression with the invalid array operation * Returns: * instance of ErrorExp */ ErrorExp arrayOpInvalidError(Expression e) { e.error("invalid array operation `%s` (possible missing [])", e.toChars()); return new ErrorExp(); } ================================================ FILE: gcc/d/dmd/arraytypes.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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); ================================================ FILE: gcc/d/dmd/arraytypes.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 2006-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.h */ #pragma once #include "root/array.h" typedef Array TemplateParameters; typedef Array Expressions; typedef Array Statements; typedef Array BaseClasses; typedef Array ClassDeclarations; typedef Array Dsymbols; typedef Array Objects; typedef Array DtorDeclarations; typedef Array FuncDeclarations; typedef Array Parameters; typedef Array Identifiers; typedef Array Initializers; typedef Array VarDeclarations; typedef Array Types; typedef Array Catches; typedef Array StaticDtorDeclarations; typedef Array SharedStaticDtorDeclarations; typedef Array AliasDeclarations; typedef Array Modules; typedef Array Files; typedef Array CaseStatements; typedef Array ScopeStatements; typedef Array GotoCaseStatements; typedef Array ReturnStatements; typedef Array GotoStatements; typedef Array TemplateInstances; typedef Array Ensures; ================================================ FILE: gcc/d/dmd/astcodegen.d ================================================ module dmd.astcodegen; /** * Documentation: https://dlang.org/phobos/dmd_astcodegen.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astcodegen.d */ struct ASTCodegen { public import dmd.aggregate; public import dmd.aliasthis; public import dmd.arraytypes; public import dmd.attrib; public import dmd.cond; public import dmd.dclass; public import dmd.declaration; public import dmd.denum; public import dmd.dimport; public import dmd.dmodule; public import dmd.dstruct; public import dmd.dsymbol; public import dmd.dtemplate; public import dmd.dversion; public import dmd.expression; public import dmd.func; public import dmd.hdrgen; public import dmd.init; public import dmd.initsem; public import dmd.mtype; public import dmd.nspace; public import dmd.statement; public import dmd.staticassert; public import dmd.typesem; public import dmd.ctfeexpr; alias initializerToExpression = dmd.initsem.initializerToExpression; alias typeToExpression = dmd.typesem.typeToExpression; alias UserAttributeDeclaration = dmd.attrib.UserAttributeDeclaration; alias Ensure = dmd.func.Ensure; // workaround for bug in older DMD frontends alias MODFlags = dmd.mtype.MODFlags; alias Type = dmd.mtype.Type; alias Parameter = dmd.mtype.Parameter; alias Taarray = dmd.mtype.Taarray; alias Tbool = dmd.mtype.Tbool; alias Tchar = dmd.mtype.Tchar; alias Tdchar = dmd.mtype.Tdchar; alias Tdelegate = dmd.mtype.Tdelegate; alias Tenum = dmd.mtype.Tenum; alias Terror = dmd.mtype.Terror; alias Tfloat32 = dmd.mtype.Tfloat32; alias Tfloat64 = dmd.mtype.Tfloat64; alias Tfloat80 = dmd.mtype.Tfloat80; alias Tfunction = dmd.mtype.Tfunction; alias Tident = dmd.mtype.Tident; alias Tint8 = dmd.mtype.Tint8; alias Tint16 = dmd.mtype.Tint16; alias Tint32 = dmd.mtype.Tint32; alias Tint64 = dmd.mtype.Tint64; alias Tsarray = dmd.mtype.Tsarray; alias Tstruct = dmd.mtype.Tstruct; alias Tuns8 = dmd.mtype.Tuns8; alias Tuns16 = dmd.mtype.Tuns16; alias Tuns32 = dmd.mtype.Tuns32; alias Tuns64 = dmd.mtype.Tuns64; alias Tvoid = dmd.mtype.Tvoid; alias Twchar = dmd.mtype.Twchar; alias STC = dmd.declaration.STC; alias Dsymbol = dmd.dsymbol.Dsymbol; alias Dsymbols = dmd.dsymbol.Dsymbols; alias Prot = dmd.dsymbol.Prot; alias stcToBuffer = dmd.hdrgen.stcToBuffer; alias linkageToChars = dmd.hdrgen.linkageToChars; alias protectionToChars = dmd.hdrgen.protectionToChars; alias isType = dmd.dtemplate.isType; alias isExpression = dmd.dtemplate.isExpression; alias isTuple = dmd.dtemplate.isTuple; } ================================================ FILE: gcc/d/dmd/attrib.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/attrib.d, _attrib.d) * Documentation: https://dlang.org/phobos/dmd_attrib.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d */ module dmd.attrib; import dmd.aggregate; import dmd.arraytypes; import dmd.cond; import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.target; import dmd.tokens; import dmd.visitor; /*********************************************************** */ extern (C++) abstract class AttribDeclaration : Dsymbol { Dsymbols* decl; // array of Dsymbol's extern (D) this(Dsymbols* decl) { this.decl = decl; } Dsymbols* include(Scope* sc) { if (errors) return null; return decl; } override final int apply(Dsymbol_apply_ft_t fp, void* param) { Dsymbols* d = include(_scope); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; if (s) { if (s.apply(fp, param)) return 1; } } } return 0; } /**************************************** * Create a new scope if one or more given attributes * are different from the sc's. * If the returned scope != sc, the caller should pop * the scope after it used. */ extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection, int explicitProtection, AlignDeclaration aligndecl, PINLINE inlining) { Scope* sc2 = sc; if (stc != sc.stc || linkage != sc.linkage || cppmangle != sc.cppmangle || !protection.isSubsetOf(sc.protection) || explicitProtection != sc.explicitProtection || aligndecl !is sc.aligndecl || inlining != sc.inlining) { // create new one for changes sc2 = sc.copy(); sc2.stc = stc; sc2.linkage = linkage; sc2.cppmangle = cppmangle; sc2.protection = protection; sc2.explicitProtection = explicitProtection; sc2.aligndecl = aligndecl; sc2.inlining = inlining; } return sc2; } /**************************************** * A hook point to supply scope for members. * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this. */ Scope* newScope(Scope* sc) { return sc; } override void addMember(Scope* sc, ScopeDsymbol sds) { Dsymbols* d = include(sc); if (d) { Scope* sc2 = newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); s.addMember(sc2, sds); } if (sc2 != sc) sc2.pop(); } } override void setScope(Scope* sc) { Dsymbols* d = include(sc); //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); if (d) { Scope* sc2 = newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.setScope(sc2); } if (sc2 != sc) sc2.pop(); } } override void importAll(Scope* sc) { Dsymbols* d = include(sc); //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); if (d) { Scope* sc2 = newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.importAll(sc2); } if (sc2 != sc) sc2.pop(); } } override void addComment(const(char)* comment) { //printf("AttribDeclaration::addComment %s\n", comment); if (comment) { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; //printf("AttribDeclaration::addComment %s\n", s.toChars()); s.addComment(comment); } } } } override const(char)* kind() const { return "attribute"; } override bool oneMember(Dsymbol* ps, Identifier ident) { Dsymbols* d = include(null); return Dsymbol.oneMembers(d, ps, ident); } override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.setFieldOffset(ad, poffset, isunion); } } } override final bool hasPointers() { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; if (s.hasPointers()) return true; } } return false; } override final bool hasStaticCtorOrDtor() { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; if (s.hasStaticCtorOrDtor()) return true; } } return false; } override final void checkCtorConstInit() { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.checkCtorConstInit(); } } } /**************************************** */ override final void addLocalClass(ClassDeclarations* aclasses) { Dsymbols* d = include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.addLocalClass(aclasses); } } } override final inout(AttribDeclaration) isAttribDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class StorageClassDeclaration : AttribDeclaration { StorageClass stc; extern (D) this(StorageClass stc, Dsymbols* decl) { super(decl); this.stc = stc; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { StorageClass scstc = sc.stc; /* These sets of storage classes are mutually exclusive, * so choose the innermost or most recent one. */ if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest)) scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest); if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared)) scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared); if (stc & (STC.const_ | STC.immutable_ | STC.manifest)) scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest); if (stc & (STC.gshared | STC.shared_ | STC.tls)) scstc &= ~(STC.gshared | STC.shared_ | STC.tls); if (stc & (STC.safe | STC.trusted | STC.system)) scstc &= ~(STC.safe | STC.trusted | STC.system); scstc |= stc; //printf("scstc = x%llx\n", scstc); return createNewScope(sc, scstc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); } override final bool oneMember(Dsymbol* ps, Identifier ident) { bool t = Dsymbol.oneMembers(decl, ps, ident); if (t && *ps) { /* This is to deal with the following case: * struct Tick { * template to(T) { const T to() { ... } } * } * For eponymous function templates, the 'const' needs to get attached to 'to' * before the semantic analysis of 'to', so that template overloading based on the * 'this' pointer can be successful. */ FuncDeclaration fd = (*ps).isFuncDeclaration(); if (fd) { /* Use storage_class2 instead of storage_class otherwise when we do .di generation * we'll wind up with 'const const' rather than 'const'. */ /* Don't think we need to worry about mutually exclusive storage classes here */ fd.storage_class2 |= stc; } } return t; } override void addMember(Scope* sc, ScopeDsymbol sds) { Dsymbols* d = include(sc); if (d) { Scope* sc2 = newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol) if (auto decl = s.isDeclaration()) { decl.storage_class |= stc & STC.local; if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? { sdecl.stc |= stc & STC.local; } } s.addMember(sc2, sds); } if (sc2 != sc) sc2.pop(); } } override inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration { Expression msg; const(char)* msgstr; extern (D) this(Expression msg, Dsymbols* decl) { super(STC.deprecated_, decl); this.msg = msg; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); } /** * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set * * Calls `StorageClassDeclaration.newScope` (as it must be called or copied * in any function overriding `newScope`), then set the `Scope`'s depdecl. * * Returns: * Always a new scope, to use for this `DeprecatedDeclaration`'s members. */ override Scope* newScope(Scope* sc) { auto scx = super.newScope(sc); // The enclosing scope is deprecated as well if (scx == sc) scx = sc.push(); scx.depdecl = this; return scx; } override void setScope(Scope* sc) { //printf("DeprecatedDeclaration::setScope() %p\n", this); if (decl) Dsymbol.setScope(sc); // for forward reference return AttribDeclaration.setScope(sc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class LinkDeclaration : AttribDeclaration { LINK linkage; extern (D) this(LINK p, Dsymbols* decl) { super(decl); //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); linkage = (p == LINK.system) ? Target.systemLinkage() : p; } static LinkDeclaration create(LINK p, Dsymbols* decl) { return new LinkDeclaration(p, decl); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); } override const(char)* toChars() const { return "extern ()"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CPPMangleDeclaration : AttribDeclaration { CPPMANGLE cppmangle; extern (D) this(CPPMANGLE p, Dsymbols* decl) { super(decl); //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl); cppmangle = p; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); } override const(char)* toChars() const { return "extern ()"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ProtDeclaration : AttribDeclaration { Prot protection; Identifiers* pkg_identifiers; /** * Params: * loc = source location of attribute token * p = protection attribute data * decl = declarations which are affected by this protection attribute */ extern (D) this(const ref Loc loc, Prot p, Dsymbols* decl) { super(decl); this.loc = loc; this.protection = p; //printf("decl = %p\n", decl); } /** * Params: * loc = source location of attribute token * pkg_identifiers = list of identifiers for a qualified package name * decl = declarations which are affected by this protection attribute */ extern (D) this(const ref Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl) { super(decl); this.loc = loc; this.protection.kind = Prot.Kind.package_; this.pkg_identifiers = pkg_identifiers; if (pkg_identifiers !is null && pkg_identifiers.dim > 0) { Dsymbol tmp; Package.resolve(pkg_identifiers, &tmp, null); protection.pkg = tmp ? tmp.isPackage() : null; } } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); if (protection.kind == Prot.Kind.package_) return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl)); else return new ProtDeclaration(this.loc, protection, Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { if (pkg_identifiers) dsymbolSemantic(this, sc); return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining); } override void addMember(Scope* sc, ScopeDsymbol sds) { if (pkg_identifiers) { Dsymbol tmp; Package.resolve(pkg_identifiers, &tmp, null); protection.pkg = tmp ? tmp.isPackage() : null; pkg_identifiers = null; } if (protection.kind == Prot.Kind.package_ && protection.pkg && sc._module) { Module m = sc._module; Package pkg = m.parent ? m.parent.isPackage() : null; if (!pkg || !protection.pkg.isAncestorPackageOf(pkg)) error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true)); } return AttribDeclaration.addMember(sc, sds); } override const(char)* kind() const { return "protection attribute"; } override const(char)* toPrettyChars(bool) { assert(protection.kind > Prot.Kind.undefined); OutBuffer buf; protectionToBuffer(&buf, protection); return buf.extractString(); } override inout(ProtDeclaration) isProtDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AlignDeclaration : AttribDeclaration { Expression ealign; enum structalign_t UNKNOWN = 0; static assert(STRUCTALIGN_DEFAULT != UNKNOWN); structalign_t salign = UNKNOWN; extern (D) this(const ref Loc loc, Expression ealign, Dsymbols* decl) { super(decl); this.loc = loc; this.ealign = ealign; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new AlignDeclaration(loc, ealign.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AnonDeclaration : AttribDeclaration { bool isunion; int sem; // 1 if successful semantic() uint anonoffset; // offset of anonymous struct uint anonstructsize; // size of anonymous struct uint anonalignsize; // size of anonymous struct for alignment purposes extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) { super(decl); this.loc = loc; this.isunion = isunion; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); } override void setScope(Scope* sc) { if (decl) Dsymbol.setScope(sc); return AttribDeclaration.setScope(sc); } override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); if (decl) { /* This works by treating an AnonDeclaration as an aggregate 'member', * so in order to place that member we need to compute the member's * size and alignment. */ size_t fieldstart = ad.fields.dim; /* Hackishly hijack ad's structsize and alignsize fields * for use in our fake anon aggregate member. */ uint savestructsize = ad.structsize; uint savealignsize = ad.alignsize; ad.structsize = 0; ad.alignsize = 0; uint offset = 0; for (size_t i = 0; i < decl.dim; i++) { Dsymbol s = (*decl)[i]; s.setFieldOffset(ad, &offset, this.isunion); if (this.isunion) offset = 0; } /* https://issues.dlang.org/show_bug.cgi?id=13613 * If the fields in this.members had been already * added in ad.fields, just update *poffset for the subsequent * field offset calculation. */ if (fieldstart == ad.fields.dim) { ad.structsize = savestructsize; ad.alignsize = savealignsize; *poffset = ad.structsize; return; } anonstructsize = ad.structsize; anonalignsize = ad.alignsize; ad.structsize = savestructsize; ad.alignsize = savealignsize; // 0 sized structs are set to 1 byte if (anonstructsize == 0) { anonstructsize = 1; anonalignsize = 1; } assert(_scope); auto alignment = _scope.alignment(); /* Given the anon 'member's size and alignment, * go ahead and place it. */ anonoffset = AggregateDeclaration.placeField( poffset, anonstructsize, anonalignsize, alignment, &ad.structsize, &ad.alignsize, isunion); // Add to the anon fields the base offset of this anonymous aggregate //printf("anon fields, anonoffset = %d\n", anonoffset); for (size_t i = fieldstart; i < ad.fields.dim; i++) { VarDeclaration v = ad.fields[i]; //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); v.offset += anonoffset; } } } override const(char)* kind() const { return (isunion ? "anonymous union" : "anonymous struct"); } override inout(AnonDeclaration) isAnonDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PragmaDeclaration : AttribDeclaration { Expressions* args; // array of Expression's extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) { super(decl); this.loc = loc; this.ident = ident; this.args = args; } override Dsymbol syntaxCopy(Dsymbol s) { //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); assert(!s); return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { if (ident == Id.Pinline) { PINLINE inlining = PINLINE.default_; if (!args || args.dim == 0) inlining = PINLINE.default_; else if (args.dim != 1) { error("one boolean expression expected for `pragma(inline)`, not %d", args.dim); args.setDim(1); (*args)[0] = new ErrorExp(); } else { Expression e = (*args)[0]; if (e.op != TOK.int64 || !e.type.equals(Type.tbool)) { if (e.op != TOK.error) { error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars()); (*args)[0] = new ErrorExp(); } } else if (e.isBool(true)) inlining = PINLINE.always; else if (e.isBool(false)) inlining = PINLINE.never; } return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); } return sc; } override const(char)* kind() const { return "pragma"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class ConditionalDeclaration : AttribDeclaration { Condition condition; Dsymbols* elsedecl; // array of Dsymbol's for else block extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) { super(decl); //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); this.condition = condition; this.elsedecl = elsedecl; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); } override final bool oneMember(Dsymbol* ps, Identifier ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); if (condition.inc) { Dsymbols* d = condition.include(null) ? decl : elsedecl; return Dsymbol.oneMembers(d, ps, ident); } else { bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); *ps = null; return res; } } // Decide if 'then' or 'else' code should be included override Dsymbols* include(Scope* sc) { //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope); if (errors) return null; assert(condition); return condition.include(_scope ? _scope : sc) ? decl : elsedecl; } override final void addComment(const(char)* comment) { /* Because addComment is called by the parser, if we called * include() it would define a version before it was used. * But it's no problem to drill down to both decl and elsedecl, * so that's the workaround. */ if (comment) { Dsymbols* d = decl; for (int j = 0; j < 2; j++) { if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; //printf("ConditionalDeclaration::addComment %s\n", s.toChars()); s.addComment(comment); } } d = elsedecl; } } } override void setScope(Scope* sc) { Dsymbols* d = include(sc); //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.setScope(sc); } } } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration { ScopeDsymbol scopesym; private bool addisdone = false; // true if members have been added to scope private bool onStack = false; // true if a call to `include` is currently active extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) { super(condition, decl, elsedecl); //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); } /**************************************** * Different from other AttribDeclaration subclasses, include() call requires * the completion of addMember and setScope phases. */ override Dsymbols* include(Scope* sc) { //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope); if (errors || onStack) return null; onStack = true; scope(exit) onStack = false; if (sc && condition.inc == 0) { assert(scopesym); // addMember is already done assert(_scope); // setScope is already done Dsymbols* d = ConditionalDeclaration.include(_scope); if (d && !addisdone) { // Add members lazily. for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.addMember(_scope, scopesym); } // Set the member scopes lazily. for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.setScope(_scope); } addisdone = true; } return d; } else { return ConditionalDeclaration.include(sc); } } override void addMember(Scope* sc, ScopeDsymbol sds) { //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); /* This is deferred until the condition evaluated later (by the include() call), * so that expressions in the condition can refer to declarations * in the same scope, such as: * * template Foo(int i) * { * const int j = i + 1; * static if (j == 3) * const int k; * } */ this.scopesym = sds; } override void setScope(Scope* sc) { // do not evaluate condition before semantic pass // But do set the scope, in case we need it for forward referencing Dsymbol.setScope(sc); } override void importAll(Scope* sc) { // do not evaluate condition before semantic pass } override const(char)* kind() const { return "static if"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Static foreach at declaration scope, like: * static foreach (i; [0, 1, 2]){ } */ extern (C++) final class StaticForeachDeclaration : AttribDeclaration { StaticForeach sfe; /// contains `static foreach` expansion logic ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration) /++ `include` can be called multiple times, but a `static foreach` should be expanded at most once. Achieved by caching the result of the first call. We need both `cached` and `cache`, because `null` is a valid value for `cache`. +/ bool onStack = false; bool cached = false; Dsymbols* cache = null; extern (D) this(StaticForeach sfe, Dsymbols* decl) { super(decl); this.sfe = sfe; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new StaticForeachDeclaration( sfe.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); } override bool oneMember(Dsymbol* ps, Identifier ident) { // Required to support IFTI on a template that contains a // `static foreach` declaration. `super.oneMember` calls // include with a `null` scope. As `static foreach` requires // the scope for expansion, `oneMember` can only return a // precise result once `static foreach` has been expanded. if (cached) { return super.oneMember(ps, ident); } *ps = null; // a `static foreach` declaration may in general expand to multiple symbols return false; } override Dsymbols* include(Scope* sc) { if (errors || onStack) return null; if (cached) { assert(!onStack); return cache; } onStack = true; scope(exit) onStack = false; if (_scope) { sfe.prepare(_scope); // lower static foreach aggregate } if (!sfe.ready()) { return null; // TODO: ok? } // expand static foreach import dmd.statementsem: makeTupleForeach; Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion); if (d) // process generated declarations { // Add members lazily. for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.addMember(_scope, scopesym); } // Set the member scopes lazily. for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.setScope(_scope); } } cached = true; cache = d; return d; } override void addMember(Scope* sc, ScopeDsymbol sds) { // used only for caching the enclosing symbol this.scopesym = sds; } override void addComment(const(char)* comment) { // do nothing // change this to give semantics to documentation comments on static foreach declarations } override void setScope(Scope* sc) { // do not evaluate condition before semantic pass // But do set the scope, in case we need it for forward referencing Dsymbol.setScope(sc); } override void importAll(Scope* sc) { // do not evaluate aggregate before semantic pass } override const(char)* kind() const { return "static foreach"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Collection of declarations that stores foreach index variables in a * local symbol table. Other symbols declared within are forwarded to * another scope, like: * * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict. * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable * } * * static foreach (i; 0.. 10) * { * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope * } * * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop * * A StaticForeachDeclaration generates one * ForwardingAttribDeclaration for each expansion of its body. The * AST of the ForwardingAttribDeclaration contains both the `static * foreach` variables and the respective copy of the `static foreach` * body. The functionality is achieved by using a * ForwardingScopeDsymbol as the parent symbol for the generated * declarations. */ extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration { ForwardingScopeDsymbol sym = null; this(Dsymbols* decl) { super(decl); sym = new ForwardingScopeDsymbol(null); sym.symtab = new DsymbolTable(); } /************************************** * Use the ForwardingScopeDsymbol as the parent symbol for members. */ override Scope* newScope(Scope* sc) { return sc.push(sym); } /*************************************** * Lazily initializes the scope to forward to. */ override void addMember(Scope* sc, ScopeDsymbol sds) { parent = sym.parent = sym.forward = sds; return super.addMember(sc, sym); } override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return this; } } /*********************************************************** * Mixin declarations, like: * mixin("int x"); * https://dlang.org/spec/module.html#mixin-declaration */ extern (C++) final class CompileDeclaration : AttribDeclaration { Expressions* exps; ScopeDsymbol scopesym; bool compiled; extern (D) this(const ref Loc loc, Expressions* exps) { super(null); //printf("CompileDeclaration(loc = %d)\n", loc.linnum); this.loc = loc; this.exps = exps; } override Dsymbol syntaxCopy(Dsymbol s) { //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps)); } override void addMember(Scope* sc, ScopeDsymbol sds) { //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); this.scopesym = sds; } override void setScope(Scope* sc) { Dsymbol.setScope(sc); } override const(char)* kind() const { return "mixin"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * User defined attributes look like: * @foo(args, ...) * @(args, ...) */ extern (C++) final class UserAttributeDeclaration : AttribDeclaration { Expressions* atts; extern (D) this(Expressions* atts, Dsymbols* decl) { super(decl); //printf("UserAttributeDeclaration()\n"); this.atts = atts; } override Dsymbol syntaxCopy(Dsymbol s) { //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); assert(!s); return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl)); } override Scope* newScope(Scope* sc) { Scope* sc2 = sc; if (atts && atts.dim) { // create new one for changes sc2 = sc.copy(); sc2.userAttribDecl = this; } return sc2; } override void setScope(Scope* sc) { //printf("UserAttributeDeclaration::setScope() %p\n", this); if (decl) Dsymbol.setScope(sc); // for forward reference of UDAs return AttribDeclaration.setScope(sc); } extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) { Expressions* udas; if (!udas1 || udas1.dim == 0) udas = udas2; else if (!udas2 || udas2.dim == 0) udas = udas1; else { /* Create a new tuple that combines them * (do not append to left operand, as this is a copy-on-write operation) */ udas = new Expressions(); udas.push(new TupleExp(Loc.initial, udas1)); udas.push(new TupleExp(Loc.initial, udas2)); } return udas; } Expressions* getAttributes() { if (auto sc = _scope) { _scope = null; arrayExpressionSemantic(atts, sc); } auto exps = new Expressions(); if (userAttribDecl) exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes())); if (atts && atts.dim) exps.push(new TupleExp(Loc.initial, atts)); return exps; } override const(char)* kind() const { return "UserAttribute"; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/attrib.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/attrib.h */ #pragma once #include "root/port.h" #include "dsymbol.h" class Expression; class Condition; class StaticForeach; /**************************************************************/ class AttribDeclaration : public Dsymbol { public: Dsymbols *decl; // array of Dsymbol's virtual Dsymbols *include(Scope *sc); int apply(Dsymbol_apply_ft_t fp, void *param); virtual Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); void importAll(Scope *sc); void addComment(const utf8_t *comment); const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); bool hasPointers(); bool hasStaticCtorOrDtor(); void checkCtorConstInit(); void addLocalClass(ClassDeclarations *); AttribDeclaration *isAttribDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class StorageClassDeclaration : public AttribDeclaration { public: StorageClass stc; Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); bool oneMember(Dsymbol **ps, Identifier *ident); void addMember(Scope *sc, ScopeDsymbol *sds); StorageClassDeclaration *isStorageClassDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class DeprecatedDeclaration : public StorageClassDeclaration { public: Expression *msg; const char *msgstr; Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void setScope(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class LinkDeclaration : public AttribDeclaration { public: LINK linkage; static LinkDeclaration *create(LINK p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); const char *toChars(); void accept(Visitor *v) { v->visit(this); } }; class CPPMangleDeclaration : public AttribDeclaration { public: CPPMANGLE cppmangle; Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); const char *toChars(); void accept(Visitor *v) { v->visit(this); } }; class ProtDeclaration : public AttribDeclaration { public: Prot protection; Identifiers* pkg_identifiers; Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); const char *kind() const; const char *toPrettyChars(bool unused); ProtDeclaration *isProtDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class AlignDeclaration : public AttribDeclaration { public: Expression *ealign; structalign_t salign; AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class AnonDeclaration : public AttribDeclaration { public: bool isunion; int sem; // 1 if successful semantic() unsigned anonoffset; // offset of anonymous struct unsigned anonstructsize; // size of anonymous struct unsigned anonalignsize; // size of anonymous struct for alignment purposes Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *kind() const; AnonDeclaration *isAnonDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class PragmaDeclaration : public AttribDeclaration { public: Expressions *args; // array of Expression's Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; class ConditionalDeclaration : public AttribDeclaration { public: Condition *condition; Dsymbols *elsedecl; // array of Dsymbol's for else block Dsymbol *syntaxCopy(Dsymbol *s); bool oneMember(Dsymbol **ps, Identifier *ident); Dsymbols *include(Scope *sc); void addComment(const utf8_t *comment); void setScope(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class StaticIfDeclaration : public ConditionalDeclaration { public: ScopeDsymbol *scopesym; bool addisdone; bool onStack; Dsymbol *syntaxCopy(Dsymbol *s); Dsymbols *include(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); void importAll(Scope *sc); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; class StaticForeachDeclaration : public ConditionalDeclaration { public: StaticForeach *sfe; ScopeDsymbol *scopesym; bool cached; Dsymbols *cache; Dsymbol *syntaxCopy(Dsymbol *s); bool oneMember(Dsymbol **ps, Identifier *ident); Dsymbols *include(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); void addComment(const utf8_t *comment); void setScope(Scope *sc); void importAll(Scope *sc); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; class ForwardingAttribDeclaration : AttribDeclaration { public: ForwardingScopeDsymbol *sym; Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; } }; // Mixin declarations class CompileDeclaration : public AttribDeclaration { public: Expressions *exps; ScopeDsymbol *scopesym; bool compiled; Dsymbol *syntaxCopy(Dsymbol *s); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; /** * User defined attributes look like: * @(args, ...) */ class UserAttributeDeclaration : public AttribDeclaration { public: Expressions *atts; Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); void setScope(Scope *sc); Expressions *getAttributes(); const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/blockexit.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/blockexit.d, _blockexit.d) * Documentation: https://dlang.org/phobos/dmd_blockexit.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/blockexit.d */ module dmd.blockexit; import core.stdc.stdio; import dmd.arraytypes; import dmd.canthrow; import dmd.dclass; import dmd.declaration; import dmd.expression; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.statement; import dmd.tokens; import dmd.visitor; /** * BE stands for BlockExit. * * It indicates if a statement does transfer control to another block. * A block is a sequence of statements enclosed in { } */ enum BE : int { none = 0, fallthru = 1, throw_ = 2, return_ = 4, goto_ = 8, halt = 0x10, break_ = 0x20, continue_ = 0x40, errthrow = 0x80, any = (fallthru | throw_ | return_ | goto_ | halt), } /********************************************* * Determine mask of ways that a statement can exit. * * Only valid after semantic analysis. * Params: * s = statement to check for block exit status * func = function that statement s is in * mustNotThrow = generate an error if it throws * Returns: * BE.xxxx */ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { extern (C++) final class BlockExit : Visitor { alias visit = Visitor.visit; public: FuncDeclaration func; bool mustNotThrow; int result; extern (D) this(FuncDeclaration func, bool mustNotThrow) { this.func = func; this.mustNotThrow = mustNotThrow; result = BE.none; } override void visit(Statement s) { printf("Statement::blockExit(%p)\n", s); printf("%s\n", s.toChars()); assert(0); } override void visit(ErrorStatement s) { result = BE.none; } override void visit(ExpStatement s) { result = BE.fallthru; if (s.exp) { if (s.exp.op == TOK.halt) { result = BE.halt; return; } if (s.exp.op == TOK.assert_) { AssertExp a = cast(AssertExp)s.exp; if (a.e1.isBool(false)) // if it's an assert(0) { result = BE.halt; return; } } if (canThrow(s.exp, func, mustNotThrow)) result |= BE.throw_; } } override void visit(CompileStatement s) { assert(global.errors); result = BE.fallthru; } override void visit(CompoundStatement cs) { //printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.dim, result); result = BE.fallthru; Statement slast = null; foreach (s; *cs.statements) { if (s) { //printf("result = x%x\n", result); //printf("s: %s\n", s.toChars()); if (result & BE.fallthru && slast) { slast = slast.last(); if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement())) { // Allow if last case/default was empty CaseStatement sc = slast.isCaseStatement(); DefaultStatement sd = slast.isDefaultStatement(); if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement())) { } else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement())) { } else { const(char)* gototype = s.isCaseStatement() ? "case" : "default"; s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype); } } } if (!(result & BE.fallthru) && !s.comeFrom()) { if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode()) s.warning("statement is not reachable"); } else { result &= ~BE.fallthru; result |= blockExit(s, func, mustNotThrow); } slast = s; } } } override void visit(UnrolledLoopStatement uls) { result = BE.fallthru; foreach (s; *uls.statements) { if (s) { int r = blockExit(s, func, mustNotThrow); result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru); if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0) result &= ~BE.fallthru; } } } override void visit(ScopeStatement s) { //printf("ScopeStatement::blockExit(%p)\n", s.statement); result = blockExit(s.statement, func, mustNotThrow); } override void visit(WhileStatement s) { assert(global.errors); result = BE.fallthru; } override void visit(DoStatement s) { if (s._body) { result = blockExit(s._body, func, mustNotThrow); if (result == BE.break_) { result = BE.fallthru; return; } if (result & BE.continue_) result |= BE.fallthru; } else result = BE.fallthru; if (result & BE.fallthru) { if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; if (!(result & BE.break_) && s.condition.isBool(true)) result &= ~BE.fallthru; } result &= ~(BE.break_ | BE.continue_); } override void visit(ForStatement s) { result = BE.fallthru; if (s._init) { result = blockExit(s._init, func, mustNotThrow); if (!(result & BE.fallthru)) return; } if (s.condition) { if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; if (s.condition.isBool(true)) result &= ~BE.fallthru; else if (s.condition.isBool(false)) return; } else result &= ~BE.fallthru; // the body must do the exiting if (s._body) { int r = blockExit(s._body, func, mustNotThrow); if (r & (BE.break_ | BE.goto_)) result |= BE.fallthru; result |= r & ~(BE.fallthru | BE.break_ | BE.continue_); } if (s.increment && canThrow(s.increment, func, mustNotThrow)) result |= BE.throw_; } override void visit(ForeachStatement s) { result = BE.fallthru; if (canThrow(s.aggr, func, mustNotThrow)) result |= BE.throw_; if (s._body) result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_); } override void visit(ForeachRangeStatement s) { assert(global.errors); result = BE.fallthru; } override void visit(IfStatement s) { //printf("IfStatement::blockExit(%p)\n", s); result = BE.none; if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; if (s.condition.isBool(true)) { result |= blockExit(s.ifbody, func, mustNotThrow); } else if (s.condition.isBool(false)) { result |= blockExit(s.elsebody, func, mustNotThrow); } else { result |= blockExit(s.ifbody, func, mustNotThrow); result |= blockExit(s.elsebody, func, mustNotThrow); } //printf("IfStatement::blockExit(%p) = x%x\n", s, result); } override void visit(ConditionalStatement s) { result = blockExit(s.ifbody, func, mustNotThrow); if (s.elsebody) result |= blockExit(s.elsebody, func, mustNotThrow); } override void visit(PragmaStatement s) { result = BE.fallthru; } override void visit(StaticAssertStatement s) { result = BE.fallthru; } override void visit(SwitchStatement s) { result = BE.none; if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; if (s._body) { result |= blockExit(s._body, func, mustNotThrow); if (result & BE.break_) { result |= BE.fallthru; result &= ~BE.break_; } } else result |= BE.fallthru; } override void visit(CaseStatement s) { result = blockExit(s.statement, func, mustNotThrow); } override void visit(DefaultStatement s) { result = blockExit(s.statement, func, mustNotThrow); } override void visit(GotoDefaultStatement s) { result = BE.goto_; } override void visit(GotoCaseStatement s) { result = BE.goto_; } override void visit(SwitchErrorStatement s) { // Switch errors are non-recoverable result = BE.halt; } override void visit(ReturnStatement s) { result = BE.return_; if (s.exp && canThrow(s.exp, func, mustNotThrow)) result |= BE.throw_; } override void visit(BreakStatement s) { //printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BE.goto_ : BE.break_); result = s.ident ? BE.goto_ : BE.break_; } override void visit(ContinueStatement s) { result = s.ident ? BE.continue_ | BE.goto_ : BE.continue_; } override void visit(SynchronizedStatement s) { result = blockExit(s._body, func, mustNotThrow); } override void visit(WithStatement s) { result = BE.none; if (canThrow(s.exp, func, mustNotThrow)) result = BE.throw_; result |= blockExit(s._body, func, mustNotThrow); } override void visit(TryCatchStatement s) { assert(s._body); result = blockExit(s._body, func, false); int catchresult = 0; foreach (c; *s.catches) { if (c.type == Type.terror) continue; int cresult = blockExit(c.handler, func, mustNotThrow); /* If we're catching Object, then there is no throwing */ Identifier id = c.type.toBasetype().isClassHandle().ident; if (c.internalCatch && (cresult & BE.fallthru)) { // https://issues.dlang.org/show_bug.cgi?id=11542 // leave blockExit flags of the body cresult &= ~BE.fallthru; } else if (id == Id.Object || id == Id.Throwable) { result &= ~(BE.throw_ | BE.errthrow); } else if (id == Id.Exception) { result &= ~BE.throw_; } catchresult |= cresult; } if (mustNotThrow && (result & BE.throw_)) { // now explain why this is nothrow blockExit(s._body, func, mustNotThrow); } result |= catchresult; } override void visit(TryFinallyStatement s) { result = BE.fallthru; if (s._body) result = blockExit(s._body, func, false); // check finally body as well, it may throw (bug #4082) int finalresult = BE.fallthru; if (s.finalbody) finalresult = blockExit(s.finalbody, func, false); // If either body or finalbody halts if (result == BE.halt) finalresult = BE.none; if (finalresult == BE.halt) result = BE.none; if (mustNotThrow) { // now explain why this is nothrow if (s._body && (result & BE.throw_)) blockExit(s._body, func, mustNotThrow); if (s.finalbody && (finalresult & BE.throw_)) blockExit(s.finalbody, func, mustNotThrow); } version (none) { // https://issues.dlang.org/show_bug.cgi?id=13201 // Mask to prevent spurious warnings for // destructor call, exit of synchronized statement, etc. if (result == BE.halt && finalresult != BE.halt && s.finalbody && s.finalbody.hasCode()) { s.finalbody.warning("statement is not reachable"); } } if (!(finalresult & BE.fallthru)) result &= ~BE.fallthru; result |= finalresult & ~BE.fallthru; } override void visit(OnScopeStatement s) { // At this point, this statement is just an empty placeholder result = BE.fallthru; } override void visit(ThrowStatement s) { if (s.internalThrow) { // https://issues.dlang.org/show_bug.cgi?id=8675 // Allow throwing 'Throwable' object even if mustNotThrow. result = BE.fallthru; return; } Type t = s.exp.type.toBasetype(); ClassDeclaration cd = t.isClassHandle(); assert(cd); if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null)) { result = BE.errthrow; return; } if (mustNotThrow) s.error("`%s` is thrown but not caught", s.exp.type.toChars()); result = BE.throw_; } override void visit(GotoStatement s) { //printf("GotoStatement::blockExit(%p)\n", s); result = BE.goto_; } override void visit(LabelStatement s) { //printf("LabelStatement::blockExit(%p)\n", s); result = blockExit(s.statement, func, mustNotThrow); if (s.breaks) result |= BE.fallthru; } override void visit(CompoundAsmStatement s) { // Assume the worst result = BE.fallthru | BE.return_ | BE.goto_ | BE.halt; if (!(s.stc & STC.nothrow_)) { if (mustNotThrow && !(s.stc & STC.nothrow_)) s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); else result |= BE.throw_; } } override void visit(ImportStatement s) { result = BE.fallthru; } } if (!s) return BE.fallthru; scope BlockExit be = new BlockExit(func, mustNotThrow); s.accept(be); return be.result; } ================================================ FILE: gcc/d/dmd/boostlicense.txt ================================================ Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: gcc/d/dmd/builtin.d ================================================ /* builtin.d -- Handlers for evaluating builtins during CTFE. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.builtin; import core.stdc.math; import core.stdc.string; import dmd.arraytypes; import dmd.expression; import dmd.func; import dmd.globals; /********************************** * Determine if function is a builtin one that we can * evaluate at compile time. */ public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd); /************************************** * Evaluate builtin function. * Return result; NULL if cannot evaluate it. */ public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments); ================================================ FILE: gcc/d/dmd/canthrow.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/canthrow.d, _canthrow.d) * Documentation: https://dlang.org/phobos/dmd_canthrow.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/canthrow.d */ module dmd.canthrow; import dmd.aggregate; import dmd.apply; import dmd.arraytypes; import dmd.attrib; import dmd.declaration; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.expression; import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; import dmd.root.rootobject; import dmd.tokens; import dmd.visitor; /******************************************** * Returns true if the expression may throw exceptions. * If 'mustNotThrow' is true, generate an error if it throws */ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow) { //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); // stop walking if we determine this expression can throw extern (C++) final class CanThrow : StoppableVisitor { alias visit = typeof(super).visit; FuncDeclaration func; bool mustNotThrow; public: extern (D) this(FuncDeclaration func, bool mustNotThrow) { this.func = func; this.mustNotThrow = mustNotThrow; } override void visit(Expression) { } override void visit(DeclarationExp de) { stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow); } override void visit(CallExp ce) { if (global.errors && !ce.e1.type) return; // error recovery /* If calling a function or delegate that is typed as nothrow, * then this expression cannot throw. * Note that pure functions can throw. */ Type t = ce.e1.type.toBasetype(); if (ce.f && ce.f == func) return; if (t.ty == Tfunction && (cast(TypeFunction)t).isnothrow) return; if (t.ty == Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) return; if (mustNotThrow) { if (ce.f) { ce.error("%s `%s` is not `nothrow`", ce.f.kind(), ce.f.toPrettyChars()); } else { auto e1 = ce.e1; if (e1.op == TOK.star) // print 'fp' if e1 is (*fp) e1 = (cast(PtrExp)e1).e1; ce.error("`%s` is not `nothrow`", e1.toChars()); } } stop = true; } override void visit(NewExp ne) { if (ne.member) { if (ne.allocator) { // https://issues.dlang.org/show_bug.cgi?id=14407 Type t = ne.allocator.type.toBasetype(); if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { if (mustNotThrow) { ne.error("%s `%s` is not `nothrow`", ne.allocator.kind(), ne.allocator.toPrettyChars()); } stop = true; } } // See if constructor call can throw Type t = ne.member.type.toBasetype(); if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { if (mustNotThrow) { ne.error("%s `%s` is not `nothrow`", ne.member.kind(), ne.member.toPrettyChars()); } stop = true; } } // regard storage allocation failures as not recoverable } override void visit(DeleteExp de) { Type tb = de.e1.type.toBasetype(); AggregateDeclaration ad = null; switch (tb.ty) { case Tclass: ad = (cast(TypeClass)tb).sym; break; case Tpointer: tb = (cast(TypePointer)tb).next.toBasetype(); if (tb.ty == Tstruct) ad = (cast(TypeStruct)tb).sym; break; case Tarray: Type tv = tb.nextOf().baseElemOf(); if (tv.ty == Tstruct) ad = (cast(TypeStruct)tv).sym; break; default: break; } if (!ad) return; if (ad.dtor) { Type t = ad.dtor.type.toBasetype(); if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { if (mustNotThrow) { de.error("%s `%s` is not `nothrow`", ad.dtor.kind(), ad.dtor.toPrettyChars()); } stop = true; } } if (ad.aggDelete && tb.ty != Tarray) { Type t = ad.aggDelete.type; if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { if (mustNotThrow) { de.error("%s `%s` is not `nothrow`", ad.aggDelete.kind(), ad.aggDelete.toPrettyChars()); } stop = true; } } } override void visit(AssignExp ae) { // blit-init cannot throw if (ae.op == TOK.blit) return; /* Element-wise assignment could invoke postblits. */ Type t; if (ae.type.toBasetype().ty == Tsarray) { if (!ae.e2.isLvalue()) return; t = ae.type; } else if (ae.e1.op == TOK.slice) t = (cast(SliceExp)ae.e1).e1.type; else return; Type tv = t.baseElemOf(); if (tv.ty != Tstruct) return; StructDeclaration sd = (cast(TypeStruct)tv).sym; if (!sd.postblit || sd.postblit.type.ty != Tfunction) return; if ((cast(TypeFunction)sd.postblit.type).isnothrow) { } else { if (mustNotThrow) { ae.error("%s `%s` is not `nothrow`", sd.postblit.kind(), sd.postblit.toPrettyChars()); } stop = true; } } override void visit(NewAnonClassExp) { assert(0); // should have been lowered by semantic() } } scope CanThrow ct = new CanThrow(func, mustNotThrow); return walkPostorder(e, ct); } /************************************** * Does symbol, when initialized, throw? * Mirrors logic in Dsymbol_toElem(). */ private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow) { AttribDeclaration ad; VarDeclaration vd; TemplateMixin tm; TupleDeclaration td; //printf("Dsymbol_toElem() %s\n", s.toChars()); ad = s.isAttribDeclaration(); if (ad) { Dsymbols* decl = ad.include(null); if (decl && decl.dim) { for (size_t i = 0; i < decl.dim; i++) { s = (*decl)[i]; if (Dsymbol_canThrow(s, func, mustNotThrow)) return true; } } } else if ((vd = s.isVarDeclaration()) !is null) { s = s.toAlias(); if (s != vd) return Dsymbol_canThrow(s, func, mustNotThrow); if (vd.storage_class & STC.manifest) { } else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared)) { } else { if (vd._init) { ExpInitializer ie = vd._init.isExpInitializer(); if (ie && canThrow(ie.exp, func, mustNotThrow)) return true; } if (vd.needsScopeDtor()) return canThrow(vd.edtor, func, mustNotThrow); } } else if ((tm = s.isTemplateMixin()) !is null) { //printf("%s\n", tm.toChars()); if (tm.members) { for (size_t i = 0; i < tm.members.dim; i++) { Dsymbol sm = (*tm.members)[i]; if (Dsymbol_canThrow(sm, func, mustNotThrow)) return true; } } } else if ((td = s.isTupleDeclaration()) !is null) { for (size_t i = 0; i < td.objects.dim; i++) { RootObject o = (*td.objects)[i]; if (o.dyncast() == DYNCAST.expression) { Expression eo = cast(Expression)o; if (eo.op == TOK.dSymbol) { DsymbolExp se = cast(DsymbolExp)eo; if (Dsymbol_canThrow(se.s, func, mustNotThrow)) return true; } } } } return false; } ================================================ FILE: gcc/d/dmd/clone.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/clone.d, _clone.d) * Documentation: https://dlang.org/phobos/dmd_clone.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/clone.d */ module dmd.clone; import core.stdc.stdio; import dmd.aggregate; import dmd.arraytypes; import dmd.dclass; import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.opover; import dmd.semantic2; import dmd.statement; import dmd.target; import dmd.typesem; import dmd.tokens; /******************************************* * Merge function attributes pure, nothrow, @safe, @nogc, and @disable * from f into s1. * Params: * s1 = storage class to merge into * f = function * Returns: * merged storage class */ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure { if (!f) return s1; StorageClass s2 = (f.storage_class & STC.disable); TypeFunction tf = cast(TypeFunction)f.type; if (tf.trust == TRUST.safe) s2 |= STC.safe; else if (tf.trust == TRUST.system) s2 |= STC.system; else if (tf.trust == TRUST.trusted) s2 |= STC.trusted; if (tf.purity != PURE.impure) s2 |= STC.pure_; if (tf.isnothrow) s2 |= STC.nothrow_; if (tf.isnogc) s2 |= STC.nogc; const sa = s1 & s2; const so = s1 | s2; StorageClass stc = (sa & (STC.pure_ | STC.nothrow_ | STC.nogc)) | (so & STC.disable); if (so & STC.system) stc |= STC.system; else if (sa & STC.trusted) stc |= STC.trusted; else if ((so & (STC.trusted | STC.safe)) == (STC.trusted | STC.safe)) stc |= STC.trusted; else if (sa & STC.safe) stc |= STC.safe; return stc; } /******************************************* * Check given aggregate actually has an identity opAssign or not. * Params: * ad = struct or class * sc = current scope * Returns: * if found, returns FuncDeclaration of opAssign, otherwise null */ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) { Dsymbol assign = search_function(ad, Id.assign); if (assign) { /* check identity opAssign exists */ scope er = new NullExp(ad.loc, ad.type); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue el.type = ad.type; Expressions a; a.setDim(1); const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. sc = sc.push(); sc.tinst = null; sc.minst = null; a[0] = er; auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); if (!f) { a[0] = el; f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); } sc = sc.pop(); global.endGagging(errors); if (f) { if (f.errors) return null; int varargs; auto fparams = f.getParameters(&varargs); if (fparams.dim >= 1) { auto fparam0 = Parameter.getNth(fparams, 0); if (fparam0.type.toDsymbol(null) != ad) f = null; } } // BUGS: This detection mechanism cannot find some opAssign-s like follows: // struct S { void opAssign(ref immutable S) const; } return f; } return null; } /******************************************* * We need an opAssign for the struct if * it has a destructor or a postblit. * We need to generate one if a user-specified one does not exist. */ private bool needOpAssign(StructDeclaration sd) { //printf("StructDeclaration::needOpAssign() %s\n", sd.toChars()); static bool isNeeded() { //printf("\tneed\n"); return true; } if (sd.isUnionDeclaration()) return !isNeeded(); if (sd.hasIdentityAssign || // because has identity==elaborate opAssign sd.dtor || sd.postblit) return isNeeded(); /* If any of the fields need an opAssign, then we * need it too. */ foreach (v; sd.fields) { if (v.storage_class & STC.ref_) continue; if (v.overlapped) // if field of a union continue; // user must handle it themselves Type tv = v.type.baseElemOf(); if (tv.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tv; if (ts.sym.isUnionDeclaration()) continue; if (needOpAssign(ts.sym)) return isNeeded(); } } return !isNeeded(); } /****************************************** * Build opAssign for a `struct`. * * The generated `opAssign` function has the following signature: *--- *ref S opAssign(S s) // S is the name of the `struct` *--- * * The opAssign function will be built for a struct `S` if the * following constraints are met: * * 1. `S` does not have an identity `opAssign` defined. * * 2. `S` has at least one of the following members: a postblit (user-defined or * generated for fields that have a defined postblit), a destructor * (user-defined or generated for fields that have a defined destructor) * or at least one field that has a defined `opAssign`. * * 3. `S` does not have any non-mutable fields. * * If `S` has a disabled destructor or at least one field that has a disabled * `opAssign`, `S.opAssign` is going to be generated, but marked with `@disable` * * If `S` defines a destructor, the generated code for `opAssign` is: * *--- *S __swap = void; *__swap = this; // bit copy *this = s; // bit copy *__swap.dtor(); *--- * * Otherwise, if `S` defines a postblit, the generated code for `opAssign` is: * *--- *this = s; *--- * * Note that the parameter to the generated `opAssign` is passed by value, which means * that the postblit is going to be called (if it is defined) in both of the above * situations before entering the body of `opAssign`. The assignments in the above generated * function bodies are blit expressions, so they can be regarded as `memcpy`s * (`opAssign` is not called as this will result in an infinite recursion; the postblit * is not called because it has already been called when the parameter was passed by value). * * If `S` does not have a postblit or a destructor, but contains at least one field that defines * an `opAssign` function (which is not disabled), then the body will make member-wise * assignments: * *--- *this.field1 = s.field1; *this.field2 = s.field2; *...; *--- * * In this situation, the assignemnts are actual assign expressions (`opAssign` is used * if defined). * * References: * https://dlang.org/spec/struct.html#assign-overload * Params: * sd = struct to generate opAssign for * sc = context * Returns: * generated `opAssign` function */ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) { if (FuncDeclaration f = hasIdentityOpAssign(sd, sc)) { sd.hasIdentityAssign = true; return f; } // Even if non-identity opAssign is defined, built-in identity opAssign // will be defined. if (!needOpAssign(sd)) return null; //printf("StructDeclaration::buildOpAssign() %s\n", sd.toChars()); StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; Loc declLoc = sd.loc; Loc loc; // internal code should have no loc to prevent coverage // One of our sub-field might have `@disable opAssign` so we need to // check for it. // In this event, it will be reflected by having `stc` (opAssign's // storage class) include `STC.disabled`. foreach (v; sd.fields) { if (v.storage_class & STC.ref_) continue; if (v.overlapped) continue; Type tv = v.type.baseElemOf(); if (tv.ty != Tstruct) continue; StructDeclaration sdv = (cast(TypeStruct)tv).sym; stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc)); } if (sd.dtor || sd.postblit) { // if the type is not assignable, we cannot generate opAssign if (!sd.type.isAssignable()) // https://issues.dlang.org/show_bug.cgi?id=13044 return null; stc = mergeFuncAttrs(stc, sd.dtor); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; } auto fparams = new Parameters(); fparams.push(new Parameter(STC.nodtor, sd.type, Id.p, null, null)); auto tf = new TypeFunction(fparams, sd.handleType(), 0, LINK.d, stc | STC.ref_); auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf); fop.storage_class |= STC.inference; fop.generated = true; Expression e; if (stc & STC.disable) { e = null; } /* Do swap this and rhs. * __swap = this; this = s; __swap.dtor(); */ else if (sd.dtor) { //printf("\tswap copy\n"); TypeFunction tdtor = cast(TypeFunction)sd.dtor.type; assert(tdtor.ty == Tfunction); auto idswap = Identifier.generateId("__swap"); auto swap = new VarDeclaration(loc, sd.type, idswap, new VoidInitializer(loc)); swap.storage_class |= STC.nodtor | STC.temp | STC.ctfe; if (tdtor.isscope) swap.storage_class |= STC.scope_; auto e1 = new DeclarationExp(loc, swap); auto e2 = new BlitExp(loc, new VarExp(loc, swap), new ThisExp(loc)); auto e3 = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p)); /* Instead of running the destructor on s, run it * on swap. This avoids needing to copy swap back in to s. */ auto e4 = new CallExp(loc, new DotVarExp(loc, new VarExp(loc, swap), sd.dtor, false)); e = Expression.combine(e1, e2, e3, e4); } /* postblit was called when the value was passed to opAssign, we just need to blit the result */ else if (sd.postblit) e = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p)); else { /* Do memberwise copy. * * If sd is a nested struct, its vthis field assignment is: * 1. If it's nested in a class, it's a rebind of class reference. * 2. If it's nested in a function or struct, it's an update of void*. * In both cases, it will change the parent context. */ //printf("\tmemberwise copy\n"); e = null; foreach (v; sd.fields) { // this.v = s.v; auto ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v), new DotVarExp(loc, new IdentifierExp(loc, Id.p), v)); e = Expression.combine(e, ec); } } if (e) { Statement s1 = new ExpStatement(loc, e); /* Add: * return this; */ auto er = new ThisExp(loc); Statement s2 = new ReturnStatement(loc, er); fop.fbody = new CompoundStatement(loc, s1, s2); tf.isreturn = true; } sd.members.push(fop); fop.addMember(sc, sd); sd.hasIdentityAssign = true; // temporary mark identity assignable const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. Scope* sc2 = sc.push(); sc2.stc = 0; sc2.linkage = LINK.d; fop.dsymbolSemantic(sc2); fop.semantic2(sc2); // https://issues.dlang.org/show_bug.cgi?id=15044 //semantic3(fop, sc2); // isn't run here for lazy forward reference resolution. sc2.pop(); if (global.endGagging(errors)) // if errors happened { // Disable generated opAssign, because some members forbid identity assignment. fop.storage_class |= STC.disable; fop.fbody = null; // remove fbody which contains the error } //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd.toChars(), (fop.storage_class & STC.disable) != 0); //printf("fop.type: %s\n", fop.type.toPrettyChars()); return fop; } /******************************************* * We need an opEquals for the struct if * any fields has an opEquals. * Generate one if a user-specified one does not exist. */ bool needOpEquals(StructDeclaration sd) { //printf("StructDeclaration::needOpEquals() %s\n", sd.toChars()); if (sd.isUnionDeclaration()) goto Ldontneed; if (sd.hasIdentityEquals) goto Lneed; /* If any of the fields has an opEquals, then we * need it too. */ for (size_t i = 0; i < sd.fields.dim; i++) { VarDeclaration v = sd.fields[i]; if (v.storage_class & STC.ref_) continue; if (v.overlapped) continue; Type tv = v.type.toBasetype(); auto tvbase = tv.baseElemOf(); if (tvbase.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tvbase; if (ts.sym.isUnionDeclaration()) continue; if (needOpEquals(ts.sym)) goto Lneed; if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14806 goto Lneed; } if (tv.isfloating()) { // This is necessray for: // 1. comparison of +0.0 and -0.0 should be true. // 2. comparison of NANs should be false always. goto Lneed; } if (tv.ty == Tarray) goto Lneed; if (tv.ty == Taarray) goto Lneed; if (tv.ty == Tclass) goto Lneed; } Ldontneed: //printf("\tdontneed\n"); return false; Lneed: //printf("\tneed\n"); return true; } /******************************************* * Check given aggregate actually has an identity opEquals or not. */ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) { Dsymbol eq = search_function(ad, Id.eq); if (eq) { /* check identity opEquals exists */ scope er = new NullExp(ad.loc, null); // dummy rvalue scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue Expressions a; a.setDim(1); foreach (i; 0 .. 5) { Type tthis = null; // dead-store to prevent spurious warning final switch (i) { case 0: tthis = ad.type; break; case 1: tthis = ad.type.constOf(); break; case 2: tthis = ad.type.immutableOf(); break; case 3: tthis = ad.type.sharedOf(); break; case 4: tthis = ad.type.sharedConstOf(); break; } FuncDeclaration f = null; const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it. sc = sc.push(); sc.tinst = null; sc.minst = null; foreach (j; 0 .. 2) { a[0] = (j == 0 ? er : el); a[0].type = tthis; f = resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, 1); if (f) break; } sc = sc.pop(); global.endGagging(errors); if (f) { if (f.errors) return null; return f; } } } return null; } /****************************************** * Build opEquals for struct. * const bool opEquals(const S s) { ... } * * By fixing https://issues.dlang.org/show_bug.cgi?id=3789 * opEquals is changed to be never implicitly generated. * Now, struct objects comparison s1 == s2 is translated to: * s1.tupleof == s2.tupleof * to calculate structural equality. See EqualExp.op_overload. */ FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc) { if (hasIdentityOpEquals(sd, sc)) { sd.hasIdentityEquals = true; } return null; } /****************************************** * Build __xopEquals for TypeInfo_Struct * static bool __xopEquals(ref const S p, ref const S q) * { * return p == q; * } * * This is called by TypeInfo.equals(p1, p2). If the struct does not support * const objects comparison, it will throw "not implemented" Error in runtime. */ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) { if (!needOpEquals(sd)) return null; // bitwise comparison would work //printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars()); if (Dsymbol eq = search_function(sd, Id.eq)) { if (FuncDeclaration fd = eq.isFuncDeclaration()) { TypeFunction tfeqptr; { Scope scx; /* const bool opEquals(ref const S s); */ auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null)); tfeqptr = new TypeFunction(parameters, Type.tbool, 0, LINK.d); tfeqptr.mod = MODFlags.const_; tfeqptr = cast(TypeFunction)tfeqptr.typeSemantic(Loc.initial, &scx); } fd = fd.overloadExactMatch(tfeqptr); if (fd) return fd; } } if (!sd.xerreq) { // object._xopEquals Identifier id = Identifier.idPool("_xopEquals"); Expression e = new IdentifierExp(sd.loc, Id.empty); e = new DotIdExp(sd.loc, e, Id.object); e = new DotIdExp(sd.loc, e, id); e = e.expressionSemantic(sc); Dsymbol s = getDsymbol(e); assert(s); sd.xerreq = s.isFuncDeclaration(); } Loc declLoc; // loc is unnecessary so __xopEquals is never called directly Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null)); auto tf = new TypeFunction(parameters, Type.tbool, 0, LINK.d); Identifier id = Id.xopEquals; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); fop.generated = true; Expression e1 = new IdentifierExp(loc, Id.p); Expression e2 = new IdentifierExp(loc, Id.q); Expression e = new EqualExp(TOK.equal, loc, e1, e2); fop.fbody = new ReturnStatement(loc, e); uint errors = global.startGagging(); // Do not report errors Scope* sc2 = sc.push(); sc2.stc = 0; sc2.linkage = LINK.d; fop.dsymbolSemantic(sc2); fop.semantic2(sc2); sc2.pop(); if (global.endGagging(errors)) // if errors happened fop = sd.xerreq; return fop; } /****************************************** * Build __xopCmp for TypeInfo_Struct * static bool __xopCmp(ref const S p, ref const S q) * { * return p.opCmp(q); * } * * This is called by TypeInfo.compare(p1, p2). If the struct does not support * const objects comparison, it will throw "not implemented" Error in runtime. */ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) { //printf("StructDeclaration::buildXopCmp() %s\n", toChars()); if (Dsymbol cmp = search_function(sd, Id.cmp)) { if (FuncDeclaration fd = cmp.isFuncDeclaration()) { TypeFunction tfcmpptr; { Scope scx; /* const int opCmp(ref const S s); */ auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null)); tfcmpptr = new TypeFunction(parameters, Type.tint32, 0, LINK.d); tfcmpptr.mod = MODFlags.const_; tfcmpptr = cast(TypeFunction)tfcmpptr.typeSemantic(Loc.initial, &scx); } fd = fd.overloadExactMatch(tfcmpptr); if (fd) return fd; } } else { version (none) // FIXME: doesn't work for recursive alias this { /* Check opCmp member exists. * Consider 'alias this', but except opDispatch. */ Expression e = new DsymbolExp(sd.loc, sd); e = new DotIdExp(sd.loc, e, Id.cmp); Scope* sc2 = sc.push(); e = e.trySemantic(sc2); sc2.pop(); if (e) { Dsymbol s = null; switch (e.op) { case TOK.overloadSet: s = (cast(OverExp)e).vars; break; case TOK.scope_: s = (cast(ScopeExp)e).sds; break; case TOK.variable: s = (cast(VarExp)e).var; break; default: break; } if (!s || s.ident != Id.cmp) e = null; // there's no valid member 'opCmp' } if (!e) return null; // bitwise comparison would work /* Essentially, a struct which does not define opCmp is not comparable. * At this time, typeid(S).compare might be correct that throwing "not implement" Error. * But implementing it would break existing code, such as: * * struct S { int value; } // no opCmp * int[S] aa; // Currently AA key uses bitwise comparison * // (It's default behavior of TypeInfo_Strust.compare). * * Not sure we should fix this inconsistency, so just keep current behavior. */ } else { return null; } } if (!sd.xerrcmp) { // object._xopCmp Identifier id = Identifier.idPool("_xopCmp"); Expression e = new IdentifierExp(sd.loc, Id.empty); e = new DotIdExp(sd.loc, e, Id.object); e = new DotIdExp(sd.loc, e, id); e = e.expressionSemantic(sc); Dsymbol s = getDsymbol(e); assert(s); sd.xerrcmp = s.isFuncDeclaration(); } Loc declLoc; // loc is unnecessary so __xopCmp is never called directly Loc loc; // loc is unnecessary so errors are gagged auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null)); auto tf = new TypeFunction(parameters, Type.tint32, 0, LINK.d); Identifier id = Id.xopCmp; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); fop.generated = true; Expression e1 = new IdentifierExp(loc, Id.p); Expression e2 = new IdentifierExp(loc, Id.q); version (IN_GCC) Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2); else Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1); fop.fbody = new ReturnStatement(loc, e); uint errors = global.startGagging(); // Do not report errors Scope* sc2 = sc.push(); sc2.stc = 0; sc2.linkage = LINK.d; fop.dsymbolSemantic(sc2); fop.semantic2(sc2); sc2.pop(); if (global.endGagging(errors)) // if errors happened fop = sd.xerrcmp; return fop; } /******************************************* * We need a toHash for the struct if * any fields has a toHash. * Generate one if a user-specified one does not exist. */ private bool needToHash(StructDeclaration sd) { //printf("StructDeclaration::needToHash() %s\n", sd.toChars()); if (sd.isUnionDeclaration()) goto Ldontneed; if (sd.xhash) goto Lneed; /* If any of the fields has an opEquals, then we * need it too. */ for (size_t i = 0; i < sd.fields.dim; i++) { VarDeclaration v = sd.fields[i]; if (v.storage_class & STC.ref_) continue; if (v.overlapped) continue; Type tv = v.type.toBasetype(); auto tvbase = tv.baseElemOf(); if (tvbase.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tvbase; if (ts.sym.isUnionDeclaration()) continue; if (needToHash(ts.sym)) goto Lneed; if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14948 goto Lneed; } if (tv.isfloating()) { /* This is necessary because comparison of +0.0 and -0.0 should be true, * i.e. not a bit compare. */ goto Lneed; } if (tv.ty == Tarray) goto Lneed; if (tv.ty == Taarray) goto Lneed; if (tv.ty == Tclass) goto Lneed; } Ldontneed: //printf("\tdontneed\n"); return false; Lneed: //printf("\tneed\n"); return true; } /****************************************** * Build __xtoHash for non-bitwise hashing * static hash_t xtoHash(ref const S p) nothrow @trusted; */ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) { if (Dsymbol s = search_function(sd, Id.tohash)) { __gshared TypeFunction tftohash; if (!tftohash) { tftohash = new TypeFunction(null, Type.thash_t, 0, LINK.d); tftohash.mod = MODFlags.const_; tftohash = cast(TypeFunction)tftohash.merge(); } if (FuncDeclaration fd = s.isFuncDeclaration()) { fd = fd.overloadExactMatch(tftohash); if (fd) return fd; } } if (!needToHash(sd)) return null; //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars()); Loc declLoc; // loc is unnecessary so __xtoHash is never called directly Loc loc; // internal code should have no loc to prevent coverage auto parameters = new Parameters(); parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null)); auto tf = new TypeFunction(parameters, Type.thash_t, 0, LINK.d, STC.nothrow_ | STC.trusted); Identifier id = Id.xtoHash; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); fop.generated = true; /* Do memberwise hashing. * * If sd is a nested struct, and if it's nested in a class, the calculated * hash value will also contain the result of parent class's toHash(). */ const(char)* code = "size_t h = 0;" ~ "foreach (i, T; typeof(p.tupleof))" ~ // workaround https://issues.dlang.org/show_bug.cgi?id=17968 " static if(is(T* : const(.object.Object)*)) " ~ " h = h * 33 + typeid(const(.object.Object)).getHash(cast(const void*)&p.tupleof[i]);" ~ " else " ~ " h = h * 33 + typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~ "return h;"; fop.fbody = new CompileStatement(loc, new StringExp(loc, cast(char*)code)); Scope* sc2 = sc.push(); sc2.stc = 0; sc2.linkage = LINK.d; fop.dsymbolSemantic(sc2); fop.semantic2(sc2); sc2.pop(); //printf("%s fop = %s %s\n", sd.toChars(), fop.toChars(), fop.type.toChars()); return fop; } /***************************************** * Create inclusive destructor for struct/class by aggregating * all the destructors in dtors[] with the destructors for * all the members. * Params: * ad = struct or class to build destructor for * sc = context * Returns: * generated function, null if none needed * Note: * Close similarity with StructDeclaration::buildPostBlit(), * and the ordering changes (runs backward instead of forwards). */ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) { //printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars()); if (ad.isUnionDeclaration()) return null; // unions don't have destructors StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc; Loc loc; // internal code should have no loc to prevent coverage // if the dtor is an extern(C++) prototype, then we expect it performs a full-destruction; we don't need to build a full-dtor const bool dtorIsCppPrototype = ad.dtors.dim == 1 && ad.dtors[0].linkage == LINK.cpp && !ad.dtors[0].fbody; if (!dtorIsCppPrototype) { Expression e = null; for (size_t i = 0; i < ad.fields.dim; i++) { auto v = ad.fields[i]; if (v.storage_class & STC.ref_) continue; if (v.overlapped) continue; auto tv = v.type.baseElemOf(); if (tv.ty != Tstruct) continue; auto sdv = (cast(TypeStruct)tv).sym; if (!sdv.dtor) continue; sdv.dtor.functionSemantic(); stc = mergeFuncAttrs(stc, sdv.dtor); if (stc & STC.disable) { e = null; break; } Expression ex; tv = v.type.toBasetype(); if (tv.ty == Tstruct) { // this.v.__xdtor() ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, v); // This is a hack so we can call destructors on const/immutable objects. // Do it as a type 'paint'. ex = new CastExp(loc, ex, v.type.mutableOf()); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new DotVarExp(loc, ex, sdv.dtor, false); ex = new CallExp(loc, ex); } else { // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) const n = tv.numberOfElems(loc); if (n == 0) continue; ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, v); // This is a hack so we can call destructors on const/immutable objects. ex = new DotIdExp(loc, ex, Id.ptr); ex = new CastExp(loc, ex, sdv.type.pointerTo()); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t)); // Prevent redundant bounds check (cast(SliceExp)ex).upperIsInBounds = true; (cast(SliceExp)ex).lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex); } e = Expression.combine(ex, e); // combine in reverse order } /* extern(C++) destructors call into super to destruct the full hierarchy */ ClassDeclaration cldec = ad.isClassDeclaration(); if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.primaryDtor) { // WAIT BUT: do I need to run `cldec.baseClass.dtor` semantic? would it have been run before? cldec.baseClass.dtor.functionSemantic(); stc = mergeFuncAttrs(stc, cldec.baseClass.primaryDtor); if (!(stc & STC.disable)) { // super.__xdtor() Expression ex = new SuperExp(loc); // This is a hack so we can call destructors on const/immutable objects. // Do it as a type 'paint'. ex = new CastExp(loc, ex, cldec.baseClass.type.mutableOf()); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new DotVarExp(loc, ex, cldec.baseClass.primaryDtor, false); ex = new CallExp(loc, ex); e = Expression.combine(e, ex); // super dtor last } } /* Build our own "destructor" which executes e */ if (e || (stc & STC.disable)) { //printf("Building __fieldDtor(), %s\n", e.toChars()); auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor); dd.generated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.dtors.shift(dd); ad.members.push(dd); dd.dsymbolSemantic(sc); ad.fieldDtor = dd; } } DtorDeclaration xdtor = null; switch (ad.dtors.dim) { case 0: break; case 1: xdtor = ad.dtors[0]; break; default: assert(!dtorIsCppPrototype); Expression e = null; e = null; stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; for (size_t i = 0; i < ad.dtors.dim; i++) { FuncDeclaration fd = ad.dtors[i]; stc = mergeFuncAttrs(stc, fd); if (stc & STC.disable) { e = null; break; } Expression ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, fd, false); ex = new CallExp(loc, ex); e = Expression.combine(ex, e); } auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor); dd.generated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.members.push(dd); dd.dsymbolSemantic(sc); xdtor = dd; break; } ad.primaryDtor = xdtor; if (xdtor && xdtor.linkage == LINK.cpp && !Target.twoDtorInVtable) xdtor = buildWindowsCppDtor(ad, xdtor, sc); // Add an __xdtor alias to make the inclusive dtor accessible if (xdtor) { auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor); _alias.dsymbolSemantic(sc); ad.members.push(_alias); _alias.addMember(sc, ad); // add to symbol table } return xdtor; } /** * build a shim function around the compound dtor that accepts an argument * that is used to implement the deleting C++ destructor * * Params: * ad = the aggregate that contains the destructor to wrap * dtor = the destructor to wrap * sc = the scope in which to analyze the new function * * Returns: * the shim destructor, semantically analyzed and added to the class as a member */ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclaration dtor, Scope* sc) { auto cldec = ad.isClassDeclaration(); if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors return dtor; // generate deleting C++ destructor corresponding to: // void* C::~C(int del) // { // this->~C(); // // TODO: if (del) delete (char*)this; // return (void*) this; // } Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null); Parameters* params = new Parameters; params.push(delparam); auto ftype = new TypeFunction(params, Type.tvoidptr, false, LINK.cpp, dtor.storage_class); auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor); func.type = ftype; if (dtor.fbody) { const loc = dtor.loc; auto stmts = new Statements; auto call = new CallExp(loc, dtor, null); call.directcall = true; stmts.push(new ExpStatement(loc, call)); stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr))); func.fbody = new CompoundStatement(loc, stmts); func.generated = true; } auto sc2 = sc.push(); sc2.stc &= ~STC.static_; // not a static destructor sc2.linkage = LINK.cpp; ad.members.push(func); func.addMember(sc2, ad); func.dsymbolSemantic(sc2); sc2.pop(); return func; } /** * build a shim function around the compound dtor that translates * a C++ destructor to a destructor with extern(D) calling convention * * Params: * ad = the aggregate that contains the destructor to wrap * sc = the scope in which to analyze the new function * * Returns: * the shim destructor, semantically analyzed and added to the class as a member */ DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) { auto dtor = ad.primaryDtor; if (!dtor) return null; // ABI incompatible on all (?) x86 32-bit platforms if (ad.classKind != ClassKind.cpp || global.params.is64bit) return dtor; // generate member function that adjusts calling convention // (EAX used for 'this' instead of ECX on Windows/stack on others): // extern(D) void __ticppdtor() // { // Class.__dtor(); // } auto ftype = new TypeFunction(null, Type.tvoid, false, LINK.d, dtor.storage_class); auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.ticppdtor); func.type = ftype; auto call = new CallExp(dtor.loc, dtor, null); call.directcall = true; // non-virtual call Class.__dtor(); func.fbody = new ExpStatement(dtor.loc, call); func.generated = true; func.storage_class |= STC.inference; auto sc2 = sc.push(); sc2.stc &= ~STC.static_; // not a static destructor sc2.linkage = LINK.d; ad.members.push(func); func.addMember(sc2, ad); func.dsymbolSemantic(sc2); func.functionSemantic(); // to infer attributes sc2.pop(); return func; } /****************************************** * Create inclusive invariant for struct/class by aggregating * all the invariants in invs[]. * void __invariant() const [pure nothrow @trusted] * { * invs[0](), invs[1](), ...; * } */ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc) { switch (ad.invs.dim) { case 0: return null; case 1: // Don't return invs[0] so it has uniquely generated name. goto default; default: Expression e = null; StorageClass stcx = 0; StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; foreach (i, inv; ad.invs) { stc = mergeFuncAttrs(stc, inv); if (stc & STC.disable) { // What should do? } const stcy = (inv.storage_class & STC.synchronized_) | (inv.type.mod & MODFlags.shared_ ? STC.shared_ : 0); if (i == 0) stcx = stcy; else if (stcx ^ stcy) { version (all) { // currently rejects ad.error(inv.loc, "mixing invariants with different `shared`/`synchronized` qualifiers is not supported"); e = null; break; } } e = Expression.combine(e, new CallExp(Loc.initial, new VarExp(Loc.initial, inv, false))); } auto inv = new InvariantDeclaration(ad.loc, Loc.initial, stc | stcx, Id.classInvariant, new ExpStatement(Loc.initial, e)); ad.members.push(inv); inv.dsymbolSemantic(sc); return inv; } } ================================================ FILE: gcc/d/dmd/compiler.d ================================================ /* compiler.d -- Compiler interface for the D front end. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.compiler; import dmd.dmodule; import dmd.dscope; import dmd.expression; import dmd.mtype; /** * A data structure that describes a back-end compiler and implements * compiler-specific actions. */ struct Compiler { /** * Generate C main() in response to seeing D main(). * * This function will generate a module called `__entrypoint`, * and set the globals `entrypoint` and `rootHasMain`. * * This used to be in druntime, but contained a reference to _Dmain * which didn't work when druntime was made into a dll and was linked * to a program, such as a C++ program, that didn't have a _Dmain. * * Params: * sc = Scope which triggered the generation of the C main, * used to get the module where the D main is. */ extern (C++) static void genCmain(Scope* sc); /****************************** * Encode the given expression, which is assumed to be an rvalue literal * as another type for use in CTFE. * This corresponds roughly to the idiom *(Type *)&e. */ extern (C++) static Expression paintAsType(Expression e, Type type); /****************************** * For the given module, perform any post parsing analysis. * Certain compiler backends (ie: GDC) have special placeholder * modules whose source are empty, but code gets injected * immediately after loading. */ extern (C++) static void loadModule(Module m); /** * A callback function that is called once an imported module is * parsed. If the callback returns true, then it tells the * frontend that the driver intends on compiling the import. */ extern(C++) static bool onImport(Module m); } ================================================ FILE: gcc/d/dmd/compiler.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/compiler.h */ #pragma once #include "root/array.h" // This file contains a data structure that describes a back-end compiler // and implements compiler-specific actions. class Expression; class Module; class Type; struct Scope; // DMD-generated module `__entrypoint` where the C main resides extern Module *entrypoint; // Module in which the D main is extern Module *rootHasMain; extern bool includeImports; // array of module patterns used to include/exclude imported modules extern Array includeModulePatterns; extern Array compiledImports; struct Compiler { // CTFE support for cross-compilation. static Expression *paintAsType(Expression *, Type *); // Backend static void loadModule(Module *); static void genCmain(Scope *); static bool onImport(Module *); }; ================================================ FILE: gcc/d/dmd/complex.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/complex.d, _complex.d) * Documentation: https://dlang.org/phobos/dmd_complex.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/complex.d */ module dmd.complex; import dmd.root.ctfloat; struct complex_t { real_t re; real_t im; this() @disable; this(real_t re) { this(re, CTFloat.zero); } this(real_t re, real_t im) { this.re = re; this.im = im; } complex_t opAdd(complex_t y) { return complex_t(re + y.re, im + y.im); } complex_t opSub(complex_t y) { return complex_t(re - y.re, im - y.im); } complex_t opNeg() { return complex_t(-re, -im); } complex_t opMul(complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } complex_t opMul_r(real_t x) { return complex_t(x) * this; } complex_t opMul(real_t y) { return this * complex_t(y); } complex_t opDiv(real_t y) { return this / complex_t(y); } complex_t opDiv(complex_t y) { if (CTFloat.fabs(y.re) < CTFloat.fabs(y.im)) { const r = y.re / y.im; const den = y.im + r * y.re; return complex_t((re * r + im) / den, (im * r - re) / den); } else { const r = y.im / y.re; const den = y.re + r * y.im; return complex_t((re + r * im) / den, (im - r * re) / den); } } bool opCast(T : bool)() const { return re || im; } int opEquals(complex_t y) const { return re == y.re && im == y.im; } } extern (C++) real_t creall(complex_t x) { return x.re; } extern (C++) real_t cimagl(complex_t x) { return x.im; } ================================================ FILE: gcc/d/dmd/complex_t.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/complex_t.h */ #pragma once #include "root/ctfloat.h" /* Roll our own complex type for compilers that don't support complex */ struct complex_t { real_t re; real_t im; complex_t(real_t re) : re(re), im(CTFloat::zero) {} complex_t(real_t re, real_t im) : re(re), im(im) {} complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); } complex_t operator - (complex_t y) { return complex_t(re - y.re, im - y.im); } complex_t operator - () { return complex_t(-re, -im); } complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } complex_t operator / (complex_t y) { if (CTFloat::fabs(y.re) < CTFloat::fabs(y.im)) { real_t r = y.re / y.im; real_t den = y.im + r * y.re; return complex_t((re * r + im) / den, (im * r - re) / den); } else { real_t r = y.im / y.re; real_t den = y.re + r * y.im; return complex_t((re + r * im) / den, (im - r * re) / den); } } operator bool () { return re || im; } int operator == (complex_t y) { return re == y.re && im == y.im; } int operator != (complex_t y) { return re != y.re || im != y.im; } private: complex_t() : re(CTFloat::zero), im(CTFloat::zero) {} }; inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; } inline complex_t operator * (complex_t x, real_t y) { return x * complex_t(y); } inline complex_t operator / (complex_t x, real_t y) { return x / complex_t(y); } inline real_t creall(complex_t x) { return x.re; } inline real_t cimagl(complex_t x) { return x.im; } ================================================ FILE: gcc/d/dmd/cond.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/cond.d, _cond.d) * Documentation: https://dlang.org/phobos/dmd_cond.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cond.d */ module dmd.cond; import core.stdc.string; import dmd.arraytypes; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.globals; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.tokens; import dmd.utils; import dmd.visitor; import dmd.id; import dmd.statement; import dmd.declaration; import dmd.dstruct; import dmd.func; /*********************************************************** */ extern (C++) abstract class Condition : RootObject { Loc loc; // 0: not computed yet // 1: include // 2: do not include int inc; override final DYNCAST dyncast() const { return DYNCAST.condition; } extern (D) this(const ref Loc loc) { this.loc = loc; } abstract Condition syntaxCopy(); abstract int include(Scope* sc); DebugCondition isDebugCondition() { return null; } void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Implements common functionality for StaticForeachDeclaration and * StaticForeachStatement This performs the necessary lowerings before * dmd.statementsem.makeTupleForeach can be used to expand the * corresponding `static foreach` declaration or statement. */ extern (C++) final class StaticForeach : RootObject { extern(D) static immutable tupleFieldName = "tuple"; // used in lowering Loc loc; /*************** * Not `null` iff the `static foreach` is over an aggregate. In * this case, it contains the corresponding ForeachStatement. For * StaticForeachDeclaration, the body is `null`. */ ForeachStatement aggrfe; /*************** * Not `null` iff the `static foreach` is over a range. Exactly * one of the `aggrefe` and `rangefe` fields is not null. See * `aggrfe` field for more details. */ ForeachRangeStatement rangefe; /*************** * true if it is necessary to expand a tuple into multiple * variables (see lowerNonArrayAggregate). */ bool needExpansion = false; extern (D) this(const ref Loc loc,ForeachStatement aggrfe,ForeachRangeStatement rangefe) { assert(!!aggrfe ^ !!rangefe); this.loc = loc; this.aggrfe = aggrfe; this.rangefe = rangefe; } StaticForeach syntaxCopy() { return new StaticForeach( loc, aggrfe ? cast(ForeachStatement)aggrfe.syntaxCopy() : null, rangefe ? cast(ForeachRangeStatement)rangefe.syntaxCopy() : null ); } /***************************************** * Turn an aggregate which is an array into an expression tuple * of its elements. I.e., lower * static foreach (x; [1, 2, 3, 4]) { ... } * to * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... } */ private extern(D) void lowerArrayAggregate(Scope* sc) { auto aggr = aggrfe.aggr; Expression el = new ArrayLengthExp(aggr.loc, aggr); sc = sc.startCTFE(); el = el.expressionSemantic(sc); sc = sc.endCTFE(); el = el.optimize(WANTvalue); el = el.ctfeInterpret(); if (el.op == TOK.int64) { dinteger_t length = el.toInteger(); auto es = new Expressions(); foreach (i; 0 .. length) { auto index = new IntegerExp(loc, i, Type.tsize_t); auto value = new IndexExp(aggr.loc, aggr, index); es.push(value); } aggrfe.aggr = new TupleExp(aggr.loc, es); aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc); aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue); } else { aggrfe.aggr = new ErrorExp(); } } /***************************************** * Wrap a statement into a function literal and call it. * * Params: * loc = The source location. * s = The statement. * Returns: * AST of the expression `(){ s; }()` with location loc. */ private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s) { auto tf = new TypeFunction(new Parameters(), null, 0, LINK.default_, 0); auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null); fd.fbody = s; auto fe = new FuncExp(loc, fd); auto ce = new CallExp(loc, fe, new Expressions()); return ce; } /***************************************** * Create a `foreach` statement from `aggrefe/rangefe` with given * `foreach` variables and body `s`. * * Params: * loc = The source location. * parameters = The foreach variables. * s = The `foreach` body. * Returns: * `foreach (parameters; aggregate) s;` or * `foreach (parameters; lower .. upper) s;` * Where aggregate/lower, upper are as for the current StaticForeach. */ private extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s) { if (aggrfe) { return new ForeachStatement(loc, aggrfe.op, parameters, aggrfe.aggr.syntaxCopy(), s, loc); } else { assert(rangefe && parameters.dim == 1); return new ForeachRangeStatement(loc, rangefe.op, (*parameters)[0], rangefe.lwr.syntaxCopy(), rangefe.upr.syntaxCopy(), s, loc); } } /***************************************** * For a `static foreach` with multiple loop variables, the * aggregate is lowered to an array of tuples. As D does not have * built-in tuples, we need a suitable tuple type. This generates * a `struct` that serves as the tuple type. This type is only * used during CTFE and hence its typeinfo will not go to the * object file. * * Params: * loc = The source location. * e = The expressions we wish to store in the tuple. * sc = The current scope. * Returns: * A struct type of the form * struct Tuple * { * typeof(AliasSeq!(e)) tuple; * } */ private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc) { // TODO: move to druntime? auto sid = Identifier.generateId("Tuple"); auto sdecl = new StructDeclaration(loc, sid, false); sdecl.storage_class |= STC.static_; sdecl.members = new Dsymbols(); auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length); auto ty = new TypeTypeof(loc, new TupleExp(loc, e)); sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0)); auto r = cast(TypeStruct)sdecl.type; r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file return r; } /***************************************** * Create the AST for an instantiation of a suitable tuple type. * * Params: * loc = The source location. * type = A Tuple type, created with createTupleType. * e = The expressions we wish to store in the tuple. * Returns: * An AST for the expression `Tuple(e)`. */ private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e) { // TODO: move to druntime? return new CallExp(loc, new TypeExp(loc, type), e); } /***************************************** * Lower any aggregate that is not an array to an array using a * regular foreach loop within CTFE. If there are multiple * `static foreach` loop variables, an array of tuples is * generated. In thise case, the field `needExpansion` is set to * true to indicate that the static foreach loop expansion will * need to expand the tuples into multiple variables. * * For example, `static foreach (x; range) { ... }` is lowered to: * * static foreach (x; { * typeof({ * foreach (x; range) return x; * }())[] __res; * foreach (x; range) __res ~= x; * return __res; * }()) { ... } * * Finally, call `lowerArrayAggregate` to turn the produced * array into an expression tuple. * * Params: * sc = The current scope. */ private void lowerNonArrayAggregate(Scope* sc) { auto nvars = aggrfe ? aggrfe.parameters.dim : 1; auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc; // We need three sets of foreach loop variables because the // lowering contains three foreach loops. Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()]; foreach (i; 0 .. nvars) { foreach (params; pparams) { auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm; params.push(new Parameter(p.storageClass, p.type, p.ident, null, null)); } } Expression[2] res; TypeStruct tplty = null; if (nvars == 1) // only one `static foreach` variable, generate identifiers. { foreach (i; 0 .. 2) { res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident); } } else // multiple `static foreach` variables, generate tuples. { foreach (i; 0 .. 2) { auto e = new Expressions(); foreach (j; 0 .. pparams[0].dim) { auto p = (*pparams[i])[j]; e.push(new IdentifierExp(aloc, p.ident)); } if (!tplty) { tplty = createTupleType(aloc, e, sc); } res[i] = createTuple(aloc, tplty, e); } needExpansion = true; // need to expand the tuples later } // generate remaining code for the new aggregate which is an // array (see documentation comment). if (rangefe) { sc = sc.startCTFE(); rangefe.lwr = rangefe.lwr.expressionSemantic(sc); rangefe.lwr = resolveProperties(sc, rangefe.lwr); rangefe.upr = rangefe.upr.expressionSemantic(sc); rangefe.upr = resolveProperties(sc, rangefe.upr); sc = sc.endCTFE(); rangefe.lwr = rangefe.lwr.optimize(WANTvalue); rangefe.lwr = rangefe.lwr.ctfeInterpret(); rangefe.upr = rangefe.upr.optimize(WANTvalue); rangefe.upr = rangefe.upr.ctfeInterpret(); } auto s1 = new Statements(); auto sfe = new Statements(); if (tplty) sfe.push(new ExpStatement(loc, tplty.sym)); sfe.push(new ReturnStatement(aloc, res[0])); s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe))); s1.push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type.tint32)))); auto ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1))); auto aty = ety.arrayOf(); auto idres = Identifier.generateId("__res"); auto vard = new VarDeclaration(aloc, aty, idres, null); auto s2 = new Statements(); s2.push(new ExpStatement(aloc, vard)); auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]); s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass))); s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres))); auto aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2)); sc = sc.startCTFE(); aggr = aggr.expressionSemantic(sc); aggr = resolveProperties(sc, aggr); sc = sc.endCTFE(); aggr = aggr.optimize(WANTvalue); aggr = aggr.ctfeInterpret(); assert(!!aggrfe ^ !!rangefe); aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr, aggrfe ? aggrfe._body : rangefe._body, aggrfe ? aggrfe.endloc : rangefe.endloc); rangefe = null; lowerArrayAggregate(sc); // finally, turn generated array into expression tuple } /***************************************** * Perform `static foreach` lowerings that are necessary in order * to finally expand the `static foreach` using * `dmd.statementsem.makeTupleForeach`. */ extern(D) void prepare(Scope* sc) { assert(sc); if (aggrfe) { sc = sc.startCTFE(); aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc); sc = sc.endCTFE(); aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue); auto tab = aggrfe.aggr.type.toBasetype(); if (tab.ty != Ttuple) { aggrfe.aggr = aggrfe.aggr.ctfeInterpret(); } } if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror) { return; } if (!ready()) { if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray) { lowerArrayAggregate(sc); } else { lowerNonArrayAggregate(sc); } } } /***************************************** * Returns: * `true` iff ready to call `dmd.statementsem.makeTupleForeach`. */ extern(D) bool ready() { return aggrfe && aggrfe.aggr && aggrfe.aggr.type && aggrfe.aggr.type.toBasetype().ty == Ttuple; } } /*********************************************************** */ extern (C++) class DVCondition : Condition { uint level; Identifier ident; Module mod; extern (D) this(Module mod, uint level, Identifier ident) { super(Loc.initial); this.mod = mod; this.level = level; this.ident = ident; } override final Condition syntaxCopy() { return this; // don't need to copy } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DebugCondition : DVCondition { /** * Add an user-supplied identifier to the list of global debug identifiers * * Can be called from either the driver or a `debug = Ident;` statement. * Unlike version identifier, there isn't any reserved debug identifier * so no validation takes place. * * Params: * ident = identifier to add */ deprecated("Kept for C++ compat - Use the string overload instead") static void addGlobalIdent(const(char)* ident) { addGlobalIdent(ident[0 .. ident.strlen]); } /// Ditto extern(D) static void addGlobalIdent(string ident) { // Overload necessary for string literals addGlobalIdent(cast(const(char)[])ident); } /// Ditto extern(D) static void addGlobalIdent(const(char)[] ident) { if (!global.debugids) global.debugids = new Identifiers(); global.debugids.push(Identifier.idPool(ident)); } /** * Instantiate a new `DebugCondition` * * Params: * mod = Module this node belongs to * level = Minimum global level this condition needs to pass. * Only used if `ident` is `null`. * ident = Identifier required for this condition to pass. * If `null`, this conditiion will use an integer level. */ extern (D) this(Module mod, uint level, Identifier ident) { super(mod, level, ident); } override int include(Scope* sc) { //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); if (inc == 0) { inc = 2; bool definedInModule = false; if (ident) { if (findCondition(mod.debugids, ident)) { inc = 1; definedInModule = true; } else if (findCondition(global.debugids, ident)) inc = 1; else { if (!mod.debugidsNot) mod.debugidsNot = new Identifiers(); mod.debugidsNot.push(ident); } } else if (level <= global.params.debuglevel || level <= mod.debuglevel) inc = 1; if (!definedInModule) printDepsConditional(sc, this, "depsDebug "); } return (inc == 1); } override DebugCondition isDebugCondition() { return this; } override void accept(Visitor v) { v.visit(this); } override const(char)* toChars() { return ident ? ident.toChars() : "debug".ptr; } } /** * Node to represent a version condition * * A version condition is of the form: * --- * version (Identifier) * --- * In user code. * This class also provides means to add version identifier * to the list of global (cross module) identifiers. */ extern (C++) final class VersionCondition : DVCondition { /** * Check if a given version identifier is reserved. * * Params: * ident = identifier being checked * * Returns: * `true` if it is reserved, `false` otherwise */ extern(D) private static bool isReserved(const(char)[] ident) { // This list doesn't include "D_*" versions, see the last return switch (ident) { case "DigitalMars": case "GNU": case "LDC": case "SDC": case "Windows": case "Win32": case "Win64": case "linux": case "OSX": case "iOS": case "TVOS": case "WatchOS": case "FreeBSD": case "OpenBSD": case "NetBSD": case "DragonFlyBSD": case "BSD": case "Solaris": case "Posix": case "AIX": case "Haiku": case "SkyOS": case "SysV3": case "SysV4": case "Hurd": case "Android": case "Emscripten": case "PlayStation": case "PlayStation4": case "Cygwin": case "MinGW": case "FreeStanding": case "X86": case "X86_64": case "ARM": case "ARM_Thumb": case "ARM_SoftFloat": case "ARM_SoftFP": case "ARM_HardFloat": case "AArch64": case "AsmJS": case "Epiphany": case "PPC": case "PPC_SoftFloat": case "PPC_HardFloat": case "PPC64": case "IA64": case "MIPS32": case "MIPS64": case "MIPS_O32": case "MIPS_N32": case "MIPS_O64": case "MIPS_N64": case "MIPS_EABI": case "MIPS_SoftFloat": case "MIPS_HardFloat": case "MSP430": case "NVPTX": case "NVPTX64": case "RISCV32": case "RISCV64": case "SPARC": case "SPARC_V8Plus": case "SPARC_SoftFloat": case "SPARC_HardFloat": case "SPARC64": case "S390": case "S390X": case "SystemZ": case "HPPA": case "HPPA64": case "SH": case "WebAssembly": case "Alpha": case "Alpha_SoftFloat": case "Alpha_HardFloat": case "LittleEndian": case "BigEndian": case "ELFv1": case "ELFv2": case "CRuntime_Bionic": case "CRuntime_DigitalMars": case "CRuntime_Glibc": case "CRuntime_Microsoft": case "CRuntime_Musl": case "CRuntime_UClibc": case "CppRuntime_Clang": case "CppRuntime_DigitalMars": case "CppRuntime_Gcc": case "CppRuntime_Microsoft": case "CppRuntime_Sun": case "unittest": case "assert": case "all": case "none": return true; default: // Anything that starts with "D_" is reserved return (ident.length >= 2 && ident[0 .. 2] == "D_"); } } /** * Raises an error if a version identifier is reserved. * * Called when setting a version identifier, e.g. `-version=identifier` * parameter to the compiler or `version = Foo` in user code. * * Params: * loc = Where the identifier is set * ident = identifier being checked (ident[$] must be '\0') */ extern(D) static void checkReserved(const ref Loc loc, const(char)[] ident) { if (isReserved(ident)) error(loc, "version identifier `%s` is reserved and cannot be set", ident.ptr); } /** * Add an user-supplied global identifier to the list * * Only called from the driver for `-version=Ident` parameters. * Will raise an error if the identifier is reserved. * * Params: * ident = identifier to add */ deprecated("Kept for C++ compat - Use the string overload instead") static void addGlobalIdent(const(char)* ident) { addGlobalIdent(ident[0 .. ident.strlen]); } /// Ditto extern(D) static void addGlobalIdent(string ident) { // Overload necessary for string literals addGlobalIdent(cast(const(char)[])ident); } /// Ditto extern(D) static void addGlobalIdent(const(char)[] ident) { checkReserved(Loc.initial, ident); addPredefinedGlobalIdent(ident); } /** * Add any global identifier to the list, without checking * if it's predefined * * Only called from the driver after platform detection, * and internally. * * Params: * ident = identifier to add (ident[$] must be '\0') */ deprecated("Kept for C++ compat - Use the string overload instead") static void addPredefinedGlobalIdent(const(char)* ident) { addPredefinedGlobalIdent(ident[0 .. ident.strlen]); } /// Ditto extern(D) static void addPredefinedGlobalIdent(string ident) { // Forward: Overload necessary for string literal addPredefinedGlobalIdent(cast(const(char)[])ident); } /// Ditto extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) { if (!global.versionids) global.versionids = new Identifiers(); global.versionids.push(Identifier.idPool(ident)); } /** * Instantiate a new `VersionCondition` * * Params: * mod = Module this node belongs to * level = Minimum global level this condition needs to pass. * Only used if `ident` is `null`. * ident = Identifier required for this condition to pass. * If `null`, this conditiion will use an integer level. */ extern (D) this(Module mod, uint level, Identifier ident) { super(mod, level, ident); } override int include(Scope* sc) { //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); //if (ident) printf("\tident = '%s'\n", ident.toChars()); if (inc == 0) { inc = 2; bool definedInModule = false; if (ident) { if (findCondition(mod.versionids, ident)) { inc = 1; definedInModule = true; } else if (findCondition(global.versionids, ident)) inc = 1; else { if (!mod.versionidsNot) mod.versionidsNot = new Identifiers(); mod.versionidsNot.push(ident); } } else if (level <= global.params.versionlevel || level <= mod.versionlevel) inc = 1; if (!definedInModule && (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert))) { printDepsConditional(sc, this, "depsVersion "); } } return (inc == 1); } override void accept(Visitor v) { v.visit(this); } override const(char)* toChars() { return ident ? ident.toChars() : "version".ptr; } } /*********************************************************** */ extern (C++) final class StaticIfCondition : Condition { Expression exp; extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } override Condition syntaxCopy() { return new StaticIfCondition(loc, exp.syntaxCopy()); } override int include(Scope* sc) { // printf("StaticIfCondition::include(sc = %p) this=%p inc = %d\n", sc, this, inc); int errorReturn() { if (!global.gag) inc = 2; // so we don't see the error message again return 0; } if (inc == 0) { if (!sc) { error(loc, "`static if` conditional cannot be at global scope"); inc = 2; return 0; } sc = sc.push(sc.scopesym); import dmd.staticcond; bool errors; bool result = evalStaticCondition(sc, exp, exp, errors); sc.pop(); // Prevent repeated condition evaluation. // See: fail_compilation/fail7815.d if (inc != 0) return (inc == 1); if (errors) return errorReturn(); if (result) inc = 1; else inc = 2; } return (inc == 1); } override void accept(Visitor v) { v.visit(this); } override const(char)* toChars() { return exp ? exp.toChars() : "static if".ptr; } } /**************************************** * Find `ident` in an array of identifiers. * Params: * ids = array of identifiers * ident = identifier to search for * Returns: * true if found */ extern (C++) bool findCondition(Identifiers* ids, Identifier ident) { if (ids) { foreach (id; *ids) { if (id == ident) return true; } } return false; } // Helper for printing dependency information private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType) { if (!global.params.moduleDeps || global.params.moduleDepsFile) return; OutBuffer* ob = global.params.moduleDeps; Module imod = sc ? sc.instantiatingModule() : condition.mod; if (!imod) return; ob.writestring(depType); ob.writestring(imod.toPrettyChars()); ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); if (condition.ident) ob.writestring(condition.ident.toString()); else ob.print(condition.level); ob.writeByte('\n'); } ================================================ FILE: gcc/d/dmd/cond.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/cond.h */ #pragma once #include "globals.h" #include "visitor.h" class Expression; class Identifier; class Module; struct Scope; class DebugCondition; class ForeachStatement; class ForeachRangeStatement; int findCondition(Strings *ids, Identifier *ident); class Condition { public: Loc loc; // 0: not computed yet // 1: include // 2: do not include int inc; virtual Condition *syntaxCopy() = 0; virtual int include(Scope *sc) = 0; virtual DebugCondition *isDebugCondition() { return NULL; } virtual void accept(Visitor *v) { v->visit(this); } }; class StaticForeach { public: Loc loc; ForeachStatement *aggrfe; ForeachRangeStatement *rangefe; bool needExpansion; StaticForeach *syntaxCopy(); }; class DVCondition : public Condition { public: unsigned level; Identifier *ident; Module *mod; Condition *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class DebugCondition : public DVCondition { public: static void addGlobalIdent(const char *ident); int include(Scope *sc); DebugCondition *isDebugCondition() { return this; } void accept(Visitor *v) { v->visit(this); } }; class VersionCondition : public DVCondition { public: static void addGlobalIdent(const char *ident); static void addPredefinedGlobalIdent(const char *ident); int include(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class StaticIfCondition : public Condition { public: Expression *exp; int nest; // limit circular dependencies Condition *syntaxCopy(); int include(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/constfold.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/constfold.d, _constfold.d) * Documentation: https://dlang.org/phobos/dmd_constfold.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d */ module dmd.constfold; import core.stdc.string; import core.stdc.stdio; import dmd.arraytypes; import dmd.complex; import dmd.ctfeexpr; import dmd.declaration; import dmd.dstruct; import dmd.errors; import dmd.expression; import dmd.globals; import dmd.mtype; import dmd.root.ctfloat; import dmd.root.port; import dmd.root.rmem; import dmd.sideeffect; import dmd.target; import dmd.tokens; import dmd.utf; private enum LOG = false; private Expression expType(Type type, Expression e) { if (type != e.type) { e = e.copy(); e.type = type; } return e; } /************************************ * Returns: * true if e is a constant */ int isConst(Expression e) { //printf("Expression::isConst(): %s\n", e.toChars()); switch (e.op) { case TOK.int64: case TOK.float64: case TOK.complex80: return 1; case TOK.null_: return 0; case TOK.symbolOffset: return 2; default: return 0; } assert(0); } /********************************** * Initialize a TOK.cantExpression Expression. * Params: * ue = where to write it */ void cantExp(out UnionExp ue) { emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); } /* =============================== constFold() ============================== */ /* The constFold() functions were redundant with the optimize() ones, * and so have been folded in with them. */ /* ========================================================================== */ UnionExp Neg(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; if (e1.type.isreal()) { emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type); } else if (e1.type.isimaginary()) { emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type); } else if (e1.type.iscomplex()) { emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type); } else { emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type); } return ue; } UnionExp Com(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type); return ue; } UnionExp Not(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type); return ue; } private UnionExp Bool(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type); return ue; } UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; static if (LOG) { printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); } if (type.isreal()) { emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type); } else if (type.isimaginary()) { emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type); } else if (type.iscomplex()) { // This rigamarole is necessary so that -0.0 doesn't get // converted to +0.0 by doing an extraneous add with +0.0 auto c1 = complex_t(CTFloat.zero); real_t r1 = CTFloat.zero; real_t i1 = CTFloat.zero; auto c2 = complex_t(CTFloat.zero); real_t r2 = CTFloat.zero; real_t i2 = CTFloat.zero; auto v = complex_t(CTFloat.zero); int x; if (e1.type.isreal()) { r1 = e1.toReal(); x = 0; } else if (e1.type.isimaginary()) { i1 = e1.toImaginary(); x = 3; } else { c1 = e1.toComplex(); x = 6; } if (e2.type.isreal()) { r2 = e2.toReal(); } else if (e2.type.isimaginary()) { i2 = e2.toImaginary(); x += 1; } else { c2 = e2.toComplex(); x += 2; } switch (x) { case 0 + 0: v = complex_t(r1 + r2); break; case 0 + 1: v = complex_t(r1, i2); break; case 0 + 2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; case 3 + 0: v = complex_t(r2, i1); break; case 3 + 1: v = complex_t(CTFloat.zero, i1 + i2); break; case 3 + 2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; case 6 + 0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; case 6 + 1: v = complex_t(creall(c1), cimagl(c1) + i2); break; case 6 + 2: v = c1 + c2; break; default: assert(0); } emplaceExp!(ComplexExp)(&ue, loc, v, type); } else if (e1.op == TOK.symbolOffset) { SymOffExp soe = cast(SymOffExp)e1; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger()); ue.exp().type = type; } else if (e2.op == TOK.symbolOffset) { SymOffExp soe = cast(SymOffExp)e2; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger()); ue.exp().type = type; } else emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type); return ue; } UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; if (type.isreal()) { emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type); } else if (type.isimaginary()) { emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type); } else if (type.iscomplex()) { // This rigamarole is necessary so that -0.0 doesn't get // converted to +0.0 by doing an extraneous add with +0.0 auto c1 = complex_t(CTFloat.zero); real_t r1 = CTFloat.zero; real_t i1 = CTFloat.zero; auto c2 = complex_t(CTFloat.zero); real_t r2 = CTFloat.zero; real_t i2 = CTFloat.zero; auto v = complex_t(CTFloat.zero); int x; if (e1.type.isreal()) { r1 = e1.toReal(); x = 0; } else if (e1.type.isimaginary()) { i1 = e1.toImaginary(); x = 3; } else { c1 = e1.toComplex(); x = 6; } if (e2.type.isreal()) { r2 = e2.toReal(); } else if (e2.type.isimaginary()) { i2 = e2.toImaginary(); x += 1; } else { c2 = e2.toComplex(); x += 2; } switch (x) { case 0 + 0: v = complex_t(r1 - r2); break; case 0 + 1: v = complex_t(r1, -i2); break; case 0 + 2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; case 3 + 0: v = complex_t(-r2, i1); break; case 3 + 1: v = complex_t(CTFloat.zero, i1 - i2); break; case 3 + 2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; case 6 + 0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; case 6 + 1: v = complex_t(creall(c1), cimagl(c1) - i2); break; case 6 + 2: v = c1 - c2; break; default: assert(0); } emplaceExp!(ComplexExp)(&ue, loc, v, type); } else if (e1.op == TOK.symbolOffset) { SymOffExp soe = cast(SymOffExp)e1; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); ue.exp().type = type; } else { emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type); } return ue; } UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; if (type.isfloating()) { auto c = complex_t(CTFloat.zero); real_t r = CTFloat.zero; if (e1.type.isreal()) { r = e1.toReal(); c = e2.toComplex(); c = complex_t(r * creall(c), r * cimagl(c)); } else if (e1.type.isimaginary()) { r = e1.toImaginary(); c = e2.toComplex(); c = complex_t(-r * cimagl(c), r * creall(c)); } else if (e2.type.isreal()) { r = e2.toReal(); c = e1.toComplex(); c = complex_t(r * creall(c), r * cimagl(c)); } else if (e2.type.isimaginary()) { r = e2.toImaginary(); c = e1.toComplex(); c = complex_t(-r * cimagl(c), r * creall(c)); } else c = e1.toComplex() * e2.toComplex(); if (type.isreal()) emplaceExp!(RealExp)(&ue, loc, creall(c), type); else if (type.isimaginary()) emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); else if (type.iscomplex()) emplaceExp!(ComplexExp)(&ue, loc, c, type); else assert(0); } else { emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type); } return ue; } UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; if (type.isfloating()) { auto c = complex_t(CTFloat.zero); if (e2.type.isreal()) { if (e1.type.isreal()) { emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type); return ue; } const r = e2.toReal(); c = e1.toComplex(); c = complex_t(creall(c) / r, cimagl(c) / r); } else if (e2.type.isimaginary()) { const r = e2.toImaginary(); c = e1.toComplex(); c = complex_t(cimagl(c) / r, -creall(c) / r); } else { c = e1.toComplex() / e2.toComplex(); } if (type.isreal()) emplaceExp!(RealExp)(&ue, loc, creall(c), type); else if (type.isimaginary()) emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); else if (type.iscomplex()) emplaceExp!(ComplexExp)(&ue, loc, c, type); else assert(0); } else { sinteger_t n1; sinteger_t n2; sinteger_t n; n1 = e1.toInteger(); n2 = e2.toInteger(); if (n2 == 0) { e2.error("divide by 0"); emplaceExp!(ErrorExp)(&ue); return ue; } if (n2 == -1 && !type.isunsigned()) { // Check for int.min / -1 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64) { e2.error("integer overflow: `int.min / -1`"); emplaceExp!(ErrorExp)(&ue); return ue; } else if (n1 == 0x8000000000000000L) // long.min / -1 { e2.error("integer overflow: `long.min / -1L`"); emplaceExp!(ErrorExp)(&ue); return ue; } } if (e1.type.isunsigned() || e2.type.isunsigned()) n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2); else n = n1 / n2; emplaceExp!(IntegerExp)(&ue, loc, n, type); } return ue; } UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; if (type.isfloating()) { auto c = complex_t(CTFloat.zero); if (e2.type.isreal()) { const r2 = e2.toReal(); c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2); } else if (e2.type.isimaginary()) { const i2 = e2.toImaginary(); c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2); } else assert(0); if (type.isreal()) emplaceExp!(RealExp)(&ue, loc, creall(c), type); else if (type.isimaginary()) emplaceExp!(RealExp)(&ue, loc, cimagl(c), type); else if (type.iscomplex()) emplaceExp!(ComplexExp)(&ue, loc, c, type); else assert(0); } else { sinteger_t n1; sinteger_t n2; sinteger_t n; n1 = e1.toInteger(); n2 = e2.toInteger(); if (n2 == 0) { e2.error("divide by 0"); emplaceExp!(ErrorExp)(&ue); return ue; } if (n2 == -1 && !type.isunsigned()) { // Check for int.min % -1 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64) { e2.error("integer overflow: `int.min %% -1`"); emplaceExp!(ErrorExp)(&ue); return ue; } else if (n1 == 0x8000000000000000L) // long.min % -1 { e2.error("integer overflow: `long.min %% -1L`"); emplaceExp!(ErrorExp)(&ue); return ue; } } if (e1.type.isunsigned() || e2.type.isunsigned()) n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2); else n = n1 % n2; emplaceExp!(IntegerExp)(&ue, loc, n, type); } return ue; } UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2) { //printf("Pow()\n"); UnionExp ue; // Handle integer power operations. if (e2.type.isintegral()) { dinteger_t n = e2.toInteger(); bool neg; if (!e2.type.isunsigned() && cast(sinteger_t)n < 0) { if (e1.type.isintegral()) { cantExp(ue); return ue; } // Don't worry about overflow, from now on n is unsigned. neg = true; n = -n; } else neg = false; UnionExp ur, uv; if (e1.type.iscomplex()) { emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type); emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type); } else if (e1.type.isfloating()) { emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type); emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type); } else { emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type); emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type); } Expression r = ur.exp(); Expression v = uv.exp(); while (n != 0) { if (n & 1) { // v = v * r; uv = Mul(loc, v.type, v, r); } n >>= 1; // r = r * r ur = Mul(loc, r.type, r, r); } if (neg) { // ue = 1.0 / v UnionExp one; emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type); uv = Div(loc, v.type, one.exp(), v); } if (type.iscomplex()) emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type); else if (type.isintegral()) emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type); else emplaceExp!(RealExp)(&ue, loc, v.toReal(), type); } else if (e2.type.isfloating()) { // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN if (e1.toReal() < CTFloat.zero) { emplaceExp!(RealExp)(&ue, loc, Target.RealProperties.nan, type); } else cantExp(ue); } else cantExp(ue); return ue; } UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type); return ue; } UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; dinteger_t value = e1.toInteger(); dinteger_t dcount = e2.toInteger(); assert(dcount <= 0xFFFFFFFF); uint count = cast(uint)dcount; switch (e1.type.toBasetype().ty) { case Tint8: value = cast(d_int8)value >> count; break; case Tuns8: case Tchar: value = cast(d_uns8)value >> count; break; case Tint16: value = cast(d_int16)value >> count; break; case Tuns16: case Twchar: value = cast(d_uns16)value >> count; break; case Tint32: value = cast(d_int32)value >> count; break; case Tuns32: case Tdchar: value = cast(d_uns32)value >> count; break; case Tint64: value = cast(d_int64)value >> count; break; case Tuns64: value = cast(d_uns64)value >> count; break; case Terror: emplaceExp!(ErrorExp)(&ue); return ue; default: assert(0); } emplaceExp!(IntegerExp)(&ue, loc, value, type); return ue; } UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; dinteger_t value = e1.toInteger(); dinteger_t dcount = e2.toInteger(); assert(dcount <= 0xFFFFFFFF); uint count = cast(uint)dcount; switch (e1.type.toBasetype().ty) { case Tint8: case Tuns8: case Tchar: // Possible only with >>>=. >>> always gets promoted to int. value = (value & 0xFF) >> count; break; case Tint16: case Tuns16: case Twchar: // Possible only with >>>=. >>> always gets promoted to int. value = (value & 0xFFFF) >> count; break; case Tint32: case Tuns32: case Tdchar: value = (value & 0xFFFFFFFF) >> count; break; case Tint64: case Tuns64: value = cast(d_uns64)value >> count; break; case Terror: emplaceExp!(ErrorExp)(&ue); return ue; default: assert(0); } emplaceExp!(IntegerExp)(&ue, loc, value, type); return ue; } UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type); return ue; } UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type); return ue; } UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2) { //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars()); UnionExp ue = void; emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type); return ue; } /* Also returns TOK.cantExpression if cannot be computed. */ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; int cmp = 0; real_t r1 = CTFloat.zero; real_t r2 = CTFloat.zero; //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); assert(op == TOK.equal || op == TOK.notEqual); if (e1.op == TOK.null_) { if (e2.op == TOK.null_) cmp = 1; else if (e2.op == TOK.string_) { StringExp es2 = cast(StringExp)e2; cmp = (0 == es2.len); } else if (e2.op == TOK.arrayLiteral) { ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; cmp = !es2.elements || (0 == es2.elements.dim); } else { cantExp(ue); return ue; } } else if (e2.op == TOK.null_) { if (e1.op == TOK.string_) { StringExp es1 = cast(StringExp)e1; cmp = (0 == es1.len); } else if (e1.op == TOK.arrayLiteral) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; cmp = !es1.elements || (0 == es1.elements.dim); } else { cantExp(ue); return ue; } } else if (e1.op == TOK.string_ && e2.op == TOK.string_) { StringExp es1 = cast(StringExp)e1; StringExp es2 = cast(StringExp)e2; if (es1.sz != es2.sz) { assert(global.errors); cantExp(ue); return ue; } if (es1.len == es2.len && memcmp(es1.string, es2.string, es1.sz * es1.len) == 0) cmp = 1; else cmp = 0; } else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) cmp = 1; // both arrays are empty else if (!es1.elements || !es2.elements) cmp = 0; else if (es1.elements.dim != es2.elements.dim) cmp = 0; else { for (size_t i = 0; i < es1.elements.dim; i++) { auto ee1 = es1.getElement(i); auto ee2 = es2.getElement(i); ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2); if (CTFEExp.isCantExp(ue.exp())) return ue; cmp = cast(int)ue.exp().toInteger(); if (cmp == 0) break; } } } else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_) { // Swap operands and use common code Expression etmp = e1; e1 = e2; e2 = etmp; goto Lsa; } else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral) { Lsa: StringExp es1 = cast(StringExp)e1; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; size_t dim1 = es1.len; size_t dim2 = es2.elements ? es2.elements.dim : 0; if (dim1 != dim2) cmp = 0; else { cmp = 1; // if dim1 winds up being 0 for (size_t i = 0; i < dim1; i++) { uinteger_t c = es1.charAt(i); auto ee2 = es2.getElement(i); if (ee2.isConst() != 1) { cantExp(ue); return ue; } cmp = (c == ee2.toInteger()); if (cmp == 0) break; } } } else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral) { StructLiteralExp es1 = cast(StructLiteralExp)e1; StructLiteralExp es2 = cast(StructLiteralExp)e2; if (es1.sd != es2.sd) cmp = 0; else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) cmp = 1; // both arrays are empty else if (!es1.elements || !es2.elements) cmp = 0; else if (es1.elements.dim != es2.elements.dim) cmp = 0; else { cmp = 1; for (size_t i = 0; i < es1.elements.dim; i++) { Expression ee1 = (*es1.elements)[i]; Expression ee2 = (*es2.elements)[i]; if (ee1 == ee2) continue; if (!ee1 || !ee2) { cmp = 0; break; } ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2); if (ue.exp().op == TOK.cantExpression) return ue; cmp = cast(int)ue.exp().toInteger(); if (cmp == 0) break; } } } else if (e1.isConst() != 1 || e2.isConst() != 1) { cantExp(ue); return ue; } else if (e1.type.isreal()) { r1 = e1.toReal(); r2 = e2.toReal(); goto L1; } else if (e1.type.isimaginary()) { r1 = e1.toImaginary(); r2 = e2.toImaginary(); L1: if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered { cmp = 0; } else { cmp = (r1 == r2); } } else if (e1.type.iscomplex()) { cmp = e1.toComplex() == e2.toComplex(); } else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer) { cmp = (e1.toInteger() == e2.toInteger()); } else { cantExp(ue); return ue; } if (op == TOK.notEqual) cmp ^= 1; emplaceExp!(IntegerExp)(&ue, loc, cmp, type); return ue; } UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; int cmp; if (e1.op == TOK.null_) { cmp = (e2.op == TOK.null_); } else if (e2.op == TOK.null_) { cmp = 0; } else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset) { SymOffExp es1 = cast(SymOffExp)e1; SymOffExp es2 = cast(SymOffExp)e2; cmp = (es1.var == es2.var && es1.offset == es2.offset); } else { if (e1.type.isreal()) { cmp = RealEquals(e1.toReal(), e2.toReal()); } else if (e1.type.isimaginary()) { cmp = RealEquals(e1.toImaginary(), e2.toImaginary()); } else if (e1.type.iscomplex()) { complex_t v1 = e1.toComplex(); complex_t v2 = e2.toComplex(); cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1)); } else { ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2); return ue; } } if (op == TOK.notIdentity) cmp ^= 1; emplaceExp!(IntegerExp)(&ue, loc, cmp, type); return ue; } UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; dinteger_t n; real_t r1 = CTFloat.zero; real_t r2 = CTFloat.zero; //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); if (e1.op == TOK.string_ && e2.op == TOK.string_) { StringExp es1 = cast(StringExp)e1; StringExp es2 = cast(StringExp)e2; size_t sz = es1.sz; assert(sz == es2.sz); size_t len = es1.len; if (es2.len < len) len = es2.len; int rawCmp = memcmp(es1.string, es2.string, sz * len); if (rawCmp == 0) rawCmp = cast(int)(es1.len - es2.len); n = specificCmp(op, rawCmp); } else if (e1.isConst() != 1 || e2.isConst() != 1) { cantExp(ue); return ue; } else if (e1.type.isreal()) { r1 = e1.toReal(); r2 = e2.toReal(); goto L1; } else if (e1.type.isimaginary()) { r1 = e1.toImaginary(); r2 = e2.toImaginary(); L1: n = realCmp(op, r1, r2); } else if (e1.type.iscomplex()) { assert(0); } else { sinteger_t n1; sinteger_t n2; n1 = e1.toInteger(); n2 = e2.toInteger(); if (e1.type.isunsigned() || e2.type.isunsigned()) n = intUnsignedCmp(op, n1, n2); else n = intSignedCmp(op, n1, n2); } emplaceExp!(IntegerExp)(&ue, loc, n, type); return ue; } /* Also returns TOK.cantExpression if cannot be computed. * to: type to cast to * type: type to paint the result */ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) { UnionExp ue = void; Type tb = to.toBasetype(); Type typeb = type.toBasetype(); //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars()); //printf("\te1.type = %s\n", e1.type.toChars()); if (e1.type.equals(type) && type.equals(to)) { emplaceExp!(UnionExp)(&ue, e1); return ue; } if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to)) { Expression ex = (cast(VectorExp)e1).e1; emplaceExp!(UnionExp)(&ue, ex); return ue; } if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant) { goto L1; } // Allow covariant converions of delegates // (Perhaps implicit conversion from pure to impure should be a MATCH.constant, // then we wouldn't need this extra check.) if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert) { goto L1; } /* Allow casting from one string type to another */ if (e1.op == TOK.string_) { if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size()) { goto L1; } } if (e1.op == TOK.arrayLiteral && typeb == tb) { L1: Expression ex = expType(to, e1); emplaceExp!(UnionExp)(&ue, ex); return ue; } if (e1.isConst() != 1) { cantExp(ue); } else if (tb.ty == Tbool) { emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type); } else if (type.isintegral()) { if (e1.type.isfloating()) { dinteger_t result; real_t r = e1.toReal(); switch (typeb.ty) { case Tint8: result = cast(d_int8)cast(sinteger_t)r; break; case Tchar: case Tuns8: result = cast(d_uns8)cast(dinteger_t)r; break; case Tint16: result = cast(d_int16)cast(sinteger_t)r; break; case Twchar: case Tuns16: result = cast(d_uns16)cast(dinteger_t)r; break; case Tint32: result = cast(d_int32)r; break; case Tdchar: case Tuns32: result = cast(d_uns32)r; break; case Tint64: result = cast(d_int64)r; break; case Tuns64: result = cast(d_uns64)r; break; default: assert(0); } emplaceExp!(IntegerExp)(&ue, loc, result, type); } else if (type.isunsigned()) emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type); else emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type); } else if (tb.isreal()) { real_t value = e1.toReal(); emplaceExp!(RealExp)(&ue, loc, value, type); } else if (tb.isimaginary()) { real_t value = e1.toImaginary(); emplaceExp!(RealExp)(&ue, loc, value, type); } else if (tb.iscomplex()) { complex_t value = e1.toComplex(); emplaceExp!(ComplexExp)(&ue, loc, value, type); } else if (tb.isscalar()) { emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type); } else if (tb.ty == Tvoid) { cantExp(ue); } else if (tb.ty == Tstruct && e1.op == TOK.int64) { // Struct = 0; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); assert(sd); auto elements = new Expressions(); for (size_t i = 0; i < sd.fields.dim; i++) { VarDeclaration v = sd.fields[i]; UnionExp zero; emplaceExp!(IntegerExp)(&zero, 0); ue = Cast(loc, v.type, v.type, zero.exp()); if (ue.exp().op == TOK.cantExpression) return ue; elements.push(ue.exp().copy()); } emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements); ue.exp().type = type; } else { if (type != Type.terror) { // have to change to Internal Compiler Error // all invalid casts should be handled already in Expression::castTo(). error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars()); } emplaceExp!(ErrorExp)(&ue); } return ue; } UnionExp ArrayLength(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; if (e1.op == TOK.string_) { StringExp es1 = cast(StringExp)e1; emplaceExp!(IntegerExp)(&ue, loc, es1.len, type); } else if (e1.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; size_t dim = ale.elements ? ale.elements.dim : 0; emplaceExp!(IntegerExp)(&ue, loc, dim, type); } else if (e1.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1; size_t dim = ale.keys.dim; emplaceExp!(IntegerExp)(&ue, loc, dim, type); } else if (e1.type.toBasetype().ty == Tsarray) { Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim; emplaceExp!(UnionExp)(&ue, e); } else cantExp(ue); return ue; } /* Also return TOK.cantExpression if this fails */ UnionExp Index(Type type, Expression e1, Expression e2) { UnionExp ue = void; Loc loc = e1.loc; //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); assert(e1.type); if (e1.op == TOK.string_ && e2.op == TOK.int64) { StringExp es1 = cast(StringExp)e1; uinteger_t i = e2.toInteger(); if (i >= es1.len) { e1.error("string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len); emplaceExp!(ErrorExp)(&ue); } else { emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type); } } else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64) { TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); uinteger_t length = tsa.dim.toInteger(); uinteger_t i = e2.toInteger(); if (i >= length) { e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length); emplaceExp!(ErrorExp)(&ue); } else if (e1.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; auto e = ale.getElement(cast(size_t)i); e.type = type; e.loc = loc; if (hasSideEffect(e)) cantExp(ue); else emplaceExp!(UnionExp)(&ue, e); } else cantExp(ue); } else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64) { uinteger_t i = e2.toInteger(); if (e1.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; if (i >= ale.elements.dim) { e1.error("array index %llu is out of bounds `%s[0 .. %u]`", i, e1.toChars(), ale.elements.dim); emplaceExp!(ErrorExp)(&ue); } else { auto e = ale.getElement(cast(size_t)i); e.type = type; e.loc = loc; if (hasSideEffect(e)) cantExp(ue); else emplaceExp!(UnionExp)(&ue, e); } } else cantExp(ue); } else if (e1.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1; /* Search the keys backwards, in case there are duplicate keys */ for (size_t i = ae.keys.dim; i;) { i--; Expression ekey = (*ae.keys)[i]; ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2); if (CTFEExp.isCantExp(ue.exp())) return ue; if (ue.exp().isBool(true)) { Expression e = (*ae.values)[i]; e.type = type; e.loc = loc; if (hasSideEffect(e)) cantExp(ue); else emplaceExp!(UnionExp)(&ue, e); return ue; } } cantExp(ue); } else cantExp(ue); return ue; } /* Also return TOK.cantExpression if this fails */ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) { UnionExp ue = void; Loc loc = e1.loc; static if (LOG) { printf("Slice()\n"); if (lwr) { printf("\te1 = %s\n", e1.toChars()); printf("\tlwr = %s\n", lwr.toChars()); printf("\tupr = %s\n", upr.toChars()); } } static bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure { assert(lwr <= upr); return !(newlwr <= newupr && lwr <= newlwr && newupr <= upr); } if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64) { StringExp es1 = cast(StringExp)e1; const uinteger_t ilwr = lwr.toInteger(); const uinteger_t iupr = upr.toInteger(); if (sliceBoundsCheck(0, es1.len, ilwr, iupr)) cantExp(ue); // https://issues.dlang.org/show_bug.cgi?id=18115 else { const len = cast(size_t)(iupr - ilwr); const sz = es1.sz; void* s = mem.xmalloc(len * sz); memcpy(s, es1.string + ilwr * sz, len * sz); emplaceExp!(StringExp)(&ue, loc, s, len, es1.postfix); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = es1.committed; es.type = type; } } else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1)) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; const uinteger_t ilwr = lwr.toInteger(); const uinteger_t iupr = upr.toInteger(); if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr)) cantExp(ue); else { auto elements = new Expressions(cast(size_t)(iupr - ilwr)); memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof); emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements); } } else cantExp(ue); return ue; } /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'. * existingAE[firstIndex..firstIndex+newval.length] = newval. */ void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex) { const len = newval.len; Type elemType = existingAE.type.nextOf(); foreach (j; 0 .. len) { const val = newval.getCodeUnit(j); (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); } } /* Set a slice of string 'existingSE' from a char array literal 'newae'. * existingSE[firstIndex..firstIndex+newae.length] = newae. */ void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex) { assert(existingSE.ownedByCtfe != OwnedBy.code); foreach (j; 0 .. newae.elements.dim) { existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae.getElement(j).toInteger()); } } /* Set a slice of string 'existingSE' from a string 'newstr'. * existingSE[firstIndex..firstIndex+newstr.length] = newstr. */ void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex) { assert(existingSE.ownedByCtfe != OwnedBy.code); size_t sz = existingSE.sz; assert(sz == newstr.sz); memcpy(existingSE.string + firstIndex * sz, newstr.string, sz * newstr.len); } /* Compare a string slice with another string slice. * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) */ int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len) { size_t sz = se1.sz; assert(sz == se2.sz); return memcmp(se1.string + sz * lo1, se2.string + sz * lo2, sz * len); } /* Compare a string slice with an array literal slice * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) */ int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len) { foreach (j; 0 .. len) { const val2 = cast(dchar)ae2.getElement(j + lo2).toInteger(); const val1 = se1.getCodeUnit(j + lo1); const int c = val1 - val2; if (c) return c; } return 0; } /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s. * Params: * e1 = If it's ArrayLiteralExp, its `elements` will be copied. * Otherwise, `e1` itself will be pushed into the new `Expressions`. * e2 = If it's not `null`, it will be pushed/appended to the new * `Expressions` by the same way with `e1`. * Returns: * Newly allocated `Expressions`. Note that it points to the original * `Expression` values in e1 and e2. */ private Expressions* copyElements(Expression e1, Expression e2 = null) { auto elems = new Expressions(); void append(ArrayLiteralExp ale) { if (!ale.elements) return; auto d = elems.dim; elems.append(ale.elements); foreach (ref el; (*elems)[d .. elems.dim]) { if (!el) el = ale.basis; } } if (e1.op == TOK.arrayLiteral) append(cast(ArrayLiteralExp)e1); else elems.push(e1); if (e2) { if (e2.op == TOK.arrayLiteral) append(cast(ArrayLiteralExp)e2); else elems.push(e2); } return elems; } /* Also return TOK.cantExpression if this fails */ UnionExp Cat(Type type, Expression e1, Expression e2) { UnionExp ue = void; Expression e = CTFEExp.cantexp; Loc loc = e1.loc; Type t; Type t1 = e1.type.toBasetype(); Type t2 = e2.type.toBasetype(); //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars()); if (e1.op == TOK.null_ && (e2.op == TOK.int64 || e2.op == TOK.structLiteral)) { e = e2; t = t1; goto L2; } else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_) { e = e1; t = t2; L2: Type tn = e.type.toBasetype(); if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar) { // Create a StringExp if (t.nextOf()) t = t.nextOf().toBasetype(); ubyte sz = cast(ubyte)t.size(); dinteger_t v = e.toInteger(); size_t len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v); void* s = mem.xmalloc(len * sz); if (t.ty == tn.ty) Port.valcpy(s, v, sz); else utf_encode(sz, s, cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.type = type; es.sz = sz; es.committed = 1; } else { // Create an ArrayLiteralExp auto elements = new Expressions(); elements.push(e); emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements); } assert(ue.exp().type); return ue; } else if (e1.op == TOK.null_ && e2.op == TOK.null_) { if (type == e1.type) { // Handle null ~= null if (t1.ty == Tarray && t2 == t1.nextOf()) { emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2); assert(ue.exp().type); return ue; } else { emplaceExp!(UnionExp)(&ue, e1); assert(ue.exp().type); return ue; } } if (type == e2.type) { emplaceExp!(UnionExp)(&ue, e2); assert(ue.exp().type); return ue; } emplaceExp!(NullExp)(&ue, e1.loc, type); assert(ue.exp().type); return ue; } else if (e1.op == TOK.string_ && e2.op == TOK.string_) { // Concatenate the strings StringExp es1 = cast(StringExp)e1; StringExp es2 = cast(StringExp)e2; size_t len = es1.len + es2.len; ubyte sz = es1.sz; if (sz != es2.sz) { /* Can happen with: * auto s = "foo"d ~ "bar"c; */ assert(global.errors); cantExp(ue); assert(ue.exp().type); return ue; } void* s = mem.xmalloc(len * sz); memcpy(cast(char*)s, es1.string, es1.len * sz); memcpy(cast(char*)s + es1.len * sz, es2.string, es2.len * sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = es1.committed | es2.committed; es.type = type; assert(ue.exp().type); return ue; } else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string --> [chars] StringExp es = cast(StringExp)e2; ArrayLiteralExp ea = cast(ArrayLiteralExp)e1; size_t len = es.len + ea.elements.dim; auto elems = new Expressions(len); for (size_t i = 0; i < ea.elements.dim; ++i) { (*elems)[i] = ea.getElement(i); } emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems); ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim); assert(ue.exp().type); return ue; } else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral()) { // string ~ [chars] --> [chars] StringExp es = cast(StringExp)e1; ArrayLiteralExp ea = cast(ArrayLiteralExp)e2; size_t len = es.len + ea.elements.dim; auto elems = new Expressions(len); for (size_t i = 0; i < ea.elements.dim; ++i) { (*elems)[es.len + i] = ea.getElement(i); } emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems); ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); sliceAssignArrayLiteralFromString(dest, es, 0); assert(ue.exp().type); return ue; } else if (e1.op == TOK.string_ && e2.op == TOK.int64) { // string ~ char --> string StringExp es1 = cast(StringExp)e1; StringExp es; ubyte sz = es1.sz; dinteger_t v = e2.toInteger(); // Is it a concatenation of homogenous types? // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) bool homoConcat = (sz == t2.size()); size_t len = es1.len; len += homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v); void* s = mem.xmalloc(len * sz); memcpy(s, es1.string, es1.len * sz); if (homoConcat) Port.valcpy(cast(char*)s + (sz * es1.len), v, sz); else utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s, len); es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = es1.committed; es.type = type; assert(ue.exp().type); return ue; } else if (e1.op == TOK.int64 && e2.op == TOK.string_) { // Concatenate the strings StringExp es2 = cast(StringExp)e2; size_t len = 1 + es2.len; ubyte sz = es2.sz; dinteger_t v = e1.toInteger(); void* s = mem.xmalloc(len * sz); memcpy(cast(char*)s, &v, sz); memcpy(cast(char*)s + sz, es2.string, es2.len * sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = es2.committed; es.type = type; assert(ue.exp().type); return ue; } else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // Concatenate the arrays auto elems = copyElements(e1, e2); emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems); e = ue.exp(); if (type.toBasetype().ty == Tsarray) { e.type = t1.nextOf().sarrayOf(elems.dim); } else e.type = type; assert(ue.exp().type); return ue; } else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf())) { e = e1; goto L3; } else if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { e = e2; L3: // Concatenate the array with null auto elems = copyElements(e); emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems); e = ue.exp(); if (type.toBasetype().ty == Tsarray) { e.type = t1.nextOf().sarrayOf(elems.dim); } else e.type = type; assert(ue.exp().type); return ue; } else if ((e1.op == TOK.arrayLiteral || e1.op == TOK.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type)) { auto elems = (e1.op == TOK.arrayLiteral) ? copyElements(e1) : new Expressions(); elems.push(e2); emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems); e = ue.exp(); if (type.toBasetype().ty == Tsarray) { e.type = e2.type.sarrayOf(elems.dim); } else e.type = type; assert(ue.exp().type); return ue; } else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type)) { auto elems = copyElements(e1, e2); emplaceExp!(ArrayLiteralExp)(&ue, e2.loc, cast(Type)null, elems); e = ue.exp(); if (type.toBasetype().ty == Tsarray) { e.type = e1.type.sarrayOf(elems.dim); } else e.type = type; assert(ue.exp().type); return ue; } else if (e1.op == TOK.null_ && e2.op == TOK.string_) { t = e1.type; e = e2; goto L1; } else if (e1.op == TOK.string_ && e2.op == TOK.null_) { e = e1; t = e2.type; L1: Type tb = t.toBasetype(); if (tb.ty == Tarray && tb.nextOf().equivalent(e.type)) { auto expressions = new Expressions(); expressions.push(e); emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions); e = ue.exp(); } else { emplaceExp!(UnionExp)(&ue, e); e = ue.exp(); } if (!e.type.equals(type)) { StringExp se = cast(StringExp)e.copy(); e = se.castTo(null, type); emplaceExp!(UnionExp)(&ue, e); e = ue.exp(); } } else cantExp(ue); assert(ue.exp().type); return ue; } UnionExp Ptr(Type type, Expression e1) { //printf("Ptr(e1 = %s)\n", e1.toChars()); UnionExp ue = void; if (e1.op == TOK.add) { AddExp ae = cast(AddExp)e1; if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64) { AddrExp ade = cast(AddrExp)ae.e1; if (ade.e1.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)ade.e1; uint offset = cast(uint)ae.e2.toInteger(); Expression e = se.getField(type, offset); if (e) { emplaceExp!(UnionExp)(&ue, e); return ue; } } } } cantExp(ue); return ue; } ================================================ FILE: gcc/d/dmd/cppmangle.d ================================================ /** * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) * * Do mangling for C++ linkage. * This is the POSIX side of the implementation. * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. * * Copyright: Copyright (C) 1999-2018 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/cppmangle.d, _cppmangle.d) * Documentation: https://dlang.org/phobos/dmd_cppmangle.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmangle.d * * References: * Follows Itanium C++ ABI 1.86 section 5.1 * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling * which is where the grammar comments come from. * * Bugs: * https://issues.dlang.org/query.cgi * enter `C++, mangling` as the keywords. */ module dmd.cppmangle; import core.stdc.string; import core.stdc.stdio; import dmd.arraytypes; import dmd.declaration; import dmd.dsymbol; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.nspace; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; // helper to check if an identifier is a C++ operator enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown } package CppOperator isCppOperator(Identifier id) { __gshared const(Identifier)[] operators = null; if (!operators) operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign]; foreach (i, op; operators) { if (op == id) return cast(CppOperator)i; } return CppOperator.Unknown; } /// extern(C++) const(char)* toCppMangleItanium(Dsymbol s) { //printf("toCppMangleItanium(%s)\n", s.toChars()); OutBuffer buf; scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc); v.mangleOf(s); return buf.extractString(); } /// extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s) { //printf("cppTypeInfoMangle(%s)\n", s.toChars()); OutBuffer buf; buf.writestring("_ZTI"); // "TI" means typeinfo structure scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc); v.cpp_mangle_name(s, false); return buf.extractString(); } /****************************** * Determine if sym is the 'primary' destructor, that is, * the most-aggregate destructor (the one that is defined as __xdtor) * Params: * sym = Dsymbol * Returns: * true if sym is the primary destructor for an aggregate */ bool isPrimaryDtor(const Dsymbol sym) { const dtor = sym.isDtorDeclaration(); if (!dtor) return false; const ad = dtor.isMember(); assert(ad); return dtor == ad.primaryDtor; } /// Context used when processing pre-semantic AST private struct Context { /// Template instance of the function being mangled TemplateInstance ti; /// Function declaration we're mangling FuncDeclaration fd; /// Current type / expression being processed (semantically analyzed) RootObject res; @disable ref Context opAssign(ref Context other); @disable ref Context opAssign(Context other); /** * Helper function to track `res` * * Params: * next = Value to set `this.res` to. * If `this.res` is `null`, the expression is not evalutated. * This allow this code to be used even when no context is needed. * * Returns: * The previous state of this `Context` object */ private Context push(lazy RootObject next) { auto r = this.res; if (r !is null) this.res = next; return Context(this.ti, this.fd, r); } /** * Reset the context to a previous one, making any adjustment necessary */ private void pop(ref Context prev) { this.res = prev.res; } } private final class CppMangleVisitor : Visitor { /// Context used when processing pre-semantic AST private Context context; Objects components; // array of components available for substitution OutBuffer* buf; // append the mangling to buf[] Loc loc; // location for use in error messages /** * Constructor * * Params: * buf = `OutBuffer` to write the mangling to * loc = `Loc` of the symbol being mangled */ this(OutBuffer* buf, Loc loc) { this.buf = buf; this.loc = loc; } /***** * Entry point. Append mangling to buf[] * Params: * s = symbol to mangle */ void mangleOf(Dsymbol s) { if (VarDeclaration vd = s.isVarDeclaration()) { mangle_variable(vd, false); } else if (FuncDeclaration fd = s.isFuncDeclaration()) { mangle_function(fd); } else { assert(0); } } /** * Mangle the return type of a function * * This is called on a templated function type. * Context is set to the `FuncDeclaration`. * * Params: * preSemantic = the `FuncDeclaration`'s `originalType` */ void mangleReturnType(TypeFunction preSemantic) { auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type; Type rt = preSemantic.nextOf(); if (tf.isref) rt = rt.referenceTo(); auto prev = this.context.push(tf.nextOf()); scope (exit) this.context.pop(prev); this.headOfType(rt); } /** * Write a seq-id from an index number, excluding the terminating '_' * * Params: * idx = the index in a substitution list. * Note that index 0 has no value, and `S0_` would be the * substitution at index 1 in the list. * * See-Also: * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id */ private void writeSequenceFromIndex(size_t idx) { if (idx) { void write_seq_id(size_t i) { if (i >= 36) { write_seq_id(i / 36); i %= 36; } i += (i < 10) ? '0' : 'A' - 10; buf.writeByte(cast(char)i); } write_seq_id(idx - 1); } } bool substitute(RootObject p) { //printf("substitute %s\n", p ? p.toChars() : null); auto i = find(p); if (i >= 0) { //printf("\tmatch\n"); /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... */ buf.writeByte('S'); writeSequenceFromIndex(i); buf.writeByte('_'); return true; } return false; } /****** * See if `p` exists in components[] * * Note that components can contain `null` entries, * as the index used in mangling is based on the index in the array. * * If called with an object whose dynamic type is `Nspace`, * calls the `find(Nspace)` overload. * * Returns: * index if found, -1 if not */ int find(RootObject p) { //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : null); scope v = new ComponentVisitor(p); foreach (i, component; components) { if (component) component.visitObject(v); if (v.result) return cast(int)i; } return -1; } /********************* * Append p to components[] */ void append(RootObject p) { //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null"); components.push(p); } /** * Write an identifier preceded by its length * * Params: * ident = `Identifier` to write to `this.buf` */ void writeIdentifier(const ref Identifier ident) { const name = ident.toString(); this.buf.print(name.length); this.buf.writestring(name); } /************************ * Determine if symbol is indeed the global ::std namespace. * Params: * s = symbol to check * Returns: * true if it is ::std */ static bool isStd(Dsymbol s) { return (s && s.ident == Id.std && // the right name s.isNspace() && // g++ disallows global "std" for other than a namespace !getQualifier(s)); // at global level } /****************************** * Write the mangled representation of a template argument. * Params: * ti = the template instance * arg = the template argument index */ void template_arg(TemplateInstance ti, size_t arg) { TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); assert(td); TemplateParameter tp = (*td.parameters)[arg]; RootObject o = (*ti.tiargs)[arg]; Objects* pctx; auto prev = this.context.push({ TemplateInstance parentti; if (this.context.res.dyncast() == DYNCAST.dsymbol) parentti = this.context.res.asFuncDecl().parent.isTemplateInstance(); else parentti = this.context.res.asType().toDsymbol(null).parent.isTemplateInstance(); return (*parentti.tiargs)[arg]; }()); scope (exit) this.context.pop(prev); if (tp.isTemplateTypeParameter()) { Type t = isType(o); assert(t); t.accept(this); } else if (TemplateValueParameter tv = tp.isTemplateValueParameter()) { // ::= L E # integer literal if (tv.valType.isintegral()) { Expression e = isExpression(o); assert(e); buf.writeByte('L'); tv.valType.accept(this); auto val = e.toUInteger(); if (!tv.valType.isunsigned() && cast(sinteger_t)val < 0) { val = -val; buf.writeByte('n'); } buf.print(val); buf.writeByte('E'); } else { ti.error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv.valType.toChars()); fatal(); } } else if (tp.isTemplateAliasParameter()) { // Passing a function as alias parameter is the same as passing // `&function` Dsymbol d = isDsymbol(o); Expression e = isExpression(o); if (d && d.isFuncDeclaration()) { // X .. E => template parameter is an expression // 'ad' => unary operator ('&') // L .. E => is a buf.writestring("XadL"); mangle_function(d.isFuncDeclaration()); buf.writestring("EE"); } else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration()) { VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); buf.writeByte('L'); mangle_variable(vd, true); buf.writeByte('E'); } else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) { if (!substitute(d)) { cpp_mangle_name(d, false); } } else { ti.error("Internal Compiler Error: C++ `%s` template alias parameter is not supported", o.toChars()); fatal(); } } else if (tp.isTemplateThisParameter()) { ti.error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o.toChars()); fatal(); } else { assert(0); } } /****************************** * Write the mangled representation of the template arguments. * Params: * ti = the template instance * firstArg = index of the first template argument to mangle * (used for operator overloading) * Returns: * true if any arguments were written */ bool template_args(TemplateInstance ti, int firstArg = 0) { /* ::= I + E */ if (!ti || ti.tiargs.dim <= firstArg) // could happen if std::basic_string is not a template return false; buf.writeByte('I'); foreach (i; firstArg .. ti.tiargs.dim) { TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); assert(td); TemplateParameter tp = (*td.parameters)[i]; /* * ::= # type or template * ::= X E # expression * ::= # simple expressions * ::= I * E # argument pack */ if (TemplateTupleParameter tt = tp.isTemplateTupleParameter()) { buf.writeByte('I'); // argument pack // mangle the rest of the arguments as types foreach (j; i .. (*ti.tiargs).dim) { Type t = isType((*ti.tiargs)[j]); assert(t); t.accept(this); } buf.writeByte('E'); break; } template_arg(ti, i); } buf.writeByte('E'); return true; } void source_name(Dsymbol s) { //printf("source_name(%s)\n", s.toChars()); if (TemplateInstance ti = s.isTemplateInstance()) { if (!substitute(ti.tempdecl)) { append(ti.tempdecl); this.writeIdentifier(ti.tempdecl.toAlias().ident); } template_args(ti); } else this.writeIdentifier(s.ident); } /******** * See if s is actually an instance of a template * Params: * s = symbol * Returns: * if s is instance of a template, return the instance, otherwise return s */ Dsymbol getInstance(Dsymbol s) { Dsymbol p = s.toParent(); if (p) { if (TemplateInstance ti = p.isTemplateInstance()) return ti; } return s; } /******** * Get qualifier for `s`, meaning the symbol * that s is in the symbol table of. * The module does not count as a qualifier, because C++ * does not have modules. * Params: * s = symbol that may have a qualifier * s is rewritten to be TemplateInstance if s is one * Returns: * qualifier, null if none */ static Dsymbol getQualifier(Dsymbol s) { Dsymbol p = s.toParent(); return (p && !p.isModule()) ? p : null; } // Detect type char static bool isChar(RootObject o) { Type t = isType(o); return (t && t.equals(Type.tchar)); } // Detect type ::std::char_traits static bool isChar_traits_char(RootObject o) { return isIdent_char(Id.char_traits, o); } // Detect type ::std::allocator static bool isAllocator_char(RootObject o) { return isIdent_char(Id.allocator, o); } // Detect type ::std::ident static bool isIdent_char(Identifier ident, RootObject o) { Type t = isType(o); if (!t || t.ty != Tstruct) return false; Dsymbol s = (cast(TypeStruct)t).toDsymbol(null); if (s.ident != ident) return false; Dsymbol p = s.toParent(); if (!p) return false; TemplateInstance ti = p.isTemplateInstance(); if (!ti) return false; Dsymbol q = getQualifier(ti); return isStd(q) && ti.tiargs.dim == 1 && isChar((*ti.tiargs)[0]); } /*** * Detect template args > * and write st if found. * Returns: * true if found */ bool char_std_char_traits_char(TemplateInstance ti, string st) { if (ti.tiargs.dim == 2 && isChar((*ti.tiargs)[0]) && isChar_traits_char((*ti.tiargs)[1])) { buf.writestring(st.ptr); return true; } return false; } void prefix_name(Dsymbol s) { //printf("prefix_name(%s)\n", s.toChars()); if (substitute(s)) return; auto si = getInstance(s); Dsymbol p = getQualifier(si); if (p) { if (isStd(p)) { bool needsTa; auto ti = si.isTemplateInstance(); if (this.writeStdSubstitution(ti, needsTa)) { if (needsTa) { template_args(ti); append(ti); } return; } buf.writestring("St"); } else prefix_name(p); } source_name(si); if (!isStd(si)) /* Do this after the source_name() call to keep components[] * in the right order. * https://issues.dlang.org/show_bug.cgi?id=17947 */ append(si); } /** * Write common substitution for standard types, such as std::allocator * * This function assumes that the symbol `ti` is in the namespace `std`. * * Params: * ti = Template instance to consider * needsTa = If this function returns `true`, this value indicates * if additional template argument mangling is needed * * Returns: * `true` if a special std symbol was found */ bool writeStdSubstitution(TemplateInstance ti, out bool needsTa) { if (!ti) return false; if (ti.name == Id.allocator) { buf.writestring("Sa"); needsTa = true; return true; } if (ti.name == Id.basic_string) { // ::std::basic_string, ::std::allocator> if (ti.tiargs.dim == 3 && isChar((*ti.tiargs)[0]) && isChar_traits_char((*ti.tiargs)[1]) && isAllocator_char((*ti.tiargs)[2])) { buf.writestring("Ss"); return true; } buf.writestring("Sb"); // ::std::basic_string needsTa = true; return true; } // ::std::basic_istream> if (ti.name == Id.basic_istream && char_std_char_traits_char(ti, "Si")) return true; // ::std::basic_ostream> if (ti.name == Id.basic_ostream && char_std_char_traits_char(ti, "So")) return true; // ::std::basic_iostream> if (ti.name == Id.basic_iostream && char_std_char_traits_char(ti, "Sd")) return true; return false; } void cpp_mangle_name(Dsymbol s, bool qualified) { //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); Dsymbol p = s.toParent(); Dsymbol se = s; bool write_prefix = true; if (p && p.isTemplateInstance()) { se = p; if (find(p.isTemplateInstance().tempdecl) >= 0) write_prefix = false; p = p.toParent(); } if (p && !p.isModule()) { /* The N..E is not required if: * 1. the parent is 'std' * 2. 'std' is the initial qualifier * 3. there is no CV-qualifier or a ref-qualifier for a member function * ABI 5.1.8 */ if (isStd(p) && !qualified) { TemplateInstance ti = se.isTemplateInstance(); if (s.ident == Id.allocator) { buf.writestring("Sa"); // "Sa" is short for ::std::allocator template_args(ti); } else if (s.ident == Id.basic_string) { // ::std::basic_string, ::std::allocator> if (ti.tiargs.dim == 3 && isChar((*ti.tiargs)[0]) && isChar_traits_char((*ti.tiargs)[1]) && isAllocator_char((*ti.tiargs)[2])) { buf.writestring("Ss"); return; } buf.writestring("Sb"); // ::std::basic_string template_args(ti); } else { // ::std::basic_istream> if (s.ident == Id.basic_istream) { if (char_std_char_traits_char(ti, "Si")) return; } else if (s.ident == Id.basic_ostream) { if (char_std_char_traits_char(ti, "So")) return; } else if (s.ident == Id.basic_iostream) { if (char_std_char_traits_char(ti, "Sd")) return; } buf.writestring("St"); source_name(se); } } else { buf.writeByte('N'); if (write_prefix) { if (isStd(p)) buf.writestring("St"); else prefix_name(p); } source_name(se); buf.writeByte('E'); } } else source_name(se); append(s); } /** * Write CV-qualifiers to the buffer * * CV-qualifiers are 'r': restrict (unused in D), 'V': volatile, 'K': const * * See_Also: * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.CV-qualifiers */ void CV_qualifiers(const Type t) { if (t.isConst()) buf.writeByte('K'); } void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) { // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared))) { d.error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported"); fatal(); } Dsymbol p = d.toParent(); if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" { buf.writestring("_ZN"); prefix_name(p); source_name(d); buf.writeByte('E'); } else //char beta[6] should mangle as "beta" { if (!is_temp_arg_ref) { buf.writestring(d.ident.toChars()); } else { buf.writestring("_Z"); source_name(d); } } } void mangle_function(FuncDeclaration d) { //printf("mangle_function(%s)\n", d.toChars()); /* * ::= _Z * ::= * ::= * ::= */ TypeFunction tf = cast(TypeFunction)d.type; buf.writestring("_Z"); if (TemplateDeclaration ftd = getFuncTemplateDecl(d)) { /* It's an instance of a function template */ TemplateInstance ti = d.parent.isTemplateInstance(); assert(ti); this.mangleTemplatedFunction(d, tf, ftd, ti); } else { Dsymbol p = d.toParent(); if (p && !p.isModule() && tf.linkage == LINK.cpp) { this.mangleNestedFuncPrefix(tf, p); if (d.isCtorDeclaration()) buf.writestring("C1"); else if (d.isPrimaryDtor()) buf.writestring("D1"); else if (d.ident && d.ident == Id.assign) buf.writestring("aS"); else if (d.ident && d.ident == Id.eq) buf.writestring("eq"); else if (d.ident && d.ident == Id.index) buf.writestring("ix"); else if (d.ident && d.ident == Id.call) buf.writestring("cl"); else source_name(d); buf.writeByte('E'); } else { source_name(d); } // Template args accept extern "C" symbols with special mangling if (tf.linkage == LINK.cpp) mangleFunctionParameters(tf.parameters, tf.varargs); } } /** * Mangles a function template to C++ * * Params: * d = Function declaration * tf = Function type (casted d.type) * ftd = Template declaration (ti.templdecl) * ti = Template instance (d.parent) */ void mangleTemplatedFunction(FuncDeclaration d, TypeFunction tf, TemplateDeclaration ftd, TemplateInstance ti) { Dsymbol p = ti.toParent(); // Check if this function is *not* nested if (!p || p.isModule() || tf.linkage != LINK.cpp) { this.context.ti = ti; this.context.fd = d; this.context.res = d; TypeFunction preSemantic = cast(TypeFunction)d.originalType; source_name(ti); this.mangleReturnType(preSemantic); this.mangleFunctionParameters(preSemantic.parameters, tf.varargs); return; } // It's a nested function (e.g. a member of an aggregate) this.mangleNestedFuncPrefix(tf, p); if (d.isCtorDeclaration()) { buf.writestring("C1"); } else if (d.isPrimaryDtor()) { buf.writestring("D1"); } else { int firstTemplateArg = 0; bool appendReturnType = true; bool isConvertFunc = false; string symName; // test for special symbols CppOperator whichOp = isCppOperator(ti.name); final switch (whichOp) { case CppOperator.Unknown: break; case CppOperator.Cast: symName = "cv"; firstTemplateArg = 1; isConvertFunc = true; appendReturnType = false; break; case CppOperator.Assign: symName = "aS"; break; case CppOperator.Eq: symName = "eq"; break; case CppOperator.Index: symName = "ix"; break; case CppOperator.Call: symName = "cl"; break; case CppOperator.Unary: case CppOperator.Binary: case CppOperator.OpAssign: TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); assert(td); assert(ti.tiargs.dim >= 1); TemplateParameter tp = (*td.parameters)[0]; TemplateValueParameter tv = tp.isTemplateValueParameter(); if (!tv || !tv.valType.isString()) break; // expecting a string argument to operators! Expression exp = (*ti.tiargs)[0].isExpression(); StringExp str = exp.toStringExp(); switch (whichOp) { case CppOperator.Unary: switch (str.peekSlice()) { case "*": symName = "de"; goto continue_template; case "++": symName = "pp"; goto continue_template; case "--": symName = "mm"; goto continue_template; case "-": symName = "ng"; goto continue_template; case "+": symName = "ps"; goto continue_template; case "~": symName = "co"; goto continue_template; default: break; } break; case CppOperator.Binary: switch (str.peekSlice()) { case ">>": symName = "rs"; goto continue_template; case "<<": symName = "ls"; goto continue_template; case "*": symName = "ml"; goto continue_template; case "-": symName = "mi"; goto continue_template; case "+": symName = "pl"; goto continue_template; case "&": symName = "an"; goto continue_template; case "/": symName = "dv"; goto continue_template; case "%": symName = "rm"; goto continue_template; case "^": symName = "eo"; goto continue_template; case "|": symName = "or"; goto continue_template; default: break; } break; case CppOperator.OpAssign: switch (str.peekSlice()) { case "*": symName = "mL"; goto continue_template; case "+": symName = "pL"; goto continue_template; case "-": symName = "mI"; goto continue_template; case "/": symName = "dV"; goto continue_template; case "%": symName = "rM"; goto continue_template; case ">>": symName = "rS"; goto continue_template; case "<<": symName = "lS"; goto continue_template; case "&": symName = "aN"; goto continue_template; case "|": symName = "oR"; goto continue_template; case "^": symName = "eO"; goto continue_template; default: break; } break; default: assert(0); continue_template: firstTemplateArg = 1; break; } break; } if (symName.length == 0) source_name(ti); else { buf.writestring(symName); if (isConvertFunc) template_arg(ti, 0); appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType; } buf.writeByte('E'); if (appendReturnType) headOfType(tf.nextOf()); // mangle return type } mangleFunctionParameters(tf.parameters, tf.varargs); } /** * Mangle the parameters of a function * * For templated functions, `context.res` is set to the `FuncDeclaration` * * Params: * parameters = Array of `Parameter` to mangle * varargs = if != 0, this function has varargs parameters */ void mangleFunctionParameters(Parameters* parameters, int varargs) { int numparams = 0; int paramsCppMangleDg(size_t n, Parameter fparam) { Type t = Target.cppParameterType(fparam); if (t.ty == Tsarray) { // Static arrays in D are passed by value; no counterpart in C++ .error(loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead", t.toChars()); fatal(); } auto prev = this.context.push({ auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type; return (*tf.parameters)[n].type; }()); scope (exit) this.context.pop(prev); headOfType(t); ++numparams; return 0; } if (parameters) Parameter._foreach(parameters, ¶msCppMangleDg); if (varargs) buf.writeByte('z'); else if (!numparams) buf.writeByte('v'); // encode (void) parameters } /****** The rest is type mangling ************/ void error(Type t) { const(char)* p; if (t.isImmutable()) p = "`immutable` "; else if (t.isShared()) p = "`shared` "; else p = ""; .error(loc, "Internal Compiler Error: %stype `%s` can not be mapped to C++\n", p, t.toChars()); fatal(); //Fatal, because this error should be handled in frontend } /**************************** * Mangle a type, * treating it as a Head followed by a Tail. * Params: * t = Head of a type */ void headOfType(Type t) { if (t.ty == Tclass) { mangleTypeClass(cast(TypeClass)t, true); } else { // For value types, strip const/immutable/shared from the head of the type auto prev = this.context.push(this.context.res.asType().mutableOf().unSharedOf()); scope (exit) this.context.pop(prev); t.mutableOf().unSharedOf().accept(this); } } /****** * Write out 1 or 2 character basic type mangling. * Handle const and substitutions. * Params: * t = type to mangle * p = if not 0, then character prefix * c = mangling character */ void writeBasicType(Type t, char p, char c) { if (p || t.isConst()) { if (substitute(t)) return; else append(t); } CV_qualifiers(t); if (p) buf.writeByte(p); buf.writeByte(c); } /**************** * Write structs and enums. * Params: * t = TypeStruct or TypeEnum */ void doSymbol(Type t) { if (substitute(t)) return; CV_qualifiers(t); // Handle any target-specific struct types. if (auto tm = Target.cppTypeMangle(t)) { buf.writestring(tm); } else { Dsymbol s = t.toDsymbol(null); Dsymbol p = s.toParent(); if (p && p.isTemplateInstance()) { /* https://issues.dlang.org/show_bug.cgi?id=17947 * Substitute the template instance symbol, not the struct/enum symbol */ if (substitute(p)) return; } if (!substitute(s)) { cpp_mangle_name(s, false); } } if (t.isConst()) append(t); } /************************ * Mangle a class type. * If it's the head, treat the initial pointer as a value type. * Params: * t = class type * head = true for head of a type */ void mangleTypeClass(TypeClass t, bool head) { if (t.isImmutable() || t.isShared()) return error(t); /* Mangle as a */ if (substitute(t)) return; if (!head) CV_qualifiers(t); buf.writeByte('P'); CV_qualifiers(t); { Dsymbol s = t.toDsymbol(null); Dsymbol p = s.toParent(); if (p && p.isTemplateInstance()) { /* https://issues.dlang.org/show_bug.cgi?id=17947 * Substitute the template instance symbol, not the class symbol */ if (substitute(p)) return; } } if (!substitute(t.sym)) { cpp_mangle_name(t.sym, false); } if (t.isConst()) append(null); // C++ would have an extra type here append(t); } /** * Mangle the prefix of a nested (e.g. member) function * * Params: * tf = Type of the nested function * parent = Parent in which the function is nested */ void mangleNestedFuncPrefix(TypeFunction tf, Dsymbol parent) { /* ::= N [] E * ::= N [] E */ buf.writeByte('N'); CV_qualifiers(tf); /* ::= * ::= * ::= * ::= # empty * ::= * ::= */ prefix_name(parent); } extern(C++): alias visit = Visitor.visit; override void visit(TypeNull t) { if (t.isImmutable() || t.isShared()) return error(t); writeBasicType(t, 'D', 'n'); } override void visit(TypeBasic t) { if (t.isImmutable() || t.isShared()) return error(t); /* : * v void * w wchar_t * b bool * c char * a signed char * h unsigned char * s short * t unsigned short * i int * j unsigned int * l long * m unsigned long * x long long, __int64 * y unsigned long long, __int64 * n __int128 * o unsigned __int128 * f float * d double * e long double, __float80 * g __float128 * z ellipsis * Dd 64 bit IEEE 754r decimal floating point * De 128 bit IEEE 754r decimal floating point * Df 32 bit IEEE 754r decimal floating point * Dh 16 bit IEEE 754r half-precision floating point * Di char32_t * Ds char16_t * u # vendor extended type */ char c; char p = 0; switch (t.ty) { case Tvoid: c = 'v'; break; case Tint8: c = 'a'; break; case Tuns8: c = 'h'; break; case Tint16: c = 's'; break; case Tuns16: c = 't'; break; case Tint32: c = 'i'; break; case Tuns32: c = 'j'; break; case Tfloat32: c = 'f'; break; case Tint64: c = Target.c_longsize == 8 ? 'l' : 'x'; break; case Tuns64: c = Target.c_longsize == 8 ? 'm' : 'y'; break; case Tint128: c = 'n'; break; case Tuns128: c = 'o'; break; case Tfloat64: c = 'd'; break; case Tfloat80: c = 'e'; break; case Tbool: c = 'b'; break; case Tchar: c = 'c'; break; case Twchar: c = 't'; break; // unsigned short (perhaps use 'Ds' ? case Tdchar: c = 'w'; break; // wchar_t (UTF-32) (perhaps use 'Di' ? case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary case Timaginary64: p = 'G'; c = 'd'; break; case Timaginary80: p = 'G'; c = 'e'; break; case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex case Tcomplex64: p = 'C'; c = 'd'; break; case Tcomplex80: p = 'C'; c = 'e'; break; default: // Handle any target-specific basic types. if (auto tm = Target.cppTypeMangle(t)) { if (substitute(t)) return; else append(t); CV_qualifiers(t); buf.writestring(tm); return; } return error(t); } writeBasicType(t, p, c); } override void visit(TypeVector t) { if (t.isImmutable() || t.isShared()) return error(t); if (substitute(t)) return; append(t); CV_qualifiers(t); // Handle any target-specific vector types. if (auto tm = Target.cppTypeMangle(t)) { buf.writestring(tm); } else { assert(t.basetype && t.basetype.ty == Tsarray); assert((cast(TypeSArray)t.basetype).dim); version (none) { buf.writestring("Dv"); buf.print((cast(TypeSArray *)t.basetype).dim.toInteger()); // -- Gnu ABI v.4 buf.writeByte('_'); } else buf.writestring("U8__vector"); //-- Gnu ABI v.3 t.basetype.nextOf().accept(this); } } override void visit(TypeSArray t) { if (t.isImmutable() || t.isShared()) return error(t); if (!substitute(t)) append(t); CV_qualifiers(t); buf.writeByte('A'); buf.print(t.dim ? t.dim.toInteger() : 0); buf.writeByte('_'); t.next.accept(this); } override void visit(TypePointer t) { if (t.isImmutable() || t.isShared()) return error(t); if (substitute(t)) return; CV_qualifiers(t); buf.writeByte('P'); auto prev = this.context.push(this.context.res.asType().nextOf()); scope (exit) this.context.pop(prev); t.next.accept(this); append(t); } override void visit(TypeReference t) { if (substitute(t)) return; buf.writeByte('R'); auto prev = this.context.push(this.context.res.asType().nextOf()); scope (exit) this.context.pop(prev); t.next.accept(this); append(t); } override void visit(TypeFunction t) { /* * ::= F [Y] E * ::= + * # types are possible return type, then parameter types */ /* ABI says: "The type of a non-static member function is considered to be different, for the purposes of substitution, from the type of a namespace-scope or static member function whose type appears similar. The types of two non-static member functions are considered to be different, for the purposes of substitution, if the functions are members of different classes. In other words, for the purposes of substitution, the class of which the function is a member is considered part of the type of function." BUG: Right now, types of functions are never merged, so our simplistic component matcher always finds them to be different. We should use Type.equals on these, and use different TypeFunctions for non-static member functions, and non-static member functions of different classes. */ if (substitute(t)) return; buf.writeByte('F'); if (t.linkage == LINK.c) buf.writeByte('Y'); Type tn = t.next; if (t.isref) tn = tn.referenceTo(); tn.accept(this); mangleFunctionParameters(t.parameters, t.varargs); buf.writeByte('E'); append(t); } override void visit(TypeStruct t) { if (t.isImmutable() || t.isShared()) return error(t); /* __c_long and __c_ulong get special mangling */ const id = t.sym.ident; //printf("struct id = '%s'\n", id.toChars()); if (id == Id.__c_long) return writeBasicType(t, 0, 'l'); else if (id == Id.__c_ulong) return writeBasicType(t, 0, 'm'); //printf("TypeStruct %s\n", t.toChars()); doSymbol(t); } override void visit(TypeEnum t) { if (t.isImmutable() || t.isShared()) return error(t); /* __c_(u)long(long) get special mangling */ const id = t.sym.ident; //printf("enum id = '%s'\n", id.toChars()); if (id == Id.__c_long) return writeBasicType(t, 0, 'l'); else if (id == Id.__c_ulong) return writeBasicType(t, 0, 'm'); else if (id == Id.__c_longlong) return writeBasicType(t, 0, 'x'); else if (id == Id.__c_ulonglong) return writeBasicType(t, 0, 'y'); doSymbol(t); } override void visit(TypeClass t) { mangleTypeClass(t, false); } /** * Performs template parameter substitution * * Mangling is performed on a copy of the post-parsing AST before * any semantic pass is run. * There is no easy way to link a type to the template parameters * once semantic has run, because: * - the `TemplateInstance` installs aliases in its scope to its params * - `AliasDeclaration`s are resolved in many places * - semantic passes are destructive, so the `TypeIdentifier` gets lost * * As a result, the best approach with the current architecture is to: * - Run the visitor on the `originalType` of the function, * looking up any `TypeIdentifier` at the template scope when found. * - Fallback to the post-semantic `TypeFunction` when the identifier is * not a template parameter. */ override void visit(TypeIdentifier t) { auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl; assert(decl.parameters !is null); // If not found, default to the post-semantic type if (!this.writeTemplateSubstitution(t.ident, decl.parameters, this.context.res.isType())) this.context.res.visitObject(this); } /// Ditto override void visit(TypeInstance t) { assert(t.tempinst !is null); t.tempinst.accept(this); } /// Ditto override void visit(TemplateInstance t) { assert(t.name !is null); assert(t.tiargs !is null); if (this.substitute(t)) return; auto topdecl = cast(TemplateDeclaration)this.context.ti.tempdecl; // Template names are substituted, but args still need to be written bool needclosing; if (!this.writeTemplateSubstitution(t.name, topdecl.parameters, t.getType())) { needclosing = this.writeQualified(t); this.append(t); } buf.writeByte('I'); // When visiting the arguments, the context will be set to the // resolved type auto analyzed_ti = this.context.res.asType().toDsymbol(null).isInstantiated(); auto prev = this.context; scope (exit) this.context.pop(prev); foreach (idx, RootObject o; *t.tiargs) { this.context.res = (*analyzed_ti.tiargs)[idx]; o.visitObject(this); } if (analyzed_ti.tiargs.dim > t.tiargs.dim) { // If the resolved AST has more args than the parse one, // we have default arguments auto oparams = (cast(TemplateDeclaration)analyzed_ti.tempdecl).origParameters; foreach (idx, arg; (*oparams)[t.tiargs.dim .. $]) { this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.dim]; if (auto ttp = arg.isTemplateTypeParameter()) ttp.defaultType.accept(this); else if (auto tvp = arg.isTemplateValueParameter()) tvp.defaultValue.accept(this); else if (auto tvp = arg.isTemplateThisParameter()) tvp.defaultType.accept(this); else if (auto tvp = arg.isTemplateAliasParameter()) tvp.defaultAlias.visitObject(this); else assert(0, arg.toString()); } } buf.writeByte('E'); if (needclosing) buf.writeByte('E'); } /// Ditto override void visit(IntegerExp t) { this.buf.writeByte('L'); t.type.accept(this); this.buf.print(t.getInteger()); this.buf.writeByte('E'); } override void visit(Nspace t) { if (auto p = getQualifier(t)) p.accept(this); if (isStd(t)) buf.writestring("St"); else { this.writeIdentifier(t.ident); this.append(t); } } override void visit(Type t) { error(t); } void visit(Tuple t) { assert(0); } /** * Helper function to go through the `TemplateParameter`s and perform * a substitution, if possible. * * Params: * ident = Identifier for which substitution is attempted * (e.g. `void func(T)(T param)` => `T` from `T param`) * params = `TemplateParameters` of the enclosing symbol * (in the previous example, `func`'s template parameters) * type = Resolved type of `T`, so that `void func(T)(const T)` * gets mangled correctly * * Returns: * `true` if something was written to the buffer */ private bool writeTemplateSubstitution(const ref Identifier ident, TemplateParameters* params, Type type) { foreach (idx, param; *params) { if (param.ident == ident) { if (type) CV_qualifiers(type); if (this.substitute(param)) return true; this.append(param); // expressions are mangled in if (param.isTemplateValueParameter()) buf.writeByte('X'); buf.writeByte('T'); writeSequenceFromIndex(idx); buf.writeByte('_'); if (param.isTemplateValueParameter()) buf.writeByte('E'); return true; } } return false; } /** * Given a template instance `t`, write its qualified name * without the template parameter list * * Params: * t = Post-parsing `TemplateInstance` pointing to the symbol * to mangle (one level deep) * * Returns: * `true` if the name was qualified and requires an ending `E` */ private bool writeQualified(TemplateInstance t) { auto type = isType(this.context.res); if (!type) { this.writeIdentifier(t.name); return false; } auto sym = type.toDsymbol(null); if (!sym) { this.writeIdentifier(t.name); return false; } // Get the template instance sym = getQualifier(sym); auto sym2 = getQualifier(sym); if (sym2) { if (isStd(sym2)) { bool unused; assert(sym.isTemplateInstance()); if (this.writeStdSubstitution(sym.isTemplateInstance(), unused)) return false; // std names don't require `N..E` buf.writestring("St"); this.writeIdentifier(t.name); return false; } buf.writestring("N"); if (!this.substitute(sym2)) sym2.accept(this); } this.writeIdentifier(t.name); return sym2 !is null; } } /// Helper code to visit `RootObject`, as it doesn't define `accept`, /// only its direct subtypes do. private void visitObject(V : Visitor)(RootObject o, V this_) { assert(o !is null); if (Type ta = isType(o)) ta.accept(this_); else if (Expression ea = isExpression(o)) ea.accept(this_); else if (Dsymbol sa = isDsymbol(o)) sa.accept(this_); else if (TemplateParameter t = isTemplateParameter(o)) t.accept(this_); else if (Tuple t = isTuple(o)) // `Tuple` inherits `RootObject` and does not define accept // For this reason, this uses static dispatch on the visitor this_.visit(t); else assert(0, o.toString()); } /// Helper function to safely get a type out of a `RootObject` private Type asType(RootObject o) { Type ta = isType(o); assert(ta !is null, o.toString()); return ta; } /// Helper function to safely get a `FuncDeclaration` out of a `RootObject` private FuncDeclaration asFuncDecl(RootObject o) { Dsymbol d = isDsymbol(o); assert(d !is null); auto fd = d.isFuncDeclaration(); assert(fd !is null); return fd; } /// Helper class to compare entries in components private extern(C++) final class ComponentVisitor : Visitor { /// Only one of the following is not `null`, it's always /// the most specialized type, set from the ctor private Nspace namespace; /// Ditto private TypePointer tpointer; /// Ditto private TypeReference tref; /// Ditto private TypeIdentifier tident; /// Least specialized type private RootObject object; /// Set to the result of the comparison private bool result; public this(RootObject base) { switch (base.dyncast()) { case DYNCAST.dsymbol: if (auto ns = (cast(Dsymbol)base).isNspace()) this.namespace = ns; else goto default; break; case DYNCAST.type: auto t = cast(Type)base; if (t.ty == Tpointer) this.tpointer = cast(TypePointer)t; else if (t.ty == Treference) this.tref = cast(TypeReference)t; else if (t.ty == Tident) this.tident = cast(TypeIdentifier)t; else goto default; break; default: this.object = base; } } /// Introduce base class overloads alias visit = Visitor.visit; /// Least specialized overload of each direct child of `RootObject` public override void visit(Dsymbol o) { this.result = this.object && this.object == o; } /// Ditto public override void visit(Expression o) { this.result = this.object && this.object == o; } /// Ditto public void visit(Tuple o) { this.result = this.object && this.object == o; } /// Ditto public override void visit(Type o) { this.result = this.object && this.object == o; } /// Ditto public override void visit(TemplateParameter o) { this.result = this.object && this.object == o; } /** * This overload handles composed types including template parameters * * Components for substitutions include "next" type. * For example, if `ref T` is present, `ref T` and `T` will be present * in the substitution array. * But since we don't have the final/merged type, we cannot rely on * object comparison, and need to recurse instead. */ public override void visit(TypeReference o) { if (!this.tref) return; if (this.tref == o) this.result = true; else { // It might be a reference to a template parameter that we already // saw, so we need to recurse scope v = new ComponentVisitor(this.tref.next); o.next.visitObject(v); this.result = v.result; } } /// Ditto public override void visit(TypePointer o) { if (!this.tpointer) return; if (this.tpointer == o) this.result = true; else { // It might be a pointer to a template parameter that we already // saw, so we need to recurse scope v = new ComponentVisitor(this.tpointer.next); o.next.visitObject(v); this.result = v.result; } } /// Ditto public override void visit(TypeIdentifier o) { /// Since we know they are at the same level, scope resolution will /// give us the same symbol, thus we can just compare ident. this.result = (this.tident && (this.tident.ident == o.ident)); } /** * Overload which accepts a Namespace * * It is very common for large C++ projects to have multiple files sharing * the same `namespace`. If any D project adopts the same approach * (e.g. separating data structures from functions), it will lead to two * `Nspace` objects being instantiated, with different addresses. * At the same time, we cannot compare just any Dsymbol via identifier, * because it messes with templates. * * See_Also: * https://issues.dlang.org/show_bug.cgi?id=18922 * * Params: * ns = C++ namespace to do substitution for */ public override void visit(Nspace ns) { this.result = this.namespace && this.namespace.equals(ns); } } ================================================ FILE: gcc/d/dmd/ctfe.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/ctfe.h */ #pragma once #include "tokens.h" #include "expression.h" /** A reference to a class, or an interface. We need this when we point to a base class (we must record what the type is). */ class ClassReferenceExp : public Expression { public: StructLiteralExp *value; ClassDeclaration *originalClass(); /// Return index of the field, or -1 if not found /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration int findFieldIndexByName(VarDeclaration *v); void accept(Visitor *v) { v->visit(this); } }; /** An uninitialized value */ class VoidInitExp : public Expression { public: VarDeclaration *var; const char *toChars(); void accept(Visitor *v) { v->visit(this); } }; /** Fake class which holds the thrown exception. Used for implementing exception handling. */ class ThrownExceptionExp : public Expression { public: ClassReferenceExp *thrown; // the thing being tossed const char *toChars(); /// Generate an error message when this exception is not caught void generateUncaughtError(); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ // This type is only used by the interpreter. class CTFEExp : public Expression { public: const char *toChars(); }; ================================================ FILE: gcc/d/dmd/ctfeexpr.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/ctfeexpr.d, _ctfeexpr.d) * Documentation: https://dlang.org/phobos/dmd_ctfeexpr.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d */ module dmd.ctfeexpr; import core.stdc.stdio; import core.stdc.string; import dmd.arraytypes; import dmd.complex; import dmd.constfold; import dmd.compiler; import dmd.dclass; import dmd.declaration; import dmd.dinterpret; import dmd.dstruct; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.mtype; import dmd.root.ctfloat; import dmd.root.port; import dmd.root.rmem; import dmd.tokens; import dmd.visitor; /*********************************************************** * Global status of the CTFE engine. Mostly used for performance diagnostics */ struct CtfeStatus { __gshared int callDepth = 0; // current number of recursive calls // When printing a stack trace, suppress this number of calls __gshared int stackTraceCallsToSuppress = 0; __gshared int maxCallDepth = 0; // highest number of recursive calls __gshared int numArrayAllocs = 0; // Number of allocated arrays __gshared int numAssignments = 0; // total number of assignments executed } /*********************************************************** * A reference to a class, or an interface. We need this when we * point to a base class (we must record what the type is). */ extern (C++) final class ClassReferenceExp : Expression { StructLiteralExp value; extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) { super(loc, TOK.classReference, __traits(classInstanceSize, ClassReferenceExp)); assert(lit && lit.sd && lit.sd.isClassDeclaration()); this.value = lit; this.type = type; } ClassDeclaration originalClass() { return value.sd.isClassDeclaration(); } // Return index of the field, or -1 if not found private int getFieldIndex(Type fieldtype, uint fieldoffset) { ClassDeclaration cd = originalClass(); uint fieldsSoFar = 0; for (size_t j = 0; j < value.elements.dim; j++) { while (j - fieldsSoFar >= cd.fields.dim) { fieldsSoFar += cd.fields.dim; cd = cd.baseClass; } VarDeclaration v2 = cd.fields[j - fieldsSoFar]; if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size()) { return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); } } return -1; } // Return index of the field, or -1 if not found // Same as getFieldIndex, but checks for a direct match with the VarDeclaration int findFieldIndexByName(VarDeclaration v) { ClassDeclaration cd = originalClass(); size_t fieldsSoFar = 0; for (size_t j = 0; j < value.elements.dim; j++) { while (j - fieldsSoFar >= cd.fields.dim) { fieldsSoFar += cd.fields.dim; cd = cd.baseClass; } VarDeclaration v2 = cd.fields[j - fieldsSoFar]; if (v == v2) { return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); } } return -1; } override void accept(Visitor v) { v.visit(this); } } /************************* * Same as getFieldIndex, but checks for a direct match with the VarDeclaration * Returns: * index of the field, or -1 if not found */ int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure { foreach (i, field; sd.fields) { if (field == v) return cast(int)i; } return -1; } /*********************************************************** * Fake class which holds the thrown exception. * Used for implementing exception handling. */ extern (C++) final class ThrownExceptionExp : Expression { ClassReferenceExp thrown; // the thing being tossed extern (D) this(const ref Loc loc, ClassReferenceExp victim) { super(loc, TOK.thrownException, __traits(classInstanceSize, ThrownExceptionExp)); this.thrown = victim; this.type = victim.type; } override const(char)* toChars() const { return "CTFE ThrownException"; } // Generate an error message when this exception is not caught void generateUncaughtError() { UnionExp ue = void; Expression e = resolveSlice((*thrown.value.elements)[0], &ue); StringExp se = e.toStringExp(); thrown.error("uncaught CTFE exception `%s(%s)`", thrown.type.toChars(), se ? se.toChars() : e.toChars()); /* Also give the line where the throw statement was. We won't have it * in the case where the ThrowStatement is generated internally * (eg, in ScopeStatement) */ if (loc.isValid() && !loc.equals(thrown.loc)) .errorSupplemental(loc, "thrown from here"); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * This type is only used by the interpreter. */ extern (C++) final class CTFEExp : Expression { extern (D) this(TOK tok) { super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp)); type = Type.tvoid; } override const(char)* toChars() const { switch (op) { case TOK.cantExpression: return ""; case TOK.voidExpression: return ""; case TOK.showCtfeContext: return ""; case TOK.break_: return ""; case TOK.continue_: return ""; case TOK.goto_: return ""; default: assert(0); } } extern (D) __gshared CTFEExp cantexp; extern (D) __gshared CTFEExp voidexp; extern (D) __gshared CTFEExp breakexp; extern (D) __gshared CTFEExp continueexp; extern (D) __gshared CTFEExp gotoexp; /* Used when additional information is needed regarding * a ctfe error. */ extern (D) __gshared CTFEExp showcontext; extern (D) static bool isCantExp(const Expression e) { return e && e.op == TOK.cantExpression; } extern (D) static bool isGotoExp(const Expression e) { return e && e.op == TOK.goto_; } } // True if 'e' is CTFEExp::cantexp, or an exception bool exceptionOrCantInterpret(const Expression e) { return e && (e.op == TOK.cantExpression || e.op == TOK.thrownException || e.op == TOK.showCtfeContext); } /************** Aggregate literals (AA/string/array/struct) ******************/ // Given expr, which evaluates to an array/AA/string literal, // return true if it needs to be copied bool needToCopyLiteral(const Expression expr) { Expression e = cast()expr; for (;;) { switch (e.op) { case TOK.arrayLiteral: return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; case TOK.assocArrayLiteral: return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; case TOK.structLiteral: return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code; case TOK.string_: case TOK.this_: case TOK.variable: return false; case TOK.assign: return false; case TOK.index: case TOK.dotVariable: case TOK.slice: case TOK.cast_: e = (cast(UnaExp)e).e1; continue; case TOK.concatenate: return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2); case TOK.concatenateAssign: case TOK.concatenateElemAssign: case TOK.concatenateDcharAssign: e = (cast(BinExp)e).e2; continue; default: return false; } } } private Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null) { if (!oldelems) return oldelems; CtfeStatus.numArrayAllocs++; auto newelems = new Expressions(oldelems.dim); foreach (i, el; *oldelems) { (*newelems)[i] = copyLiteral(el ? el : basis).copy(); } return newelems; } // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. // This value will be used for in-place modification. UnionExp copyLiteral(Expression e) { UnionExp ue; if (e.op == TOK.string_) // syntaxCopy doesn't make a copy for StringExp! { StringExp se = cast(StringExp)e; char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz); memcpy(s, se.string, se.len * se.sz); emplaceExp!(StringExp)(&ue, se.loc, s, se.len); StringExp se2 = cast(StringExp)ue.exp(); se2.committed = se.committed; se2.postfix = se.postfix; se2.type = se.type; se2.sz = se.sz; se2.ownedByCtfe = OwnedBy.ctfe; return ue; } if (e.op == TOK.arrayLiteral) { auto ale = cast(ArrayLiteralExp)e; auto elements = copyLiteralArray(ale.elements, ale.basis); emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements); ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp(); r.ownedByCtfe = OwnedBy.ctfe; return ue; } if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)e; emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp(); r.type = e.type; r.ownedByCtfe = OwnedBy.ctfe; return ue; } if (e.op == TOK.structLiteral) { /* syntaxCopy doesn't work for struct literals, because of a nasty special * case: block assignment is permitted inside struct literals, eg, * an int[4] array can be initialized with a single int. */ auto sle = cast(StructLiteralExp)e; auto oldelems = sle.elements; auto newelems = new Expressions(oldelems.dim); foreach (i, ref el; *newelems) { // We need the struct definition to detect block assignment auto v = sle.sd.fields[i]; auto m = (*oldelems)[i]; // If it is a void assignment, use the default initializer if (!m) m = voidInitLiteral(v.type, v).copy(); if (v.type.ty == Tarray || v.type.ty == Taarray) { // Don't have to copy array references } else { // Buzilla 15681: Copy the source element always. m = copyLiteral(m).copy(); // Block assignment from inside struct literals if (v.type.ty != m.type.ty && v.type.ty == Tsarray) { auto tsa = cast(TypeSArray)v.type; auto len = cast(size_t)tsa.dim.toInteger(); m = createBlockDuplicatedArrayLiteral(e.loc, v.type, m, len); } } el = m; } emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype); auto r = cast(StructLiteralExp)ue.exp(); r.type = e.type; r.ownedByCtfe = OwnedBy.ctfe; r.origin = (cast(StructLiteralExp)e).origin; return ue; } if (e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.symbolOffset || e.op == TOK.null_ || e.op == TOK.variable || e.op == TOK.dotVariable || e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.char_ || e.op == TOK.complex80 || e.op == TOK.void_ || e.op == TOK.vector || e.op == TOK.typeid_) { // Simple value types // Keep e1 for DelegateExp and DotVarExp emplaceExp!(UnionExp)(&ue, e); Expression r = ue.exp(); r.type = e.type; return ue; } if (e.op == TOK.slice) { SliceExp se = cast(SliceExp)e; if (se.type.toBasetype().ty == Tsarray) { // same with resolveSlice() if (se.e1.op == TOK.null_) { emplaceExp!(NullExp)(&ue, se.loc, se.type); return ue; } ue = Slice(se.type, se.e1, se.lwr, se.upr); assert(ue.exp().op == TOK.arrayLiteral); ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp(); r.elements = copyLiteralArray(r.elements); r.ownedByCtfe = OwnedBy.ctfe; return ue; } else { // Array slices only do a shallow copy emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr); Expression r = ue.exp(); r.type = e.type; return ue; } } if (isPointer(e.type)) { // For pointers, we only do a shallow copy. if (e.op == TOK.address) emplaceExp!(AddrExp)(&ue, e.loc, (cast(AddrExp)e).e1); else if (e.op == TOK.index) emplaceExp!(IndexExp)(&ue, e.loc, (cast(IndexExp)e).e1, (cast(IndexExp)e).e2); else if (e.op == TOK.dotVariable) { emplaceExp!(DotVarExp)(&ue, e.loc, (cast(DotVarExp)e).e1, (cast(DotVarExp)e).var, (cast(DotVarExp)e).hasOverloads); } else assert(0); Expression r = ue.exp(); r.type = e.type; return ue; } if (e.op == TOK.classReference) { emplaceExp!(ClassReferenceExp)(&ue, e.loc, (cast(ClassReferenceExp)e).value, e.type); return ue; } if (e.op == TOK.error) { emplaceExp!(UnionExp)(&ue, e); return ue; } e.error("CTFE internal error: literal `%s`", e.toChars()); assert(0); } /* Deal with type painting. * Type painting is a major nuisance: we can't just set * e.type = type, because that would change the original literal. * But, we can't simply copy the literal either, because that would change * the values of any pointers. */ Expression paintTypeOntoLiteral(Type type, Expression lit) { if (lit.type.equals(type)) return lit; return paintTypeOntoLiteralCopy(type, lit).copy(); } private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) { UnionExp ue; if (lit.type.equals(type)) { emplaceExp!(UnionExp)(&ue, lit); return ue; } // If it is a cast to inout, retain the original type of the referenced part. if (type.hasWild() && type.hasPointers()) { emplaceExp!(UnionExp)(&ue, lit); ue.exp().type = type; return ue; } if (lit.op == TOK.slice) { SliceExp se = cast(SliceExp)lit; emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr); } else if (lit.op == TOK.index) { IndexExp ie = cast(IndexExp)lit; emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2); } else if (lit.op == TOK.arrayLiteral) { emplaceExp!(SliceExp)(&ue, lit.loc, lit, new IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); } else if (lit.op == TOK.string_) { // For strings, we need to introduce another level of indirection emplaceExp!(SliceExp)(&ue, lit.loc, lit, new IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); } else if (lit.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)lit; // TODO: we should be creating a reference to this AAExp, not // just a ref to the keys and values. OwnedBy wasOwned = aae.ownedByCtfe; emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values); aae = cast(AssocArrayLiteralExp)ue.exp(); aae.ownedByCtfe = wasOwned; } else { // Can't type paint from struct to struct*; this needs another // level of indirection if (lit.op == TOK.structLiteral && isPointer(type)) lit.error("CTFE internal error: painting `%s`", type.toChars()); ue = copyLiteral(lit); } ue.exp().type = type; return ue; } /************************************* * If e is a SliceExp, constant fold it. * Params: * e = expression to resolve * pue = if not null, store resulting expression here * Returns: * resulting expression */ Expression resolveSlice(Expression e, UnionExp* pue = null) { if (e.op != TOK.slice) return e; SliceExp se = cast(SliceExp)e; if (se.e1.op == TOK.null_) return se.e1; if (pue) { *pue = Slice(e.type, se.e1, se.lwr, se.upr); return pue.exp(); } else return Slice(e.type, se.e1, se.lwr, se.upr).copy(); } /* Determine the array length, without interpreting it. * e must be an array literal, or a slice * It's very wasteful to resolve the slice when we only * need the length. */ uinteger_t resolveArrayLength(const Expression e) { switch (e.op) { case TOK.vector: return resolveArrayLength((cast(VectorExp)e).e1); case TOK.null_: return 0; case TOK.slice: { const ilo = (cast(SliceExp)e).lwr.toInteger(); const iup = (cast(SliceExp)e).upr.toInteger(); return iup - ilo; } case TOK.string_: return (cast(StringExp)e).len; case TOK.arrayLiteral: { const ale = cast(ArrayLiteralExp)e; return ale.elements ? ale.elements.dim : 0; } case TOK.assocArrayLiteral: { const ale = cast(AssocArrayLiteralExp)e; return ale.keys.dim; } default: assert(0); } } /****************************** * Helper for NewExp * Create an array literal consisting of 'elem' duplicated 'dim' times. * Params: * loc = source location where the interpretation occurs * type = target type of the result * elem = the source of array element, it will be owned by the result * dim = element number of the result * Returns: * Constructed ArrayLiteralExp */ ArrayLiteralExp createBlockDuplicatedArrayLiteral(const ref Loc loc, Type type, Expression elem, size_t dim) { if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray) { // If it is a multidimensional array literal, do it recursively auto tsa = cast(TypeSArray)type.nextOf(); const len = cast(size_t)tsa.dim.toInteger(); elem = createBlockDuplicatedArrayLiteral(loc, type.nextOf(), elem, len); } // Buzilla 15681 const tb = elem.type.toBasetype(); const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray; auto elements = new Expressions(dim); foreach (i, ref el; *elements) { el = mustCopy && i ? copyLiteral(elem).copy() : elem; } auto ale = new ArrayLiteralExp(loc, type, elements); ale.ownedByCtfe = OwnedBy.ctfe; return ale; } /****************************** * Helper for NewExp * Create a string literal consisting of 'value' duplicated 'dim' times. */ StringExp createBlockDuplicatedStringLiteral(const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz) { auto s = cast(char*)mem.xcalloc(dim, sz); foreach (elemi; 0 .. dim) { switch (sz) { case 1: s[elemi] = cast(char)value; break; case 2: (cast(wchar*)s)[elemi] = cast(wchar)value; break; case 4: (cast(dchar*)s)[elemi] = value; break; default: assert(0); } } auto se = new StringExp(loc, s, dim); se.type = type; se.sz = sz; se.committed = true; se.ownedByCtfe = OwnedBy.ctfe; return se; } // Return true if t is an AA bool isAssocArray(Type t) { t = t.toBasetype(); if (t.ty == Taarray) return true; return false; } // Given a template AA type, extract the corresponding built-in AA type TypeAArray toBuiltinAAType(Type t) { t = t.toBasetype(); if (t.ty == Taarray) return cast(TypeAArray)t; assert(0); } /************** TypeInfo operations ************************************/ // Return true if type is TypeInfo_Class bool isTypeInfo_Class(const Type type) { return type.ty == Tclass && (Type.dtypeinfo == (cast(TypeClass)type).sym || Type.dtypeinfo.isBaseOf((cast(TypeClass)type).sym, null)); } /************** Pointer operations ************************************/ // Return true if t is a pointer (not a function pointer) bool isPointer(Type t) { Type tb = t.toBasetype(); return tb.ty == Tpointer && tb.nextOf().ty != Tfunction; } // For CTFE only. Returns true if 'e' is true or a non-null pointer. bool isTrueBool(Expression e) { return e.isBool(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != TOK.null_); } /* Is it safe to convert from srcPointee* to destPointee* ? * srcPointee is the genuine type (never void). * destPointee may be void. */ bool isSafePointerCast(Type srcPointee, Type destPointee) { // It's safe to cast S** to D** if it's OK to cast S* to D* while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer) { srcPointee = srcPointee.nextOf(); destPointee = destPointee.nextOf(); } // It's OK if both are the same (modulo const) if (srcPointee.constConv(destPointee)) return true; // It's OK if function pointers differ only in safe/pure/nothrow if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) return srcPointee.covariant(destPointee) == 1; // it's OK to cast to void* if (destPointee.ty == Tvoid) return true; // It's OK to cast from V[K] to void* if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr) return true; // It's OK if they are the same size (static array of) integers, eg: // int* --> uint* // int[5][] --> uint[5][] if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray) { if (srcPointee.size() != destPointee.size()) return false; srcPointee = srcPointee.baseElemOf(); destPointee = destPointee.baseElemOf(); } return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size(); } Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) { *ofs = 0; if (e.op == TOK.address) e = (cast(AddrExp)e).e1; if (e.op == TOK.symbolOffset) *ofs = (cast(SymOffExp)e).offset; if (e.op == TOK.dotVariable) { const ex = (cast(DotVarExp)e).e1; const v = (cast(DotVarExp)e).var.isVarDeclaration(); assert(v); StructLiteralExp se = (ex.op == TOK.classReference) ? (cast(ClassReferenceExp)ex).value : cast(StructLiteralExp)ex; // We can't use getField, because it makes a copy const i = (ex.op == TOK.classReference) ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset) : se.getFieldIndex(e.type, v.offset); e = (*se.elements)[i]; } if (e.op == TOK.index) { IndexExp ie = cast(IndexExp)e; // Note that each AA element is part of its own memory block if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == TOK.string_ || ie.e1.op == TOK.arrayLiteral) && ie.e2.op == TOK.int64) { *ofs = ie.e2.toInteger(); return ie.e1; } } if (e.op == TOK.slice && e.type.toBasetype().ty == Tsarray) { SliceExp se = cast(SliceExp)e; if ((se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral) && se.lwr.op == TOK.int64) { *ofs = se.lwr.toInteger(); return se.e1; } } return e; } /** Return true if agg1 and agg2 are pointers to the same memory block */ bool pointToSameMemoryBlock(Expression agg1, Expression agg2) { if (agg1 == agg2) return true; // For integers cast to pointers, we regard them as non-comparable // unless they are identical. (This may be overly strict). if (agg1.op == TOK.int64 && agg2.op == TOK.int64 && agg1.toInteger() == agg2.toInteger()) { return true; } // Note that type painting can occur with VarExp, so we // must compare the variables being pointed to. if (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var) { return true; } if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) { return true; } return false; } // return e1 - e2 as an integer, or error if not possible UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(e1, &ofs1); Expression agg2 = getAggregateFromPointer(e2, &ofs2); if (agg1 == agg2) { Type pointee = (cast(TypePointer)agg1.type).next; const sz = pointee.size(); emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == TOK.string_ && agg2.op == TOK.string_ && (cast(StringExp)agg1).string == (cast(StringExp)agg2).string) { Type pointee = (cast(TypePointer)agg1.type).next; const sz = pointee.size(); emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) { emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type); } else { error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars()); emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); } return ue; } // Return eptr op e2, where eptr is a pointer, e2 is an integer, // and op is TOK.add or TOK.min UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr, Expression e2) { UnionExp ue; if (eptr.type.nextOf().ty == Tvoid) { error(loc, "cannot perform arithmetic on `void*` pointers at compile time"); Lcant: emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); return ue; } if (eptr.op == TOK.address) eptr = (cast(AddrExp)eptr).e1; dinteger_t ofs1; Expression agg1 = getAggregateFromPointer(eptr, &ofs1); if (agg1.op == TOK.symbolOffset) { if ((cast(SymOffExp)agg1).var.type.ty != Tsarray) { error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time"); goto Lcant; } } else if (agg1.op != TOK.string_ && agg1.op != TOK.arrayLiteral) { error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); goto Lcant; } dinteger_t ofs2 = e2.toInteger(); Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next; dinteger_t sz = pointee.size(); sinteger_t indx; dinteger_t len; if (agg1.op == TOK.symbolOffset) { indx = ofs1 / sz; len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger(); } else { Expression dollar = ArrayLength(Type.tsize_t, agg1).copy(); assert(!CTFEExp.isCantExp(dollar)); indx = ofs1; len = dollar.toInteger(); } if (op == TOK.add || op == TOK.addAssign || op == TOK.plusPlus) indx += ofs2 / sz; else if (op == TOK.min || op == TOK.minAssign || op == TOK.minusMinus) indx -= ofs2 / sz; else { error(loc, "CTFE internal error: bad pointer operation"); goto Lcant; } if (indx < 0 || len < indx) { error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len); goto Lcant; } if (agg1.op == TOK.symbolOffset) { emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz); SymOffExp se = cast(SymOffExp)ue.exp(); se.type = type; return ue; } if (agg1.op != TOK.arrayLiteral && agg1.op != TOK.string_) { error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars()); goto Lcant; } if (eptr.type.toBasetype().ty == Tsarray) { dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger(); // Create a CTFE pointer &agg1[indx .. indx+dim] auto se = new SliceExp(loc, agg1, new IntegerExp(loc, indx, Type.tsize_t), new IntegerExp(loc, indx + dim, Type.tsize_t)); se.type = type.toBasetype().nextOf(); emplaceExp!(AddrExp)(&ue, loc, se); ue.exp().type = type; return ue; } // Create a CTFE pointer &agg1[indx] auto ofs = new IntegerExp(loc, indx, Type.tsize_t); Expression ie = new IndexExp(loc, agg1, ofs); ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992 emplaceExp!(AddrExp)(&ue, loc, ie); ue.exp().type = type; return ue; } // Return 1 if true, 0 if false // -1 if comparison is illegal because they point to non-comparable memory blocks int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2) { if (pointToSameMemoryBlock(agg1, agg2)) { int n; switch (op) { case TOK.lessThan: n = (ofs1 < ofs2); break; case TOK.lessOrEqual: n = (ofs1 <= ofs2); break; case TOK.greaterThan: n = (ofs1 > ofs2); break; case TOK.greaterOrEqual: n = (ofs1 >= ofs2); break; case TOK.identity: case TOK.equal: n = (ofs1 == ofs2); break; case TOK.notIdentity: case TOK.notEqual: n = (ofs1 != ofs2); break; default: assert(0); } return n; } const null1 = (agg1.op == TOK.null_); const null2 = (agg2.op == TOK.null_); int cmp; if (null1 || null2) { switch (op) { case TOK.lessThan: cmp = null1 && !null2; break; case TOK.greaterThan: cmp = !null1 && null2; break; case TOK.lessOrEqual: cmp = null1; break; case TOK.greaterOrEqual: cmp = null2; break; case TOK.identity: case TOK.equal: case TOK.notIdentity: // 'cmp' gets inverted below case TOK.notEqual: cmp = (null1 == null2); break; default: assert(0); } } else { switch (op) { case TOK.identity: case TOK.equal: case TOK.notIdentity: // 'cmp' gets inverted below case TOK.notEqual: cmp = 0; break; default: return -1; // memory blocks are different } } if (op == TOK.notIdentity || op == TOK.notEqual) cmp ^= 1; return cmp; } // True if conversion from type 'from' to 'to' involves a reinterpret_cast // floating point -> integer or integer -> floating point bool isFloatIntPaint(Type to, Type from) { return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral()); } // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. Expression paintFloatInt(Expression fromVal, Type to) { if (exceptionOrCantInterpret(fromVal)) return fromVal; assert(to.size() == 4 || to.size() == 8); return Compiler.paintAsType(fromVal, to); } /******** Constant folding, with support for CTFE ***************************/ /// Return true if non-pointer expression e can be compared /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity bool isCtfeComparable(Expression e) { if (e.op == TOK.slice) e = (cast(SliceExp)e).e1; if (e.isConst() != 1) { if (e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.arrayLiteral || e.op == TOK.structLiteral || e.op == TOK.assocArrayLiteral || e.op == TOK.classReference) { return true; } // https://issues.dlang.org/show_bug.cgi?id=14123 // TypeInfo object is comparable in CTFE if (e.op == TOK.typeid_) return true; return false; } return true; } /// Map TOK comparison ops private bool numCmp(N)(TOK op, N n1, N n2) { switch (op) { case TOK.lessThan: return n1 < n2; case TOK.lessOrEqual: return n1 <= n2; case TOK.greaterThan: return n1 > n2; case TOK.greaterOrEqual: return n1 >= n2; default: assert(0); } } /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 int specificCmp(TOK op, int rawCmp) { return numCmp!int(op, rawCmp, 0); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2) { return numCmp!dinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2) { return numCmp!sinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 int realCmp(TOK op, real_t r1, real_t r2) { // Don't rely on compiler, handle NAN arguments separately if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered { switch (op) { case TOK.lessThan: case TOK.lessOrEqual: case TOK.greaterThan: case TOK.greaterOrEqual: return 0; default: assert(0); } } else { return numCmp!real_t(op, r1, r2); } } /* Conceptually the same as memcmp(e1, e2). * e1 and e2 may be strings, arrayliterals, or slices. * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. */ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len) { // Resolve slices, if necessary uinteger_t lo1 = 0; uinteger_t lo2 = 0; Expression x = e1; if (x.op == TOK.slice) { lo1 = (cast(SliceExp)x).lwr.toInteger(); x = (cast(SliceExp)x).e1; } StringExp se1 = (x.op == TOK.string_) ? cast(StringExp)x : null; ArrayLiteralExp ae1 = (x.op == TOK.arrayLiteral) ? cast(ArrayLiteralExp)x : null; x = e2; if (x.op == TOK.slice) { lo2 = (cast(SliceExp)x).lwr.toInteger(); x = (cast(SliceExp)x).e1; } StringExp se2 = (x.op == TOK.string_) ? cast(StringExp)x : null; ArrayLiteralExp ae2 = (x.op == TOK.arrayLiteral) ? cast(ArrayLiteralExp)x : null; // Now both must be either TOK.arrayLiteral or TOK.string_ if (se1 && se2) return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); if (se1 && ae2) return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); if (se2 && ae1) return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len); assert(ae1 && ae2); // Comparing two array literals. This case is potentially recursive. // If they aren't strings, we just need an equality check rather than // a full cmp. const bool needCmp = ae1.type.nextOf().isintegral(); foreach (size_t i; 0 .. cast(size_t)len) { Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)]; Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)]; if (needCmp) { const sinteger_t c = ee1.toInteger() - ee2.toInteger(); if (c > 0) return 1; if (c < 0) return -1; } else { if (ctfeRawCmp(loc, ee1, ee2)) return 1; } } return 0; } /* Given a delegate expression e, return .funcptr. * If e is NullExp, return NULL. */ private FuncDeclaration funcptrOf(Expression e) { assert(e.type.ty == Tdelegate); if (e.op == TOK.delegate_) return (cast(DelegateExp)e).func; if (e.op == TOK.function_) return (cast(FuncExp)e).fd; assert(e.op == TOK.null_); return null; } private bool isArray(const Expression e) { return e.op == TOK.arrayLiteral || e.op == TOK.string_ || e.op == TOK.slice || e.op == TOK.null_; } /* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. */ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2) { if (e1.op == TOK.classReference || e2.op == TOK.classReference) { if (e1.op == TOK.classReference && e2.op == TOK.classReference && (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value) return 0; return 1; } if (e1.op == TOK.typeid_ && e2.op == TOK.typeid_) { // printf("e1: %s\n", e1.toChars()); // printf("e2: %s\n", e2.toChars()); Type t1 = isType((cast(TypeidExp)e1).obj); Type t2 = isType((cast(TypeidExp)e2).obj); assert(t1); assert(t2); return t1 != t2; } // null == null, regardless of type if (e1.op == TOK.null_ && e2.op == TOK.null_) return 0; if (e1.type.ty == Tpointer && e2.type.ty == Tpointer) { // Can only be an equality test. dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(e1, &ofs1); Expression agg2 = getAggregateFromPointer(e2, &ofs2); if ((agg1 == agg2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) { if (ofs1 == ofs2) return 0; } return 1; } if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate) { // If .funcptr isn't the same, they are not equal if (funcptrOf(e1) != funcptrOf(e2)) return 1; // If both are delegate literals, assume they have the // same closure pointer. TODO: We don't support closures yet! if (e1.op == TOK.function_ && e2.op == TOK.function_) return 0; assert(e1.op == TOK.delegate_ && e2.op == TOK.delegate_); // Same .funcptr. Do they have the same .ptr? Expression ptr1 = (cast(DelegateExp)e1).e1; Expression ptr2 = (cast(DelegateExp)e2).e1; dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(ptr1, &ofs1); Expression agg2 = getAggregateFromPointer(ptr2, &ofs2); // If they are TOK.variable, it means they are FuncDeclarations if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) { return 0; } return 1; } if (isArray(e1) && isArray(e2)) { const uinteger_t len1 = resolveArrayLength(e1); const uinteger_t len2 = resolveArrayLength(e2); // workaround for dmc optimizer bug calculating wrong len for // uinteger_t len = (len1 < len2 ? len1 : len2); // if (len == 0) ... if (len1 > 0 && len2 > 0) { const uinteger_t len = (len1 < len2 ? len1 : len2); const int res = ctfeCmpArrays(loc, e1, e2, len); if (res != 0) return res; } return cast(int)(len1 - len2); } if (e1.type.isintegral()) { return e1.toInteger() != e2.toInteger(); } if (e1.type.isreal() || e1.type.isimaginary()) { real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary(); real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary(); if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered { return 1; } else { return (r1 != r2); } } else if (e1.type.iscomplex()) { return e1.toComplex() != e2.toComplex(); } if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral) { StructLiteralExp es1 = cast(StructLiteralExp)e1; StructLiteralExp es2 = cast(StructLiteralExp)e2; // For structs, we only need to return 0 or 1 (< and > aren't legal). if (es1.sd != es2.sd) return 1; else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) return 0; // both arrays are empty else if (!es1.elements || !es2.elements) return 1; else if (es1.elements.dim != es2.elements.dim) return 1; else { foreach (size_t i; 0 .. es1.elements.dim) { Expression ee1 = (*es1.elements)[i]; Expression ee2 = (*es2.elements)[i]; if (ee1 == ee2) continue; if (!ee1 || !ee2) return 1; const int cmp = ctfeRawCmp(loc, ee1, ee2); if (cmp) return 1; } return 0; // All elements are equal } } if (e1.op == TOK.assocArrayLiteral && e2.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1; AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2; size_t dim = es1.keys.dim; if (es2.keys.dim != dim) return 1; bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim); memset(used, 0, bool.sizeof * dim); foreach (size_t i; 0 .. dim) { Expression k1 = (*es1.keys)[i]; Expression v1 = (*es1.values)[i]; Expression v2 = null; foreach (size_t j; 0 .. dim) { if (used[j]) continue; Expression k2 = (*es2.keys)[j]; if (ctfeRawCmp(loc, k1, k2)) continue; used[j] = true; v2 = (*es2.values)[j]; break; } if (!v2 || ctfeRawCmp(loc, v1, v2)) { mem.xfree(used); return 1; } } mem.xfree(used); return 0; } error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1.toChars(), e2.toChars()); assert(0); } /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 int ctfeEqual(const ref Loc loc, TOK op, Expression e1, Expression e2) { return !ctfeRawCmp(loc, e1, e2) ^ (op == TOK.notEqual); } /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 int ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2) { //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op), // Token::toChars(e1.op), e1.toChars(), Token::toChars(e2.op), e1.toChars()); int cmp; if (e1.op == TOK.null_) { cmp = (e2.op == TOK.null_); } else if (e2.op == TOK.null_) { cmp = 0; } else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset) { SymOffExp es1 = cast(SymOffExp)e1; SymOffExp es2 = cast(SymOffExp)e2; cmp = (es1.var == es2.var && es1.offset == es2.offset); } else if (e1.type.isreal()) cmp = RealEquals(e1.toReal(), e2.toReal()); else if (e1.type.isimaginary()) cmp = RealEquals(e1.toImaginary(), e2.toImaginary()); else if (e1.type.iscomplex()) { complex_t v1 = e1.toComplex(); complex_t v2 = e2.toComplex(); cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1)); } else cmp = !ctfeRawCmp(loc, e1, e2); if (op == TOK.notIdentity || op == TOK.notEqual) cmp ^= 1; return cmp; } /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1 int ctfeCmp(const ref Loc loc, TOK op, Expression e1, Expression e2) { Type t1 = e1.type.toBasetype(); Type t2 = e2.type.toBasetype(); if (t1.isString() && t2.isString()) return specificCmp(op, ctfeRawCmp(loc, e1, e2)); else if (t1.isreal()) return realCmp(op, e1.toReal(), e2.toReal()); else if (t1.isimaginary()) return realCmp(op, e1.toImaginary(), e2.toImaginary()); else if (t1.isunsigned() || t2.isunsigned()) return intUnsignedCmp(op, e1.toInteger(), e2.toInteger()); else return intSignedCmp(op, e1.toInteger(), e2.toInteger()); } UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) { Type t1 = e1.type.toBasetype(); Type t2 = e2.type.toBasetype(); UnionExp ue; if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string => string (only valid for CTFE) StringExp es1 = cast(StringExp)e2; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1; const len = es1.len + es2.elements.dim; const sz = es1.sz; void* s = mem.xmalloc((len + 1) * sz); memcpy(cast(char*)s + sz * es2.elements.dim, es1.string, es1.len * sz); foreach (size_t i; 0 .. es2.elements.dim) { Expression es2e = (*es2.elements)[i]; if (es2e.op != TOK.int64) { emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); return ue; } dinteger_t v = es2e.toInteger(); Port.valcpy(cast(char*)s + i * sz, v, sz); } // Add terminating 0 memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = 0; es.type = type; return ue; } if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral()) { // string ~ [chars] => string (only valid for CTFE) // Concatenate the strings StringExp es1 = cast(StringExp)e1; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; const len = es1.len + es2.elements.dim; const sz = es1.sz; void* s = mem.xmalloc((len + 1) * sz); memcpy(s, es1.string, es1.len * sz); foreach (size_t i; 0 .. es2.elements.dim) { Expression es2e = (*es2.elements)[i]; if (es2e.op != TOK.int64) { emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); return ue; } const v = es2e.toInteger(); Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz); } // Add terminating 0 memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; es.committed = 0; //es1.committed; es.type = type; return ue; } if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements)); es1 = cast(ArrayLiteralExp)ue.exp(); es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements)); return ue; } if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf())) { // [ e1 ] ~ null ----> [ e1 ].dup ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy()); return ue; } if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // null ~ [ e2 ] ----> [ e2 ].dup ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy()); return ue; } ue = Cat(type, e1, e2); return ue; } /* Given an AA literal 'ae', and a key 'e2': * Return ae[e2] if present, or NULL if not found. */ Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2) { /* Search the keys backwards, in case there are duplicate keys */ for (size_t i = ae.keys.dim; i;) { --i; Expression ekey = (*ae.keys)[i]; const int eq = ctfeEqual(loc, TOK.equal, ekey, e2); if (eq) { return (*ae.values)[i]; } } return null; } /* Same as for constfold.Index, except that it only works for static arrays, * dynamic arrays, and strings. We know that e1 is an * interpreted CTFE expression, so it cannot have side-effects. */ Expression ctfeIndex(const ref Loc loc, Type type, Expression e1, uinteger_t indx) { //printf("ctfeIndex(e1 = %s)\n", e1.toChars()); assert(e1.type); if (e1.op == TOK.string_) { StringExp es1 = cast(StringExp)e1; if (indx >= es1.len) { error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); return CTFEExp.cantexp; } return new IntegerExp(loc, es1.charAt(indx), type); } assert(e1.op == TOK.arrayLiteral); { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; if (indx >= ale.elements.dim) { error(loc, "array index %llu is out of bounds `%s[0 .. %llu]`", indx, e1.toChars(), cast(ulong)ale.elements.dim); return CTFEExp.cantexp; } Expression e = (*ale.elements)[cast(size_t)indx]; return paintTypeOntoLiteral(type, e); } } Expression ctfeCast(const ref Loc loc, Type type, Type to, Expression e) { if (e.op == TOK.null_) return paintTypeOntoLiteral(to, e); if (e.op == TOK.classReference) { // Disallow reinterpreting class casts. Do this by ensuring that // the original class can implicitly convert to the target class ClassDeclaration originalClass = (cast(ClassReferenceExp)e).originalClass(); if (originalClass.type.implicitConvTo(to.mutableOf())) return paintTypeOntoLiteral(to, e); else return new NullExp(loc, to); } // Allow TypeInfo type painting if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to)) return paintTypeOntoLiteral(to, e); // Allow casting away const for struct literals if (e.op == TOK.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0)) { return paintTypeOntoLiteral(to, e); } Expression r; if (e.type.equals(type) && type.equals(to)) { // necessary not to change e's address for pointer comparisons r = e; } else if (to.toBasetype().ty == Tarray && type.toBasetype().ty == Tarray && to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size()) { // https://issues.dlang.org/show_bug.cgi?id=12495 // Array reinterpret casts: eg. string to immutable(ubyte)[] return paintTypeOntoLiteral(to, e); } else { r = Cast(loc, type, to, e).copy(); } if (CTFEExp.isCantExp(r)) error(loc, "cannot cast `%s` to `%s` at compile time", e.toChars(), to.toChars()); if (e.op == TOK.arrayLiteral) (cast(ArrayLiteralExp)e).ownedByCtfe = OwnedBy.ctfe; if (e.op == TOK.string_) (cast(StringExp)e).ownedByCtfe = OwnedBy.ctfe; return r; } /******** Assignment helper functions ***************************/ /* Set dest = src, where both dest and src are container value literals * (ie, struct literals, or static arrays (can be an array literal or a string)) * Assignment is recursively in-place. * Purpose: any reference to a member of 'dest' will remain valid after the * assignment. */ void assignInPlace(Expression dest, Expression src) { assert(dest.op == TOK.structLiteral || dest.op == TOK.arrayLiteral || dest.op == TOK.string_); Expressions* oldelems; Expressions* newelems; if (dest.op == TOK.structLiteral) { assert(dest.op == src.op); oldelems = (cast(StructLiteralExp)dest).elements; newelems = (cast(StructLiteralExp)src).elements; if ((cast(StructLiteralExp)dest).sd.isNested() && oldelems.dim == newelems.dim - 1) oldelems.push(null); } else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral) { oldelems = (cast(ArrayLiteralExp)dest).elements; newelems = (cast(ArrayLiteralExp)src).elements; } else if (dest.op == TOK.string_ && src.op == TOK.string_) { sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0); return; } else if (dest.op == TOK.arrayLiteral && src.op == TOK.string_) { sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0); return; } else if (src.op == TOK.arrayLiteral && dest.op == TOK.string_) { sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0); return; } else assert(0); assert(oldelems.dim == newelems.dim); foreach (size_t i; 0 .. oldelems.dim) { Expression e = (*newelems)[i]; Expression o = (*oldelems)[i]; if (e.op == TOK.structLiteral) { assert(o.op == e.op); assignInPlace(o, e); } else if (e.type.ty == Tsarray && e.op != TOK.void_ && o.type.ty == Tsarray) { assignInPlace(o, e); } else { (*oldelems)[i] = (*newelems)[i]; } } } // Given an AA literal aae, set aae[index] = newval and return newval. Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval) { /* Create new associative array literal reflecting updated key/value */ Expressions* keysx = aae.keys; Expressions* valuesx = aae.values; int updated = 0; for (size_t j = valuesx.dim; j;) { j--; Expression ekey = (*aae.keys)[j]; int eq = ctfeEqual(loc, TOK.equal, ekey, index); if (eq) { (*valuesx)[j] = newval; updated = 1; } } if (!updated) { // Append index/newval to keysx[]/valuesx[] valuesx.push(newval); keysx.push(index); } return newval; } /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length /// oldlen, change its length to newlen. If the newlen is longer than oldlen, /// all new elements will be set to the default initializer for the element type. UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen) { UnionExp ue; Type elemType = arrayType.next; assert(elemType); Expression defaultElem = elemType.defaultInitLiteral(loc); auto elements = new Expressions(newlen); // Resolve slices size_t indxlo = 0; if (oldval.op == TOK.slice) { indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger(); oldval = (cast(SliceExp)oldval).e1; } size_t copylen = oldlen < newlen ? oldlen : newlen; if (oldval.op == TOK.string_) { StringExp oldse = cast(StringExp)oldval; void* s = mem.xcalloc(newlen + 1, oldse.sz); memcpy(s, oldse.string, copylen * oldse.sz); const defaultValue = cast(uint)defaultElem.toInteger(); foreach (size_t elemi; copylen .. newlen) { switch (oldse.sz) { case 1: (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue; break; case 2: (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue; break; case 4: (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; break; default: assert(0); } } emplaceExp!(StringExp)(&ue, loc, s, newlen); StringExp se = cast(StringExp)ue.exp(); se.type = arrayType; se.sz = oldse.sz; se.committed = oldse.committed; se.ownedByCtfe = OwnedBy.ctfe; } else { if (oldlen != 0) { assert(oldval.op == TOK.arrayLiteral); ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval; foreach (size_t i; 0 .. copylen) (*elements)[i] = (*ae.elements)[indxlo + i]; } if (elemType.ty == Tstruct || elemType.ty == Tsarray) { /* If it is an aggregate literal representing a value type, * we need to create a unique copy for each element */ foreach (size_t i; copylen .. newlen) (*elements)[i] = copyLiteral(defaultElem).copy(); } else { foreach (size_t i; copylen .. newlen) (*elements)[i] = defaultElem; } emplaceExp!(ArrayLiteralExp)(&ue, loc, arrayType, elements); ArrayLiteralExp aae = cast(ArrayLiteralExp)ue.exp(); aae.ownedByCtfe = OwnedBy.ctfe; } return ue; } /*************************** CTFE Sanity Checks ***************************/ bool isCtfeValueValid(Expression newval) { Type tb = newval.type.toBasetype(); if (newval.op == TOK.int64 || newval.op == TOK.float64 || newval.op == TOK.char_ || newval.op == TOK.complex80) { return tb.isscalar(); } if (newval.op == TOK.null_) { return tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate; } if (newval.op == TOK.string_) return true; // CTFE would directly use the StringExp in AST. if (newval.op == TOK.arrayLiteral) return true; //((ArrayLiteralExp *)newval)->ownedByCtfe; if (newval.op == TOK.assocArrayLiteral) return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe; if (newval.op == TOK.structLiteral) return true; //((StructLiteralExp *)newval)->ownedByCtfe; if (newval.op == TOK.classReference) return true; if (newval.op == TOK.vector) return true; // vector literal if (newval.op == TOK.function_) return true; // function literal or delegate literal if (newval.op == TOK.delegate_) { // &struct.func or &clasinst.func // &nestedfunc Expression ethis = (cast(DelegateExp)newval).e1; return (ethis.op == TOK.structLiteral || ethis.op == TOK.classReference || ethis.op == TOK.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func); } if (newval.op == TOK.symbolOffset) { // function pointer, or pointer to static variable Declaration d = (cast(SymOffExp)newval).var; return d.isFuncDeclaration() || d.isDataseg(); } if (newval.op == TOK.typeid_) { // always valid return true; } if (newval.op == TOK.address) { // e1 should be a CTFE reference Expression e1 = (cast(AddrExp)newval).e1; return tb.ty == Tpointer && (e1.op == TOK.structLiteral && isCtfeValueValid(e1) || e1.op == TOK.variable || e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) || e1.op == TOK.index && isCtfeReferenceValid(e1) || e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray); } if (newval.op == TOK.slice) { // e1 should be an array aggregate const SliceExp se = cast(SliceExp)newval; assert(se.lwr && se.lwr.op == TOK.int64); assert(se.upr && se.upr.op == TOK.int64); return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral); } if (newval.op == TOK.void_) return true; // uninitialized value newval.error("CTFE internal error: illegal CTFE value `%s`", newval.toChars()); return false; } bool isCtfeReferenceValid(Expression newval) { if (newval.op == TOK.this_) return true; if (newval.op == TOK.variable) { const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration(); assert(v); // Must not be a reference to a reference return true; } if (newval.op == TOK.index) { const Expression eagg = (cast(IndexExp)newval).e1; return eagg.op == TOK.string_ || eagg.op == TOK.arrayLiteral || eagg.op == TOK.assocArrayLiteral; } if (newval.op == TOK.dotVariable) { Expression eagg = (cast(DotVarExp)newval).e1; return (eagg.op == TOK.structLiteral || eagg.op == TOK.classReference) && isCtfeValueValid(eagg); } // Internally a ref variable may directly point a stack memory. // e.g. ref int v = 1; return isCtfeValueValid(newval); } // Used for debugging only void showCtfeExpr(Expression e, int level = 0) { for (int i = level; i > 0; --i) printf(" "); Expressions* elements = null; // We need the struct definition to detect block assignment StructDeclaration sd = null; ClassDeclaration cd = null; if (e.op == TOK.structLiteral) { elements = (cast(StructLiteralExp)e).elements; sd = (cast(StructLiteralExp)e).sd; printf("STRUCT type = %s %p:\n", e.type.toChars(), e); } else if (e.op == TOK.classReference) { elements = (cast(ClassReferenceExp)e).value.elements; cd = (cast(ClassReferenceExp)e).originalClass(); printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value); } else if (e.op == TOK.arrayLiteral) { elements = (cast(ArrayLiteralExp)e).elements; printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e); } else if (e.op == TOK.assocArrayLiteral) { printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e); } else if (e.op == TOK.string_) { printf("STRING %s %p\n", e.toChars(), (cast(StringExp)e).string); } else if (e.op == TOK.slice) { printf("SLICE %p: %s\n", e, e.toChars()); showCtfeExpr((cast(SliceExp)e).e1, level + 1); } else if (e.op == TOK.variable) { printf("VAR %p %s\n", e, e.toChars()); VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && getValue(v)) showCtfeExpr(getValue(v), level + 1); } else if (e.op == TOK.address) { // This is potentially recursive. We mustn't try to print the thing we're pointing to. printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars()); } else printf("VALUE %p: %s\n", e, e.toChars()); if (elements) { size_t fieldsSoFar = 0; for (size_t i = 0; i < elements.dim; i++) { Expression z = null; VarDeclaration v = null; if (i > 15) { printf("...(total %d elements)\n", cast(int)elements.dim); return; } if (sd) { v = sd.fields[i]; z = (*elements)[i]; } else if (cd) { while (i - fieldsSoFar >= cd.fields.dim) { fieldsSoFar += cd.fields.dim; cd = cd.baseClass; for (int j = level; j > 0; --j) printf(" "); printf(" BASE CLASS: %s\n", cd.toChars()); } v = cd.fields[i - fieldsSoFar]; assert((elements.dim + i) >= (fieldsSoFar + cd.fields.dim)); size_t indx = (elements.dim - fieldsSoFar) - cd.fields.dim + i; assert(indx < elements.dim); z = (*elements)[indx]; } if (!z) { for (int j = level; j > 0; --j) printf(" "); printf(" void\n"); continue; } if (v) { // If it is a void assignment, use the default initializer if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray) { for (int j = level; --j;) printf(" "); printf(" field: block initialized static array\n"); continue; } } showCtfeExpr(z, level + 1); } } } /*************************** Void initialization ***************************/ UnionExp voidInitLiteral(Type t, VarDeclaration var) { UnionExp ue; if (t.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)t; Expression elem = voidInitLiteral(tsa.next, var).copy(); // For aggregate value types (structs, static arrays) we must // create an a separate copy for each element. const mustCopy = (elem.op == TOK.arrayLiteral || elem.op == TOK.structLiteral); const d = cast(size_t)tsa.dim.toInteger(); auto elements = new Expressions(d); foreach (i; 0 .. d) { if (mustCopy && i > 0) elem = copyLiteral(elem).copy(); (*elements)[i] = elem; } emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements); ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp(); ae.ownedByCtfe = OwnedBy.ctfe; } else if (t.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)t; auto exps = new Expressions(ts.sym.fields.dim); foreach (size_t i; 0 .. ts.sym.fields.dim) { (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy(); } emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps); StructLiteralExp se = cast(StructLiteralExp)ue.exp(); se.type = ts; se.ownedByCtfe = OwnedBy.ctfe; } else emplaceExp!(VoidInitExp)(&ue, var); return ue; } ================================================ FILE: gcc/d/dmd/ctorflow.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Manage flow analysis for constructors. * * Copyright: Copyright (C) 1999-2018 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/ctorflow.d, _ctorflow.d) * Documentation: https://dlang.org/phobos/dmd_ctorflow.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctorflow.d */ module dmd.ctorflow; import core.stdc.stdio; import dmd.root.rmem; import dmd.globals : Loc; enum CSX : ushort { none = 0, this_ctor = 0x01, /// called this() super_ctor = 0x02, /// called super() label = 0x04, /// seen a label return_ = 0x08, /// seen a return statement any_ctor = 0x10, /// either this() or super() was called halt = 0x20, /// assert(0) deprecate_18719 = 0x40, // issue deprecation for Issue 18719 - delete when deprecation period is over } /// Individual field in the Ctor with information about its callees and location. struct FieldInit { CSX csx; /// information about the field's callees Loc loc; /// location of the field initialization } /*********** * Primitive flow analysis for constructors */ struct CtorFlow { CSX callSuper; /// state of calling other constructors FieldInit[] fieldinit; /// state of field initializations void allocFieldinit(size_t dim) { fieldinit = (cast(FieldInit*)mem.xcalloc(FieldInit.sizeof, dim))[0 .. dim]; } void freeFieldinit() { if (fieldinit.ptr) mem.xfree(fieldinit.ptr); fieldinit = null; } /*********************** * Create a deep copy of `this` * Returns: * a copy */ CtorFlow clone() { return CtorFlow(callSuper, fieldinit.arraydup); } /********************************** * Set CSX bits in flow analysis state * Params: * csx = bits to set */ void orCSX(CSX csx) nothrow pure { callSuper |= csx; foreach (ref u; fieldinit) u.csx |= csx; } /****************************** * OR CSX bits to `this` * Params: * ctorflow = bits to OR in */ void OR(const ref CtorFlow ctorflow) pure nothrow { callSuper |= ctorflow.callSuper; if (fieldinit.length && ctorflow.fieldinit.length) { assert(fieldinit.length == ctorflow.fieldinit.length); foreach (i, u; ctorflow.fieldinit) { auto fi = &fieldinit[i]; fi.csx |= u.csx; if (fi.loc == Loc.init) fi.loc = u.loc; } } } } /**************************************** * Merge `b` flow analysis results into `a`. * Params: * a = the path to merge `b` into * b = the other path * Returns: * false means one of the paths skips construction */ bool mergeCallSuper(ref CSX a, const CSX b) pure nothrow { // This does a primitive flow analysis to support the restrictions // regarding when and how constructors can appear. // It merges the results of two paths. // The two paths are `a` and `b`; the result is merged into `a`. if (b == a) return true; // Have ALL branches called a constructor? const aAll = (a & (CSX.this_ctor | CSX.super_ctor)) != 0; const bAll = (b & (CSX.this_ctor | CSX.super_ctor)) != 0; // Have ANY branches called a constructor? const aAny = (a & CSX.any_ctor) != 0; const bAny = (b & CSX.any_ctor) != 0; // Have any branches returned? const aRet = (a & CSX.return_) != 0; const bRet = (b & CSX.return_) != 0; // Have any branches halted? const aHalt = (a & CSX.halt) != 0; const bHalt = (b & CSX.halt) != 0; if (aHalt && bHalt) { a = CSX.halt; } else if ((!bHalt && bRet && !bAny && aAny) || (!aHalt && aRet && !aAny && bAny)) { // If one has returned without a constructor call, there must not // be ctor calls in the other. return false; } else if (bHalt || bRet && bAll) { // If one branch has called a ctor and then exited, anything the // other branch has done is OK (except returning without a // ctor call, but we already checked that). a |= b & (CSX.any_ctor | CSX.label); } else if (aHalt || aRet && aAll) { a = cast(CSX)(b | (a & (CSX.any_ctor | CSX.label))); } else if (aAll != bAll) // both branches must have called ctors, or both not return false; else { // If one returned without a ctor, remember that if (bRet && !bAny) a |= CSX.return_; a |= b & (CSX.any_ctor | CSX.label); } return true; } /**************************************** * Merge `b` flow analysis results into `a`. * Params: * a = the path to merge `b` into * b = the other path * Returns: * false means either `a` or `b` skips initialization */ bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow { if (b == a) return true; // Have any branches returned? const aRet = (a & CSX.return_) != 0; const bRet = (b & CSX.return_) != 0; // Have any branches halted? const aHalt = (a & CSX.halt) != 0; const bHalt = (b & CSX.halt) != 0; if (aHalt && bHalt) { a = CSX.halt; return true; } bool ok; if (!bHalt && bRet) { ok = (b & CSX.this_ctor); a = a; } else if (!aHalt && aRet) { ok = (a & CSX.this_ctor); a = b; } else if (bHalt) { ok = (a & CSX.this_ctor); a = a; } else if (aHalt) { ok = (b & CSX.this_ctor); a = b; } else { ok = !((a ^ b) & CSX.this_ctor); a |= b; } return ok; } ================================================ FILE: gcc/d/dmd/dcast.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dcast.d, _dcast.d) * Documentation: https://dlang.org/phobos/dmd_dcast.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d */ module dmd.dcast; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.dclass; import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.impcnvtab; import dmd.id; import dmd.init; import dmd.intrange; import dmd.mtype; import dmd.opover; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.tokens; import dmd.typesem; import dmd.utf; import dmd.visitor; enum LOG = false; /************************************** * Do an implicit cast. * Issue error if it can't be done. */ Expression implicitCastTo(Expression e, Scope* sc, Type t) { extern (C++) final class ImplicitCastTo : Visitor { alias visit = Visitor.visit; public: Type t; Scope* sc; Expression result; extern (D) this(Scope* sc, Type t) { this.sc = sc; this.t = t; } override void visit(Expression e) { //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); MATCH match = e.implicitConvTo(t); if (match) { if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t))) { /* Do not emit CastExp for const conversions and * unique conversions on rvalue. */ result = e.copy(); result.type = t; return; } result = e.castTo(sc, t); return; } result = e.optimize(WANTvalue); if (result != e) { result.accept(this); return; } if (t.ty != Terror && e.type.ty != Terror) { if (!t.deco) { e.error("forward reference to type `%s`", t.toChars()); } else { //printf("type %p ty %d deco %p\n", type, type.ty, type.deco); //type = type.typeSemantic(loc, sc); //printf("type %s t %s\n", type.deco, t.deco); auto ts = toAutoQualChars(e.type, t); e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", e.toChars(), ts[0], ts[1]); } } result = new ErrorExp(); } override void visit(StringExp e) { //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); visit(cast(Expression)e); if (result.op == TOK.string_) { // Retain polysemous nature if it started out that way (cast(StringExp)result).committed = e.committed; } } override void visit(ErrorExp e) { result = e; } override void visit(FuncExp e) { //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); FuncExp fe; if (e.matchType(t, sc, &fe) > MATCH.nomatch) { result = fe; return; } visit(cast(Expression)e); } override void visit(ArrayLiteralExp e) { visit(cast(Expression)e); Type tb = result.type.toBasetype(); if (tb.ty == Tarray && global.params.useTypeInfo && Type.dtypeinfo) semanticTypeInfo(sc, (cast(TypeDArray)tb).next); } override void visit(SliceExp e) { visit(cast(Expression)e); if (result.op != TOK.slice) return; e = cast(SliceExp)result; if (e.e1.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e.e1; Type tb = t.toBasetype(); Type tx; if (tb.ty == Tsarray) tx = tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0); else tx = tb.nextOf().arrayOf(); e.e1 = ale.implicitCastTo(sc, tx); } } } scope ImplicitCastTo v = new ImplicitCastTo(sc, t); e.accept(v); return v.result; } /******************************************* * Return MATCH level of implicitly converting e to type t. * Don't do the actual cast; don't change e. */ MATCH implicitConvTo(Expression e, Type t) { extern (C++) final class ImplicitConvTo : Visitor { alias visit = Visitor.visit; public: Type t; MATCH result; extern (D) this(Type t) { this.t = t; result = MATCH.nomatch; } override void visit(Expression e) { version (none) { printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } //static int nest; if (++nest == 10) assert(0); if (t == Type.terror) return; if (!e.type) { e.error("`%s` is not an expression", e.toChars()); e.type = Type.terror; } Expression ex = e.optimize(WANTvalue); if (ex.type.equals(t)) { result = MATCH.exact; return; } if (ex != e) { //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars()); result = ex.implicitConvTo(t); return; } MATCH match = e.type.implicitConvTo(t); if (match != MATCH.nomatch) { result = match; return; } /* See if we can do integral narrowing conversions */ if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic()) { IntRange src = getIntRange(e); IntRange target = IntRange.fromType(t); if (target.contains(src)) { result = MATCH.convert; return; } } } /****** * Given expression e of type t, see if we can implicitly convert e * to type tprime, where tprime is type t with mod bits added. * Returns: * match level */ static MATCH implicitMod(Expression e, Type t, MOD mod) { Type tprime; if (t.ty == Tpointer) tprime = t.nextOf().castMod(mod).pointerTo(); else if (t.ty == Tarray) tprime = t.nextOf().castMod(mod).arrayOf(); else if (t.ty == Tsarray) tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size()); else tprime = t.castMod(mod); return e.implicitConvTo(tprime); } static MATCH implicitConvToAddMin(BinExp e, Type t) { /* Is this (ptr +- offset)? If so, then ask ptr * if the conversion can be done. * This is to support doing things like implicitly converting a mutable unique * pointer to an immutable pointer. */ Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (typeb.ty != Tpointer || tb.ty != Tpointer) return MATCH.nomatch; Type t1b = e.e1.type.toBasetype(); Type t2b = e.e2.type.toBasetype(); if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb)) { // ptr + offset // ptr - offset MATCH m = e.e1.implicitConvTo(t); return (m > MATCH.constant) ? MATCH.constant : m; } if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb)) { // offset + ptr MATCH m = e.e2.implicitConvTo(t); return (m > MATCH.constant) ? MATCH.constant : m; } return MATCH.nomatch; } override void visit(AddExp e) { version (none) { printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } visit(cast(Expression)e); if (result == MATCH.nomatch) result = implicitConvToAddMin(e, t); } override void visit(MinExp e) { version (none) { printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } visit(cast(Expression)e); if (result == MATCH.nomatch) result = implicitConvToAddMin(e, t); } override void visit(IntegerExp e) { version (none) { printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } MATCH m = e.type.implicitConvTo(t); if (m >= MATCH.constant) { result = m; return; } TY ty = e.type.toBasetype().ty; TY toty = t.toBasetype().ty; TY oldty = ty; if (m == MATCH.nomatch && t.ty == Tenum) return; if (t.ty == Tvector) { TypeVector tv = cast(TypeVector)t; TypeBasic tb = tv.elementType(); if (tb.ty == Tvoid) return; toty = tb.ty; } switch (ty) { case Tbool: case Tint8: case Tchar: case Tuns8: case Tint16: case Tuns16: case Twchar: ty = Tint32; break; case Tdchar: ty = Tuns32; break; default: break; } // Only allow conversion if no change in value immutable dinteger_t value = e.toInteger(); bool isLosslesslyConvertibleToFP(T)() { if (e.type.isunsigned()) { const f = cast(T) value; return cast(dinteger_t) f == value; } const f = cast(T) cast(sinteger_t) value; return cast(sinteger_t) f == cast(sinteger_t) value; } switch (toty) { case Tbool: if ((value & 1) != value) return; break; case Tint8: if (ty == Tuns64 && value & ~0x7FU) return; else if (cast(byte)value != value) return; break; case Tchar: if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) return; goto case Tuns8; case Tuns8: //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); if (cast(ubyte)value != value) return; break; case Tint16: if (ty == Tuns64 && value & ~0x7FFFU) return; else if (cast(short)value != value) return; break; case Twchar: if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) return; goto case Tuns16; case Tuns16: if (cast(ushort)value != value) return; break; case Tint32: if (ty == Tuns32) { } else if (ty == Tuns64 && value & ~0x7FFFFFFFU) return; else if (cast(int)value != value) return; break; case Tuns32: if (ty == Tint32) { } else if (cast(uint)value != value) return; break; case Tdchar: if (value > 0x10FFFFU) return; break; case Tfloat32: if (!isLosslesslyConvertibleToFP!float) return; break; case Tfloat64: if (!isLosslesslyConvertibleToFP!double) return; break; case Tfloat80: if (!isLosslesslyConvertibleToFP!real_t) return; break; case Tpointer: //printf("type = %s\n", type.toBasetype()->toChars()); //printf("t = %s\n", t.toBasetype()->toChars()); if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty) { /* Allow things like: * const char* P = cast(char *)3; * char* q = P; */ break; } goto default; default: visit(cast(Expression)e); return; } //printf("MATCH.convert\n"); result = MATCH.convert; } override void visit(ErrorExp e) { // no match } override void visit(NullExp e) { version (none) { printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", e.toChars(), e.type.toChars(), t.toChars(), e.committed); } if (e.type.equals(t)) { result = MATCH.exact; return; } /* Allow implicit conversions from immutable to mutable|const, * and mutable to immutable. It works because, after all, a null * doesn't actually point to anything. */ if (t.equivalent(e.type)) { result = MATCH.constant; return; } visit(cast(Expression)e); } override void visit(StructLiteralExp e) { version (none) { printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } visit(cast(Expression)e); if (result != MATCH.nomatch) return; if (e.type.ty == t.ty && e.type.ty == Tstruct && (cast(TypeStruct)e.type).sym == (cast(TypeStruct)t).sym) { result = MATCH.constant; for (size_t i = 0; i < e.elements.dim; i++) { Expression el = (*e.elements)[i]; if (!el) continue; Type te = e.sd.fields[i].type.addMod(t.mod); MATCH m2 = el.implicitConvTo(te); //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2); if (m2 < result) result = m2; } } } override void visit(StringExp e) { version (none) { printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars()); } if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) return; if (e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer) { TY tyn = e.type.nextOf().ty; if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) { switch (t.ty) { case Tsarray: if (e.type.ty == Tsarray) { TY tynto = t.nextOf().ty; if (tynto == tyn) { if ((cast(TypeSArray)e.type).dim.toInteger() == (cast(TypeSArray)t).dim.toInteger()) { result = MATCH.exact; } return; } if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) { if (e.committed && tynto != tyn) return; size_t fromlen = e.numberOfCodeUnits(tynto); size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); if (tolen < fromlen) return; if (tolen != fromlen) { // implicit length extending result = MATCH.convert; return; } } if (!e.committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) { result = MATCH.exact; return; } } else if (e.type.ty == Tarray) { TY tynto = t.nextOf().ty; if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) { if (e.committed && tynto != tyn) return; size_t fromlen = e.numberOfCodeUnits(tynto); size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); if (tolen < fromlen) return; if (tolen != fromlen) { // implicit length extending result = MATCH.convert; return; } } if (tynto == tyn) { result = MATCH.exact; return; } if (!e.committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) { result = MATCH.exact; return; } } goto case; /+ fall through +/ case Tarray: case Tpointer: Type tn = t.nextOf(); MATCH m = MATCH.exact; if (e.type.nextOf().mod != tn.mod) { // https://issues.dlang.org/show_bug.cgi?id=16183 if (!tn.isConst() && !tn.isImmutable()) return; m = MATCH.constant; } if (!e.committed) { switch (tn.ty) { case Tchar: if (e.postfix == 'w' || e.postfix == 'd') m = MATCH.convert; result = m; return; case Twchar: if (e.postfix != 'w') m = MATCH.convert; result = m; return; case Tdchar: if (e.postfix != 'd') m = MATCH.convert; result = m; return; default: break; } } break; default: break; } } } visit(cast(Expression)e); } override void visit(ArrayLiteralExp e) { version (none) { printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if ((tb.ty == Tarray || tb.ty == Tsarray) && (typeb.ty == Tarray || typeb.ty == Tsarray)) { result = MATCH.exact; Type typen = typeb.nextOf().toBasetype(); if (tb.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tb; if (e.elements.dim != tsa.dim.toInteger()) result = MATCH.nomatch; } Type telement = tb.nextOf(); if (!e.elements.dim) { if (typen.ty != Tvoid) result = typen.implicitConvTo(telement); } else { if (e.basis) { MATCH m = e.basis.implicitConvTo(telement); if (m < result) result = m; } for (size_t i = 0; i < e.elements.dim; i++) { Expression el = (*e.elements)[i]; if (result == MATCH.nomatch) break; if (!el) continue; MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match } } if (!result) result = e.type.implicitConvTo(t); return; } else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) { result = MATCH.exact; // Convert array literal to vector type TypeVector tv = cast(TypeVector)tb; TypeSArray tbase = cast(TypeSArray)tv.basetype; assert(tbase.ty == Tsarray); const edim = e.elements.dim; const tbasedim = tbase.dim.toInteger(); if (edim > tbasedim) { result = MATCH.nomatch; return; } Type telement = tv.elementType(); if (edim < tbasedim) { Expression el = typeb.nextOf.defaultInitLiteral(e.loc); MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match } foreach (i; 0 .. edim) { Expression el = (*e.elements)[i]; MATCH m = el.implicitConvTo(telement); if (m < result) result = m; // remember worst match if (result == MATCH.nomatch) break; // no need to check for worse } return; } visit(cast(Expression)e); } override void visit(AssocArrayLiteralExp e) { Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.ty == Taarray && typeb.ty == Taarray) { result = MATCH.exact; for (size_t i = 0; i < e.keys.dim; i++) { Expression el = (*e.keys)[i]; MATCH m = el.implicitConvTo((cast(TypeAArray)tb).index); if (m < result) result = m; // remember worst match if (result == MATCH.nomatch) break; // no need to check for worse el = (*e.values)[i]; m = el.implicitConvTo(tb.nextOf()); if (m < result) result = m; // remember worst match if (result == MATCH.nomatch) break; // no need to check for worse } return; } else visit(cast(Expression)e); } override void visit(CallExp e) { enum LOG = false; static if (LOG) { printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } visit(cast(Expression)e); if (result != MATCH.nomatch) return; /* Allow the result of strongly pure functions to * convert to immutable */ if (e.f && e.f.isReturnIsolated() && (!global.params.vsafe || // lots of legacy code breaks with the following purity check e.f.isPure() >= PURE.strong || // Special case exemption for Object.dup() which we assume is implemented correctly e.f.ident == Id.dup && e.f.toParent2() == ClassDeclaration.object.toParent()) ) { result = e.type.immutableOf().implicitConvTo(t); if (result > MATCH.constant) // Match level is MATCH.constant at best. result = MATCH.constant; return; } /* Conversion is 'const' conversion if: * 1. function is pure (weakly pure is ok) * 2. implicit conversion only fails because of mod bits * 3. each function parameter can be implicitly converted to the mod bits */ Type tx = e.f ? e.f.type : e.e1.type; tx = tx.toBasetype(); if (tx.ty != Tfunction) return; TypeFunction tf = cast(TypeFunction)tx; if (tf.purity == PURE.impure) return; if (e.f && e.f.isNested()) return; /* See if fail only because of mod bits. * * https://issues.dlang.org/show_bug.cgi?id=14155 * All pure functions can access global immutable data. * So the returned pointer may refer an immutable global data, * and then the returned pointer that points non-mutable object * cannot be unique pointer. * * Example: * immutable g; * static this() { g = 1; } * const(int*) foo() pure { return &g; } * void test() { * immutable(int*) ip = foo(); // OK * int* mp = foo(); // should be disallowed * } */ if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) { return; } // Allow a conversion to immutable type, or // conversions of mutable types between thread-local and shared. /* Get mod bits of what we're converting to */ Type tb = t.toBasetype(); MOD mod = tb.mod; if (tf.isref) { } else { Type ti = getIndirection(t); if (ti) mod = ti.mod; } static if (LOG) { printf("mod = x%x\n", mod); } if (mod & MODFlags.wild) return; // not sure what to do with this /* Apply mod bits to each function parameter, * and see if we can convert the function argument to the modded type */ size_t nparams = Parameter.dim(tf.parameters); size_t j = (tf.linkage == LINK.d && tf.varargs == 1); // if TypeInfoArray was prepended if (e.e1.op == TOK.dotVariable) { /* Treat 'this' as just another function argument */ DotVarExp dve = cast(DotVarExp)e.e1; Type targ = dve.e1.type; if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) return; } for (size_t i = j; i < e.arguments.dim; ++i) { Expression earg = (*e.arguments)[i]; Type targ = earg.type.toBasetype(); static if (LOG) { printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); } if (i - j < nparams) { Parameter fparam = Parameter.getNth(tf.parameters, i - j); if (fparam.storageClass & STC.lazy_) return; // not sure what to do with this Type tparam = fparam.type; if (!tparam) continue; if (fparam.storageClass & (STC.out_ | STC.ref_)) { if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) return; continue; } } static if (LOG) { printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); } if (implicitMod(earg, targ, mod) == MATCH.nomatch) return; } /* Success */ result = MATCH.constant; } override void visit(AddrExp e) { version (none) { printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } result = e.type.implicitConvTo(t); //printf("\tresult = %d\n", result); if (result != MATCH.nomatch) return; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); // Look for pointers to functions where the functions are overloaded. if (e.e1.op == TOK.overloadSet && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { OverExp eo = cast(OverExp)e.e1; FuncDeclaration f = null; for (size_t i = 0; i < eo.vars.a.dim; i++) { Dsymbol s = eo.vars.a[i]; FuncDeclaration f2 = s.isFuncDeclaration(); assert(f2); if (f2.overloadExactMatch(tb.nextOf())) { if (f) { /* Error if match in more than one overload set, * even if one is a 'better' match than the other. */ ScopeDsymbol.multiplyDefined(e.loc, f, f2); } else f = f2; result = MATCH.exact; } } } if (e.e1.op == TOK.variable && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && tb.ty == Tpointer && tb.nextOf().ty == Tfunction) { /* I don't think this can ever happen - * it should have been * converted to a SymOffExp. */ assert(0); } //printf("\tresult = %d\n", result); } override void visit(SymOffExp e) { version (none) { printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } result = e.type.implicitConvTo(t); //printf("\tresult = %d\n", result); if (result != MATCH.nomatch) return; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); // Look for pointers to functions where the functions are overloaded. if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { if (FuncDeclaration f = e.var.isFuncDeclaration()) { f = f.overloadExactMatch(tb.nextOf()); if (f) { if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) || (tb.ty == Tpointer && !(f.needThis() || f.isNested()))) { result = MATCH.exact; } } } } //printf("\tresult = %d\n", result); } override void visit(DelegateExp e) { version (none) { printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } result = e.type.implicitConvTo(t); if (result != MATCH.nomatch) return; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); // Look for pointers to functions where the functions are overloaded. if (typeb.ty == Tdelegate && tb.ty == Tdelegate) { if (e.func && e.func.overloadExactMatch(tb.nextOf())) result = MATCH.exact; } } override void visit(FuncExp e) { //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars()); MATCH m = e.matchType(t, null, null, 1); if (m > MATCH.nomatch) { result = m; return; } visit(cast(Expression)e); } override void visit(OrExp e) { visit(cast(Expression)e); if (result != MATCH.nomatch) return; MATCH m1 = e.e1.implicitConvTo(t); MATCH m2 = e.e2.implicitConvTo(t); // Pick the worst match result = (m1 < m2) ? m1 : m2; } override void visit(XorExp e) { visit(cast(Expression)e); if (result != MATCH.nomatch) return; MATCH m1 = e.e1.implicitConvTo(t); MATCH m2 = e.e2.implicitConvTo(t); // Pick the worst match result = (m1 < m2) ? m1 : m2; } override void visit(CondExp e) { MATCH m1 = e.e1.implicitConvTo(t); MATCH m2 = e.e2.implicitConvTo(t); //printf("CondExp: m1 %d m2 %d\n", m1, m2); // Pick the worst match result = (m1 < m2) ? m1 : m2; } override void visit(CommaExp e) { e.e2.accept(this); } override void visit(CastExp e) { version (none) { printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } result = e.type.implicitConvTo(t); if (result != MATCH.nomatch) return; if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch) result = MATCH.convert; else visit(cast(Expression)e); } override void visit(NewExp e) { version (none) { printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } visit(cast(Expression)e); if (result != MATCH.nomatch) return; /* Calling new() is like calling a pure function. We can implicitly convert the * return from new() to t using the same algorithm as in CallExp, with the function * 'arguments' being: * thisexp * newargs * arguments * .init * 'member' and 'allocator' need to be pure. */ /* See if fail only because of mod bits */ if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch) return; /* Get mod bits of what we're converting to */ Type tb = t.toBasetype(); MOD mod = tb.mod; if (Type ti = getIndirection(t)) mod = ti.mod; static if (LOG) { printf("mod = x%x\n", mod); } if (mod & MODFlags.wild) return; // not sure what to do with this /* Apply mod bits to each argument, * and see if we can convert the argument to the modded type */ if (e.thisexp) { /* Treat 'this' as just another function argument */ Type targ = e.thisexp.type; if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) return; } /* Check call to 'allocator', then 'member' */ FuncDeclaration fd = e.allocator; for (int count = 0; count < 2; ++count, (fd = e.member)) { if (!fd) continue; if (fd.errors || fd.type.ty != Tfunction) return; // error TypeFunction tf = cast(TypeFunction)fd.type; if (tf.purity == PURE.impure) return; // impure if (fd == e.member) { if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) { return; } // Allow a conversion to immutable type, or // conversions of mutable types between thread-local and shared. } Expressions* args = (fd == e.allocator) ? e.newargs : e.arguments; size_t nparams = Parameter.dim(tf.parameters); size_t j = (tf.linkage == LINK.d && tf.varargs == 1); // if TypeInfoArray was prepended for (size_t i = j; i < e.arguments.dim; ++i) { Expression earg = (*args)[i]; Type targ = earg.type.toBasetype(); static if (LOG) { printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); } if (i - j < nparams) { Parameter fparam = Parameter.getNth(tf.parameters, i - j); if (fparam.storageClass & STC.lazy_) return; // not sure what to do with this Type tparam = fparam.type; if (!tparam) continue; if (fparam.storageClass & (STC.out_ | STC.ref_)) { if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) return; continue; } } static if (LOG) { printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); } if (implicitMod(earg, targ, mod) == MATCH.nomatch) return; } } /* If no 'member', then construction is by simple assignment, * and just straight check 'arguments' */ if (!e.member && e.arguments) { for (size_t i = 0; i < e.arguments.dim; ++i) { Expression earg = (*e.arguments)[i]; if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853 // if it's on overlapped field continue; Type targ = earg.type.toBasetype(); static if (LOG) { printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); } if (implicitMod(earg, targ, mod) == MATCH.nomatch) return; } } /* Consider the .init expression as an argument */ Type ntb = e.newtype.toBasetype(); if (ntb.ty == Tarray) ntb = ntb.nextOf().toBasetype(); if (ntb.ty == Tstruct) { // Don't allow nested structs - uplevel reference may not be convertible StructDeclaration sd = (cast(TypeStruct)ntb).sym; sd.size(e.loc); // resolve any forward references if (sd.isNested()) return; } if (ntb.isZeroInit(e.loc)) { /* Zeros are implicitly convertible, except for special cases. */ if (ntb.ty == Tclass) { /* With new() must look at the class instance initializer. */ ClassDeclaration cd = (cast(TypeClass)ntb).sym; cd.size(e.loc); // resolve any forward references if (cd.isNested()) return; // uplevel reference may not be convertible assert(!cd.isInterfaceDeclaration()); struct ClassCheck { extern (C++) static bool convertible(Loc loc, ClassDeclaration cd, MOD mod) { for (size_t i = 0; i < cd.fields.dim; i++) { VarDeclaration v = cd.fields[i]; Initializer _init = v._init; if (_init) { if (_init.isVoidInitializer()) { } else if (ExpInitializer ei = _init.isExpInitializer()) { Type tb = v.type.toBasetype(); if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch) return false; } else { /* Enhancement: handle StructInitializer and ArrayInitializer */ return false; } } else if (!v.type.isZeroInit(loc)) return false; } return cd.baseClass ? convertible(loc, cd.baseClass, mod) : true; } } if (!ClassCheck.convertible(e.loc, cd, mod)) return; } } else { Expression earg = e.newtype.defaultInitLiteral(e.loc); Type targ = e.newtype.toBasetype(); if (implicitMod(earg, targ, mod) == MATCH.nomatch) return; } /* Success */ result = MATCH.constant; } override void visit(SliceExp e) { //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars()); visit(cast(Expression)e); if (result != MATCH.nomatch) return; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.ty == Tsarray && typeb.ty == Tarray) { typeb = toStaticArrayType(e); if (typeb) result = typeb.implicitConvTo(t); return; } /* If the only reason it won't convert is because of the mod bits, * then test for conversion by seeing if e1 can be converted with those * same mod bits. */ Type t1b = e.e1.type.toBasetype(); if (tb.ty == Tarray && typeb.equivalent(tb)) { Type tbn = tb.nextOf(); Type tx = null; /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1 * is equivalent with the uniqueness of the referred data. And in here * we can have arbitrary typed reference for that. */ if (t1b.ty == Tarray) tx = tbn.arrayOf(); if (t1b.ty == Tpointer) tx = tbn.pointerTo(); /* If e.e1 is static array, at least it should be an rvalue. * If not, e.e1 is a reference, and its uniqueness does not link * to the uniqueness of the referred data. */ if (t1b.ty == Tsarray && !e.e1.isLvalue()) tx = tbn.sarrayOf(t1b.size() / tbn.size()); if (tx) { result = e.e1.implicitConvTo(tx); if (result > MATCH.constant) // Match level is MATCH.constant at best. result = MATCH.constant; } } // Enhancement 10724 if (tb.ty == Tpointer && e.e1.op == TOK.string_) e.e1.accept(this); } } scope ImplicitConvTo v = new ImplicitConvTo(t); e.accept(v); return v.result; } Type toStaticArrayType(SliceExp e) { if (e.lwr && e.upr) { // For the following code to work, e should be optimized beforehand. // (eg. $ in lwr and upr should be already resolved, if possible) Expression lwr = e.lwr.optimize(WANTvalue); Expression upr = e.upr.optimize(WANTvalue); if (lwr.isConst() && upr.isConst()) { size_t len = cast(size_t)(upr.toUInteger() - lwr.toUInteger()); return e.type.toBasetype().nextOf().sarrayOf(len); } } else { Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tsarray) return t1b; } return null; } /************************************** * Do an explicit cast. * Assume that the 'this' expression does not have any indirections. */ Expression castTo(Expression e, Scope* sc, Type t) { extern (C++) final class CastTo : Visitor { alias visit = Visitor.visit; public: Type t; Scope* sc; Expression result; extern (D) this(Scope* sc, Type t) { this.sc = sc; this.t = t; } override void visit(Expression e) { //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); version (none) { printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } if (e.type.equals(t)) { result = e; return; } if (e.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && v.storage_class & STC.manifest) { result = e.ctfeInterpret(); /* https://issues.dlang.org/show_bug.cgi?id=18236 * * The expression returned by ctfeInterpret points * to the line where the manifest constant was declared * so we need to update the location before trying to cast */ result.loc = e.loc; result = result.castTo(sc, t); return; } } Type tob = t.toBasetype(); Type t1b = e.type.toBasetype(); if (tob.equals(t1b)) { result = e.copy(); // because of COW for assignment to e.type result.type = t; return; } /* Make semantic error against invalid cast between concrete types. * Assume that 'e' is never be any placeholder expressions. * The result of these checks should be consistent with CastExp::toElem(). */ // Fat Value types const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector); const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector); // Fat Reference types const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate); const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate); // Reference types const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass); const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass); // Arithmetic types (== valueable basic types) const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector); const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector); if (AggregateDeclaration t1ad = isAggregate(t1b)) { AggregateDeclaration toad = isAggregate(tob); if (t1ad != toad && t1ad.aliasthis) { if (t1b.ty == Tclass && tob.ty == Tclass) { ClassDeclaration t1cd = t1b.isClassHandle(); ClassDeclaration tocd = tob.isClassHandle(); int offset; if (tocd.isBaseOf(t1cd, &offset)) goto Lok; } /* Forward the cast to our alias this member, rewrite to: * cast(to)e1.aliasthis */ result = resolveAliasThis(sc, e); result = result.castTo(sc, t); return; } } else if (tob.ty == Tvector && t1b.ty != Tvector) { //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); TypeVector tv = cast(TypeVector)tob; result = new CastExp(e.loc, e, tv.elementType()); result = new VectorExp(e.loc, result, tob); result = result.expressionSemantic(sc); return; } else if (tob.ty != Tvector && t1b.ty == Tvector) { // T[n] <-- __vector(U[m]) if (tob.ty == Tsarray) { if (t1b.size(e.loc) == tob.size(e.loc)) goto Lok; } goto Lfail; } else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf())) { result = e.copy(); result.type = t; return; } // arithmetic values vs. other arithmetic values // arithmetic values vs. T* if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer)) { goto Lok; } // arithmetic values vs. references or fat values if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV)) { goto Lfail; } // Bugzlla 3133: A cast between fat values is possible only when the sizes match. if (tob_isFV && t1b_isFV) { if (t1b.size(e.loc) == tob.size(e.loc)) goto Lok; auto ts = toAutoQualChars(e.type, t); e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes", e.toChars(), ts[0], ts[1]); result = new ErrorExp(); return; } // Fat values vs. null or references if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR)) { if (tob.ty == Tpointer && t1b.ty == Tsarray) { // T[n] sa; // cast(U*)sa; // ==> cast(U*)sa.ptr; result = new AddrExp(e.loc, e, t); return; } if (tob.ty == Tarray && t1b.ty == Tsarray) { // T[n] sa; // cast(U[])sa; // ==> cast(U[])sa[]; d_uns64 fsize = t1b.nextOf().size(); d_uns64 tsize = tob.nextOf().size(); if (((cast(TypeSArray)t1b).dim.toInteger() * fsize) % tsize != 0) { // copied from sarray_toDarray() in e2ir.c e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", e.toChars(), e.type.toChars(), t.toChars()); result = new ErrorExp(); return; } goto Lok; } goto Lfail; } /* For references, any reinterpret casts are allowed to same 'ty' type. * T* to U* * R1 function(P1) to R2 function(P2) * R1 delegate(P1) to R2 delegate(P2) * T[] to U[] * V1[K1] to V2[K2] * class/interface A to B (will be a dynamic cast if possible) */ if (tob.ty == t1b.ty && tob_isR && t1b_isR) goto Lok; // typeof(null) <-- non-null references or values if (tob.ty == Tnull && t1b.ty != Tnull) goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629 // typeof(null) --> non-null references or arithmetic values if (t1b.ty == Tnull && tob.ty != Tnull) goto Lok; // Check size mismatch of references. // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof. if (tob_isFR && t1b_isR || t1b_isFR && tob_isR) { if (tob.ty == Tpointer && t1b.ty == Tarray) { // T[] da; // cast(U*)da; // ==> cast(U*)da.ptr; goto Lok; } if (tob.ty == Tpointer && t1b.ty == Tdelegate) { // void delegate() dg; // cast(U*)dg; // ==> cast(U*)dg.ptr; // Note that it happens even when U is a Tfunction! e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars()); goto Lok; } goto Lfail; } if (t1b.ty == Tvoid && tob.ty != Tvoid) { Lfail: e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars()); result = new ErrorExp(); return; } Lok: result = new CastExp(e.loc, e, t); result.type = t; // Don't call semantic() //printf("Returning: %s\n", result.toChars()); } override void visit(ErrorExp e) { result = e; } override void visit(RealExp e) { if (!e.type.equals(t)) { if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary())) { result = e.copy(); result.type = t; } else visit(cast(Expression)e); return; } result = e; } override void visit(ComplexExp e) { if (!e.type.equals(t)) { if (e.type.iscomplex() && t.iscomplex()) { result = e.copy(); result.type = t; } else visit(cast(Expression)e); return; } result = e; } override void visit(NullExp e) { //printf("NullExp::castTo(t = %s) %s\n", t.toChars(), toChars()); visit(cast(Expression)e); if (result.op == TOK.null_) { NullExp ex = cast(NullExp)result; ex.committed = 1; return; } } override void visit(StructLiteralExp e) { visit(cast(Expression)e); if (result.op == TOK.structLiteral) (cast(StructLiteralExp)result).stype = t; // commit type } override void visit(StringExp e) { /* This follows copy-on-write; any changes to 'this' * will result in a copy. * The this.string member is considered immutable. */ int copied = 0; //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed); if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) { e.error("cannot convert string literal to `void*`"); result = new ErrorExp(); return; } StringExp se = e; if (!e.committed) { se = cast(StringExp)e.copy(); se.committed = 1; copied = 1; } if (e.type.equals(t)) { result = se; return; } Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); //printf("\ttype = %s\n", e.type.toChars()); if (tb.ty == Tdelegate && typeb.ty != Tdelegate) { visit(cast(Expression)e); return; } if (typeb.equals(tb)) { if (!copied) { se = cast(StringExp)e.copy(); copied = 1; } se.type = t; result = se; return; } /* Handle reinterpret casts: * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000] * cast(wchar[2])"abcd"c --> [\u6261, \u6463] * cast(wchar[1])"abcd"c --> [\u6261] */ if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray) { se = cast(StringExp)e.copy(); d_uns64 szx = tb.nextOf().size(); assert(szx <= 255); se.sz = cast(ubyte)szx; se.len = cast(size_t)(cast(TypeSArray)tb).dim.toInteger(); se.committed = 1; se.type = t; /* Assure space for terminating 0 */ if ((se.len + 1) * se.sz > (e.len + 1) * e.sz) { void* s = mem.xmalloc((se.len + 1) * se.sz); memcpy(s, se.string, se.len * se.sz); memset(s + se.len * se.sz, 0, se.sz); se.string = cast(char*)s; } result = se; return; } if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer) { if (!copied) { se = cast(StringExp)e.copy(); copied = 1; } goto Lcast; } if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) { if (!copied) { se = cast(StringExp)e.copy(); copied = 1; } goto Lcast; } if (typeb.nextOf().size() == tb.nextOf().size()) { if (!copied) { se = cast(StringExp)e.copy(); copied = 1; } if (tb.ty == Tsarray) goto L2; // handle possible change in static array dimension se.type = t; result = se; return; } if (e.committed) goto Lcast; auto X(T, U)(T tf, U tt) { return (cast(int)tf * 256 + cast(int)tt); } { OutBuffer buffer; size_t newlen = 0; int tfty = typeb.nextOf().toBasetype().ty; int ttty = tb.nextOf().toBasetype().ty; switch (X(tfty, ttty)) { case X(Tchar, Tchar): case X(Twchar, Twchar): case X(Tdchar, Tdchar): break; case X(Tchar, Twchar): for (size_t u = 0; u < e.len;) { dchar c; const p = utf_decodeChar(se.string, e.len, u, c); if (p) e.error("%s", p); else buffer.writeUTF16(c); } newlen = buffer.offset / 2; buffer.writeUTF16(0); goto L1; case X(Tchar, Tdchar): for (size_t u = 0; u < e.len;) { dchar c; const p = utf_decodeChar(se.string, e.len, u, c); if (p) e.error("%s", p); buffer.write4(c); newlen++; } buffer.write4(0); goto L1; case X(Twchar, Tchar): for (size_t u = 0; u < e.len;) { dchar c; const p = utf_decodeWchar(se.wstring, e.len, u, c); if (p) e.error("%s", p); else buffer.writeUTF8(c); } newlen = buffer.offset; buffer.writeUTF8(0); goto L1; case X(Twchar, Tdchar): for (size_t u = 0; u < e.len;) { dchar c; const p = utf_decodeWchar(se.wstring, e.len, u, c); if (p) e.error("%s", p); buffer.write4(c); newlen++; } buffer.write4(0); goto L1; case X(Tdchar, Tchar): for (size_t u = 0; u < e.len; u++) { uint c = se.dstring[u]; if (!utf_isValidDchar(c)) e.error("invalid UCS-32 char \\U%08x", c); else buffer.writeUTF8(c); newlen++; } newlen = buffer.offset; buffer.writeUTF8(0); goto L1; case X(Tdchar, Twchar): for (size_t u = 0; u < e.len; u++) { uint c = se.dstring[u]; if (!utf_isValidDchar(c)) e.error("invalid UCS-32 char \\U%08x", c); else buffer.writeUTF16(c); newlen++; } newlen = buffer.offset / 2; buffer.writeUTF16(0); goto L1; L1: if (!copied) { se = cast(StringExp)e.copy(); copied = 1; } se.string = buffer.extractData(); se.len = newlen; { d_uns64 szx = tb.nextOf().size(); assert(szx <= 255); se.sz = cast(ubyte)szx; } break; default: assert(typeb.nextOf().size() != tb.nextOf().size()); goto Lcast; } } L2: assert(copied); // See if need to truncate or extend the literal if (tb.ty == Tsarray) { size_t dim2 = cast(size_t)(cast(TypeSArray)tb).dim.toInteger(); //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2); // Changing dimensions if (dim2 != se.len) { // Copy when changing the string literal size_t newsz = se.sz; size_t d = (dim2 < se.len) ? dim2 : se.len; void* s = mem.xmalloc((dim2 + 1) * newsz); memcpy(s, se.string, d * newsz); // Extend with 0, add terminating 0 memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz); se.string = cast(char*)s; se.len = dim2; } } se.type = t; result = se; return; Lcast: result = new CastExp(e.loc, se, t); result.type = t; // so semantic() won't be run on e } override void visit(AddrExp e) { version (none) { printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } result = e; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.equals(typeb)) { result = e.copy(); result.type = t; return; } // Look for pointers to functions where the functions are overloaded. if (e.e1.op == TOK.overloadSet && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { OverExp eo = cast(OverExp)e.e1; FuncDeclaration f = null; for (size_t i = 0; i < eo.vars.a.dim; i++) { auto s = eo.vars.a[i]; auto f2 = s.isFuncDeclaration(); assert(f2); if (f2.overloadExactMatch(tb.nextOf())) { if (f) { /* Error if match in more than one overload set, * even if one is a 'better' match than the other. */ ScopeDsymbol.multiplyDefined(e.loc, f, f2); } else f = f2; } } if (f) { f.tookAddressOf++; auto se = new SymOffExp(e.loc, f, 0, false); se.expressionSemantic(sc); // Let SymOffExp::castTo() do the heavy lifting visit(se); return; } } if (e.e1.op == TOK.variable && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && tb.ty == Tpointer && tb.nextOf().ty == Tfunction) { auto ve = cast(VarExp)e.e1; auto f = ve.var.isFuncDeclaration(); if (f) { assert(f.isImportedSymbol()); f = f.overloadExactMatch(tb.nextOf()); if (f) { result = new VarExp(e.loc, f, false); result.type = f.type; result = new AddrExp(e.loc, result, t); return; } } } if (auto f = isFuncAddress(e)) { if (f.checkForwardRef(e.loc)) { result = new ErrorExp(); return; } } visit(cast(Expression)e); } override void visit(TupleExp e) { if (e.type.equals(t)) { result = e; return; } TupleExp te = cast(TupleExp)e.copy(); te.e0 = e.e0 ? e.e0.copy() : null; te.exps = e.exps.copy(); for (size_t i = 0; i < te.exps.dim; i++) { Expression ex = (*te.exps)[i]; ex = ex.castTo(sc, t); (*te.exps)[i] = ex; } result = te; /* Questionable behavior: In here, result.type is not set to t. * Therefoe: * TypeTuple!(int, int) values; * auto values2 = cast(long)values; * // typeof(values2) == TypeTuple!(int, int) !! * * Only when the casted tuple is immediately expanded, it would work. * auto arr = [cast(long)values]; * // typeof(arr) == long[] */ } override void visit(ArrayLiteralExp e) { version (none) { printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); } ArrayLiteralExp ae = e; Type tb = t.toBasetype(); if (tb.ty == Tarray && global.params.vsafe) { if (checkArrayLiteralEscape(sc, ae, false)) { result = new ErrorExp(); return; } } if (e.type == t) { result = e; return; } Type typeb = e.type.toBasetype(); if ((tb.ty == Tarray || tb.ty == Tsarray) && (typeb.ty == Tarray || typeb.ty == Tsarray)) { if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) { // Don't do anything to cast non-void[] to void[] } else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid) { // Don't do anything for casting void[n] to others } else { if (tb.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tb; if (e.elements.dim != tsa.dim.toInteger()) goto L1; } ae = cast(ArrayLiteralExp)e.copy(); if (e.basis) ae.basis = e.basis.castTo(sc, tb.nextOf()); ae.elements = e.elements.copy(); for (size_t i = 0; i < e.elements.dim; i++) { Expression ex = (*e.elements)[i]; if (!ex) continue; ex = ex.castTo(sc, tb.nextOf()); (*ae.elements)[i] = ex; } ae.type = t; result = ae; return; } } else if (tb.ty == Tpointer && typeb.ty == Tsarray) { Type tp = typeb.nextOf().pointerTo(); if (!tp.equals(ae.type)) { ae = cast(ArrayLiteralExp)e.copy(); ae.type = tp; } } else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) { // Convert array literal to vector type TypeVector tv = cast(TypeVector)tb; TypeSArray tbase = cast(TypeSArray)tv.basetype; assert(tbase.ty == Tsarray); const edim = e.elements.dim; const tbasedim = tbase.dim.toInteger(); if (edim > tbasedim) goto L1; ae = cast(ArrayLiteralExp)e.copy(); ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642 ae.elements = e.elements.copy(); Type telement = tv.elementType(); foreach (i; 0 .. edim) { Expression ex = (*e.elements)[i]; ex = ex.castTo(sc, telement); (*ae.elements)[i] = ex; } // Fill in the rest with the default initializer ae.elements.setDim(cast(size_t)tbasedim); foreach (i; edim .. cast(size_t)tbasedim) { Expression ex = typeb.nextOf.defaultInitLiteral(e.loc); ex = ex.castTo(sc, telement); (*ae.elements)[i] = ex; } Expression ev = new VectorExp(e.loc, ae, tb); ev = ev.expressionSemantic(sc); result = ev; return; } L1: visit(cast(Expression)ae); } override void visit(AssocArrayLiteralExp e) { //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars()); if (e.type == t) { result = e; return; } Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.ty == Taarray && typeb.ty == Taarray && tb.nextOf().toBasetype().ty != Tvoid) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e.copy(); ae.keys = e.keys.copy(); ae.values = e.values.copy(); assert(e.keys.dim == e.values.dim); for (size_t i = 0; i < e.keys.dim; i++) { Expression ex = (*e.values)[i]; ex = ex.castTo(sc, tb.nextOf()); (*ae.values)[i] = ex; ex = (*e.keys)[i]; ex = ex.castTo(sc, (cast(TypeAArray)tb).index); (*ae.keys)[i] = ex; } ae.type = t; result = ae; return; } visit(cast(Expression)e); } override void visit(SymOffExp e) { version (none) { printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } if (e.type == t && !e.hasOverloads) { result = e; return; } Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.equals(typeb)) { result = e.copy(); result.type = t; (cast(SymOffExp)result).hasOverloads = false; return; } // Look for pointers to functions where the functions are overloaded. if (e.hasOverloads && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { FuncDeclaration f = e.var.isFuncDeclaration(); f = f ? f.overloadExactMatch(tb.nextOf()) : null; if (f) { if (tb.ty == Tdelegate) { if (f.needThis() && hasThis(sc)) { result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false); result = result.expressionSemantic(sc); } else if (f.isNested()) { result = new DelegateExp(e.loc, new IntegerExp(0), f, false); result = result.expressionSemantic(sc); } else if (f.needThis()) { e.error("no `this` to create delegate for `%s`", f.toChars()); result = new ErrorExp(); return; } else { e.error("cannot cast from function pointer to delegate"); result = new ErrorExp(); return; } } else { result = new SymOffExp(e.loc, f, 0, false); result.type = t; } f.tookAddressOf++; return; } } if (auto f = isFuncAddress(e)) { if (f.checkForwardRef(e.loc)) { result = new ErrorExp(); return; } } visit(cast(Expression)e); } override void visit(DelegateExp e) { version (none) { printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } __gshared const(char)* msg = "cannot form delegate due to covariant return type"; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (tb.equals(typeb) && !e.hasOverloads) { int offset; e.func.tookAddressOf++; if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) e.error("%s", msg); result = e.copy(); result.type = t; return; } // Look for delegates to functions where the functions are overloaded. if (typeb.ty == Tdelegate && tb.ty == Tdelegate) { if (e.func) { auto f = e.func.overloadExactMatch(tb.nextOf()); if (f) { int offset; if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) e.error("%s", msg); if (f != e.func) // if address not already marked as taken f.tookAddressOf++; result = new DelegateExp(e.loc, e.e1, f, false); result.type = t; return; } if (e.func.tintro) e.error("%s", msg); } } if (auto f = isFuncAddress(e)) { if (f.checkForwardRef(e.loc)) { result = new ErrorExp(); return; } } visit(cast(Expression)e); } override void visit(FuncExp e) { //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars()); FuncExp fe; if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch) { result = fe; return; } visit(cast(Expression)e); } override void visit(CondExp e) { if (!e.type.equals(t)) { result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t)); result.type = t; return; } result = e; } override void visit(CommaExp e) { Expression e2c = e.e2.castTo(sc, t); if (e2c != e.e2) { result = new CommaExp(e.loc, e.e1, e2c); result.type = e2c.type; } else { result = e; result.type = e.e2.type; } } override void visit(SliceExp e) { //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars()); Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); if (e.type.equals(t) || typeb.ty != Tarray || (tb.ty != Tarray && tb.ty != Tsarray)) { visit(cast(Expression)e); return; } if (tb.ty == Tarray) { if (typeb.nextOf().equivalent(tb.nextOf())) { // T[] to const(T)[] result = e.copy(); result.type = t; } else { visit(cast(Expression)e); } return; } // Handle the cast from Tarray to Tsarray with CT-known slicing TypeSArray tsa = cast(TypeSArray)toStaticArrayType(e); if (tsa && tsa.size(e.loc) == tb.size(e.loc)) { /* Match if the sarray sizes are equal: * T[a .. b] to const(T)[b-a] * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim) * * If a SliceExp has Tsarray, it will become lvalue. * That's handled in SliceExp::isLvalue and toLvalue */ result = e.copy(); result.type = t; return; } if (tsa && tsa.dim.equals((cast(TypeSArray)tb).dim)) { /* Match if the dimensions are equal * with the implicit conversion of e.e1: * cast(float[2]) [2.0, 1.0, 0.0][0..2]; */ Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tsarray) t1b = tb.nextOf().sarrayOf((cast(TypeSArray)t1b).dim.toInteger()); else if (t1b.ty == Tarray) t1b = tb.nextOf().arrayOf(); else if (t1b.ty == Tpointer) t1b = tb.nextOf().pointerTo(); else assert(0); if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) { Expression e1x = e.e1.implicitCastTo(sc, t1b); assert(e1x.op != TOK.error); e = cast(SliceExp)e.copy(); e.e1 = e1x; e.type = t; result = e; return; } } auto ts = toAutoQualChars(tsa ? tsa : e.type, t); e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), ts[0], ts[1]); result = new ErrorExp(); } } scope CastTo v = new CastTo(sc, t); e.accept(v); return v.result; } /**************************************** * Set type inference target * t Target type * flag 1: don't put an error when inference fails */ Expression inferType(Expression e, Type t, int flag = 0) { extern (C++) final class InferType : Visitor { alias visit = Visitor.visit; public: Type t; int flag; Expression result; extern (D) this(Type t, int flag) { this.t = t; this.flag = flag; } override void visit(Expression e) { result = e; } override void visit(ArrayLiteralExp ale) { Type tb = t.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { Type tn = tb.nextOf(); if (ale.basis) ale.basis = inferType(ale.basis, tn, flag); for (size_t i = 0; i < ale.elements.dim; i++) { Expression e = (*ale.elements)[i]; if (e) { e = inferType(e, tn, flag); (*ale.elements)[i] = e; } } } result = ale; } override void visit(AssocArrayLiteralExp aale) { Type tb = t.toBasetype(); if (tb.ty == Taarray) { TypeAArray taa = cast(TypeAArray)tb; Type ti = taa.index; Type tv = taa.nextOf(); for (size_t i = 0; i < aale.keys.dim; i++) { Expression e = (*aale.keys)[i]; if (e) { e = inferType(e, ti, flag); (*aale.keys)[i] = e; } } for (size_t i = 0; i < aale.values.dim; i++) { Expression e = (*aale.values)[i]; if (e) { e = inferType(e, tv, flag); (*aale.values)[i] = e; } } } result = aale; } override void visit(FuncExp fe) { //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars()); if (t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction) { fe.fd.treq = t; } result = fe; } override void visit(CondExp ce) { Type tb = t.toBasetype(); ce.e1 = inferType(ce.e1, tb, flag); ce.e2 = inferType(ce.e2, tb, flag); result = ce; } } if (!t) return e; scope InferType v = new InferType(t, flag); e.accept(v); return v.result; } /**************************************** * Scale addition/subtraction to/from pointer. */ Expression scaleFactor(BinExp be, Scope* sc) { Type t1b = be.e1.type.toBasetype(); Type t2b = be.e2.type.toBasetype(); Expression eoff; if (t1b.ty == Tpointer && t2b.isintegral()) { // Need to adjust operator by the stride // Replace (ptr + int) with (ptr + (int * stride)) Type t = Type.tptrdiff_t; d_uns64 stride = t1b.nextOf().size(be.loc); if (!t.equals(t2b)) be.e2 = be.e2.castTo(sc, t); eoff = be.e2; be.e2 = new MulExp(be.loc, be.e2, new IntegerExp(Loc.initial, stride, t)); be.e2.type = t; be.type = be.e1.type; } else if (t2b.ty == Tpointer && t1b.isintegral()) { // Need to adjust operator by the stride // Replace (int + ptr) with (ptr + (int * stride)) Type t = Type.tptrdiff_t; Expression e; d_uns64 stride = t2b.nextOf().size(be.loc); if (!t.equals(t1b)) e = be.e1.castTo(sc, t); else e = be.e1; eoff = e; e = new MulExp(be.loc, e, new IntegerExp(Loc.initial, stride, t)); e.type = t; be.type = be.e2.type; be.e1 = be.e2; be.e2 = e; } else assert(0); if (sc.func && !sc.intypeof) { eoff = eoff.optimize(WANTvalue); if (eoff.op == TOK.int64 && eoff.toInteger() == 0) { } else if (sc.func.setUnsafe()) { be.error("pointer arithmetic not allowed in @safe functions"); return new ErrorExp(); } } return be; } /************************************** * Return true if e is an empty array literal with dimensionality * equal to or less than type of other array. * [], [[]], [[[]]], etc. * I.e., make sure that [1,2] is compatible with [], * [[1,2]] is compatible with [[]], etc. */ private bool isVoidArrayLiteral(Expression e, Type other) { while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1)) { auto ale = cast(ArrayLiteralExp)e; e = ale.getElement(0); if (other.ty == Tsarray || other.ty == Tarray) other = other.nextOf(); else return false; } if (other.ty != Tsarray && other.ty != Tarray) return false; Type t = e.type; return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0); } /************************************** * Combine types. * Output: * *pt merged type, if *pt is not NULL * *pe1 rewritten e1 * *pe2 rewritten e2 * Returns: * true success * false failed */ bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2) { //printf("typeMerge() %s op %s\n", pe1.toChars(), pe2.toChars()); MATCH m; Expression e1 = *pe1; Expression e2 = *pe2; Type t1b = e1.type.toBasetype(); Type t2b = e2.type.toBasetype(); if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic())) { e1 = integralPromotions(e1, sc); e2 = integralPromotions(e2, sc); } Type t1 = e1.type; Type t2 = e2.type; assert(t1); Type t = t1; /* The start type of alias this type recursion. * In following case, we should save A, and stop recursion * if it appears again. * X -> Y -> [A] -> B -> A -> B -> ... */ Type att1 = null; Type att2 = null; //if (t1) printf("\tt1 = %s\n", t1.toChars()); //if (t2) printf("\tt2 = %s\n", t2.toChars()); debug { if (!t2) printf("\te2 = '%s'\n", e2.toChars()); } assert(t2); if (t1.mod != t2.mod && t1.ty == Tenum && t2.ty == Tenum && (cast(TypeEnum)t1).sym == (cast(TypeEnum)t2).sym) { ubyte mod = MODmerge(t1.mod, t2.mod); t1 = t1.castMod(mod); t2 = t2.castMod(mod); } Lagain: t1b = t1.toBasetype(); t2b = t2.toBasetype(); TY ty = cast(TY)impcnvResult[t1b.ty][t2b.ty]; if (ty != Terror) { TY ty1 = cast(TY)impcnvType1[t1b.ty][t2b.ty]; TY ty2 = cast(TY)impcnvType2[t1b.ty][t2b.ty]; if (t1b.ty == ty1) // if no promotions { if (t1.equals(t2)) { t = t1; goto Lret; } if (t1b.equals(t2b)) { t = t1b; goto Lret; } } t = Type.basic[ty]; t1 = Type.basic[ty1]; t2 = Type.basic[ty2]; e1 = e1.castTo(sc, t1); e2 = e2.castTo(sc, t2); goto Lret; } t1 = t1b; t2 = t2b; if (t1.ty == Ttuple || t2.ty == Ttuple) goto Lincompatible; if (t1.equals(t2)) { // merging can not result in new enum type if (t.ty == Tenum) t = t1b; } else if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate)) { // Bring pointers to compatible type Type t1n = t1.nextOf(); Type t2n = t2.nextOf(); if (t1n.equals(t2n)) { } else if (t1n.ty == Tvoid) // pointers to void are always compatible t = t2; else if (t2n.ty == Tvoid) { } else if (t1.implicitConvTo(t2)) { goto Lt2; } else if (t2.implicitConvTo(t1)) { goto Lt1; } else if (t1n.ty == Tfunction && t2n.ty == Tfunction) { TypeFunction tf1 = cast(TypeFunction)t1n; TypeFunction tf2 = cast(TypeFunction)t2n; tf1.purityLevel(); tf2.purityLevel(); TypeFunction d = cast(TypeFunction)tf1.syntaxCopy(); if (tf1.purity != tf2.purity) d.purity = PURE.impure; assert(d.purity != PURE.fwdref); d.isnothrow = (tf1.isnothrow && tf2.isnothrow); d.isnogc = (tf1.isnogc && tf2.isnogc); if (tf1.trust == tf2.trust) d.trust = tf1.trust; else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system) d.trust = TRUST.system; else d.trust = TRUST.trusted; Type tx = null; if (t1.ty == Tdelegate) { tx = new TypeDelegate(d); } else tx = d.pointerTo(); tx = tx.typeSemantic(e1.loc, sc); if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx)) { t = tx; e1 = e1.castTo(sc, t); e2 = e2.castTo(sc, t); goto Lret; } goto Lincompatible; } else if (t1n.mod != t2n.mod) { if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) goto Lincompatible; ubyte mod = MODmerge(t1n.mod, t2n.mod); t1 = t1n.castMod(mod).pointerTo(); t2 = t2n.castMod(mod).pointerTo(); t = t1; goto Lagain; } else if (t1n.ty == Tclass && t2n.ty == Tclass) { ClassDeclaration cd1 = t1n.isClassHandle(); ClassDeclaration cd2 = t2n.isClassHandle(); int offset; if (cd1.isBaseOf(cd2, &offset)) { if (offset) e2 = e2.castTo(sc, t); } else if (cd2.isBaseOf(cd1, &offset)) { t = t2; if (offset) e1 = e1.castTo(sc, t); } else goto Lincompatible; } else { t1 = t1n.constOf().pointerTo(); t2 = t2n.constOf().pointerTo(); if (t1.implicitConvTo(t2)) { goto Lt2; } else if (t2.implicitConvTo(t1)) { goto Lt1; } goto Lincompatible; } } else if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && (cast(TypeSArray)t2).dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1))) { /* (T[n] op void*) => T[] * (T[] op void*) => T[] * (T[n] op void[0]) => T[] * (T[] op void[0]) => T[] * (T[n] op void[]) => T[] * (T[] op void[]) => T[] */ goto Lx1; } else if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && (cast(TypeSArray)t1).dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2))) { /* (void* op T[n]) => T[] * (void* op T[]) => T[] * (void[0] op T[n]) => T[] * (void[0] op T[]) => T[] * (void[] op T[n]) => T[] * (void[] op T[]) => T[] */ goto Lx2; } else if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch) { // https://issues.dlang.org/show_bug.cgi?id=7285 // Tsarray op [x, y, ...] should to be Tsarray // https://issues.dlang.org/show_bug.cgi?id=14737 // Tsarray ~ [x, y, ...] should to be Tarray if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate) goto Lt1; if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign)) { // Don't make the lvalue const t = t2; goto Lret; } goto Lt2; } else if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1)) { // https://issues.dlang.org/show_bug.cgi?id=7285 // https://issues.dlang.org/show_bug.cgi?id=14737 if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate) goto Lt2; goto Lt1; } else if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod) { /* If one is mutable and the other invariant, then retry * with both of them as const */ Type t1n = t1.nextOf(); Type t2n = t2.nextOf(); ubyte mod; if (e1.op == TOK.null_ && e2.op != TOK.null_) mod = t2n.mod; else if (e1.op != TOK.null_ && e2.op == TOK.null_) mod = t1n.mod; else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) goto Lincompatible; else mod = MODmerge(t1n.mod, t2n.mod); if (t1.ty == Tpointer) t1 = t1n.castMod(mod).pointerTo(); else t1 = t1n.castMod(mod).arrayOf(); if (t2.ty == Tpointer) t2 = t2n.castMod(mod).pointerTo(); else t2 = t2n.castMod(mod).arrayOf(); t = t1; goto Lagain; } else if (t1.ty == Tclass && t2.ty == Tclass) { if (t1.mod != t2.mod) { ubyte mod; if (e1.op == TOK.null_ && e2.op != TOK.null_) mod = t2.mod; else if (e1.op != TOK.null_ && e2.op == TOK.null_) mod = t1.mod; else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) goto Lincompatible; else mod = MODmerge(t1.mod, t2.mod); t1 = t1.castMod(mod); t2 = t2.castMod(mod); t = t1; goto Lagain; } goto Lcc; } else if (t1.ty == Tclass || t2.ty == Tclass) { Lcc: while (1) { MATCH i1 = e2.implicitConvTo(t1); MATCH i2 = e1.implicitConvTo(t2); if (i1 && i2) { // We have the case of class vs. void*, so pick class if (t1.ty == Tpointer) i1 = MATCH.nomatch; else if (t2.ty == Tpointer) i2 = MATCH.nomatch; } if (i2) { e2 = e2.castTo(sc, t2); goto Lt2; } else if (i1) { e1 = e1.castTo(sc, t1); goto Lt1; } else if (t1.ty == Tclass && t2.ty == Tclass) { TypeClass tc1 = cast(TypeClass)t1; TypeClass tc2 = cast(TypeClass)t2; /* Pick 'tightest' type */ ClassDeclaration cd1 = tc1.sym.baseClass; ClassDeclaration cd2 = tc2.sym.baseClass; if (cd1 && cd2) { t1 = cd1.type.castMod(t1.mod); t2 = cd2.type.castMod(t2.mod); } else if (cd1) t1 = cd1.type; else if (cd2) t2 = cd2.type; else goto Lincompatible; } else if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis) { if (att1 && e1.type == att1) goto Lincompatible; if (!att1 && e1.type.checkAliasThisRec()) att1 = e1.type; //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars()); e1 = resolveAliasThis(sc, e1); t1 = e1.type; continue; } else if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis) { if (att2 && e2.type == att2) goto Lincompatible; if (!att2 && e2.type.checkAliasThisRec()) att2 = e2.type; //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars()); e2 = resolveAliasThis(sc, e2); t2 = e2.type; continue; } else goto Lincompatible; } } else if (t1.ty == Tstruct && t2.ty == Tstruct) { if (t1.mod != t2.mod) { if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) goto Lincompatible; ubyte mod = MODmerge(t1.mod, t2.mod); t1 = t1.castMod(mod); t2 = t2.castMod(mod); t = t1; goto Lagain; } TypeStruct ts1 = cast(TypeStruct)t1; TypeStruct ts2 = cast(TypeStruct)t2; if (ts1.sym != ts2.sym) { if (!ts1.sym.aliasthis && !ts2.sym.aliasthis) goto Lincompatible; MATCH i1 = MATCH.nomatch; MATCH i2 = MATCH.nomatch; Expression e1b = null; Expression e2b = null; if (ts2.sym.aliasthis) { if (att2 && e2.type == att2) goto Lincompatible; if (!att2 && e2.type.checkAliasThisRec()) att2 = e2.type; //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars()); e2b = resolveAliasThis(sc, e2); i1 = e2b.implicitConvTo(t1); } if (ts1.sym.aliasthis) { if (att1 && e1.type == att1) goto Lincompatible; if (!att1 && e1.type.checkAliasThisRec()) att1 = e1.type; //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars()); e1b = resolveAliasThis(sc, e1); i2 = e1b.implicitConvTo(t2); } if (i1 && i2) goto Lincompatible; if (i1) goto Lt1; else if (i2) goto Lt2; if (e1b) { e1 = e1b; t1 = e1b.type.toBasetype(); } if (e2b) { e2 = e2b; t2 = e2b.type.toBasetype(); } t = t1; goto Lagain; } } else if (t1.ty == Tstruct || t2.ty == Tstruct) { if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis) { if (att1 && e1.type == att1) goto Lincompatible; if (!att1 && e1.type.checkAliasThisRec()) att1 = e1.type; //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars()); e1 = resolveAliasThis(sc, e1); t1 = e1.type; t = t1; goto Lagain; } if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis) { if (att2 && e2.type == att2) goto Lincompatible; if (!att2 && e2.type.checkAliasThisRec()) att2 = e2.type; //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars()); e2 = resolveAliasThis(sc, e2); t2 = e2.type; t = t2; goto Lagain; } goto Lincompatible; } else if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2)) { goto Lt2; } else if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1)) { goto Lt1; } else if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf())) { Lx1: t = t1.nextOf().arrayOf(); // T[] e1 = e1.castTo(sc, t); e2 = e2.castTo(sc, t); } else if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf())) { Lx2: t = t2.nextOf().arrayOf(); e1 = e1.castTo(sc, t); e2 = e2.castTo(sc, t); } else if (t1.ty == Tvector && t2.ty == Tvector) { // https://issues.dlang.org/show_bug.cgi?id=13841 // all vector types should have no common types between // different vectors, even though their sizes are same. auto tv1 = cast(TypeVector)t1; auto tv2 = cast(TypeVector)t2; if (!tv1.basetype.equals(tv2.basetype)) goto Lincompatible; goto LmodCompare; } else if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1)) { e2 = e2.castTo(sc, t1); t2 = t1; t = t1; goto Lagain; } else if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2)) { e1 = e1.castTo(sc, t2); t1 = t2; t = t1; goto Lagain; } else if (t1.isintegral() && t2.isintegral()) { if (t1.ty != t2.ty) { if (t1.ty == Tvector || t2.ty == Tvector) goto Lincompatible; e1 = integralPromotions(e1, sc); e2 = integralPromotions(e2, sc); t1 = e1.type; t2 = e2.type; goto Lagain; } assert(t1.ty == t2.ty); LmodCompare: if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) goto Lincompatible; ubyte mod = MODmerge(t1.mod, t2.mod); t1 = t1.castMod(mod); t2 = t2.castMod(mod); t = t1; e1 = e1.castTo(sc, t); e2 = e2.castTo(sc, t); goto Lagain; } else if (t1.ty == Tnull && t2.ty == Tnull) { ubyte mod = MODmerge(t1.mod, t2.mod); t = t1.castMod(mod); e1 = e1.castTo(sc, t); e2 = e2.castTo(sc, t); goto Lret; } else if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray)) { goto Lt1; } else if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray)) { goto Lt2; } else if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1)) { if (e2.implicitConvTo(t1.nextOf())) { // T[] op T // T[] op cast(T)U e2 = e2.castTo(sc, t1.nextOf()); t = t1.nextOf().arrayOf(); } else if (t1.nextOf().implicitConvTo(e2.type)) { // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780) // e1 is left as U[], it will be handled in arrayOp() later. t = e2.type.arrayOf(); } else if (t2.ty == Tarray && isArrayOpOperand(e2)) { if (t1.nextOf().implicitConvTo(t2.nextOf())) { // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780) // e1 is left as U[], it will be handled in arrayOp() later. t = t2.nextOf().arrayOf(); } else if (t2.nextOf().implicitConvTo(t1.nextOf())) { // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) // e2 is left as U[], it will be handled in arrayOp() later. t = t1.nextOf().arrayOf(); } else goto Lincompatible; } else goto Lincompatible; } else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2)) { if (e1.implicitConvTo(t2.nextOf())) { // T op T[] // cast(T)U op T[] e1 = e1.castTo(sc, t2.nextOf()); t = t2.nextOf().arrayOf(); } else if (t2.nextOf().implicitConvTo(e1.type)) { // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780) // e2 is left as U[], it will be handled in arrayOp() later. t = e1.type.arrayOf(); } else goto Lincompatible; //printf("test %s\n", Token::toChars(op)); e1 = e1.optimize(WANTvalue); if (isCommutative(op) && e1.isConst()) { /* Swap operands to minimize number of functions generated */ //printf("swap %s\n", Token::toChars(op)); Expression tmp = e1; e1 = e2; e2 = tmp; } } else { Lincompatible: return false; } Lret: if (!*pt) *pt = t; *pe1 = e1; *pe2 = e2; version (none) { printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); if (e1.type) printf("\tt1 = %s\n", e1.type.toChars()); if (e2.type) printf("\tt2 = %s\n", e2.type.toChars()); printf("\ttype = %s\n", t.toChars()); } return true; Lt1: e2 = e2.castTo(sc, t1); t = t1; goto Lret; Lt2: e1 = e1.castTo(sc, t2); t = t2; goto Lret; } /************************************ * Bring leaves to common type. * Returns: * null on success, ErrorExp if error occurs */ Expression typeCombine(BinExp be, Scope* sc) { Expression errorReturn() { Expression ex = be.incompatibleTypes(); if (ex.op == TOK.error) return ex; return new ErrorExp(); } Type t1 = be.e1.type.toBasetype(); Type t2 = be.e2.type.toBasetype(); if (be.op == TOK.min || be.op == TOK.add) { // struct+struct, and class+class are errors if (t1.ty == Tstruct && t2.ty == Tstruct) return errorReturn(); else if (t1.ty == Tclass && t2.ty == Tclass) return errorReturn(); else if (t1.ty == Taarray && t2.ty == Taarray) return errorReturn(); } if (!typeMerge(sc, be.op, &be.type, &be.e1, &be.e2)) return errorReturn(); // If the types have no value, return an error if (be.e1.op == TOK.error) return be.e1; if (be.e2.op == TOK.error) return be.e2; return null; } /*********************************** * Do integral promotions (convertchk). * Don't convert to */ Expression integralPromotions(Expression e, Scope* sc) { //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars()); switch (e.type.toBasetype().ty) { case Tvoid: e.error("void has no value"); return new ErrorExp(); case Tint8: case Tuns8: case Tint16: case Tuns16: case Tbool: case Tchar: case Twchar: e = e.castTo(sc, Type.tint32); break; case Tdchar: e = e.castTo(sc, Type.tuns32); break; default: break; } return e; } /****************************************************** * This provides a transition from the non-promoting behavior * of unary + - ~ to the C-like integral promotion behavior. * Params: * sc = context * ue = NegExp, UAddExp, or ComExp which is revised per rules * References: * https://issues.dlang.org/show_bug.cgi?id=16997 */ void fix16997(Scope* sc, UnaExp ue) { if (global.params.fix16997) ue.e1 = integralPromotions(ue.e1, sc); // desired C-like behavor else { switch (ue.e1.type.toBasetype.ty) { case Tint8: case Tuns8: case Tint16: case Tuns16: //case Tbool: // these operations aren't allowed on bool anyway case Tchar: case Twchar: case Tdchar: ue.deprecation("integral promotion not done for `%s`, use '-transition=intpromote' switch or `%scast(int)(%s)`", ue.toChars(), Token.toChars(ue.op), ue.e1.toChars()); break; default: break; } } } /*********************************** * See if both types are arrays that can be compared * for equality. Return true if so. * If they are arrays, but incompatible, issue error. * This is to enable comparing things like an immutable * array with a mutable one. */ extern (C++) bool arrayTypeCompatible(Loc loc, Type t1, Type t2) { t1 = t1.toBasetype().merge2(); t2 = t2.toBasetype().merge2(); if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) { if (t1.nextOf().implicitConvTo(t2.nextOf()) < MATCH.constant && t2.nextOf().implicitConvTo(t1.nextOf()) < MATCH.constant && (t1.nextOf().ty != Tvoid && t2.nextOf().ty != Tvoid)) { error(loc, "array equality comparison type mismatch, `%s` vs `%s`", t1.toChars(), t2.toChars()); } return true; } return false; } /*********************************** * See if both types are arrays that can be compared * for equality without any casting. Return true if so. * This is to enable comparing things like an immutable * array with a mutable one. */ extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2) { t1 = t1.toBasetype(); t2 = t2.toBasetype(); if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty) { if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant) return true; } return false; } /******************************************************************/ /* Determine the integral ranges of an expression. * This is used to determine if implicit narrowing conversions will * be allowed. */ IntRange getIntRange(Expression e) { extern (C++) final class IntRangeVisitor : Visitor { alias visit = Visitor.visit; public: IntRange range; override void visit(Expression e) { range = IntRange.fromType(e.type); } override void visit(IntegerExp e) { range = IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type); } override void visit(CastExp e) { range = getIntRange(e.e1)._cast(e.type); } override void visit(AddExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 + ir2)._cast(e.type); } override void visit(MinExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 - ir2)._cast(e.type); } override void visit(DivExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 / ir2)._cast(e.type); } override void visit(MulExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 * ir2)._cast(e.type); } override void visit(ModExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); // Modding on 0 is invalid anyway. if (!ir2.absNeg().imin.negative) { visit(cast(Expression)e); return; } range = (ir1 % ir2)._cast(e.type); } override void visit(AndExp e) { IntRange result; bool hasResult = false; result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult); assert(hasResult); range = result._cast(e.type); } override void visit(OrExp e) { IntRange result; bool hasResult = false; result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult); assert(hasResult); range = result._cast(e.type); } override void visit(XorExp e) { IntRange result; bool hasResult = false; result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult); assert(hasResult); range = result._cast(e.type); } override void visit(ShlExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 << ir2)._cast(e.type); } override void visit(ShrExp e) { IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = (ir1 >> ir2)._cast(e.type); } override void visit(UshrExp e) { IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type); IntRange ir2 = getIntRange(e.e2); range = (ir1 >>> ir2)._cast(e.type); } override void visit(AssignExp e) { range = getIntRange(e.e2)._cast(e.type); } override void visit(CondExp e) { // No need to check e.econd; assume caller has called optimize() IntRange ir1 = getIntRange(e.e1); IntRange ir2 = getIntRange(e.e2); range = ir1.unionWith(ir2)._cast(e.type); } override void visit(VarExp e) { Expression ie; VarDeclaration vd = e.var.isVarDeclaration(); if (vd && vd.range) range = vd.range._cast(e.type); else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null) ie.accept(this); else visit(cast(Expression)e); } override void visit(CommaExp e) { e.e2.accept(this); } override void visit(ComExp e) { IntRange ir = getIntRange(e.e1); range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type); } override void visit(NegExp e) { IntRange ir = getIntRange(e.e1); range = (-ir)._cast(e.type); } } scope IntRangeVisitor v = new IntRangeVisitor(); e.accept(v); return v.range; } ================================================ FILE: gcc/d/dmd/dclass.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dclass.d, _dclass.d) * Documentation: https://dlang.org/phobos/dmd_dclass.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d */ module dmd.dclass; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.objc; import dmd.root.rmem; import dmd.target; import dmd.visitor; enum Abstract : int { fwdref = 0, // whether an abstract class is not yet computed yes, // is abstract class no, // is not abstract class } /*********************************************************** */ struct BaseClass { Type type; // (before semantic processing) ClassDeclaration sym; uint offset; // 'this' pointer offset // for interfaces: Array of FuncDeclaration's making up the vtbl[] FuncDeclarations vtbl; // if BaseClass is an interface, these // are a copy of the InterfaceDeclaration.interfaces BaseClass[] baseInterfaces; extern (D) this(Type type) { //printf("BaseClass(this = %p, '%s')\n", this, type.toChars()); this.type = type; } /**************************************** * Fill in vtbl[] for base class based on member functions of class cd. * Input: * vtbl if !=NULL, fill it in * newinstance !=0 means all entries must be filled in by members * of cd, not members of any base classes of cd. * Returns: * true if any entries were filled in by members of cd (not exclusively * by base classes) */ extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance) { bool result = false; //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars()); if (vtbl) vtbl.setDim(sym.vtbl.dim); // first entry is ClassInfo reference for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++) { FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration(); FuncDeclaration fd; TypeFunction tf; //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null"); assert(ifd); // Find corresponding function in this class tf = ifd.type.toTypeFunction(); fd = cd.findFunc(ifd.ident, tf); if (fd && !fd.isAbstract()) { //printf(" found\n"); // Check that calling conventions match if (fd.linkage != ifd.linkage) fd.error("linkage doesn't match interface function"); // Check that it is current //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n", //newinstance, fd.toParent().toChars(), ifd.toParent().toChars()); if (newinstance && fd.toParent() != cd && ifd.toParent() == sym) cd.error("interface function `%s` is not implemented", ifd.toFullSignature()); if (fd.toParent() == cd) result = true; } else { //printf(" not found %p\n", fd); // BUG: should mark this class as abstract? if (!cd.isAbstract()) cd.error("interface function `%s` is not implemented", ifd.toFullSignature()); fd = null; } if (vtbl) (*vtbl)[j] = fd; } return result; } extern (C++) void copyBaseInterfaces(BaseClasses* vtblInterfaces) { //printf("+copyBaseInterfaces(), %s\n", sym.toChars()); // if (baseInterfaces.length) // return; auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof); baseInterfaces = bc[0 .. sym.interfaces.length]; //printf("%s.copyBaseInterfaces()\n", sym.toChars()); for (size_t i = 0; i < baseInterfaces.length; i++) { BaseClass* b = &baseInterfaces[i]; BaseClass* b2 = sym.interfaces[i]; assert(b2.vtbl.dim == 0); // should not be filled yet memcpy(b, b2, BaseClass.sizeof); if (i) // single inheritance is i==0 vtblInterfaces.push(b); // only need for M.I. b.copyBaseInterfaces(vtblInterfaces); } //printf("-copyBaseInterfaces\n"); } } enum ClassFlags : int { none = 0x0, isCOMclass = 0x1, noPointers = 0x2, hasOffTi = 0x4, hasCtor = 0x8, hasGetMembers = 0x10, hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, } /*********************************************************** */ extern (C++) class ClassDeclaration : AggregateDeclaration { extern (C++) __gshared { // Names found by reading object.d in druntime ClassDeclaration object; ClassDeclaration throwable; ClassDeclaration exception; ClassDeclaration errorException; ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr } ClassDeclaration baseClass; // NULL only if this is Object FuncDeclaration staticCtor; FuncDeclaration staticDtor; Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] // Array of BaseClass's; first is super, rest are Interface's BaseClasses* baseclasses; /* Slice of baseclasses[] that does not include baseClass */ BaseClass*[] interfaces; // array of base interfaces that have their own vtbl[] BaseClasses* vtblInterfaces; // the ClassInfo object for this ClassDeclaration TypeInfoClassDeclaration vclassinfo; // true if this is a COM class bool com; /// true if this is a scope class bool stack; /// if this is a C++ class, this is the slot reserved for the virtual destructor int cppDtorVtblIndex = -1; /// to prevent recursive attempts private bool inuse; /// true if this class has an identifier, but was originally declared anonymous /// used in support of https://issues.dlang.org/show_bug.cgi?id=17371 private bool isActuallyAnonymous; Abstract isabstract; /// set the progress of base classes resolving Baseok baseok; /** * Data for a class declaration that is needed for the Objective-C * integration. */ ObjcClassDeclaration objc; Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject) { if (!id) { id = Identifier.generateId("__anonclass"); isActuallyAnonymous = true; } assert(id); super(loc, id); __gshared const(char)* msg = "only object.d can define this reserved class name"; if (baseclasses) { // Actually, this is a transfer this.baseclasses = baseclasses; } else this.baseclasses = new BaseClasses(); this.members = members; //printf("ClassDeclaration(%s), dim = %d\n", id.toChars(), this.baseclasses.dim); // For forward references type = new TypeClass(this); if (id) { // Look for special class names if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof) error("illegal class name"); // BUG: What if this is the wrong TypeInfo, i.e. it is nested? if (id.toChars()[0] == 'T') { if (id == Id.TypeInfo) { if (!inObject) error("%s", msg); Type.dtypeinfo = this; } if (id == Id.TypeInfo_Class) { if (!inObject) error("%s", msg); Type.typeinfoclass = this; } if (id == Id.TypeInfo_Interface) { if (!inObject) error("%s", msg); Type.typeinfointerface = this; } if (id == Id.TypeInfo_Struct) { if (!inObject) error("%s", msg); Type.typeinfostruct = this; } if (id == Id.TypeInfo_Pointer) { if (!inObject) error("%s", msg); Type.typeinfopointer = this; } if (id == Id.TypeInfo_Array) { if (!inObject) error("%s", msg); Type.typeinfoarray = this; } if (id == Id.TypeInfo_StaticArray) { //if (!inObject) // Type.typeinfostaticarray.error("%s", msg); Type.typeinfostaticarray = this; } if (id == Id.TypeInfo_AssociativeArray) { if (!inObject) error("%s", msg); Type.typeinfoassociativearray = this; } if (id == Id.TypeInfo_Enum) { if (!inObject) error("%s", msg); Type.typeinfoenum = this; } if (id == Id.TypeInfo_Function) { if (!inObject) error("%s", msg); Type.typeinfofunction = this; } if (id == Id.TypeInfo_Delegate) { if (!inObject) error("%s", msg); Type.typeinfodelegate = this; } if (id == Id.TypeInfo_Tuple) { if (!inObject) error("%s", msg); Type.typeinfotypelist = this; } if (id == Id.TypeInfo_Const) { if (!inObject) error("%s", msg); Type.typeinfoconst = this; } if (id == Id.TypeInfo_Invariant) { if (!inObject) error("%s", msg); Type.typeinfoinvariant = this; } if (id == Id.TypeInfo_Shared) { if (!inObject) error("%s", msg); Type.typeinfoshared = this; } if (id == Id.TypeInfo_Wild) { if (!inObject) error("%s", msg); Type.typeinfowild = this; } if (id == Id.TypeInfo_Vector) { if (!inObject) error("%s", msg); Type.typeinfovector = this; } } if (id == Id.Object) { if (!inObject) error("%s", msg); object = this; } if (id == Id.Throwable) { if (!inObject) error("%s", msg); throwable = this; } if (id == Id.Exception) { if (!inObject) error("%s", msg); exception = this; } if (id == Id.Error) { if (!inObject) error("%s", msg); errorException = this; } if (id == Id.cpp_type_info_ptr) { if (!inObject) error("%s", msg); cpp_type_info_ptr = this; } } baseok = Baseok.none; } static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject) { return new ClassDeclaration(loc, id, baseclasses, members, inObject); } override Dsymbol syntaxCopy(Dsymbol s) { //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars()); ClassDeclaration cd = s ? cast(ClassDeclaration)s : new ClassDeclaration(loc, ident, null, null, false); cd.storage_class |= storage_class; cd.baseclasses.setDim(this.baseclasses.dim); for (size_t i = 0; i < cd.baseclasses.dim; i++) { BaseClass* b = (*this.baseclasses)[i]; auto b2 = new BaseClass(b.type.syntaxCopy()); (*cd.baseclasses)[i] = b2; } return ScopeDsymbol.syntaxCopy(cd); } override Scope* newScope(Scope* sc) { auto sc2 = super.newScope(sc); if (isCOMclass()) { /* This enables us to use COM objects under Linux and * work with things like XPCOM */ sc2.linkage = Target.systemLinkage(); } return sc2; } /********************************************* * Determine if 'this' is a base class of cd. * This is used to detect circular inheritance only. */ final bool isBaseOf2(ClassDeclaration cd) { if (!cd) return false; //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); for (size_t i = 0; i < cd.baseclasses.dim; i++) { BaseClass* b = (*cd.baseclasses)[i]; if (b.sym == this || isBaseOf2(b.sym)) return true; } return false; } enum OFFSET_RUNTIME = 0x76543210; enum OFFSET_FWDREF = 0x76543211; /******************************************* * Determine if 'this' is a base class of cd. */ bool isBaseOf(ClassDeclaration cd, int* poffset) { //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars()); if (poffset) *poffset = 0; while (cd) { /* cd.baseClass might not be set if cd is forward referenced. */ if (!cd.baseClass && cd.semanticRun < PASS.semanticdone && !cd.isInterfaceDeclaration()) { cd.dsymbolSemantic(null); if (!cd.baseClass && cd.semanticRun < PASS.semanticdone) cd.error("base class is forward referenced by `%s`", toChars()); } if (this == cd.baseClass) return true; cd = cd.baseClass; } return false; } /********************************************* * Determine if 'this' has complete base class information. * This is used to detect forward references in covariant overloads. */ final bool isBaseInfoComplete() const { return baseok >= Baseok.done; } override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags); //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); if (_scope && baseok < Baseok.done) { if (!inuse) { // must semantic on base class/interfaces inuse = true; dsymbolSemantic(this, null); inuse = false; } } if (!members || !symtab) // opaque or addMember is not yet done { error("is forward referenced when looking for `%s`", ident.toChars()); //*(char*)0=0; return null; } auto s = ScopeDsymbol.search(loc, ident, flags); // don't search imports of base classes if (flags & SearchImportsOnly) return s; if (!s) { // Search bases classes in depth-first, left to right order for (size_t i = 0; i < baseclasses.dim; i++) { BaseClass* b = (*baseclasses)[i]; if (b.sym) { if (!b.sym.symtab) error("base `%s` is forward referenced", b.sym.ident.toChars()); else { import dmd.access : symbolIsVisible; s = b.sym.search(loc, ident, flags); if (!s) continue; else if (s == this) // happens if s is nested in this and derives from this s = null; else if (!(flags & IgnoreSymbolVisibility) && !(s.prot().kind == Prot.Kind.protected_) && !symbolIsVisible(this, s)) s = null; else break; } } } } return s; } /************************************ * Search base classes in depth-first, left-to-right order for * a class or interface named 'ident'. * Stops at first found. Does not look for additional matches. * Params: * ident = identifier to search for * Returns: * ClassDeclaration if found, null if not */ final ClassDeclaration searchBase(Identifier ident) { foreach (b; *baseclasses) { auto cdb = b.type.isClassHandle(); if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616 return null; if (cdb.ident.equals(ident)) return cdb; auto result = cdb.searchBase(ident); if (result) return result; } return null; } final override void finalizeSize() { assert(sizeok != Sizeok.done); // Set the offsets of the fields and determine the size of the class if (baseClass) { assert(baseClass.sizeok == Sizeok.done); alignsize = baseClass.alignsize; structsize = baseClass.structsize; if (classKind == ClassKind.cpp && global.params.isWindows) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); } else if (isInterfaceDeclaration()) { if (interfaces.length == 0) { alignsize = Target.ptrsize; structsize = Target.ptrsize; // allow room for __vptr } } else { alignsize = Target.ptrsize; structsize = Target.ptrsize; // allow room for __vptr if (classKind != ClassKind.cpp) structsize += Target.ptrsize; // allow room for __monitor } //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); size_t bi = 0; // index into vtblInterfaces[] /**** * Runs through the inheritance graph to set the BaseClass.offset fields. * Recursive in order to account for the size of the interface classes, if they are * more than just interfaces. * Params: * cd = interface to look at * baseOffset = offset of where cd will be placed * Returns: * subset of instantiated size used by cd for interfaces */ uint membersPlace(ClassDeclaration cd, uint baseOffset) { //printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset); uint offset = baseOffset; foreach (BaseClass* b; cd.interfaces) { if (b.sym.sizeok != Sizeok.done) b.sym.finalizeSize(); assert(b.sym.sizeok == Sizeok.done); if (!b.sym.alignsize) b.sym.alignsize = Target.ptrsize; alignmember(b.sym.alignsize, b.sym.alignsize, &offset); assert(bi < vtblInterfaces.dim); BaseClass* bv = (*vtblInterfaces)[bi]; if (b.sym.interfaces.length == 0) { //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset); bv.offset = offset; ++bi; // All the base interfaces down the left side share the same offset for (BaseClass* b2 = bv; b2.baseInterfaces.length; ) { b2 = &b2.baseInterfaces[0]; b2.offset = offset; //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset); } } membersPlace(b.sym, offset); //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize); offset += b.sym.structsize; if (alignsize < b.sym.alignsize) alignsize = b.sym.alignsize; } return offset - baseOffset; } structsize += membersPlace(this, structsize); if (isInterfaceDeclaration()) { sizeok = Sizeok.done; return; } // FIXME: Currently setFieldOffset functions need to increase fields // to calculate each variable offsets. It can be improved later. fields.setDim(0); uint offset = structsize; foreach (s; *members) { s.setFieldOffset(this, &offset, false); } sizeok = Sizeok.done; // Calculate fields[i].overlapped checkOverlappedFields(); } override bool isAnonymous() { return isActuallyAnonymous; } final bool isFuncHidden(FuncDeclaration fd) { //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars()); Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); if (!s) { //printf("not found\n"); /* Because, due to a hack, if there are multiple definitions * of fd.ident, NULL is returned. */ return false; } s = s.toAlias(); if (auto os = s.isOverloadSet()) { foreach (sm; os.a) { auto fm = sm.isFuncDeclaration(); if (overloadApply(fm, s => fd == s.isFuncDeclaration())) return false; } return true; } else { auto f = s.isFuncDeclaration(); //printf("%s fdstart = %p\n", s.kind(), fdstart); if (overloadApply(f, s => fd == s.isFuncDeclaration())) return false; return !fd.parent.isTemplateMixin(); } } /**************** * Find virtual function matching identifier and type. * Used to build virtual function tables for interface implementations. * Params: * ident = function's identifier * tf = function's type * Returns: * function symbol if found, null if not * Errors: * prints error message if more than one match */ final FuncDeclaration findFunc(Identifier ident, TypeFunction tf) { //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars()); FuncDeclaration fdmatch = null; FuncDeclaration fdambig = null; void searchVtbl(ref Dsymbols vtbl) { foreach (s; vtbl) { auto fd = s.isFuncDeclaration(); if (!fd) continue; // the first entry might be a ClassInfo //printf("\t[%d] = %s\n", i, fd.toChars()); if (ident == fd.ident && fd.type.covariant(tf) == 1) { //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration()); if (!fdmatch) goto Lfd; if (fd == fdmatch) goto Lfdmatch; { // Function type matching: exact > covariant MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch; MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } { MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch; MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } { // The way of definition: non-mixin > mixin MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch; MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch; if (m1 > m2) goto Lfd; else if (m1 < m2) goto Lfdmatch; } fdambig = fd; //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars()); continue; Lfd: fdmatch = fd; fdambig = null; //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars()); continue; Lfdmatch: continue; } //else printf("\t\t%d\n", fd.type.covariant(tf)); } } searchVtbl(vtbl); for (auto cd = this; cd; cd = cd.baseClass) { searchVtbl(cd.vtblFinal); } if (fdambig) error("ambiguous virtual function `%s`", fdambig.toChars()); return fdmatch; } /**************************************** */ final bool isCOMclass() const { return com; } bool isCOMinterface() const { return false; } final bool isCPPclass() const { return classKind == ClassKind.cpp; } bool isCPPinterface() const { return false; } /**************************************** */ final bool isAbstract() { enum log = false; if (isabstract != Abstract.fwdref) return isabstract == Abstract.yes; if (log) printf("isAbstract(%s)\n", toChars()); bool no() { if (log) printf("no\n"); isabstract = Abstract.no; return false; } bool yes() { if (log) printf("yes\n"); isabstract = Abstract.yes; return true; } if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_) return yes(); if (errors) return no(); /* https://issues.dlang.org/show_bug.cgi?id=11169 * Resolve forward references to all class member functions, * and determine whether this class is abstract. */ extern (C++) static int func(Dsymbol s, void* param) { auto fd = s.isFuncDeclaration(); if (!fd) return 0; if (fd.storage_class & STC.static_) return 0; if (fd.isAbstract()) return 1; return 0; } for (size_t i = 0; i < members.dim; i++) { auto s = (*members)[i]; if (s.apply(&func, cast(void*)this)) { return yes(); } } /* If the base class is not abstract, then this class cannot * be abstract. */ if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract())) return no(); /* If any abstract functions are inherited, but not overridden, * then the class is abstract. Do this by checking the vtbl[]. * Need to do semantic() on class to fill the vtbl[]. */ this.dsymbolSemantic(null); /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic() * is called recursively it can set PASS.semanticdone without finishing it. */ //if (semanticRun < PASS.semanticdone) { /* Could not complete semantic(). Try running semantic() on * each of the virtual functions, * which will fill in the vtbl[] overrides. */ extern (C++) static int virtualSemantic(Dsymbol s, void* param) { auto fd = s.isFuncDeclaration(); if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration()) fd.dsymbolSemantic(null); return 0; } for (size_t i = 0; i < members.dim; i++) { auto s = (*members)[i]; s.apply(&virtualSemantic, cast(void*)this); } } /* Finally, check the vtbl[] */ foreach (i; 1 .. vtbl.dim) { auto fd = vtbl[i].isFuncDeclaration(); //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars()); if (!fd || fd.isAbstract()) { return yes(); } } return no(); } /**************************************** * Determine if slot 0 of the vtbl[] is reserved for something else. * For class objects, yes, this is where the classinfo ptr goes. * For COM interfaces, no. * For non-COM interfaces, yes, this is where the Interface ptr goes. * Returns: * 0 vtbl[0] is first virtual function pointer * 1 vtbl[0] is classinfo/interfaceinfo pointer */ int vtblOffset() const { return classKind == ClassKind.cpp ? 0 : 1; } /**************************************** */ override const(char)* kind() const { return "class"; } /**************************************** */ override final void addLocalClass(ClassDeclarations* aclasses) { aclasses.push(this); } // Back end Dsymbol vtblsym; final Dsymbol vtblSymbol() { if (!vtblsym) { auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim); auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_); var.addMember(null, this); var.isdataseg = 1; var.linkage = LINK.d; var.semanticRun = PASS.semanticdone; // no more semantic wanted vtblsym = var; } return vtblsym; } override final inout(ClassDeclaration) isClassDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class InterfaceDeclaration : ClassDeclaration { extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses) { super(loc, id, baseclasses, null, false); if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces { com = true; classKind = ClassKind.cpp; // IUnknown is also a C++ interface } } override Dsymbol syntaxCopy(Dsymbol s) { InterfaceDeclaration id = s ? cast(InterfaceDeclaration)s : new InterfaceDeclaration(loc, ident, null); return ClassDeclaration.syntaxCopy(id); } override Scope* newScope(Scope* sc) { auto sc2 = super.newScope(sc); if (com) sc2.linkage = LINK.windows; else if (classKind == ClassKind.cpp) sc2.linkage = LINK.cpp; else if (classKind == ClassKind.objc) sc2.linkage = LINK.objc; return sc2; } /******************************************* * Determine if 'this' is a base class of cd. * (Actually, if it is an interface supported by cd) * Output: * *poffset offset to start of class * OFFSET_RUNTIME must determine offset at runtime * Returns: * false not a base * true is a base */ override bool isBaseOf(ClassDeclaration cd, int* poffset) { //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); assert(!baseClass); foreach (b; cd.interfaces) { //printf("\tX base %s\n", b.sym.toChars()); if (this == b.sym) { //printf("\tfound at offset %d\n", b.offset); if (poffset) { // don't return incorrect offsets // https://issues.dlang.org/show_bug.cgi?id=16980 *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF; } // printf("\tfound at offset %d\n", b.offset); return true; } if (isBaseOf(b, poffset)) return true; } if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) return true; if (poffset) *poffset = 0; return false; } bool isBaseOf(BaseClass* bc, int* poffset) { //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.sym.toChars()); for (size_t j = 0; j < bc.baseInterfaces.length; j++) { BaseClass* b = &bc.baseInterfaces[j]; //printf("\tY base %s\n", b.sym.toChars()); if (this == b.sym) { //printf("\tfound at offset %d\n", b.offset); if (poffset) { *poffset = b.offset; } return true; } if (isBaseOf(b, poffset)) { return true; } } if (poffset) *poffset = 0; return false; } /******************************************* */ override const(char)* kind() const { return "interface"; } /**************************************** * Determine if slot 0 of the vtbl[] is reserved for something else. * For class objects, yes, this is where the ClassInfo ptr goes. * For COM interfaces, no. * For non-COM interfaces, yes, this is where the Interface ptr goes. */ override int vtblOffset() const { if (isCOMinterface() || isCPPinterface()) return 0; return 1; } override bool isCPPinterface() const { return classKind == ClassKind.cpp; } override bool isCOMinterface() const { return com; } override inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/ddoc/default_ddoc_theme.ddoc ================================================ LPAREN = ( RPAREN = ) BACKTICK = ` DOLLAR = $ LF = $(LF) ESCAPES = //>/ /&/&/ B = $0 I = $0 U = $0 P =

$0

DL =
$0
DT =
$0
DD =
$0
TABLE = $0
TR = $0 TH = $0 TD = $0 OL =
    $0
UL =
    $0
LI =
  • $0
  • BIG = $0 SMALL = $0 BR =
    LINK = $0 LINK2 = $+ DEPRECATED = $0 RED = $0 BLUE = $0 GREEN = $0 YELLOW = $0 BLACK = $0 WHITE = $0 D_CODE =
    1. $0
    D_INLINECODE = $0 DDOC_BACKQUOTED = $(D_INLINECODE $0) D_COMMENT = $0 D_STRING = $0 D_KEYWORD = $0 D_PSYMBOL = $0 D_PARAM = $0 DDOC_BLANKLINE =

    DDOC_COMMENT = DDOC = $(TITLE)

    $(TITLE)

    $(BODY)
    $(LF) DDOC_MODULE_MEMBERS =
    $(DDOC_MEMBERS $0)
    $(LF) DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)$(LF) DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)$(LF) DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)$(LF) DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)$(LF) DDOC_MEMBERS =
      $0
    DDOC_MEMBER =
  • $0
  • DDOC_MEMBER_HEADER =
    $0
    DDOC_HEADER_ANCHOR =
    $2
    DDOC_DECL =

    Declaration

    $0

    DDOC_ANCHOR = DDOC_DECL_DD =
    $0
    DDOC_SECTIONS =
    $0
    $(LF) DDOC_SUMMARY =

    $0

    $(LF) DDOC_DESCRIPTION =

    Discussion

    $0

    $(LF) DDOC_EXAMPLES =

    Examples

    $0

    DDOC_RETURNS =

    Return Value

    $0

    $(LF) DDOC_PARAMS =

    Parameters

    $0
    $(LF) DDOC_PARAM_ROW = $0 $(LF) DDOC_PARAM_ID = $0 $(LF) DDOC_PARAM_DESC =

    $0

    DDOC_LICENSE =

    License

    $0

    $(LF) DDOC_AUTHORS =

    Authors

    $0

    $(LF) DDOC_BUGS =

    Bugs

    $0

    $(LF) DDOC_COPYRIGHT = $(LF) DDOC_DATE =

    Date

    $0

    $(LF) DDOC_DEPRECATED =

    Deprecated

    $0

    $(LF) DDOC_HISTORY =

    History

    $0

    $(LF) DDOC_SEE_ALSO =

    See Also

    $0

    $(LF) DDOC_STANDARDS =

    Standards

    $0

    DDOC_THROWS =

    Throws

    $0

    DDOC_VERSION =

    Version

    $0

    DDOC_SECTION =

    $0

    $(LF) DDOC_SECTION_H = $0:$(LF) DDOC_DITTO =
    $0 DDOC_PSYMBOL = $0 DDOC_ENUM_BASETYPE = $0 DDOC_PSUPER_SYMBOL = $0 DDOC_KEYWORD = $0 DDOC_PARAM = $0 DDOC_CONSTRAINT = $(DDOC_CONSTRAINT) if ($0) DDOC_OVERLOAD_SEPARATOR = $0 DDOC_TEMPLATE_PARAM_LIST = $0 DDOC_TEMPLATE_PARAM = $0 DDOC_LINK_AUTODETECT = $(LINK $0) DDOC_AUTO_PSYMBOL = $(DDOC_PSYMBOL $0) DDOC_AUTO_KEYWORD = $(DDOC_KEYWORD $0) DDOC_AUTO_PARAM = $(DDOC_PARAM $0) DDOC_AUTO_PSYMBOL_SUPPRESS = $0 ================================================ FILE: gcc/d/dmd/declaration.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/declaration.d, _declaration.d) * Documentation: https://dlang.org/phobos/dmd_declaration.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/declaration.d */ module dmd.declaration; import core.stdc.stdio; import dmd.aggregate; import dmd.arraytypes; import dmd.ctorflow; import dmd.dclass; import dmd.delegatize; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.intrange; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; /************************************ * Check to see the aggregate type is nested and its context pointer is * accessible from the current scope. * Returns true if error occurs. */ bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0) { Dsymbol sparent = ad.toParent2(); Dsymbol s = sc.func; if (ad.isNested() && s) { //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent); //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars()); if (!ensureStaticLinkTo(s, sparent)) { error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars()); return true; } } bool result = false; for (size_t i = iStart; i < ad.fields.dim; i++) { VarDeclaration vd = ad.fields[i]; Type tb = vd.type.baseElemOf(); if (tb.ty == Tstruct) { result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym); } } return result; } /*********************************************** * Mark variable v as modified if it is inside a constructor that var * is a field in. */ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1) { //printf("modifyFieldVar(var = %s)\n", var.toChars()); Dsymbol s = sc.func; while (1) { FuncDeclaration fd = null; if (s) fd = s.isFuncDeclaration(); if (fd && ((fd.isCtorDeclaration() && var.isField()) || (fd.isStaticCtorDeclaration() && !var.isField())) && fd.toParent2() == var.toParent2() && (!e1 || e1.op == TOK.this_)) { bool result = true; var.ctorinit = true; //printf("setting ctorinit\n"); if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof) { assert(e1); auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 || var.type.needsNested()); const dim = sc.ctorflow.fieldinit.length; auto ad = fd.isMember2(); assert(ad); size_t i; for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ? { if (ad.fields[i] == var) break; } assert(i < dim); auto fieldInit = &sc.ctorflow.fieldinit[i]; const fi = fieldInit.csx; if (fi & CSX.this_ctor) { if (var.type.isMutable() && e1.type.isMutable()) result = false; else { const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod); // Deprecated in 2018-04. // Change to error in 2019-04 by deleting the following // if-branch and the deprecate_18719 enum member in the // dmd.ctorflow.CSX enum. // @@@DEPRECATED_2019-01@@@. if (fi & CSX.deprecate_18719) { .deprecation(loc, "%s field `%s` was initialized in a previous constructor call", modStr, var.toChars()); } else { .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars()); .errorSupplemental(fieldInit.loc, "Previous initialization is here."); } } } else if (sc.inLoop || (fi & CSX.label)) { if (!mustInit && var.type.isMutable() && e1.type.isMutable()) result = false; else { const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod); .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars()); } } fieldInit.csx |= CSX.this_ctor; fieldInit.loc = e1.loc; if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258 { foreach (j, v; ad.fields) { if (v is var || !var.isOverlappedWith(v)) continue; v.ctorinit = true; sc.ctorflow.fieldinit[j].csx = CSX.this_ctor; } } } else if (fd != sc.func) { if (var.type.isMutable()) result = false; else if (sc.func.fes) { const(char)* p = var.isField() ? "field" : var.kind(); .error(loc, "%s %s `%s` initialization is not allowed in foreach loop", MODtoChars(var.type.mod), p, var.toChars()); } else { const(char)* p = var.isField() ? "field" : var.kind(); .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`", MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars()); } } return result; } else { if (s) { s = s.toParent2(); continue; } } break; } return false; } /****************************************** */ extern (C++) void ObjectNotFound(Identifier id) { error(Loc.initial, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars()); fatal(); } enum STC : long { undefined_ = 0L, static_ = (1L << 0), extern_ = (1L << 1), const_ = (1L << 2), final_ = (1L << 3), abstract_ = (1L << 4), parameter = (1L << 5), field = (1L << 6), override_ = (1L << 7), auto_ = (1L << 8), synchronized_ = (1L << 9), deprecated_ = (1L << 10), in_ = (1L << 11), // in parameter out_ = (1L << 12), // out parameter lazy_ = (1L << 13), // lazy parameter foreach_ = (1L << 14), // variable for foreach loop //(1L << 15) variadic = (1L << 16), // the 'variadic' parameter in: T foo(T a, U b, V variadic...) ctorinit = (1L << 17), // can only be set inside constructor templateparameter = (1L << 18), // template parameter scope_ = (1L << 19), immutable_ = (1L << 20), ref_ = (1L << 21), init = (1L << 22), // has explicit initializer manifest = (1L << 23), // manifest constant nodtor = (1L << 24), // don't run destructor nothrow_ = (1L << 25), // never throws exceptions pure_ = (1L << 26), // pure function tls = (1L << 27), // thread local alias_ = (1L << 28), // alias parameter shared_ = (1L << 29), // accessible from multiple threads gshared = (1L << 30), // accessible from multiple threads, but not typed as "shared" wild = (1L << 31), // for "wild" type constructor property = (1L << 32), safe = (1L << 33), trusted = (1L << 34), system = (1L << 35), ctfe = (1L << 36), // can be used in CTFE, even if it is static disable = (1L << 37), // for functions that are not callable result = (1L << 38), // for result variables passed to out contracts nodefaultctor = (1L << 39), // must be set inside constructor temp = (1L << 40), // temporary variable rvalue = (1L << 41), // force rvalue for variables nogc = (1L << 42), // @nogc volatile_ = (1L << 43), // destined for volatile in the back end return_ = (1L << 44), // 'return ref' or 'return scope' for function parameters autoref = (1L << 45), // Mark for the already deduced 'auto ref' parameter inference = (1L << 46), // do attribute inference exptemp = (1L << 47), // temporary variable that has lifetime restricted to an expression maybescope = (1L << 48), // parameter might be 'scope' scopeinferred = (1L << 49), // 'scope' has been inferred and should not be part of mangling future = (1L << 50), // introducing new base class function local = (1L << 51), // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.safe | STC.trusted | STC.system), } enum STCStorageClass = (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ | STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.future | STC.override_ | STC.lazy_ | STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ | STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls | STC.gshared | STC.property | STC.safe | STC.trusted | STC.system | STC.disable | STC.local); struct Match { int count; // number of matches found MATCH last; // match level of lastf FuncDeclaration lastf; // last matching function we found FuncDeclaration nextf; // current matching function FuncDeclaration anyf; // pick a func, any func, to use for error recovery } /*********************************************************** */ extern (C++) abstract class Declaration : Dsymbol { Type type; Type originalType; // before semantic analysis StorageClass storage_class; Prot protection; LINK linkage; int inuse; // used to detect cycles // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; final extern (D) this(Identifier id) { super(id); storage_class = STC.undefined_; protection = Prot(Prot.Kind.undefined); linkage = LINK.default_; } override const(char)* kind() const { return "declaration"; } override final d_uns64 size(const ref Loc loc) { assert(type); return type.size(); } /** * Issue an error if an attempt to call a disabled method is made * * If the declaration is disabled but inside a disabled function, * returns `true` but do not issue an error message. * * Params: * loc = Location information of the call * sc = Scope in which the call occurs * isAliasedDeclaration = if `true` searches overload set * * Returns: * `true` if this `Declaration` is `@disable`d, `false` otherwise. */ extern (D) final bool checkDisabled(Loc loc, Scope* sc, bool isAliasedDeclaration = false) { if (storage_class & STC.disable) { if (!(sc.func && sc.func.storage_class & STC.disable)) { auto p = toParent(); if (p && isPostBlitDeclaration()) p.error(loc, "is not copyable because it is annotated with `@disable`"); else { // if the function is @disabled, maybe there // is an overload in the overload set that isn't if (isAliasedDeclaration) { FuncDeclaration fd = isFuncDeclaration(); if (fd) { for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext) if (!(ovl.storage_class & STC.disable)) return false; } } error(loc, "cannot be used because it is annotated with `@disable`"); } } return true; } return false; } /************************************* * Check to see if declaration can be modified in this context (sc). * Issue error if not. */ extern (D) final int checkModify(Loc loc, Scope* sc, Expression e1, int flag) { VarDeclaration v = isVarDeclaration(); if (v && v.canassign) return 2; if (isParameter() || isResult()) { for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx.func == parent && (scx.flags & SCOPE.contract)) { const(char)* s = isParameter() && parent.ident != Id.ensure ? "parameter" : "result"; if (!flag) error(loc, "cannot modify %s `%s` in contract", s, toChars()); return 2; // do not report type related errors } } } if (e1 && e1.op == TOK.this_ && isField()) { VarDeclaration vthis = (cast(ThisExp)e1).var; for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx.func == vthis.parent && (scx.flags & SCOPE.contract)) { if (!flag) error(loc, "cannot modify parameter 'this' in contract"); return 2; // do not report type related errors } } } if (v && (isCtorinit() || isField())) { // It's only modifiable if inside the right constructor if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_)) return 2; return modifyFieldVar(loc, sc, v, e1) ? 2 : 1; } return 1; } override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { Dsymbol s = Dsymbol.search(loc, ident, flags); if (!s && type) { s = type.toDsymbol(_scope); if (s) s = s.search(loc, ident, flags); } return s; } final bool isStatic() const pure nothrow @nogc @safe { return (storage_class & STC.static_) != 0; } bool isDelete() { return false; } bool isDataseg() { return false; } bool isThreadlocal() { return false; } bool isCodeseg() const pure nothrow @nogc @safe { return false; } final bool isCtorinit() const pure nothrow @nogc @safe { return (storage_class & STC.ctorinit) != 0; } final bool isFinal() const pure nothrow @nogc @safe { return (storage_class & STC.final_) != 0; } bool isAbstract() { return (storage_class & STC.abstract_) != 0; } final bool isConst() const pure nothrow @nogc @safe { return (storage_class & STC.const_) != 0; } final bool isImmutable() const pure nothrow @nogc @safe { return (storage_class & STC.immutable_) != 0; } final bool isWild() const pure nothrow @nogc @safe { return (storage_class & STC.wild) != 0; } final bool isAuto() const pure nothrow @nogc @safe { return (storage_class & STC.auto_) != 0; } final bool isScope() const pure nothrow @nogc @safe { return (storage_class & STC.scope_) != 0; } final bool isSynchronized() const pure nothrow @nogc @safe { return (storage_class & STC.synchronized_) != 0; } final bool isParameter() const pure nothrow @nogc @safe { return (storage_class & STC.parameter) != 0; } override final bool isDeprecated() pure nothrow @nogc @safe { return (storage_class & STC.deprecated_) != 0; } final bool isDisabled() const pure nothrow @nogc @safe { return (storage_class & STC.disable) != 0; } final bool isOverride() const pure nothrow @nogc @safe { return (storage_class & STC.override_) != 0; } final bool isResult() const pure nothrow @nogc @safe { return (storage_class & STC.result) != 0; } final bool isField() const pure nothrow @nogc @safe { return (storage_class & STC.field) != 0; } final bool isIn() const pure nothrow @nogc @safe { return (storage_class & STC.in_) != 0; } final bool isOut() const pure nothrow @nogc @safe { return (storage_class & STC.out_) != 0; } final bool isRef() const pure nothrow @nogc @safe { return (storage_class & STC.ref_) != 0; } final bool isFuture() const pure nothrow @nogc @safe { return (storage_class & STC.future) != 0; } override final Prot prot() pure nothrow @nogc @safe { return protection; } override final inout(Declaration) isDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TupleDeclaration : Declaration { Objects* objects; bool isexp; // true: expression tuple TypeTuple tupletype; // !=null if this is a type tuple extern (D) this(const ref Loc loc, Identifier id, Objects* objects) { super(id); this.loc = loc; this.objects = objects; } override Dsymbol syntaxCopy(Dsymbol s) { assert(0); } override const(char)* kind() const { return "tuple"; } override Type getType() { /* If this tuple represents a type, return that type */ //printf("TupleDeclaration::getType() %s\n", toChars()); if (isexp) return null; if (!tupletype) { /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects.dim; i++) { RootObject o = (*objects)[i]; if (o.dyncast() != DYNCAST.type) { //printf("\tnot[%d], %p, %d\n", i, o, o.dyncast()); return null; } } /* We know it's a type tuple, so build the TypeTuple */ Types* types = cast(Types*)objects; auto args = new Parameters(objects.dim); OutBuffer buf; int hasdeco = 1; for (size_t i = 0; i < types.dim; i++) { Type t = (*types)[i]; //printf("type = %s\n", t.toChars()); version (none) { buf.printf("_%s_%d", ident.toChars(), i); const len = buf.offset; const name = cast(const(char)*)buf.extractData(); auto id = Identifier.idPool(name, len); auto arg = new Parameter(STC.in_, t, id, null); } else { auto arg = new Parameter(0, t, null, null, null); } (*args)[i] = arg; if (!t.deco) hasdeco = 0; } tupletype = new TypeTuple(args); if (hasdeco) return tupletype.typeSemantic(Loc.initial, null); } return tupletype; } override Dsymbol toAlias2() { //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects.toChars()); for (size_t i = 0; i < objects.dim; i++) { RootObject o = (*objects)[i]; if (Dsymbol s = isDsymbol(o)) { s = s.toAlias2(); (*objects)[i] = s; } } return this; } override bool needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects.dim; i++) { RootObject o = (*objects)[i]; if (o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; if (e.op == TOK.dSymbol) { DsymbolExp ve = cast(DsymbolExp)e; Declaration d = ve.s.isDeclaration(); if (d && d.needThis()) { return true; } } } } return false; } override inout(TupleDeclaration) isTupleDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AliasDeclaration : Declaration { Dsymbol aliassym; Dsymbol overnext; // next in overload list Dsymbol _import; // !=null if unresolved internal alias for selective import extern (D) this(const ref Loc loc, Identifier id, Type type) { super(id); //printf("AliasDeclaration(id = '%s', type = %p)\n", id.toChars(), type); //printf("type = '%s'\n", type.toChars()); this.loc = loc; this.type = type; assert(type); } extern (D) this(const ref Loc loc, Identifier id, Dsymbol s) { super(id); //printf("AliasDeclaration(id = '%s', s = %p)\n", id.toChars(), s); assert(s != this); this.loc = loc; this.aliassym = s; assert(s); } static AliasDeclaration create(Loc loc, Identifier id, Type type) { return new AliasDeclaration(loc, id, type); } override Dsymbol syntaxCopy(Dsymbol s) { //printf("AliasDeclaration::syntaxCopy()\n"); assert(!s); AliasDeclaration sa = type ? new AliasDeclaration(loc, ident, type.syntaxCopy()) : new AliasDeclaration(loc, ident, aliassym.syntaxCopy(null)); sa.storage_class = storage_class; return sa; } override bool overloadInsert(Dsymbol s) { //printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n", // loc.toChars(), toChars(), s.kind(), s.toChars(), s.loc.toChars()); /** Aliases aren't overloadable themselves, but if their Aliasee is * overloadable they are converted to an overloadable Alias (either * FuncAliasDeclaration or OverDeclaration). * * This is done by moving the Aliasee into such an overloadable alias * which is then used to replace the existing Aliasee. The original * Alias (_this_) remains a useless shell. * * This is a horrible mess. It was probably done to avoid replacing * existing AST nodes and references, but it needs a major * simplification b/c it's too complex to maintain. * * A simpler approach might be to merge any colliding symbols into a * simple Overload class (an array) and then later have that resolve * all collisions. */ if (semanticRun >= PASS.semanticdone) { /* Semantic analysis is already finished, and the aliased entity * is not overloadable. */ if (type) return false; /* When s is added in member scope by static if, mixin("code") or others, * aliassym is determined already. See the case in: test/compilable/test61.d */ auto sa = aliassym.toAlias(); if (auto fd = sa.isFuncDeclaration()) { auto fa = new FuncAliasDeclaration(ident, fd); fa.protection = protection; fa.parent = parent; aliassym = fa; return aliassym.overloadInsert(s); } if (auto td = sa.isTemplateDeclaration()) { auto od = new OverDeclaration(ident, td); od.protection = protection; od.parent = parent; aliassym = od; return aliassym.overloadInsert(s); } if (auto od = sa.isOverDeclaration()) { if (sa.ident != ident || sa.parent != parent) { od = new OverDeclaration(ident, od); od.protection = protection; od.parent = parent; aliassym = od; } return od.overloadInsert(s); } if (auto os = sa.isOverloadSet()) { if (sa.ident != ident || sa.parent != parent) { os = new OverloadSet(ident, os); // TODO: protection is lost here b/c OverloadSets have no protection attribute // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow. // ---- // module os1; // import a, b; // private alias merged = foo; // private alias to overload set of a.foo and b.foo // ---- // module os2; // import a, b; // public alias merged = bar; // public alias to overload set of a.bar and b.bar // ---- // module bug; // import os1, os2; // void test() { merged(123); } // should only look at os2.merged // // os.protection = protection; os.parent = parent; aliassym = os; } os.push(s); return true; } return false; } /* Don't know yet what the aliased symbol is, so assume it can * be overloaded and check later for correctness. */ if (overnext) return overnext.overloadInsert(s); if (s is this) return true; overnext = s; return true; } override const(char)* kind() const { return "alias"; } override Type getType() { if (type) return type; return toAlias().getType(); } override Dsymbol toAlias() { //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n", // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse); assert(this != aliassym); //static int count; if (++count == 10) *(char*)0=0; if (inuse == 1 && type && _scope) { inuse = 2; uint olderrors = global.errors; Dsymbol s = type.toDsymbol(_scope); //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type.toChars(), s, this); if (global.errors != olderrors) goto Lerr; if (s) { s = s.toAlias(); if (global.errors != olderrors) goto Lerr; aliassym = s; inuse = 0; } else { Type t = type.typeSemantic(loc, _scope); if (t.ty == Terror) goto Lerr; if (global.errors != olderrors) goto Lerr; //printf("t = %s\n", t.toChars()); inuse = 0; } } if (inuse) { error("recursive alias declaration"); Lerr: // Avoid breaking "recursive alias" state during errors gagged if (global.gag) return this; aliassym = new AliasDeclaration(loc, ident, Type.terror); type = Type.terror; return aliassym; } if (semanticRun >= PASS.semanticdone) { // semantic is already done. // Do not see aliassym !is null, because of lambda aliases. // Do not see type.deco !is null, even so "alias T = const int;` needs // semantic analysis to take the storage class `const` as type qualifier. } else { if (_import && _import._scope) { /* If this is an internal alias for selective/renamed import, * load the module first. */ _import.dsymbolSemantic(null); } if (_scope) { aliasSemantic(this, _scope); } } inuse = 1; Dsymbol s = aliassym ? aliassym.toAlias() : this; inuse = 0; return s; } override Dsymbol toAlias2() { if (inuse) { error("recursive alias declaration"); return this; } inuse = 1; Dsymbol s = aliassym ? aliassym.toAlias2() : this; inuse = 0; return s; } override bool isOverloadable() { // assume overloadable until alias is resolved return semanticRun < PASS.semanticdone || aliassym && aliassym.isOverloadable(); } override inout(AliasDeclaration) isAliasDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class OverDeclaration : Declaration { Dsymbol overnext; // next in overload list Dsymbol aliassym; bool hasOverloads; extern (D) this(Identifier ident, Dsymbol s, bool hasOverloads = true) { super(ident); this.aliassym = s; this.hasOverloads = hasOverloads; if (hasOverloads) { if (OverDeclaration od = aliassym.isOverDeclaration()) this.hasOverloads = od.hasOverloads; } else { // for internal use assert(!aliassym.isOverDeclaration()); } } override const(char)* kind() const { return "overload alias"; // todo } override bool equals(RootObject o) { if (this == o) return true; Dsymbol s = isDsymbol(o); if (!s) return false; OverDeclaration od1 = this; if (OverDeclaration od2 = s.isOverDeclaration()) { return od1.aliassym.equals(od2.aliassym) && od1.hasOverloads == od2.hasOverloads; } if (aliassym == s) { if (hasOverloads) return true; if (FuncDeclaration fd = s.isFuncDeclaration()) { return fd.isUnique() !is null; } if (TemplateDeclaration td = s.isTemplateDeclaration()) { return td.overnext is null; } } return false; } override bool overloadInsert(Dsymbol s) { //printf("OverDeclaration::overloadInsert('%s') aliassym = %p, overnext = %p\n", s.toChars(), aliassym, overnext); if (overnext) return overnext.overloadInsert(s); if (s == this) return true; overnext = s; return true; } override bool isOverloadable() { return true; } Dsymbol isUnique() { if (!hasOverloads) { if (aliassym.isFuncDeclaration() || aliassym.isTemplateDeclaration()) { return aliassym; } } Dsymbol result = null; overloadApply(aliassym, (Dsymbol s) { if (result) { result = null; return 1; // ambiguous, done } else { result = s; return 0; } }); return result; } override inout(OverDeclaration) isOverDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class VarDeclaration : Declaration { Initializer _init; uint offset; uint sequenceNumber; // order the variables are declared __gshared uint nextSequenceNumber; // the counter for sequenceNumber FuncDeclarations nestedrefs; // referenced by these lexically nested functions structalign_t alignment; bool isargptr; // if parameter that _argptr points to bool ctorinit; // it has been initialized in a ctor bool iscatchvar; // this is the exception object variable in catch() clause // Both these mean the var is not rebindable once assigned, // and the destructor gets run when it goes out of scope bool onstack; // it is a class that was allocated on the stack bool mynew; // it is a class new'd with custom operator new int canassign; // it can be assigned to bool overlapped; // if it is a field and has overlapping bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe bool doNotInferScope; // do not infer 'scope' for this variable ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false Dsymbol aliassym; // if redone as alias to another symbol VarDeclaration lastVar; // Linked list of variables for goto-skips-init detection uint endlinnum; // line number of end of scope that this var lives in // When interpreting, these point to the value (NULL if value not determinable) // The index of this variable on the CTFE stack, -1 if not allocated int ctfeAdrOnStack; Expression edtor; // if !=null, does the destruction of the variable IntRange* range; // if !=null, the variable is known to be within the range VarDeclarations* maybes; // STC.maybescope variables that are assigned to this STC.maybescope variable final extern (D) this(const ref Loc loc, Type type, Identifier id, Initializer _init, StorageClass storage_class = STC.undefined_) { super(id); //printf("VarDeclaration('%s')\n", id.toChars()); assert(id); debug { if (!type && !_init) { //printf("VarDeclaration('%s')\n", id.toChars()); //*(char*)0=0; } } assert(type || _init); this.type = type; this._init = _init; this.loc = loc; ctfeAdrOnStack = -1; this.storage_class = storage_class; sequenceNumber = ++nextSequenceNumber; } override Dsymbol syntaxCopy(Dsymbol s) { //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); assert(!s); auto v = new VarDeclaration(loc, type ? type.syntaxCopy() : null, ident, _init ? _init.syntaxCopy() : null, storage_class); return v; } override final void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); if (aliassym) { // If this variable was really a tuple, set the offsets for the tuple fields TupleDeclaration v2 = aliassym.isTupleDeclaration(); assert(v2); for (size_t i = 0; i < v2.objects.dim; i++) { RootObject o = (*v2.objects)[i]; assert(o.dyncast() == DYNCAST.expression); Expression e = cast(Expression)o; assert(e.op == TOK.dSymbol); DsymbolExp se = cast(DsymbolExp)e; se.s.setFieldOffset(ad, poffset, isunion); } return; } if (!isField()) return; assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter | STC.tls))); //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); /* Fields that are tuples appear both as part of TupleDeclarations and * as members. That means ignore them if they are already a field. */ if (offset) { // already a field *poffset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 return; } for (size_t i = 0; i < ad.fields.dim; i++) { if (ad.fields[i] == this) { // already a field *poffset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 return; } } // Check for forward referenced types which will fail the size() call Type t = type.toBasetype(); if (storage_class & STC.ref_) { // References are the size of a pointer t = Type.tvoidptr; } Type tv = t.baseElemOf(); if (tv.ty == Tstruct) { auto ts = cast(TypeStruct)tv; assert(ts.sym != ad); // already checked in ad.determineFields() if (!ts.sym.determineSize(loc)) { type = Type.terror; errors = true; return; } } // List in ad.fields. Even if the type is error, it's necessary to avoid // pointless error diagnostic "more initializers than fields" on struct literal. ad.fields.push(this); if (t.ty == Terror) return; const sz = t.size(loc); assert(sz != SIZE_INVALID && sz < uint.max); uint memsize = cast(uint)sz; // size of member uint memalignsize = Target.fieldalign(t); // size of member for alignment purposes offset = AggregateDeclaration.placeField( poffset, memsize, memalignsize, alignment, &ad.structsize, &ad.alignsize, isunion); //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); } override const(char)* kind() const { return "variable"; } override final inout(AggregateDeclaration) isThis() inout { if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe))) { /* The casting is necessary because `s = s.parent` is otherwise rejected */ for (auto s = cast(Dsymbol)this; s; s = s.parent) { auto ad = (cast(inout)s).isMember(); if (ad) return ad; if (!s.parent || !s.parent.isTemplateMixin()) break; } } return null; } override final bool needThis() { //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); return isField(); } override final bool isExport() const { return protection.kind == Prot.Kind.export_; } override final bool isImportedSymbol() const { if (protection.kind == Prot.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule())) return true; return false; } /******************************* * Does symbol go into data segment? * Includes extern variables. */ override final bool isDataseg() { version (none) { printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); printf("%llx, isModule: %p, isTemplateInstance: %p, isNspace: %p\n", storage_class & (STC.static_ | STC.const_), parent.isModule(), parent.isTemplateInstance(), parent.isNspace()); printf("parent = '%s'\n", parent.toChars()); } if (isdataseg == 0) // the value is not cached { isdataseg = 2; // The Variables does not go into the datasegment if (!canTakeAddressOf()) { return false; } Dsymbol parent = toParent(); if (!parent && !(storage_class & STC.static_)) { error("forward referenced"); type = Type.terror; } else if (storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared) || parent.isModule() || parent.isTemplateInstance() || parent.isNspace()) { isdataseg = 1; // It is in the DataSegment } } return (isdataseg == 1); } /************************************ * Does symbol go into thread local storage? */ override final bool isThreadlocal() { //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); /* Data defaults to being thread-local. It is not thread-local * if it is immutable, const or shared. */ bool i = isDataseg() && !(storage_class & (STC.immutable_ | STC.const_ | STC.shared_ | STC.gshared)); //printf("\treturn %d\n", i); return i; } /******************************************** * Can variable be read and written by CTFE? */ final bool isCTFE() { return (storage_class & STC.ctfe) != 0; // || !isDataseg(); } final bool isOverlappedWith(VarDeclaration v) { const vsz = v.type.size(); const tsz = type.size(); assert(vsz != SIZE_INVALID && tsz != SIZE_INVALID); return offset < v.offset + vsz && v.offset < offset + tsz; } override final bool hasPointers() { //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type.ty); return (!isDataseg() && type.hasPointers()); } /************************************* * Return true if we can take the address of this variable. */ final bool canTakeAddressOf() { return !(storage_class & STC.manifest); } /****************************************** * Return true if variable needs to call the destructor. */ final bool needsScopeDtor() { //printf("VarDeclaration::needsScopeDtor() %s\n", toChars()); return edtor && !(storage_class & STC.nodtor); } /****************************************** * If a variable has a scope destructor call, return call for it. * Otherwise, return NULL. */ final Expression callScopeDtor(Scope* sc) { //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); // Destruction of STC.field's is handled by buildDtor() if (storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field)) { return null; } if (iscatchvar) return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here Expression e = null; // Destructors for structs and arrays of structs Type tv = type.baseElemOf(); if (tv.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)tv).sym; if (!sd.dtor || sd.errors) return null; const sz = type.size(); assert(sz != SIZE_INVALID); if (!sz) return null; if (type.toBasetype().ty == Tstruct) { // v.__xdtor() e = new VarExp(loc, this); /* This is a hack so we can call destructors on const/immutable objects. * Need to add things like "const ~this()" and "immutable ~this()" to * fix properly. */ e.type = e.type.mutableOf(); // Enable calling destructors on shared objects. // The destructor is always a single, non-overloaded function, // and must serve both shared and non-shared objects. e.type = e.type.unSharedOf; e = new DotVarExp(loc, e, sd.dtor, false); e = new CallExp(loc, e); } else { // __ArrayDtor(v[0 .. n]) e = new VarExp(loc, this); const sdsz = sd.type.size(); assert(sdsz != SIZE_INVALID && sdsz != 0); const n = sz / sdsz; e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t)); // Prevent redundant bounds check (cast(SliceExp)e).upperIsInBounds = true; (cast(SliceExp)e).lowerIsLessThanUpper = true; // This is a hack so we can call destructors on const/immutable objects. e.type = sd.type.arrayOf(); e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e); } return e; } // Destructors for classes if (storage_class & (STC.auto_ | STC.scope_) && !(storage_class & STC.parameter)) { for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass) { /* We can do better if there's a way with onstack * classes to determine if there's no way the monitor * could be set. */ //if (cd.isInterfaceDeclaration()) // error("interface `%s` cannot be scope", cd.toChars()); // Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them. // See https://issues.dlang.org/show_bug.cgi?id=13182 if (cd.classKind == ClassKind.cpp) { break; } if (mynew || onstack) // if any destructors { // delete this; Expression ec; ec = new VarExp(loc, this); e = new DeleteExp(loc, ec, true); e.type = Type.tvoid; break; } } } return e; } /******************************************* * If variable has a constant expression initializer, get it. * Otherwise, return null. */ final Expression getConstInitializer(bool needFullType = true) { assert(type && _init); // Ungag errors when not speculative uint oldgag = global.gag; if (global.gag) { Dsymbol sym = toParent().isAggregateDeclaration(); if (sym && !sym.isSpeculative()) global.gag = 0; } if (_scope) { inuse++; _init = _init.initializerSemantic(_scope, type, INITinterpret); _scope = null; inuse--; } Expression e = _init.initializerToExpression(needFullType ? type : null); global.gag = oldgag; return e; } /******************************************* * Helper function for the expansion of manifest constant. */ final Expression expandInitializer(Loc loc) { assert((storage_class & STC.manifest) && _init); auto e = getConstInitializer(); if (!e) { .error(loc, "cannot make expression out of initializer for `%s`", toChars()); return new ErrorExp(); } e = e.copy(); e.loc = loc; // for better error message return e; } override final void checkCtorConstInit() { version (none) { /* doesn't work if more than one static ctor */ if (ctorinit == 0 && isCtorinit() && !isField()) error("missing initializer in static constructor for const variable"); } } /************************************ * Check to see if this variable is actually in an enclosing function * rather than the current one. * Returns true if error occurs. */ extern (D) final bool checkNestedReference(Scope* sc, Loc loc) { //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); if (sc.intypeof == 1 || (sc.flags & SCOPE.ctfe)) return false; if (!parent || parent == sc.parent) return false; if (isDataseg() || (storage_class & STC.manifest)) return false; // The current function FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); if (!fdthis) return false; // out of function scope Dsymbol p = toParent2(); // Function literals from fdthis to p must be delegates ensureStaticLinkTo(fdthis, p); // The function that this variable is in FuncDeclaration fdv = p.isFuncDeclaration(); if (!fdv || fdv == fdthis) return false; // Add fdthis to nestedrefs[] if not already there for (size_t i = 0; 1; i++) { if (i == nestedrefs.dim) { nestedrefs.push(fdthis); break; } if (nestedrefs[i] == fdthis) break; } /* __require and __ensure will always get called directly, * so they never make outer functions closure. */ if (fdthis.ident == Id.require || fdthis.ident == Id.ensure) return false; //printf("\tfdv = %s\n", fdv.toChars()); //printf("\tfdthis = %s\n", fdthis.toChars()); if (loc.isValid()) { int lv = fdthis.getLevel(loc, sc, fdv); if (lv == -2) // error return true; } // Add this to fdv.closureVars[] if not already there if (!sc.intypeof && !(sc.flags & SCOPE.compile) && // https://issues.dlang.org/show_bug.cgi?id=17605 (fdv.flags & FUNCFLAG.compileTimeOnly || !(fdthis.flags & FUNCFLAG.compileTimeOnly)) ) { for (size_t i = 0; 1; i++) { if (i == fdv.closureVars.dim) { fdv.closureVars.push(this); break; } if (fdv.closureVars[i] == this) break; } } //printf("fdthis is %s\n", fdthis.toChars()); //printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars()); // __dollar creates problems because it isn't a real variable // https://issues.dlang.org/show_bug.cgi?id=3326 if (ident == Id.dollar) { .error(loc, "cannnot use `$` inside a function literal"); return true; } if (ident == Id.withSym) // https://issues.dlang.org/show_bug.cgi?id=1759 { ExpInitializer ez = _init.isExpInitializer(); assert(ez); Expression e = ez.exp; if (e.op == TOK.construct || e.op == TOK.blit) e = (cast(AssignExp)e).e2; return lambdaCheckForNestedRef(e, sc); } return false; } override final Dsymbol toAlias() { //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); if ((!type || !type.deco) && _scope) dsymbolSemantic(this, _scope); assert(this != aliassym); Dsymbol s = aliassym ? aliassym.toAlias() : this; return s; } // Eliminate need for dynamic_cast override final inout(VarDeclaration) isVarDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } /********************************** * Determine if `this` has a lifetime that lasts past * the destruction of `v` * Params: * v = variable to test against * Returns: * true if it does */ final bool enclosesLifetimeOf(VarDeclaration v) const pure { return sequenceNumber < v.sequenceNumber; } /*************************************** * Add variable to maybes[]. * When a maybescope variable `v` is assigned to a maybescope variable `this`, * we cannot determine if `this` is actually scope until the semantic * analysis for the function is completed. Thus, we save the data * until then. * Params: * v = an STC.maybescope variable that was assigned to `this` */ final void addMaybe(VarDeclaration v) { //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars()); if (!maybes) maybes = new VarDeclarations(); maybes.push(v); } } /*********************************************************** * This is a shell around a back end symbol */ extern (C++) final class SymbolDeclaration : Declaration { StructDeclaration dsym; extern (D) this(const ref Loc loc, StructDeclaration dsym) { super(dsym.ident); this.loc = loc; this.dsym = dsym; storage_class |= STC.const_; } // Eliminate need for dynamic_cast override inout(SymbolDeclaration) isSymbolDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class TypeInfoDeclaration : VarDeclaration { Type tinfo; final extern (D) this(Type tinfo) { super(Loc.initial, Type.dtypeinfo.type, tinfo.getTypeInfoIdent(), null); this.tinfo = tinfo; storage_class = STC.static_ | STC.gshared; protection = Prot(Prot.Kind.public_); linkage = LINK.c; alignment = Target.ptrsize; } static TypeInfoDeclaration create(Type tinfo) { return new TypeInfoDeclaration(tinfo); } override final Dsymbol syntaxCopy(Dsymbol s) { assert(0); // should never be produced by syntax } override final const(char)* toChars() { //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo.toChars()); OutBuffer buf; buf.writestring("typeid("); buf.writestring(tinfo.toChars()); buf.writeByte(')'); return buf.extractString(); } override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoStructDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfostruct) { ObjectNotFound(Id.TypeInfo_Struct); } type = Type.typeinfostruct.type; } static TypeInfoStructDeclaration create(Type tinfo) { return new TypeInfoStructDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoClassDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoclass) { ObjectNotFound(Id.TypeInfo_Class); } type = Type.typeinfoclass.type; } static TypeInfoClassDeclaration create(Type tinfo) { return new TypeInfoClassDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoInterfaceDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfointerface) { ObjectNotFound(Id.TypeInfo_Interface); } type = Type.typeinfointerface.type; } static TypeInfoInterfaceDeclaration create(Type tinfo) { return new TypeInfoInterfaceDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoPointerDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfopointer) { ObjectNotFound(Id.TypeInfo_Pointer); } type = Type.typeinfopointer.type; } static TypeInfoPointerDeclaration create(Type tinfo) { return new TypeInfoPointerDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoArrayDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoarray) { ObjectNotFound(Id.TypeInfo_Array); } type = Type.typeinfoarray.type; } static TypeInfoArrayDeclaration create(Type tinfo) { return new TypeInfoArrayDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfostaticarray) { ObjectNotFound(Id.TypeInfo_StaticArray); } type = Type.typeinfostaticarray.type; } static TypeInfoStaticArrayDeclaration create(Type tinfo) { return new TypeInfoStaticArrayDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoassociativearray) { ObjectNotFound(Id.TypeInfo_AssociativeArray); } type = Type.typeinfoassociativearray.type; } static TypeInfoAssociativeArrayDeclaration create(Type tinfo) { return new TypeInfoAssociativeArrayDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoEnumDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoenum) { ObjectNotFound(Id.TypeInfo_Enum); } type = Type.typeinfoenum.type; } static TypeInfoEnumDeclaration create(Type tinfo) { return new TypeInfoEnumDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoFunctionDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfofunction) { ObjectNotFound(Id.TypeInfo_Function); } type = Type.typeinfofunction.type; } static TypeInfoFunctionDeclaration create(Type tinfo) { return new TypeInfoFunctionDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoDelegateDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfodelegate) { ObjectNotFound(Id.TypeInfo_Delegate); } type = Type.typeinfodelegate.type; } static TypeInfoDelegateDeclaration create(Type tinfo) { return new TypeInfoDelegateDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoTupleDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfotypelist) { ObjectNotFound(Id.TypeInfo_Tuple); } type = Type.typeinfotypelist.type; } static TypeInfoTupleDeclaration create(Type tinfo) { return new TypeInfoTupleDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoConstDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoconst) { ObjectNotFound(Id.TypeInfo_Const); } type = Type.typeinfoconst.type; } static TypeInfoConstDeclaration create(Type tinfo) { return new TypeInfoConstDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoInvariantDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoinvariant) { ObjectNotFound(Id.TypeInfo_Invariant); } type = Type.typeinfoinvariant.type; } static TypeInfoInvariantDeclaration create(Type tinfo) { return new TypeInfoInvariantDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoSharedDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfoshared) { ObjectNotFound(Id.TypeInfo_Shared); } type = Type.typeinfoshared.type; } static TypeInfoSharedDeclaration create(Type tinfo) { return new TypeInfoSharedDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoWildDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfowild) { ObjectNotFound(Id.TypeInfo_Wild); } type = Type.typeinfowild.type; } static TypeInfoWildDeclaration create(Type tinfo) { return new TypeInfoWildDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeInfoVectorDeclaration : TypeInfoDeclaration { extern (D) this(Type tinfo) { super(tinfo); if (!Type.typeinfovector) { ObjectNotFound(Id.TypeInfo_Vector); } type = Type.typeinfovector.type; } static TypeInfoVectorDeclaration create(Type tinfo) { return new TypeInfoVectorDeclaration(tinfo); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * For the "this" parameter to member functions */ extern (C++) final class ThisDeclaration : VarDeclaration { extern (D) this(const ref Loc loc, Type t) { super(loc, t, Id.This, null); storage_class |= STC.nodtor; } override Dsymbol syntaxCopy(Dsymbol s) { assert(0); // should never be produced by syntax } override inout(ThisDeclaration) isThisDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/declaration.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/declaration.h */ #pragma once #include "dsymbol.h" #include "mtype.h" #include "tokens.h" class Expression; class Statement; class LabelDsymbol; class Initializer; class ForeachStatement; struct Ensure { Identifier *id; Statement *ensure; }; class FuncDeclaration; class StructDeclaration; struct CompiledCtfeFunction; struct ObjcSelector; struct IntRange; #define STCundefined 0LL #define STCstatic 1LL #define STCextern 2LL #define STCconst 4LL #define STCfinal 8LL #define STCabstract 0x10LL #define STCparameter 0x20LL #define STCfield 0x40LL #define STCoverride 0x80LL #define STCauto 0x100LL #define STCsynchronized 0x200LL #define STCdeprecated 0x400LL #define STCin 0x800LL // in parameter #define STCout 0x1000LL // out parameter #define STClazy 0x2000LL // lazy parameter #define STCforeach 0x4000LL // variable for foreach loop #define STCvariadic 0x10000LL // the 'variadic' parameter in: T foo(T a, U b, V variadic...) #define STCctorinit 0x20000LL // can only be set inside constructor #define STCtemplateparameter 0x40000LL // template parameter #define STCscope 0x80000LL #define STCimmutable 0x100000LL #define STCref 0x200000LL #define STCinit 0x400000LL // has explicit initializer #define STCmanifest 0x800000LL // manifest constant #define STCnodtor 0x1000000LL // don't run destructor #define STCnothrow 0x2000000LL // never throws exceptions #define STCpure 0x4000000LL // pure function #define STCtls 0x8000000LL // thread local #define STCalias 0x10000000LL // alias parameter #define STCshared 0x20000000LL // accessible from multiple threads // accessible from multiple threads // but not typed as "shared" #define STCgshared 0x40000000LL #define STCwild 0x80000000LL // for "wild" type constructor #define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild) #define STC_FUNCATTR (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem) #define STCproperty 0x100000000LL #define STCsafe 0x200000000LL #define STCtrusted 0x400000000LL #define STCsystem 0x800000000LL #define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static #define STCdisable 0x2000000000LL // for functions that are not callable #define STCresult 0x4000000000LL // for result variables passed to out contracts #define STCnodefaultctor 0x8000000000LL // must be set inside constructor #define STCtemp 0x10000000000LL // temporary variable #define STCrvalue 0x20000000000LL // force rvalue for variables #define STCnogc 0x40000000000LL // @nogc #define STCvolatile 0x80000000000LL // destined for volatile in the back end #define STCreturn 0x100000000000LL // 'return ref' or 'return scope' for function parameters #define STCautoref 0x200000000000LL // Mark for the already deduced 'auto ref' parameter #define STCinference 0x400000000000LL // do attribute inference #define STCexptemp 0x800000000000LL // temporary variable that has lifetime restricted to an expression #define STCmaybescope 0x1000000000000LL // parameter might be 'scope' #define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling #define STCfuture 0x4000000000000LL // introducing new base class function #define STClocal 0x8000000000000LL // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). void ObjectNotFound(Identifier *id); /**************************************************************/ class Declaration : public Dsymbol { public: Type *type; Type *originalType; // before semantic analysis StorageClass storage_class; Prot protection; LINK linkage; int inuse; // used to detect cycles DArray mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const; d_uns64 size(const Loc &loc); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); bool isStatic() const { return (storage_class & STCstatic) != 0; } virtual bool isDelete(); virtual bool isDataseg(); virtual bool isThreadlocal(); virtual bool isCodeseg() const; bool isCtorinit() const { return (storage_class & STCctorinit) != 0; } bool isFinal() const { return (storage_class & STCfinal) != 0; } virtual bool isAbstract() { return (storage_class & STCabstract) != 0; } bool isConst() const { return (storage_class & STCconst) != 0; } bool isImmutable() const { return (storage_class & STCimmutable) != 0; } bool isWild() const { return (storage_class & STCwild) != 0; } bool isAuto() const { return (storage_class & STCauto) != 0; } bool isScope() const { return (storage_class & STCscope) != 0; } bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; } bool isParameter() const { return (storage_class & STCparameter) != 0; } bool isDeprecated() { return (storage_class & STCdeprecated) != 0; } bool isOverride() const { return (storage_class & STCoverride) != 0; } bool isResult() const { return (storage_class & STCresult) != 0; } bool isField() const { return (storage_class & STCfield) != 0; } bool isIn() const { return (storage_class & STCin) != 0; } bool isOut() const { return (storage_class & STCout) != 0; } bool isRef() const { return (storage_class & STCref) != 0; } bool isFuture() const { return (storage_class & STCfuture) != 0; } Prot prot(); Declaration *isDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ class TupleDeclaration : public Declaration { public: Objects *objects; bool isexp; // true: expression tuple TypeTuple *tupletype; // !=NULL if this is a type tuple Dsymbol *syntaxCopy(Dsymbol *); const char *kind() const; Type *getType(); Dsymbol *toAlias2(); bool needThis(); TupleDeclaration *isTupleDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ class AliasDeclaration : public Declaration { public: Dsymbol *aliassym; Dsymbol *overnext; // next in overload list Dsymbol *_import; // !=NULL if unresolved internal alias for selective import static AliasDeclaration *create(Loc loc, Identifier *id, Type *type); Dsymbol *syntaxCopy(Dsymbol *); bool overloadInsert(Dsymbol *s); const char *kind() const; Type *getType(); Dsymbol *toAlias(); Dsymbol *toAlias2(); bool isOverloadable(); AliasDeclaration *isAliasDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ class OverDeclaration : public Declaration { public: Dsymbol *overnext; // next in overload list Dsymbol *aliassym; bool hasOverloads; const char *kind() const; bool equals(RootObject *o); bool overloadInsert(Dsymbol *s); Dsymbol *toAlias(); Dsymbol *isUnique(); bool isOverloadable(); OverDeclaration *isOverDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ class VarDeclaration : public Declaration { public: Initializer *_init; unsigned offset; unsigned sequenceNumber; // order the variables are declared FuncDeclarations nestedrefs; // referenced by these lexically nested functions structalign_t alignment; bool isargptr; // if parameter that _argptr points to bool ctorinit; // it has been initialized in a ctor bool iscatchvar; // this is the exception object variable in catch() clause bool onstack; // it is a class that was allocated on the stack bool mynew; // it is a class new'd with custom operator new int canassign; // it can be assigned to bool overlapped; // if it is a field and has overlapping bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe bool doNotInferScope; // do not infer 'scope' for this variable unsigned char isdataseg; // private data for isDataseg Dsymbol *aliassym; // if redone as alias to another symbol VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection unsigned endlinnum; // line number of end of scope that this var lives in // When interpreting, these point to the value (NULL if value not determinable) // The index of this variable on the CTFE stack, -1 if not allocated int ctfeAdrOnStack; Expression *edtor; // if !=NULL, does the destruction of the variable IntRange *range; // if !NULL, the variable is known to be within the range VarDeclarations *maybes; // STCmaybescope variables that are assigned to this STCmaybescope variable Dsymbol *syntaxCopy(Dsymbol *); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *kind() const; AggregateDeclaration *isThis(); bool needThis(); bool isExport() const; bool isImportedSymbol() const; bool isDataseg(); bool isThreadlocal(); bool isCTFE(); bool isOverlappedWith(VarDeclaration *v); bool hasPointers(); bool canTakeAddressOf(); bool needsScopeDtor(); bool enclosesLifetimeOf(VarDeclaration *v) const; Expression *callScopeDtor(Scope *sc); Expression *getConstInitializer(bool needFullType = true); Expression *expandInitializer(Loc loc); void checkCtorConstInit(); Dsymbol *toAlias(); // Eliminate need for dynamic_cast VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ // This is a shell around a back end symbol class SymbolDeclaration : public Declaration { public: StructDeclaration *dsym; // Eliminate need for dynamic_cast SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } void accept(Visitor *v) { v->visit(this); } }; class TypeInfoDeclaration : public VarDeclaration { public: Type *tinfo; static TypeInfoDeclaration *create(Type *tinfo); Dsymbol *syntaxCopy(Dsymbol *); const char *toChars(); TypeInfoDeclaration *isTypeInfoDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class TypeInfoStructDeclaration : public TypeInfoDeclaration { public: static TypeInfoStructDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoClassDeclaration : public TypeInfoDeclaration { public: static TypeInfoClassDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration { public: static TypeInfoInterfaceDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoPointerDeclaration : public TypeInfoDeclaration { public: static TypeInfoPointerDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoArrayDeclaration : public TypeInfoDeclaration { public: static TypeInfoArrayDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration { public: static TypeInfoStaticArrayDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration { public: static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoEnumDeclaration : public TypeInfoDeclaration { public: static TypeInfoEnumDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoFunctionDeclaration : public TypeInfoDeclaration { public: static TypeInfoFunctionDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoDelegateDeclaration : public TypeInfoDeclaration { public: static TypeInfoDelegateDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoTupleDeclaration : public TypeInfoDeclaration { public: static TypeInfoTupleDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoConstDeclaration : public TypeInfoDeclaration { public: static TypeInfoConstDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoInvariantDeclaration : public TypeInfoDeclaration { public: static TypeInfoInvariantDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoSharedDeclaration : public TypeInfoDeclaration { public: static TypeInfoSharedDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoWildDeclaration : public TypeInfoDeclaration { public: static TypeInfoWildDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; class TypeInfoVectorDeclaration : public TypeInfoDeclaration { public: static TypeInfoVectorDeclaration *create(Type *tinfo); void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ class ThisDeclaration : public VarDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); ThisDeclaration *isThisDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; enum ILS { ILSuninitialized, // not computed yet ILSno, // cannot inline ILSyes // can inline }; /**************************************************************/ enum BUILTIN { BUILTINunknown = -1, // not known if this is a builtin BUILTINno, // this is not a builtin BUILTINyes // this is a builtin }; Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments); BUILTIN isBuiltin(FuncDeclaration *fd); typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments); void add_builtin(const char *mangle, builtin_fp fp); void builtin_init(); class FuncDeclaration : public Declaration { public: Types *fthrows; // Array of Type's of exceptions (not used) Statements *frequires; // in contracts Ensures *fensures; // out contracts Statement *frequire; // lowered in contract Statement *fensure; // lowered out contract Statement *fbody; FuncDeclarations foverrides; // functions this function overrides FuncDeclaration *fdrequire; // function that does the in contract FuncDeclaration *fdensure; // function that does the out contract const char *mangleString; // mangled symbol created from mangleExact() 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) VarDeclaration *v_arguments; // '_arguments' parameter ObjcSelector* selector; // Objective-C method selector (member function only) VarDeclaration *v_argptr; // '_argptr' variable VarDeclarations *parameters; // Array of VarDeclaration's for parameters DsymbolTable *labtab; // statement label symbol table Dsymbol *overnext; // next in overload list FuncDeclaration *overnext0; // next in overload list (only used during IFTI) Loc endloc; // location of closing curly bracket int vtblIndex; // for member functions, index into vtbl[] bool naked; // true if naked bool generated; // true if function was generated by the compiler rather than // supplied by the user ILS inlineStatusStmt; ILS inlineStatusExp; PINLINE inlining; CompiledCtfeFunction *ctfeCode; // Compiled code for interpreter int inlineNest; // !=0 if nested inline bool isArrayOp; // true if array operation bool eh_none; /// true if no exception unwinding is needed // true if errors in semantic3 this function's frame ptr bool semantic3Errors; ForeachStatement *fes; // if foreach body, this is the foreach BaseClass* interfaceVirtual; // if virtual, but only appears in interface vtbl[] bool introducing; // true if 'introducing' function // if !=NULL, then this is the type // of the 'introducing' function // this one is overriding Type *tintro; bool inferRetType; // true if return type is to be inferred StorageClass storage_class2; // storage class for template onemember's // Things that should really go into Scope // 1 if there's a return exp; statement // 2 if there's a throw statement // 4 if there's an assert(0) // 8 if there's inline asm // 16 if there are multiple return statements int hasReturnExp; // Support for NRVO (named return value optimization) bool nrvo_can; // true means we can do it VarDeclaration *nrvo_var; // variable to replace with shidden Symbol *shidden; // hidden pointer passed to function ReturnStatements *returns; GotoStatements *gotos; // Gotos with forward references // set if this is a known, builtin function we can evaluate at compile time BUILTIN builtin; // set if someone took the address of this function int tookAddressOf; bool requiresClosure; // this function needs a closure // local variables in this function which are referenced by nested functions VarDeclarations closureVars; // Sibling nested functions which called this one FuncDeclarations siblingCallers; FuncDeclarations *inlinedNestedCallees; unsigned flags; // FUNCFLAGxxxxx static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type); Dsymbol *syntaxCopy(Dsymbol *); bool functionSemantic(); bool functionSemantic3(); // called from semantic3 VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); bool equals(RootObject *o); int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349 = true); BaseClass *overrideInterface(); bool overloadInsert(Dsymbol *s); FuncDeclaration *overloadExactMatch(Type *t); FuncDeclaration *overloadModMatch(const Loc &loc, Type *tthis, bool &hasOverloads); TemplateDeclaration *findTemplateDeclRoot(); bool inUnittest(); MATCH leastAsSpecialized(FuncDeclaration *g); LabelDsymbol *searchLabel(Identifier *ident); int getLevel(const Loc &loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference const char *toPrettyChars(bool QualifyTypes = false); const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' bool isMain() const; bool isCMain() const; bool isWinMain() const; bool isDllMain() const; bool isExport() const; bool isImportedSymbol() const; bool isCodeseg() const; bool isOverloadable(); bool isAbstract(); PURE isPure(); PURE isPureBypassingInference(); bool setImpure(); bool isSafe(); bool isSafeBypassingInference(); bool isTrusted(); bool setUnsafe(); bool isNogc(); bool isNogcBypassingInference(); bool setGC(); void printGCUsage(const Loc &loc, const char *warn); bool isolateReturn(); bool parametersIntersect(Type *t); virtual bool isNested(); AggregateDeclaration *isThis(); bool needThis(); bool isVirtualMethod(); virtual bool isVirtual() const; bool isFinalFunc() const; virtual bool addPreInvariant(); virtual bool addPostInvariant(); const char *kind() const; FuncDeclaration *isUnique(); bool needsClosure(); bool hasNestedFrameRefs(); void buildResultVar(Scope *sc, Type *tret); Statement *mergeFrequire(Statement *); Statement *mergeFensure(Statement *, Identifier *oid); Parameters *getParameters(int *pvarargs); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); FuncDeclaration *isFuncDeclaration() { return this; } virtual FuncDeclaration *toAliasFunc() { return this; } void accept(Visitor *v) { v->visit(this); } }; class FuncAliasDeclaration : public FuncDeclaration { public: FuncDeclaration *funcalias; bool hasOverloads; FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } const char *kind() const; FuncDeclaration *toAliasFunc(); void accept(Visitor *v) { v->visit(this); } }; class FuncLiteralDeclaration : public FuncDeclaration { public: TOK tok; // TOKfunction or TOKdelegate Type *treq; // target of return type inference // backend bool deferToObj; Dsymbol *syntaxCopy(Dsymbol *); bool isNested(); AggregateDeclaration *isThis(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); void modifyReturns(Scope *sc, Type *tret); FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } const char *kind() const; const char *toPrettyChars(bool QualifyTypes = false); void accept(Visitor *v) { v->visit(this); } }; class CtorDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); const char *kind() const; const char *toChars(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); CtorDeclaration *isCtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class PostBlitDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); bool overloadInsert(Dsymbol *s); PostBlitDeclaration *isPostBlitDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class DtorDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); const char *kind() const; const char *toChars(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); bool overloadInsert(Dsymbol *s); DtorDeclaration *isDtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class StaticCtorDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); AggregateDeclaration *isThis(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); bool hasStaticCtorOrDtor(); StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class SharedStaticCtorDeclaration : public StaticCtorDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class StaticDtorDeclaration : public FuncDeclaration { public: VarDeclaration *vgate; // 'gate' variable Dsymbol *syntaxCopy(Dsymbol *); AggregateDeclaration *isThis(); bool isVirtual() const; bool hasStaticCtorOrDtor(); bool addPreInvariant(); bool addPostInvariant(); StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class SharedStaticDtorDeclaration : public StaticDtorDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class InvariantDeclaration : public FuncDeclaration { public: Dsymbol *syntaxCopy(Dsymbol *); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); InvariantDeclaration *isInvariantDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class UnitTestDeclaration : public FuncDeclaration { public: char *codedoc; /** For documented unittest. */ // toObjFile() these nested functions after this one FuncDeclarations deferredNested; Dsymbol *syntaxCopy(Dsymbol *); AggregateDeclaration *isThis(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); UnitTestDeclaration *isUnitTestDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class NewDeclaration : public FuncDeclaration { public: Parameters *parameters; int varargs; Dsymbol *syntaxCopy(Dsymbol *); const char *kind() const; bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); NewDeclaration *isNewDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; class DeleteDeclaration : public FuncDeclaration { public: Parameters *parameters; Dsymbol *syntaxCopy(Dsymbol *); const char *kind() const; bool isDelete(); bool isVirtual() const; bool addPreInvariant(); bool addPostInvariant(); DeleteDeclaration *isDeleteDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/delegatize.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/delegatize.d, _delegatize.d) * Documentation: https://dlang.org/phobos/dmd_delegatize.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/delegatize.d */ module dmd.delegatize; import core.stdc.stdio; import dmd.apply; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.initsem; import dmd.mtype; import dmd.statement; import dmd.tokens; import dmd.visitor; /********************************* * Convert expression into a delegate. * * Used to convert the argument to a lazy parameter. * * Params: * e = argument to convert to a delegate * t = the type to be returned by the delegate * sc = context * Returns: * A delegate literal */ extern (C++) Expression toDelegate(Expression e, Type t, Scope* sc) { //printf("Expression::toDelegate(t = %s) %s\n", t.toChars(), e.toChars()); Loc loc = e.loc; auto tf = new TypeFunction(null, t, 0, LINK.d); if (t.hasWild()) tf.mod = MODFlags.wild; auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOK.delegate_, null); lambdaSetParent(e, fld); sc = sc.push(); sc.parent = fld; // set current function to be the delegate bool r = lambdaCheckForNestedRef(e, sc); sc = sc.pop(); if (r) return new ErrorExp(); Statement s; if (t.ty == Tvoid) s = new ExpStatement(loc, e); else s = new ReturnStatement(loc, e); fld.fbody = s; e = new FuncExp(loc, fld); e = e.expressionSemantic(sc); return e; } /****************************************** * Patch the parent of declarations to be the new function literal. * * Since the expression is going to be moved into a function literal, * the parent for declarations in the expression needs to be * reset to that function literal. * Params: * e = expression to check * fd = function literal symbol (the new parent) */ private void lambdaSetParent(Expression e, FuncDeclaration fd) { extern (C++) final class LambdaSetParent : StoppableVisitor { alias visit = typeof(super).visit; FuncDeclaration fd; public: extern (D) this(FuncDeclaration fd) { this.fd = fd; } override void visit(Expression) { } override void visit(DeclarationExp e) { e.declaration.parent = fd; } override void visit(IndexExp e) { if (e.lengthVar) { //printf("lengthVar\n"); e.lengthVar.parent = fd; } } override void visit(SliceExp e) { if (e.lengthVar) { //printf("lengthVar\n"); e.lengthVar.parent = fd; } } } scope LambdaSetParent lsp = new LambdaSetParent(fd); walkPostorder(e, lsp); } /******************************************* * Look for references to variables in a scope enclosing the new function literal. * * Essentially just calls `checkNestedReference() for each variable reference in `e`. * Params: * sc = context * e = expression to check * Returns: * true if error occurs. */ bool lambdaCheckForNestedRef(Expression e, Scope* sc) { extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor { alias visit = typeof(super).visit; public: Scope* sc; bool result; extern (D) this(Scope* sc) { this.sc = sc; } override void visit(Expression) { } override void visit(SymOffExp e) { VarDeclaration v = e.var.isVarDeclaration(); if (v) result = v.checkNestedReference(sc, Loc.initial); } override void visit(VarExp e) { VarDeclaration v = e.var.isVarDeclaration(); if (v) result = v.checkNestedReference(sc, Loc.initial); } override void visit(ThisExp e) { if (e.var) result = e.var.checkNestedReference(sc, Loc.initial); } override void visit(DeclarationExp e) { VarDeclaration v = e.declaration.isVarDeclaration(); if (v) { result = v.checkNestedReference(sc, Loc.initial); if (result) return; /* Some expressions cause the frontend to create a temporary. * For example, structs with cpctors replace the original * expression e with: * __cpcttmp = __cpcttmp.cpctor(e); * * In this instance, we need to ensure that the original * expression e does not have any nested references by * checking the declaration initializer too. */ if (v._init && v._init.isExpInitializer()) { Expression ie = v._init.initializerToExpression(); result = lambdaCheckForNestedRef(ie, sc); } } } } scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc); walkPostorder(e, v); return v.result; } /***************************************** * See if context `s` is nested within context `p`, meaning * it `p` is reachable at runtime by walking the static links. * If any of the intervening contexts are function literals, * make sure they are delegates. * Params: * s = inner context * p = outer context * Returns: * true means it is accessible by walking the context pointers at runtime * References: * for static links see https://en.wikipedia.org/wiki/Call_stack#Functions_of_the_call_stack */ bool ensureStaticLinkTo(Dsymbol s, Dsymbol p) { while (s) { if (s == p) // hit! return true; if (auto fd = s.isFuncDeclaration()) { if (!fd.isThis() && !fd.isNested()) break; // https://issues.dlang.org/show_bug.cgi?id=15332 // change to delegate if fd is actually nested. if (auto fld = fd.isFuncLiteralDeclaration()) fld.tok = TOK.delegate_; } if (auto ad = s.isAggregateDeclaration()) { if (ad.storage_class & STC.static_) break; } s = s.toParent2(); } return false; } ================================================ FILE: gcc/d/dmd/denum.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/denum.d, _denum.d) * Documentation: https://dlang.org/phobos/dmd_denum.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/denum.d */ module dmd.denum; import core.stdc.stdio; import dmd.attrib; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.expression; import dmd.expressionsem; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.tokens; import dmd.typesem; import dmd.visitor; /*********************************************************** */ extern (C++) final class EnumDeclaration : ScopeDsymbol { /* The separate, and distinct, cases are: * 1. enum { ... } * 2. enum : memtype { ... } * 3. enum id { ... } * 4. enum id : memtype { ... } * 5. enum id : memtype; * 6. enum id; */ Type type; // the TypeEnum Type memtype; // type of the members Prot protection; Expression maxval; Expression minval; Expression defaultval; // default initializer bool isdeprecated; bool added; int inuse; extern (D) this(const ref Loc loc, Identifier id, Type memtype) { super(id); //printf("EnumDeclaration() %s\n", toChars()); this.loc = loc; type = new TypeEnum(this); this.memtype = memtype; protection = Prot(Prot.Kind.undefined); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null); return ScopeDsymbol.syntaxCopy(ed); } override void addMember(Scope* sc, ScopeDsymbol sds) { version (none) { printf("EnumDeclaration::addMember() %s\n", toChars()); for (size_t i = 0; i < members.dim; i++) { EnumMember em = (*members)[i].isEnumMember(); printf(" member %s\n", em.toChars()); } } /* Anonymous enum members get added to enclosing scope. */ ScopeDsymbol scopesym = isAnonymous() ? sds : this; if (!isAnonymous()) { ScopeDsymbol.addMember(sc, sds); if (!symtab) symtab = new DsymbolTable(); } if (members) { for (size_t i = 0; i < members.dim; i++) { EnumMember em = (*members)[i].isEnumMember(); em.ed = this; //printf("add %s to scope %s\n", em.toChars(), scopesym.toChars()); em.addMember(sc, isAnonymous() ? scopesym : this); } } added = true; } override void setScope(Scope* sc) { if (semanticRun > PASS.init) return; ScopeDsymbol.setScope(sc); } override bool oneMember(Dsymbol* ps, Identifier ident) { if (isAnonymous()) return Dsymbol.oneMembers(members, ps, ident); return Dsymbol.oneMember(ps, ident); } override Type getType() { return type; } override const(char)* kind() const { return "enum"; } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars()); if (_scope) { // Try one last time to resolve this enum dsymbolSemantic(this, _scope); } if (!members || !symtab || _scope) { error("is forward referenced when looking for `%s`", ident.toChars()); //*(char*)0=0; return null; } Dsymbol s = ScopeDsymbol.search(loc, ident, flags); return s; } // is Dsymbol deprecated? override bool isDeprecated() { return isdeprecated; } override Prot prot() { return protection; } /****************************** * Get the value of the .max/.min property as an Expression. * Lazily computes the value and caches it in maxval/minval. * Reports any errors. * Params: * loc = location to use for error messages * id = Id::max or Id::min * Returns: * corresponding value of .max/.min */ Expression getMaxMinValue(const ref Loc loc, Identifier id) { //printf("EnumDeclaration::getMaxValue()\n"); bool first = true; Expression* pval = (id == Id.max) ? &maxval : &minval; Expression errorReturn() { *pval = new ErrorExp(); return *pval; } if (inuse) { error(loc, "recursive definition of `.%s` property", id.toChars()); return errorReturn(); } if (*pval) goto Ldone; if (_scope) dsymbolSemantic(this, _scope); if (errors) return errorReturn(); if (semanticRun == PASS.init || !members) { if (isSpecial()) { /* Allow these special enums to not need a member list */ return memtype.getProperty(loc, id, 0); } error("is forward referenced looking for `.%s`", id.toChars()); return errorReturn(); } if (!(memtype && memtype.isintegral())) { error(loc, "has no `.%s` property because base type `%s` is not an integral type", id.toChars(), memtype ? memtype.toChars() : ""); return errorReturn(); } for (size_t i = 0; i < members.dim; i++) { EnumMember em = (*members)[i].isEnumMember(); if (!em) continue; if (em.errors) return errorReturn(); Expression e = em.value; if (first) { *pval = e; first = false; } else { /* In order to work successfully with UDTs, * build expressions to do the comparisons, * and let the semantic analyzer and constant * folder give us the result. */ /* Compute: * if (e > maxval) * maxval = e; */ Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval); inuse++; ec = ec.expressionSemantic(em._scope); inuse--; ec = ec.ctfeInterpret(); if (ec.toInteger()) *pval = e; } } Ldone: Expression e = *pval; if (e.op != TOK.error) { e = e.copy(); e.loc = loc; } return e; } /**************** * Determine if enum is a 'special' one. * Returns: * true if special */ bool isSpecial() const nothrow @nogc { return (ident == Id.__c_long || ident == Id.__c_ulong || ident == Id.__c_longlong || ident == Id.__c_ulonglong || ident == Id.__c_long_double) && memtype; } Expression getDefaultValue(const ref Loc loc) { //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); if (defaultval) return defaultval; if (_scope) dsymbolSemantic(this, _scope); if (errors) goto Lerrors; if (semanticRun == PASS.init || !members) { if (isSpecial()) { /* Allow these special enums to not need a member list */ return memtype.defaultInit(loc); } error(loc, "forward reference of `%s.init`", toChars()); goto Lerrors; } foreach (const i; 0 .. members.dim) { EnumMember em = (*members)[i].isEnumMember(); if (em) { defaultval = em.value; return defaultval; } } Lerrors: defaultval = new ErrorExp(); return defaultval; } Type getMemtype(const ref Loc loc) { if (_scope) { /* Enum is forward referenced. We don't need to resolve the whole thing, * just the base type */ if (memtype) { Loc locx = loc.isValid() ? loc : this.loc; memtype = memtype.typeSemantic(locx, _scope); } else { if (!isAnonymous() && members) memtype = Type.tint32; } } if (!memtype) { if (!isAnonymous() && members) memtype = Type.tint32; else { Loc locx = loc.isValid() ? loc : this.loc; error(locx, "is forward referenced looking for base type"); return Type.terror; } } return memtype; } override inout(EnumDeclaration) isEnumDeclaration() inout { return this; } Symbol* sinit; override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class EnumMember : VarDeclaration { /* Can take the following forms: * 1. id * 2. id = value * 3. type id = value */ @property ref value() { return (cast(ExpInitializer)_init).exp; } // A cast() is injected to 'value' after dsymbolSemantic(), // but 'origValue' will preserve the original value, // or previous value + 1 if none was specified. Expression origValue; Type origType; EnumDeclaration ed; extern (D) this(const ref Loc loc, Identifier id, Expression value, Type origType) { super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value)); this.origValue = value; this.origType = origType; } extern(D) this(Loc loc, Identifier id, Expression value, Type memtype, StorageClass stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd) { this(loc, id, value, memtype); storage_class = stc; userAttribDecl = uad; depdecl = dd; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new EnumMember( loc, ident, value ? value.syntaxCopy() : null, origType ? origType.syntaxCopy() : null, storage_class, userAttribDecl ? cast(UserAttributeDeclaration)userAttribDecl.syntaxCopy(s) : null, depdecl ? cast(DeprecatedDeclaration)depdecl.syntaxCopy(s) : null); } override const(char)* kind() const { return "enum member"; } Expression getVarExp(const ref Loc loc, Scope* sc) { dsymbolSemantic(this, sc); if (errors) return new ErrorExp(); checkDisabled(loc, sc); if (depdecl && !depdecl._scope) depdecl._scope = sc; checkDeprecated(loc, sc); if (errors) return new ErrorExp(); Expression e = new VarExp(loc, this); return e.expressionSemantic(sc); } override inout(EnumMember) isEnumMember() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/dimport.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dimport.d, _dimport.d) * Documentation: https://dlang.org/phobos/dmd_dimport.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d */ module dmd.dimport; import dmd.arraytypes; import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.globals; import dmd.identifier; import dmd.mtype; import dmd.visitor; /*********************************************************** */ extern (C++) final class Import : Dsymbol { /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; */ Identifiers* packages; // array of Identifier's representing packages Identifier id; // module Identifier Identifier aliasId; int isstatic; // !=0 if static import Prot protection; // Pairs of alias=name to bind into current namespace Identifiers names; Identifiers aliases; Module mod; Package pkg; // leftmost package/module // corresponding AliasDeclarations for alias=name pairs AliasDeclarations aliasdecls; extern (D) this(const ref Loc loc, Identifiers* packages, Identifier id, Identifier aliasId, int isstatic) { super(null); assert(id); version (none) { printf("Import::Import("); if (packages && packages.dim) { for (size_t i = 0; i < packages.dim; i++) { Identifier id = (*packages)[i]; printf("%s.", id.toChars()); } } printf("%s)\n", id.toChars()); } this.loc = loc; this.packages = packages; this.id = id; this.aliasId = aliasId; this.isstatic = isstatic; this.protection = Prot.Kind.private_; // default to private // Set symbol name (bracketed) if (aliasId) { // import [cstdio] = std.stdio; this.ident = aliasId; } else if (packages && packages.dim) { // import [std].stdio; this.ident = (*packages)[0]; } else { // import [foo]; this.ident = id; } } void addAlias(Identifier name, Identifier _alias) { if (isstatic) error("cannot have an import bind list"); if (!aliasId) this.ident = null; // make it an anonymous import names.push(name); aliases.push(_alias); } override const(char)* kind() const { return isstatic ? "static import" : "import"; } override Prot prot() { return protection; } // copy only syntax trees override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto si = new Import(loc, packages, id, aliasId, isstatic); for (size_t i = 0; i < names.dim; i++) { si.addAlias(names[i], aliases[i]); } return si; } /******************************* * Load this module. * Returns: * true for errors, false for success */ bool load(Scope* sc) { //printf("Import::load('%s') %p\n", toPrettyChars(), this); // See if existing module const errors = global.errors; DsymbolTable dst = Package.resolve(packages, null, &pkg); version (none) { if (pkg && pkg.isModule()) { .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars()); mod = pkg.isModule(); // Error recovery - treat as import of that module return true; } } Dsymbol s = dst.lookup(id); if (s) { if (s.isModule()) mod = cast(Module)s; else { if (s.isAliasDeclaration()) { .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars()); } else if (Package p = s.isPackage()) { if (p.isPkgMod == PKG.unknown) { mod = Module.load(loc, packages, id); if (!mod) p.isPkgMod = PKG.package_; else { // mod is a package.d, or a normal module which conflicts with the package name. assert(mod.isPackageFile == (p.isPkgMod == PKG.module_)); if (mod.isPackageFile) mod.tag = p.tag; // reuse the same package tag } } else { mod = p.isPackageMod(); } if (!mod) { .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars()); } } else if (pkg) { .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars()); } else { .error(loc, "can only import from a module, not from package `%s`", id.toChars()); } } } if (!mod) { // Load module mod = Module.load(loc, packages, id); if (mod) { // id may be different from mod.ident, if so then insert alias dst.insert(id, mod); } } if (mod && !mod.importedFrom) mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; if (!pkg) pkg = mod; //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); return global.errors != errors; } override void importAll(Scope* sc) { if (!mod) { load(sc); if (mod) // if successfully loaded module { if (mod.md && mod.md.isdeprecated) { Expression msg = mod.md.msg; if (StringExp se = msg ? msg.toStringExp() : null) mod.deprecation(loc, "is deprecated - %s", se.string); else mod.deprecation(loc, "is deprecated"); } mod.importAll(null); if (sc.explicitProtection) protection = sc.protection; if (!isstatic && !aliasId && !names.dim) { sc.scopesym.importScope(mod, protection); } } } } override Dsymbol toAlias() { if (aliasId) return mod; return this; } /***************************** * Add import to sd's symbol table. */ override void addMember(Scope* sc, ScopeDsymbol sd) { //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); if (names.dim == 0) return Dsymbol.addMember(sc, sd); if (aliasId) Dsymbol.addMember(sc, sd); /* Instead of adding the import to sd's symbol table, * add each of the alias=name pairs */ for (size_t i = 0; i < names.dim; i++) { Identifier name = names[i]; Identifier _alias = aliases[i]; if (!_alias) _alias = name; auto tname = new TypeIdentifier(loc, name); auto ad = new AliasDeclaration(loc, _alias, tname); ad._import = this; ad.addMember(sc, sd); aliasdecls.push(ad); } } override void setScope(Scope* sc) { Dsymbol.setScope(sc); if (aliasdecls.dim) { if (!mod) importAll(sc); sc = sc.push(mod); sc.protection = protection; foreach (ad; aliasdecls) ad.setScope(sc); sc = sc.pop(); } } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); if (!pkg) { load(null); mod.importAll(null); mod.dsymbolSemantic(null); } // Forward it to the package/module return pkg.search(loc, ident, flags); } override bool overloadInsert(Dsymbol s) { /* Allow multiple imports with the same package base, but disallow * alias collisions * https://issues.dlang.org/show_bug.cgi?id=5412 */ assert(ident && ident == s.ident); Import imp; if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId) return true; else return false; } override inout(Import) isImport() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/dinterpret.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dinterpret.d, _dinterpret.d) * Documentation: https://dlang.org/phobos/dmd_dinterpret.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d */ module dmd.dinterpret; import core.stdc.stdio; import core.stdc.string; import dmd.apply; import dmd.arraytypes; import dmd.attrib; import dmd.builtin; import dmd.constfold; import dmd.ctfeexpr; import dmd.dclass; import dmd.declaration; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.mtype; import dmd.root.array; import dmd.root.rootobject; import dmd.statement; import dmd.tokens; import dmd.utf; import dmd.visitor; /************************************* * Entry point for CTFE. * A compile-time result is required. Give an error if not possible. * * `e` must be semantically valid expression. In other words, it should not * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over * functions and may invoke a function that contains `ErrorStatement` in its body. * If that, the "CTFE failed because of previous errors" error is raised. */ public Expression ctfeInterpret(Expression e) { if (e.op == TOK.error) return e; assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642 //assert(e.type.ty != Terror); // FIXME if (e.type.ty == Terror) return new ErrorExp(); // This code is outside a function, but still needs to be compiled // (there are compiler-generated temporary variables such as __dollar). // However, this will only be run once and can then be discarded. auto ctfeCodeGlobal = CompiledCtfeFunction(null); ctfeCodeGlobal.callingloc = e.loc; ctfeCodeGlobal.onExpression(e); Expression result = interpret(e, null); if (!CTFEExp.isCantExp(result)) result = scrubReturnValue(e.loc, result); if (CTFEExp.isCantExp(result)) result = new ErrorExp(); return result; } /* Run CTFE on the expression, but allow the expression to be a TypeExp * or a tuple containing a TypeExp. (This is required by pragma(msg)). */ public Expression ctfeInterpretForPragmaMsg(Expression e) { if (e.op == TOK.error || e.op == TOK.type) return e; // It's also OK for it to be a function declaration (happens only with // __traits(getOverloads)) if (e.op == TOK.variable && (cast(VarExp)e).var.isFuncDeclaration()) { return e; } if (e.op != TOK.tuple) return e.ctfeInterpret(); // Tuples need to be treated separately, since they are // allowed to contain a TypeExp in this case. TupleExp tup = cast(TupleExp)e; Expressions* expsx = null; for (size_t i = 0; i < tup.exps.dim; ++i) { Expression g = (*tup.exps)[i]; Expression h = g; h = ctfeInterpretForPragmaMsg(g); if (h != g) { if (!expsx) { expsx = new Expressions(tup.exps.dim); for (size_t j = 0; j < tup.exps.dim; j++) (*expsx)[j] = (*tup.exps)[j]; } (*expsx)[i] = h; } } if (expsx) { auto te = new TupleExp(e.loc, expsx); expandTuples(te.exps); te.type = new TypeTuple(te.exps); return te; } return e; } public extern (C++) Expression getValue(VarDeclaration vd) { return ctfeStack.getValue(vd); } // CTFE diagnostic information public extern (C++) void printCtfePerformanceStats() { debug (SHOWPERFORMANCE) { printf(" ---- CTFE Performance ----\n"); printf("max call depth = %d\tmax stack = %d\n", CtfeStatus.maxCallDepth, ctfeStack.maxStackUsage()); printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus.numArrayAllocs, CtfeStatus.numAssignments); } } /********* * Typesafe PIMPL idiom so we can keep CompiledCtfeFunction private. */ struct CompiledCtfeFunctionPimpl { private CompiledCtfeFunction* pimpl; private alias pimpl this; } /* ================================================ Implementation ======================================= */ private: enum CtfeGoal : int { ctfeNeedRvalue, // Must return an Rvalue (== CTFE value) ctfeNeedLvalue, // Must return an Lvalue (== CTFE reference) ctfeNeedNothing, // The return value is not required } alias ctfeNeedRvalue = CtfeGoal.ctfeNeedRvalue; alias ctfeNeedLvalue = CtfeGoal.ctfeNeedLvalue; alias ctfeNeedNothing = CtfeGoal.ctfeNeedNothing; //debug = LOG; //debug = LOGASSIGN; //debug = LOGCOMPILE; //debug = SHOWPERFORMANCE; // Maximum allowable recursive function calls in CTFE enum CTFE_RECURSION_LIMIT = 1000; /** The values of all CTFE variables */ struct CtfeStack { private: /* The stack. Every declaration we encounter is pushed here, * together with the VarDeclaration, and the previous * stack address of that variable, so that we can restore it * when we leave the stack frame. * Note that when a function is forward referenced, the interpreter must * run semantic3, and that may start CTFE again with a NULL istate. Thus * the stack might not be empty when CTFE begins. * * Ctfe Stack addresses are just 0-based integers, but we save * them as 'void *' because Array can only do pointers. */ Expressions values; // values on the stack VarDeclarations vars; // corresponding variables Array!(void*) savedId; // id of the previous state of that var Array!(void*) frames; // all previous frame pointers Expressions savedThis; // all previous values of localThis /* Global constants get saved here after evaluation, so we never * have to redo them. This saves a lot of time and memory. */ Expressions globalValues; // values of global constants size_t framepointer; // current frame pointer size_t maxStackPointer; // most stack we've ever used Expression localThis; // value of 'this', or NULL if none public: extern (C++) size_t stackPointer() { return values.dim; } // The current value of 'this', or NULL if none extern (C++) Expression getThis() { return localThis; } // Largest number of stack positions we've used extern (C++) size_t maxStackUsage() { return maxStackPointer; } // Start a new stack frame, using the provided 'this'. extern (C++) void startFrame(Expression thisexp) { frames.push(cast(void*)cast(size_t)framepointer); savedThis.push(localThis); framepointer = stackPointer(); localThis = thisexp; } extern (C++) void endFrame() { size_t oldframe = cast(size_t)frames[frames.dim - 1]; localThis = savedThis[savedThis.dim - 1]; popAll(framepointer); framepointer = oldframe; frames.setDim(frames.dim - 1); savedThis.setDim(savedThis.dim - 1); } extern (C++) bool isInCurrentFrame(VarDeclaration v) { if (v.isDataseg() && !v.isCTFE()) return false; // It's a global return v.ctfeAdrOnStack >= framepointer; } extern (C++) Expression getValue(VarDeclaration v) { if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE()) { assert(v.ctfeAdrOnStack >= 0 && v.ctfeAdrOnStack < globalValues.dim); return globalValues[v.ctfeAdrOnStack]; } assert(v.ctfeAdrOnStack >= 0 && v.ctfeAdrOnStack < stackPointer()); return values[v.ctfeAdrOnStack]; } extern (C++) void setValue(VarDeclaration v, Expression e) { assert(!v.isDataseg() || v.isCTFE()); assert(v.ctfeAdrOnStack >= 0 && v.ctfeAdrOnStack < stackPointer()); values[v.ctfeAdrOnStack] = e; } extern (C++) void push(VarDeclaration v) { assert(!v.isDataseg() || v.isCTFE()); if (v.ctfeAdrOnStack != cast(size_t)-1 && v.ctfeAdrOnStack >= framepointer) { // Already exists in this frame, reuse it. values[v.ctfeAdrOnStack] = null; return; } savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack); v.ctfeAdrOnStack = cast(int)values.dim; vars.push(v); values.push(null); } extern (C++) void pop(VarDeclaration v) { assert(!v.isDataseg() || v.isCTFE()); assert(!(v.storage_class & (STC.ref_ | STC.out_))); int oldid = v.ctfeAdrOnStack; v.ctfeAdrOnStack = cast(int)cast(size_t)savedId[oldid]; if (v.ctfeAdrOnStack == values.dim - 1) { values.pop(); vars.pop(); savedId.pop(); } } extern (C++) void popAll(size_t stackpointer) { if (stackPointer() > maxStackPointer) maxStackPointer = stackPointer(); assert(values.dim >= stackpointer); for (size_t i = stackpointer; i < values.dim; ++i) { VarDeclaration v = vars[i]; v.ctfeAdrOnStack = cast(int)cast(size_t)savedId[i]; } values.setDim(stackpointer); vars.setDim(stackpointer); savedId.setDim(stackpointer); } extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e) { assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE()); v.ctfeAdrOnStack = cast(int)globalValues.dim; globalValues.push(e); } } private struct InterState { InterState* caller; // calling function's InterState FuncDeclaration fd; // function being interpreted Statement start; // if !=NULL, start execution at this statement /* target of CTFEExp result; also * target of labelled CTFEExp or * CTFEExp. (null if no label). */ Statement gotoTarget; } private __gshared CtfeStack ctfeStack; /*********************************************************** * CTFE-object code for a single function * * Currently only counts the number of local variables in the function */ struct CompiledCtfeFunction { FuncDeclaration func; // Function being compiled, NULL if global scope int numVars; // Number of variables declared in this function Loc callingloc; extern (D) this(FuncDeclaration f) { func = f; } extern (C++) void onDeclaration(VarDeclaration v) { //printf("%s CTFE declare %s\n", v.loc.toChars(), v.toChars()); ++numVars; } extern (C++) void onExpression(Expression e) { extern (C++) final class VarWalker : StoppableVisitor { alias visit = typeof(super).visit; public: CompiledCtfeFunction* ccf; extern (D) this(CompiledCtfeFunction* ccf) { this.ccf = ccf; } override void visit(Expression e) { } override void visit(ErrorExp e) { // Currently there's a front-end bug: silent errors // can occur inside delegate literals inside is(typeof()). // Suppress the check in this case. if (global.gag && ccf.func) { stop = 1; return; } .error(e.loc, "CTFE internal error: ErrorExp in `%s`\n", ccf.func ? ccf.func.loc.toChars() : ccf.callingloc.toChars()); assert(0); } override void visit(DeclarationExp e) { VarDeclaration v = e.declaration.isVarDeclaration(); if (!v) return; TupleDeclaration td = v.toAlias().isTupleDeclaration(); if (td) { if (!td.objects) return; for (size_t i = 0; i < td.objects.dim; ++i) { RootObject o = td.objects.tdata()[i]; Expression ex = isExpression(o); DsymbolExp s = (ex && ex.op == TOK.dSymbol) ? cast(DsymbolExp)ex : null; assert(s); VarDeclaration v2 = s.s.isVarDeclaration(); assert(v2); if (!v2.isDataseg() || v2.isCTFE()) ccf.onDeclaration(v2); } } else if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE()) ccf.onDeclaration(v); Dsymbol s = v.toAlias(); if (s == v && !v.isStatic() && v._init) { ExpInitializer ie = v._init.isExpInitializer(); if (ie) ccf.onExpression(ie.exp); } } override void visit(IndexExp e) { if (e.lengthVar) ccf.onDeclaration(e.lengthVar); } override void visit(SliceExp e) { if (e.lengthVar) ccf.onDeclaration(e.lengthVar); } } scope VarWalker v = new VarWalker(&this); walkPostorder(e, v); } } private extern (C++) final class CtfeCompiler : SemanticTimeTransitiveVisitor { alias visit = SemanticTimeTransitiveVisitor.visit; public: CompiledCtfeFunction* ccf; extern (D) this(CompiledCtfeFunction* ccf) { this.ccf = ccf; } override void visit(Statement s) { debug (LOGCOMPILE) { printf("%s Statement::ctfeCompile %s\n", s.loc.toChars(), s.toChars()); } assert(0); } override void visit(ExpStatement s) { debug (LOGCOMPILE) { printf("%s ExpStatement::ctfeCompile\n", s.loc.toChars()); } if (s.exp) ccf.onExpression(s.exp); } override void visit(IfStatement s) { debug (LOGCOMPILE) { printf("%s IfStatement::ctfeCompile\n", s.loc.toChars()); } ccf.onExpression(s.condition); if (s.ifbody) ctfeCompile(s.ifbody); if (s.elsebody) ctfeCompile(s.elsebody); } override void visit(OnScopeStatement s) { debug (LOGCOMPILE) { printf("%s OnScopeStatement::ctfeCompile\n", s.loc.toChars()); } // rewritten to try/catch/finally assert(0); } override void visit(DoStatement s) { debug (LOGCOMPILE) { printf("%s DoStatement::ctfeCompile\n", s.loc.toChars()); } ccf.onExpression(s.condition); if (s._body) ctfeCompile(s._body); } override void visit(WhileStatement s) { debug (LOGCOMPILE) { printf("%s WhileStatement::ctfeCompile\n", s.loc.toChars()); } // rewritten to ForStatement assert(0); } override void visit(ForStatement s) { debug (LOGCOMPILE) { printf("%s ForStatement::ctfeCompile\n", s.loc.toChars()); } if (s._init) ctfeCompile(s._init); if (s.condition) ccf.onExpression(s.condition); if (s.increment) ccf.onExpression(s.increment); if (s._body) ctfeCompile(s._body); } override void visit(ForeachStatement s) { debug (LOGCOMPILE) { printf("%s ForeachStatement::ctfeCompile\n", s.loc.toChars()); } // rewritten for ForStatement assert(0); } override void visit(SwitchStatement s) { debug (LOGCOMPILE) { printf("%s SwitchStatement::ctfeCompile\n", s.loc.toChars()); } ccf.onExpression(s.condition); // Note that the body contains the the Case and Default // statements, so we only need to compile the expressions for (size_t i = 0; i < s.cases.dim; i++) { ccf.onExpression((*s.cases)[i].exp); } if (s._body) ctfeCompile(s._body); } override void visit(CaseStatement s) { debug (LOGCOMPILE) { printf("%s CaseStatement::ctfeCompile\n", s.loc.toChars()); } if (s.statement) ctfeCompile(s.statement); } override void visit(GotoDefaultStatement s) { debug (LOGCOMPILE) { printf("%s GotoDefaultStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(GotoCaseStatement s) { debug (LOGCOMPILE) { printf("%s GotoCaseStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(SwitchErrorStatement s) { debug (LOGCOMPILE) { printf("%s SwitchErrorStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(ReturnStatement s) { debug (LOGCOMPILE) { printf("%s ReturnStatement::ctfeCompile\n", s.loc.toChars()); } if (s.exp) ccf.onExpression(s.exp); } override void visit(BreakStatement s) { debug (LOGCOMPILE) { printf("%s BreakStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(ContinueStatement s) { debug (LOGCOMPILE) { printf("%s ContinueStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(WithStatement s) { debug (LOGCOMPILE) { printf("%s WithStatement::ctfeCompile\n", s.loc.toChars()); } // If it is with(Enum) {...}, just execute the body. if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) { } else { ccf.onDeclaration(s.wthis); ccf.onExpression(s.exp); } if (s._body) ctfeCompile(s._body); } override void visit(TryCatchStatement s) { debug (LOGCOMPILE) { printf("%s TryCatchStatement::ctfeCompile\n", s.loc.toChars()); } if (s._body) ctfeCompile(s._body); for (size_t i = 0; i < s.catches.dim; i++) { Catch ca = (*s.catches)[i]; if (ca.var) ccf.onDeclaration(ca.var); if (ca.handler) ctfeCompile(ca.handler); } } override void visit(ThrowStatement s) { debug (LOGCOMPILE) { printf("%s ThrowStatement::ctfeCompile\n", s.loc.toChars()); } ccf.onExpression(s.exp); } override void visit(GotoStatement s) { debug (LOGCOMPILE) { printf("%s GotoStatement::ctfeCompile\n", s.loc.toChars()); } } override void visit(ImportStatement s) { debug (LOGCOMPILE) { printf("%s ImportStatement::ctfeCompile\n", s.loc.toChars()); } // Contains no variables or executable code } override void visit(ForeachRangeStatement s) { debug (LOGCOMPILE) { printf("%s ForeachRangeStatement::ctfeCompile\n", s.loc.toChars()); } // rewritten for ForStatement assert(0); } override void visit(AsmStatement s) { debug (LOGCOMPILE) { printf("%s AsmStatement::ctfeCompile\n", s.loc.toChars()); } // we can't compile asm statements } void ctfeCompile(Statement s) { s.accept(this); } } /************************************* * Compile this function for CTFE. * At present, this merely allocates variables. */ private void ctfeCompile(FuncDeclaration fd) { debug (LOGCOMPILE) { printf("\n%s FuncDeclaration::ctfeCompile %s\n", fd.loc.toChars(), fd.toChars()); } assert(!fd.ctfeCode); assert(!fd.semantic3Errors); assert(fd.semanticRun == PASS.semantic3done); fd.ctfeCode = new CompiledCtfeFunction(fd); if (fd.parameters) { Type tb = fd.type.toBasetype(); assert(tb.ty == Tfunction); for (size_t i = 0; i < fd.parameters.dim; i++) { VarDeclaration v = (*fd.parameters)[i]; fd.ctfeCode.onDeclaration(v); } } if (fd.vresult) fd.ctfeCode.onDeclaration(fd.vresult); scope CtfeCompiler v = new CtfeCompiler(fd.ctfeCode); v.ctfeCompile(fd.fbody); } /************************************* * Attempt to interpret a function given the arguments. * Input: * istate state for calling function (NULL if none) * arguments function arguments * thisarg 'this', if a needThis() function, NULL if not. * * Return result expression if successful, TOK.cantExpression if not, * or CTFEExp if function returned void. */ private Expression interpretFunction(FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg) { debug (LOG) { printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars()); } if (fd.semanticRun == PASS.semantic3) { fd.error("circular dependency. Functions cannot be interpreted while being compiled"); return CTFEExp.cantexp; } if (!fd.functionSemantic3()) return CTFEExp.cantexp; if (fd.semanticRun < PASS.semantic3done) return CTFEExp.cantexp; // CTFE-compile the function if (!fd.ctfeCode) ctfeCompile(fd); Type tb = fd.type.toBasetype(); assert(tb.ty == Tfunction); TypeFunction tf = cast(TypeFunction)tb; if (tf.varargs && arguments && ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim))) { fd.error("C-style variadic functions are not yet implemented in CTFE"); return CTFEExp.cantexp; } // Nested functions always inherit the 'this' pointer from the parent, // except for delegates. (Note that the 'this' pointer may be null). // Func literals report isNested() even if they are in global scope, // so we need to check that the parent is a function. if (fd.isNested() && fd.toParent2().isFuncDeclaration() && !thisarg && istate) thisarg = ctfeStack.getThis(); if (fd.needThis() && !thisarg) { // error, no this. Prevent segfault. // Here should be unreachable by the strict 'this' check in front-end. fd.error("need `this` to access member `%s`", fd.toChars()); return CTFEExp.cantexp; } // Place to hold all the arguments to the function while // we are evaluating them. size_t dim = arguments ? arguments.dim : 0; assert((fd.parameters ? fd.parameters.dim : 0) == dim); /* Evaluate all the arguments to the function, * store the results in eargs[] */ Expressions eargs = Expressions(dim); for (size_t i = 0; i < dim; i++) { Expression earg = (*arguments)[i]; Parameter fparam = Parameter.getNth(tf.parameters, i); if (fparam.storageClass & (STC.out_ | STC.ref_)) { if (!istate && (fparam.storageClass & STC.out_)) { // initializing an out parameter involves writing to it. earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars()); return CTFEExp.cantexp; } // Convert all reference arguments into lvalue references earg = interpret(earg, istate, ctfeNeedLvalue); if (CTFEExp.isCantExp(earg)) return earg; } else if (fparam.storageClass & STC.lazy_) { } else { /* Value parameters */ Type ta = fparam.type.toBasetype(); if (ta.ty == Tsarray && earg.op == TOK.address) { /* Static arrays are passed by a simple pointer. * Skip past this to get at the actual arg. */ earg = (cast(AddrExp)earg).e1; } earg = interpret(earg, istate); if (CTFEExp.isCantExp(earg)) return earg; /* Struct literals are passed by value, but we don't need to * copy them if they are passed as const */ if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_))) earg = copyLiteral(earg).copy(); } if (earg.op == TOK.thrownException) { if (istate) return earg; (cast(ThrownExceptionExp)earg).generateUncaughtError(); return CTFEExp.cantexp; } eargs[i] = earg; } // Now that we've evaluated all the arguments, we can start the frame // (this is the moment when the 'call' actually takes place). InterState istatex; istatex.caller = istate; istatex.fd = fd; ctfeStack.startFrame(thisarg); if (fd.vthis && thisarg) { ctfeStack.push(fd.vthis); setValue(fd.vthis, thisarg); } for (size_t i = 0; i < dim; i++) { Expression earg = eargs[i]; Parameter fparam = Parameter.getNth(tf.parameters, i); VarDeclaration v = (*fd.parameters)[i]; debug (LOG) { printf("arg[%d] = %s\n", i, earg.toChars()); } ctfeStack.push(v); if ((fparam.storageClass & (STC.out_ | STC.ref_)) && earg.op == TOK.variable && (cast(VarExp)earg).var.toParent2() == fd) { VarDeclaration vx = (cast(VarExp)earg).var.isVarDeclaration(); if (!vx) { fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars()); return CTFEExp.cantexp; } /* vx is a variable that is declared in fd. * It means that fd is recursively called. e.g. * * void fd(int n, ref int v = dummy) { * int vx; * if (n == 1) fd(2, vx); * } * fd(1); * * The old value of vx on the stack in fd(1) * should be saved at the start of fd(2, vx) call. */ int oldadr = vx.ctfeAdrOnStack; ctfeStack.push(vx); assert(!hasValue(vx)); // vx is made uninitialized // https://issues.dlang.org/show_bug.cgi?id=14299 // v.ctfeAdrOnStack should be saved already // in the stack before the overwrite. v.ctfeAdrOnStack = oldadr; assert(hasValue(v)); // ref parameter v should refer existing value. } else { // Value parameters and non-trivial references setValueWithoutChecking(v, earg); } debug (LOG) { printf("interpreted arg[%d] = %s\n", i, earg.toChars()); showCtfeExpr(earg); } debug (LOGASSIGN) { printf("interpreted arg[%d] = %s\n", i, earg.toChars()); showCtfeExpr(earg); } } if (fd.vresult) ctfeStack.push(fd.vresult); // Enter the function ++CtfeStatus.callDepth; if (CtfeStatus.callDepth > CtfeStatus.maxCallDepth) CtfeStatus.maxCallDepth = CtfeStatus.callDepth; Expression e = null; while (1) { if (CtfeStatus.callDepth > CTFE_RECURSION_LIMIT) { // This is a compiler error. It must not be suppressed. global.gag = 0; fd.error("CTFE recursion limit exceeded"); e = CTFEExp.cantexp; break; } e = interpret(fd.fbody, &istatex); if (CTFEExp.isCantExp(e)) { debug (LOG) { printf("function body failed to interpret\n"); } } if (istatex.start) { fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars()); return CTFEExp.cantexp; } /* This is how we deal with a recursive statement AST * that has arbitrary goto statements in it. * Bubble up a 'result' which is the target of the goto * statement, then go recursively down the AST looking * for that statement, then execute starting there. */ if (CTFEExp.isGotoExp(e)) { istatex.start = istatex.gotoTarget; // set starting statement istatex.gotoTarget = null; } else { assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_)); break; } } // If fell off the end of a void function, return void if (!e && tf.next.ty == Tvoid) e = CTFEExp.voidexp; if (tf.isref && e.op == TOK.variable && (cast(VarExp)e).var == fd.vthis) e = thisarg; assert(e !is null); // Leave the function --CtfeStatus.callDepth; ctfeStack.endFrame(); // If it generated an uncaught exception, report error. if (!istate && e.op == TOK.thrownException) { (cast(ThrownExceptionExp)e).generateUncaughtError(); e = CTFEExp.cantexp; } return e; } private extern (C++) final class Interpreter : Visitor { alias visit = Visitor.visit; public: InterState* istate; CtfeGoal goal; Expression result; UnionExp* pue; // storage for `result` extern (D) this(UnionExp* pue, InterState* istate, CtfeGoal goal) { this.pue = pue; this.istate = istate; this.goal = goal; } // If e is TOK.throw_exception or TOK.cantExpression, // set it to 'result' and returns true. bool exceptionOrCant(Expression e) { if (exceptionOrCantInterpret(e)) { // Make sure e is not pointing to a stack temporary result = (e.op == TOK.cantExpression) ? CTFEExp.cantexp : e; return true; } return false; } static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) { if (exps is original) { if (!original) exps = new Expressions(); else exps = original.copy(); ++CtfeStatus.numArrayAllocs; } return exps; } /******************************** Statement ***************************/ override void visit(Statement s) { debug (LOG) { printf("%s Statement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } s.error("statement `%s` cannot be interpreted at compile time", s.toChars()); result = CTFEExp.cantexp; } override void visit(ExpStatement s) { debug (LOG) { printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : ""); } if (istate.start) { if (istate.start != s) return; istate.start = null; } Expression e = interpret(pue, s.exp, istate, ctfeNeedNothing); if (exceptionOrCant(e)) return; } override void visit(CompoundStatement s) { debug (LOG) { printf("%s CompoundStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; const dim = s.statements ? s.statements.dim : 0; foreach (i; 0 .. dim) { Statement sx = (*s.statements)[i]; result = interpret(pue, sx, istate); if (result) break; } debug (LOG) { printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result); } } override void visit(UnrolledLoopStatement s) { debug (LOG) { printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; const dim = s.statements ? s.statements.dim : 0; foreach (i; 0 .. dim) { Statement sx = (*s.statements)[i]; Expression e = interpret(pue, sx, istate); if (!e) // succeeds to interpret, or goto target was not found continue; if (exceptionOrCant(e)) return; if (e.op == TOK.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // break at a higher level return; } istate.gotoTarget = null; result = null; return; } if (e.op == TOK.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // continue at a higher level return; } istate.gotoTarget = null; continue; } // expression from return statement, or thrown exception result = e; break; } } override void visit(IfStatement s) { debug (LOG) { printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars()); } if (istate.start == s) istate.start = null; if (istate.start) { Expression e = null; e = interpret(s.ifbody, istate); if (!e && istate.start) e = interpret(s.elsebody, istate); result = e; return; } UnionExp ue = void; Expression e = interpret(&ue, s.condition, istate); assert(e); if (exceptionOrCant(e)) return; if (isTrueBool(e)) result = interpret(pue, s.ifbody, istate); else if (e.isBool(false)) result = interpret(pue, s.elsebody, istate); else { // no error, or assert(0)? result = CTFEExp.cantexp; } } override void visit(ScopeStatement s) { debug (LOG) { printf("%s ScopeStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; result = interpret(pue, s.statement, istate); } /** Given an expression e which is about to be returned from the current function, generate an error if it contains pointers to local variables. Only checks expressions passed by value (pointers to local variables may already be stored in members of classes, arrays, or AAs which were passed as mutable function parameters). Returns: true if it is safe to return, false if an error was generated. */ static bool stopPointersEscaping(const ref Loc loc, Expression e) { if (!e.type.hasPointers()) return true; if (isPointer(e.type)) { Expression x = e; if (e.op == TOK.address) x = (cast(AddrExp)e).e1; VarDeclaration v; while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null) { if (v.storage_class & STC.ref_) { x = getValue(v); if (e.op == TOK.address) (cast(AddrExp)e).e1 = x; continue; } if (ctfeStack.isInCurrentFrame(v)) { error(loc, "returning a pointer to a local stack variable"); return false; } else break; } // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not // pointing to a local struct or static array. } if (e.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)e; return stopPointersEscapingFromArray(loc, se.elements); } if (e.op == TOK.arrayLiteral) { return stopPointersEscapingFromArray(loc, (cast(ArrayLiteralExp)e).elements); } if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)e; if (!stopPointersEscapingFromArray(loc, aae.keys)) return false; return stopPointersEscapingFromArray(loc, aae.values); } return true; } // Check all members of an array for escaping local variables. Return false if error static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems) { for (size_t i = 0; i < elems.dim; i++) { Expression m = (*elems)[i]; if (!m) continue; if (!stopPointersEscaping(loc, m)) return false; } return true; } override void visit(ReturnStatement s) { debug (LOG) { printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : ""); } if (istate.start) { if (istate.start != s) return; istate.start = null; } if (!s.exp) { result = CTFEExp.voidexp; return; } assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)istate.fd.type; /* If the function returns a ref AND it's been called from an assignment, * we need to return an lvalue. Otherwise, just do an (rvalue) interpret. */ if (tf.isref) { result = interpret(pue, s.exp, istate, ctfeNeedLvalue); return; } if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0) { // To support this, we need to copy all the closure vars // into the delegate literal. s.error("closures are not yet supported in CTFE"); result = CTFEExp.cantexp; return; } // We need to treat pointers specially, because TOK.symbolOffset can be used to // return a value OR a pointer Expression e = interpret(pue, s.exp, istate); if (exceptionOrCant(e)) return; // Disallow returning pointers to stack-allocated variables (bug 7876) if (!stopPointersEscaping(s.loc, e)) { result = CTFEExp.cantexp; return; } if (needToCopyLiteral(e)) e = copyLiteral(e).copy(); debug (LOGASSIGN) { printf("RETURN %s\n", s.loc.toChars()); showCtfeExpr(e); } result = e; } static Statement findGotoTarget(InterState* istate, Identifier ident) { Statement target = null; if (ident) { LabelDsymbol label = istate.fd.searchLabel(ident); assert(label && label.statement); LabelStatement ls = label.statement; target = ls.gotoTarget ? ls.gotoTarget : ls.statement; } return target; } override void visit(BreakStatement s) { debug (LOG) { printf("%s BreakStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } istate.gotoTarget = findGotoTarget(istate, s.ident); result = CTFEExp.breakexp; } override void visit(ContinueStatement s) { debug (LOG) { printf("%s ContinueStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } istate.gotoTarget = findGotoTarget(istate, s.ident); result = CTFEExp.continueexp; } override void visit(WhileStatement s) { debug (LOG) { printf("WhileStatement::interpret()\n"); } assert(0); // rewritten to ForStatement } override void visit(DoStatement s) { debug (LOG) { printf("%s DoStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; while (1) { Expression e = interpret(s._body, istate); if (!e && istate.start) // goto target was not found return; assert(!istate.start); if (exceptionOrCant(e)) return; if (e && e.op == TOK.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // break at a higher level return; } istate.gotoTarget = null; break; } if (e && e.op == TOK.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // continue at a higher level return; } istate.gotoTarget = null; e = null; } if (e) { result = e; // bubbled up from ReturnStatement return; } UnionExp ue = void; e = interpret(&ue, s.condition, istate); if (exceptionOrCant(e)) return; if (!e.isConst()) { result = CTFEExp.cantexp; return; } if (e.isBool(false)) break; assert(isTrueBool(e)); } assert(result is null); } override void visit(ForStatement s) { debug (LOG) { printf("%s ForStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; UnionExp ueinit = void; Expression ei = interpret(&ueinit, s._init, istate); if (exceptionOrCant(ei)) return; assert(!ei); // s.init never returns from function, or jumps out from it while (1) { if (s.condition && !istate.start) { UnionExp ue = void; Expression e = interpret(&ue, s.condition, istate); if (exceptionOrCant(e)) return; if (e.isBool(false)) break; assert(isTrueBool(e)); } Expression e = interpret(pue, s._body, istate); if (!e && istate.start) // goto target was not found return; assert(!istate.start); if (exceptionOrCant(e)) return; if (e && e.op == TOK.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // break at a higher level return; } istate.gotoTarget = null; break; } if (e && e.op == TOK.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // continue at a higher level return; } istate.gotoTarget = null; e = null; } if (e) { result = e; // bubbled up from ReturnStatement return; } UnionExp uei = void; e = interpret(&uei, s.increment, istate, ctfeNeedNothing); if (exceptionOrCant(e)) return; } assert(result is null); } override void visit(ForeachStatement s) { assert(0); // rewritten to ForStatement } override void visit(ForeachRangeStatement s) { assert(0); // rewritten to ForStatement } override void visit(SwitchStatement s) { debug (LOG) { printf("%s SwitchStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; if (istate.start) { Expression e = interpret(s._body, istate); if (istate.start) // goto target was not found return; if (exceptionOrCant(e)) return; if (e && e.op == TOK.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // break at a higher level return; } istate.gotoTarget = null; e = null; } result = e; return; } UnionExp uecond = void; Expression econdition = interpret(&uecond, s.condition, istate); if (exceptionOrCant(econdition)) return; Statement scase = null; size_t dim = s.cases ? s.cases.dim : 0; for (size_t i = 0; i < dim; i++) { CaseStatement cs = (*s.cases)[i]; UnionExp uecase = void; Expression ecase = interpret(&uecase, cs.exp, istate); if (exceptionOrCant(ecase)) return; if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase)) { scase = cs; break; } } if (!scase) { if (s.hasNoDefault) s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars()); scase = s.sdefault; } assert(scase); /* Jump to scase */ istate.start = scase; Expression e = interpret(pue, s._body, istate); assert(!istate.start); // jump must not fail if (e && e.op == TOK.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { result = e; // break at a higher level return; } istate.gotoTarget = null; e = null; } result = e; } override void visit(CaseStatement s) { debug (LOG) { printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s); } if (istate.start == s) istate.start = null; result = interpret(pue, s.statement, istate); } override void visit(DefaultStatement s) { debug (LOG) { printf("%s DefaultStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; result = interpret(pue, s.statement, istate); } override void visit(GotoStatement s) { debug (LOG) { printf("%s GotoStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } assert(s.label && s.label.statement); istate.gotoTarget = s.label.statement; result = CTFEExp.gotoexp; } override void visit(GotoCaseStatement s) { debug (LOG) { printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } assert(s.cs); istate.gotoTarget = s.cs; result = CTFEExp.gotoexp; } override void visit(GotoDefaultStatement s) { debug (LOG) { printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } assert(s.sw && s.sw.sdefault); istate.gotoTarget = s.sw.sdefault; result = CTFEExp.gotoexp; } override void visit(LabelStatement s) { debug (LOG) { printf("%s LabelStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; result = interpret(pue, s.statement, istate); } override void visit(TryCatchStatement s) { debug (LOG) { printf("%s TryCatchStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; if (istate.start) { Expression e = null; e = interpret(pue, s._body, istate); for (size_t i = 0; i < s.catches.dim; i++) { if (e || !istate.start) // goto target was found break; Catch ca = (*s.catches)[i]; e = interpret(pue, ca.handler, istate); } result = e; return; } Expression e = interpret(s._body, istate); // An exception was thrown if (e && e.op == TOK.thrownException) { ThrownExceptionExp ex = cast(ThrownExceptionExp)e; Type extype = ex.thrown.originalClass().type; // Search for an appropriate catch clause. for (size_t i = 0; i < s.catches.dim; i++) { Catch ca = (*s.catches)[i]; Type catype = ca.type; if (!catype.equals(extype) && !catype.isBaseOf(extype, null)) continue; // Execute the handler if (ca.var) { ctfeStack.push(ca.var); setValue(ca.var, ex.thrown); } e = interpret(ca.handler, istate); if (CTFEExp.isGotoExp(e)) { /* This is an optimization that relies on the locality of the jump target. * If the label is in the same catch handler, the following scan * would find it quickly and can reduce jump cost. * Otherwise, the catch block may be unnnecessary scanned again * so it would make CTFE speed slower. */ InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; Expression eh = interpret(ca.handler, &istatex); if (!istatex.start) { istate.gotoTarget = null; e = eh; } } break; } } result = e; } static bool isAnErrorException(ClassDeclaration cd) { return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null); } static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest) { debug (LOG) { printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars()); } // Little sanity check to make sure it's really a Throwable ClassReferenceExp boss = oldest.thrown; const next = 4; // index of Throwable.next assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next ClassReferenceExp collateral = newest.thrown; if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass())) { /* Find the index of the Error.bypassException field */ auto bypass = next + 1; if ((*collateral.value.elements)[bypass].type.ty == Tuns32) bypass += 1; // skip over _refcount field assert((*collateral.value.elements)[bypass].type.ty == Tclass); // The new exception bypass the existing chain (*collateral.value.elements)[bypass] = boss; return newest; } while ((*boss.value.elements)[next].op == TOK.classReference) { boss = cast(ClassReferenceExp)(*boss.value.elements)[next]; } (*boss.value.elements)[next] = collateral; return oldest; } override void visit(TryFinallyStatement s) { debug (LOG) { printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; if (istate.start) { Expression e = null; e = interpret(pue, s._body, istate); // Jump into/out from finalbody is disabled in semantic analysis. // and jump inside will be handled by the ScopeStatement == finalbody. result = e; return; } Expression ex = interpret(s._body, istate); if (CTFEExp.isCantExp(ex)) { result = ex; return; } while (CTFEExp.isGotoExp(ex)) { // If the goto target is within the body, we must not interpret the finally statement, // because that will call destructors for objects within the scope, which we should not do. InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; Expression bex = interpret(s._body, &istatex); if (istatex.start) { // The goto target is outside the current scope. break; } // The goto target was within the body. if (CTFEExp.isCantExp(bex)) { result = bex; return; } *istate = istatex; ex = bex; } Expression ey = interpret(s.finalbody, istate); if (CTFEExp.isCantExp(ey)) { result = ey; return; } if (ey && ey.op == TOK.thrownException) { // Check for collided exceptions if (ex && ex.op == TOK.thrownException) ex = chainExceptions(cast(ThrownExceptionExp)ex, cast(ThrownExceptionExp)ey); else ex = ey; } result = ex; } override void visit(ThrowStatement s) { debug (LOG) { printf("%s ThrowStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } Expression e = interpret(s.exp, istate); if (exceptionOrCant(e)) return; assert(e.op == TOK.classReference); result = new ThrownExceptionExp(s.loc, cast(ClassReferenceExp)e); } override void visit(OnScopeStatement s) { assert(0); } override void visit(WithStatement s) { debug (LOG) { printf("%s WithStatement::interpret()\n", s.loc.toChars()); } if (istate.start == s) istate.start = null; if (istate.start) { result = s._body ? interpret(s._body, istate) : null; return; } // If it is with(Enum) {...}, just execute the body. if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) { result = interpret(pue, s._body, istate); return; } Expression e = interpret(s.exp, istate); if (exceptionOrCant(e)) return; if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer) { e = new AddrExp(s.loc, e, s.wthis.type); } ctfeStack.push(s.wthis); setValue(s.wthis, e); e = interpret(s._body, istate); if (CTFEExp.isGotoExp(e)) { /* This is an optimization that relies on the locality of the jump target. * If the label is in the same WithStatement, the following scan * would find it quickly and can reduce jump cost. * Otherwise, the statement body may be unnnecessary scanned again * so it would make CTFE speed slower. */ InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; Expression ex = interpret(s._body, &istatex); if (!istatex.start) { istate.gotoTarget = null; e = ex; } } ctfeStack.pop(s.wthis); result = e; } override void visit(AsmStatement s) { debug (LOG) { printf("%s AsmStatement::interpret()\n", s.loc.toChars()); } if (istate.start) { if (istate.start != s) return; istate.start = null; } s.error("`asm` statements cannot be interpreted at compile time"); result = CTFEExp.cantexp; } override void visit(ImportStatement s) { debug (LOG) { printf("ImportStatement::interpret()\n"); } if (istate.start) { if (istate.start != s) return; istate.start = null; } } /******************************** Expression ***************************/ override void visit(Expression e) { debug (LOG) { printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars()); printf("type = %s\n", e.type.toChars()); e.print(); } e.error("cannot interpret `%s` at compile time", e.toChars()); result = CTFEExp.cantexp; } override void visit(ThisExp e) { debug (LOG) { printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (goal == ctfeNeedLvalue) { // We might end up here with istate being zero // https://issues.dlang.org/show_bug.cgi?id=16382 if (istate && istate.fd.vthis) { result = new VarExp(e.loc, istate.fd.vthis); result.type = e.type; } else result = e; return; } result = ctfeStack.getThis(); if (result) { assert(result.op == TOK.structLiteral || result.op == TOK.classReference); return; } e.error("value of `this` is not known at compile time"); result = CTFEExp.cantexp; } override void visit(NullExp e) { result = e; } override void visit(IntegerExp e) { debug (LOG) { printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } result = e; } override void visit(RealExp e) { debug (LOG) { printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } result = e; } override void visit(ComplexExp e) { result = e; } override void visit(StringExp e) { debug (LOG) { printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } /* Attempts to modify string literals are prevented * in BinExp::interpretAssignCommon. */ result = e; } override void visit(FuncExp e) { debug (LOG) { printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } result = e; } override void visit(SymOffExp e) { debug (LOG) { printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.var.isFuncDeclaration() && e.offset == 0) { result = e; return; } if (isTypeInfo_Class(e.type) && e.offset == 0) { result = e; return; } if (e.type.ty != Tpointer) { // Probably impossible e.error("cannot interpret `%s` at compile time", e.toChars()); result = CTFEExp.cantexp; return; } Type pointee = (cast(TypePointer)e.type).next; if (e.var.isThreadlocal()) { e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars()); result = CTFEExp.cantexp; return; } // Check for taking an address of a shared variable. // If the shared variable is an array, the offset might not be zero. Type fromType = null; if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray) { fromType = (cast(TypeArray)e.var.type).next; } if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee)))) { result = e; return; } Expression val = getVarExp(e.loc, istate, e.var, goal); if (exceptionOrCant(val)) return; if (val.type.ty == Tarray || val.type.ty == Tsarray) { // Check for unsupported type painting operations Type elemtype = (cast(TypeArray)val.type).next; d_uns64 elemsize = elemtype.size(); // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* if (val.type.ty == Tsarray && pointee.ty == Tarray && elemsize == pointee.nextOf().size()) { emplaceExp!(AddrExp)(pue, e.loc, val, e.type); result = pue.exp(); return; } // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*. if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size()) { size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger(); Expression elwr = new IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t); Expression eupr = new IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t); // Create a CTFE pointer &val[ofs..ofs+d] auto se = new SliceExp(e.loc, val, elwr, eupr); se.type = pointee; emplaceExp!(AddrExp)(pue, e.loc, se, e.type); result = pue.exp(); return; } if (!isSafePointerCast(elemtype, pointee)) { // It's also OK to cast from &string to string*. if (e.offset == 0 && isSafePointerCast(e.var.type, pointee)) { // Create a CTFE pointer &var auto ve = new VarExp(e.loc, e.var); ve.type = elemtype; emplaceExp!(AddrExp)(pue, e.loc, ve, e.type); result = pue.exp(); return; } e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars()); result = CTFEExp.cantexp; return; } const dinteger_t sz = pointee.size(); dinteger_t indx = e.offset / sz; assert(sz * indx == e.offset); Expression aggregate = null; if (val.op == TOK.arrayLiteral || val.op == TOK.string_) { aggregate = val; } else if (val.op == TOK.slice) { aggregate = (cast(SliceExp)val).e1; UnionExp uelwr = void; Expression lwr = interpret(&uelwr, (cast(SliceExp)val).lwr, istate); indx += lwr.toInteger(); } if (aggregate) { // Create a CTFE pointer &aggregate[ofs] auto ofs = new IntegerExp(e.loc, indx, Type.tsize_t); auto ei = new IndexExp(e.loc, aggregate, ofs); ei.type = elemtype; emplaceExp!(AddrExp)(pue, e.loc, ei, e.type); result = pue.exp(); return; } } else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee)) { // Create a CTFE pointer &var auto ve = new VarExp(e.loc, e.var); ve.type = e.var.type; emplaceExp!(AddrExp)(pue, e.loc, ve, e.type); result = pue.exp(); return; } e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars()); result = CTFEExp.cantexp; } override void visit(AddrExp e) { debug (LOG) { printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.e1.op == TOK.variable) { Declaration decl = (cast(VarExp)e.e1).var; // We cannot take the address of an imported symbol at compile time if (decl.isImportedSymbol()) { e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars()); result = CTFEExp.cantexp; return; } if (decl.isDataseg()) { // Normally this is already done by optimize() // Do it here in case optimize(WANTvalue) wasn't run before CTFE result = new SymOffExp(e.loc, (cast(VarExp)e.e1).var, 0); result.type = e.type; return; } } auto er = interpret(e.e1, istate, ctfeNeedLvalue); if (er.op == TOK.variable && (cast(VarExp)er).var == istate.fd.vthis) er = interpret(er, istate); if (exceptionOrCant(er)) return; // Return a simplified address expression emplaceExp!(AddrExp)(pue, e.loc, er, e.type); result = pue.exp(); } override void visit(DelegateExp e) { debug (LOG) { printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } // TODO: Really we should create a CTFE-only delegate expression // of a pointer and a funcptr. // If it is &nestedfunc, just return it // TODO: We should save the context pointer if (e.e1.op == TOK.variable && (cast(VarExp)e.e1).var == e.func) { result = e; return; } auto er = interpret(e.e1, istate); if (exceptionOrCant(er)) return; if (er == e.e1) { // If it has already been CTFE'd, just return it result = e; } else { emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false); result = pue.exp(); result.type = e.type; } } static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CtfeGoal goal) { Expression e = CTFEExp.cantexp; if (VarDeclaration v = d.isVarDeclaration()) { /* Magic variable __ctfe always returns true when interpreting */ if (v.ident == Id.ctfe) return new IntegerExp(loc, 1, Type.tbool); if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run { v.dsymbolSemantic(null); if (v.type.ty == Terror) return CTFEExp.cantexp; } if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE()) { if (v.inuse) { error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); return CTFEExp.cantexp; } if (v._scope) { v.inuse++; v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members v.inuse--; } e = v._init.initializerToExpression(v.type); if (!e) return CTFEExp.cantexp; assert(e.type); if (e.op == TOK.construct || e.op == TOK.blit) { AssignExp ae = cast(AssignExp)e; e = ae.e2; } if (e.op == TOK.error) { // FIXME: Ultimately all errors should be detected in prior semantic analysis stage. } else if (v.isDataseg() || (v.storage_class & STC.manifest)) { /* https://issues.dlang.org/show_bug.cgi?id=14304 * e is a value that is not yet owned by CTFE. * Mark as "cached", and use it directly during interpretation. */ e = scrubCacheValue(v.loc, e); ctfeStack.saveGlobalConstant(v, e); } else { v.inuse++; e = interpret(e, istate); v.inuse--; if (CTFEExp.isCantExp(e) && !global.gag && !CtfeStatus.stackTraceCallsToSuppress) errorSupplemental(loc, "while evaluating %s.init", v.toChars()); if (exceptionOrCantInterpret(e)) return e; } } else if (v.isCTFE() && !hasValue(v)) { if (v._init && v.type.size() != 0) { if (v._init.isVoidInitializer()) { // var should have been initialized when it was created error(loc, "CTFE internal error: trying to access uninitialized var"); assert(0); } e = v._init.initializerToExpression(); } else e = v.type.defaultInitLiteral(e.loc); e = interpret(e, istate); } else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate) { error(loc, "variable `%s` cannot be read at compile time", v.toChars()); return CTFEExp.cantexp; } else { e = hasValue(v) ? getValue(v) : null; if (!e && !v.isCTFE() && v.isDataseg()) { error(loc, "static variable `%s` cannot be read at compile time", v.toChars()); return CTFEExp.cantexp; } if (!e) { assert(!(v._init && v._init.isVoidInitializer())); // CTFE initiated from inside a function error(loc, "variable `%s` cannot be read at compile time", v.toChars()); return CTFEExp.cantexp; } if (e.op == TOK.void_) { VoidInitExp ve = cast(VoidInitExp)e; error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars()); errorSupplemental(ve.var.loc, "`%s` was uninitialized and used before set", ve.var.toChars()); return CTFEExp.cantexp; } if (goal != ctfeNeedLvalue && (v.isRef() || v.isOut())) e = interpret(e, istate, goal); } if (!e) e = CTFEExp.cantexp; } else if (SymbolDeclaration s = d.isSymbolDeclaration()) { // Struct static initializers, for example e = s.dsym.type.defaultInitLiteral(loc); if (e.op == TOK.error) error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars()); e = e.expressionSemantic(null); if (e.op == TOK.error) e = CTFEExp.cantexp; else // Convert NULL to CTFEExp e = interpret(e, istate, goal); } else error(loc, "cannot interpret declaration `%s` at compile time", d.toChars()); return e; } override void visit(VarExp e) { debug (LOG) { printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal); } if (e.var.isFuncDeclaration()) { result = e; return; } if (goal == ctfeNeedLvalue) { VarDeclaration v = e.var.isVarDeclaration(); if (v && !v.isDataseg() && !v.isCTFE() && !istate) { e.error("variable `%s` cannot be read at compile time", v.toChars()); result = CTFEExp.cantexp; return; } if (v && !hasValue(v)) { if (!v.isCTFE() && v.isDataseg()) e.error("static variable `%s` cannot be read at compile time", v.toChars()); else // CTFE initiated from inside a function e.error("variable `%s` cannot be read at compile time", v.toChars()); result = CTFEExp.cantexp; return; } if (v && (v.storage_class & (STC.out_ | STC.ref_)) && hasValue(v)) { // Strip off the nest of ref variables Expression ev = getValue(v); if (ev.op == TOK.variable || ev.op == TOK.index || ev.op == TOK.dotVariable) { result = interpret(pue, ev, istate, goal); return; } } result = e; return; } result = getVarExp(e.loc, istate, e.var, goal); if (exceptionOrCant(result)) return; if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct) { /* Ultimately, STC.ref_|STC.out_ check should be enough to see the * necessity of type repainting. But currently front-end paints * non-ref struct variables by the const type. * * auto foo(ref const S cs); * S s; * foo(s); // VarExp('s') will have const(S) */ // A VarExp may include an implicit cast. It must be done explicitly. result = paintTypeOntoLiteral(e.type, result); } } override void visit(DeclarationExp e) { debug (LOG) { printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Dsymbol s = e.declaration; if (VarDeclaration v = s.isVarDeclaration()) { if (TupleDeclaration td = v.toAlias().isTupleDeclaration()) { result = null; // Reserve stack space for all tuple members if (!td.objects) return; for (size_t i = 0; i < td.objects.dim; ++i) { RootObject o = (*td.objects)[i]; Expression ex = isExpression(o); DsymbolExp ds = (ex && ex.op == TOK.dSymbol) ? cast(DsymbolExp)ex : null; VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null; assert(v2); if (v2.isDataseg() && !v2.isCTFE()) continue; ctfeStack.push(v2); if (v2._init) { Expression einit; if (ExpInitializer ie = v2._init.isExpInitializer()) { einit = interpret(ie.exp, istate, goal); if (exceptionOrCant(einit)) return; } else if (v2._init.isVoidInitializer()) { einit = voidInitLiteral(v2.type, v2).copy(); } else { e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); result = CTFEExp.cantexp; return; } setValue(v2, einit); } } return; } if (v.isStatic()) { // Just ignore static variables which aren't read or written yet result = null; return; } if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE()) ctfeStack.push(v); if (v._init) { if (ExpInitializer ie = v._init.isExpInitializer()) { result = interpret(ie.exp, istate, goal); } else if (v._init.isVoidInitializer()) { result = voidInitLiteral(v.type, v).copy(); // There is no AssignExp for void initializers, // so set it here. setValue(v, result); } else { e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); result = CTFEExp.cantexp; } } else if (v.type.size() == 0) { // Zero-length arrays don't need an initializer result = v.type.defaultInitLiteral(e.loc); } else { e.error("variable `%s` cannot be modified at compile time", v.toChars()); result = CTFEExp.cantexp; } return; } if (s.isAttribDeclaration() || s.isTemplateMixin() || s.isTupleDeclaration()) { // Check for static struct declarations, which aren't executable AttribDeclaration ad = e.declaration.isAttribDeclaration(); if (ad && ad.decl && ad.decl.dim == 1) { Dsymbol sparent = (*ad.decl)[0]; if (sparent.isAggregateDeclaration() || sparent.isTemplateDeclaration() || sparent.isAliasDeclaration()) { result = null; return; // static (template) struct declaration. Nothing to do. } } // These can be made to work, too lazy now e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); result = CTFEExp.cantexp; return; } // Others should not contain executable code, so are trivial to evaluate result = null; debug (LOG) { printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result); } } override void visit(TypeidExp e) { debug (LOG) { printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (Type t = isType(e.obj)) { result = e; return; } if (Expression ex = isExpression(e.obj)) { result = interpret(ex, istate); if (exceptionOrCant(ex)) return; if (result.op == TOK.null_) { e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars()); result = CTFEExp.cantexp; return; } if (result.op != TOK.classReference) { e.error("CTFE internal error: determining classinfo"); result = CTFEExp.cantexp; return; } ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass(); assert(cd); emplaceExp!(TypeidExp)(pue, e.loc, cd.type); result = pue.exp(); result.type = e.type; return; } visit(cast(Expression)e); } override void visit(TupleExp e) { debug (LOG) { printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (exceptionOrCant(interpret(e.e0, istate, ctfeNeedNothing))) return; auto expsx = e.exps; for (size_t i = 0; i < expsx.dim; i++) { Expression exp = (*expsx)[i]; Expression ex = interpret(exp, istate); if (exceptionOrCant(ex)) return; // A tuple of assignments can contain void (Bug 5676). if (goal == ctfeNeedNothing) continue; if (ex.op == TOK.voidExpression) { e.error("CTFE internal error: void element `%s` in tuple", exp.toChars()); assert(0); } /* If any changes, do Copy On Write */ if (ex !is exp) { expsx = copyArrayOnWrite(expsx, e.exps); (*expsx)[i] = ex; } } if (expsx !is e.exps) { expandTuples(expsx); emplaceExp!(TupleExp)(pue, e.loc, expsx); result = pue.exp(); result.type = new TypeTuple(expsx); } else result = e; } override void visit(ArrayLiteralExp e) { debug (LOG) { printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements { result = e; return; } Type tn = e.type.toBasetype().nextOf().toBasetype(); bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct); auto basis = interpret(e.basis, istate); if (exceptionOrCant(basis)) return; auto expsx = e.elements; size_t dim = expsx ? expsx.dim : 0; for (size_t i = 0; i < dim; i++) { Expression exp = (*expsx)[i]; Expression ex; if (!exp) { ex = copyLiteral(basis).copy(); } else { // segfault bug 6250 assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e); ex = interpret(exp, istate); if (exceptionOrCant(ex)) return; /* Each elements should have distinct CTFE memory. * int[1] z = 7; * int[1][] pieces = [z,z]; // here */ if (wantCopy) ex = copyLiteral(ex).copy(); } /* If any changes, do Copy On Write */ if (ex !is exp) { expsx = copyArrayOnWrite(expsx, e.elements); (*expsx)[i] = ex; } } if (expsx !is e.elements) { // todo: all tuple expansions should go in semantic phase. expandTuples(expsx); if (expsx.dim != dim) { e.error("CTFE internal error: invalid array literal"); result = CTFEExp.cantexp; return; } emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx); auto ale = cast(ArrayLiteralExp)pue.exp(); ale.ownedByCtfe = OwnedBy.ctfe; result = ale; } else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_)) { // If it's immutable, we don't need to dup it result = e; } else result = copyLiteral(e).copy(); } override void visit(AssocArrayLiteralExp e) { debug (LOG) { printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements { result = e; return; } auto keysx = e.keys; auto valuesx = e.values; for (size_t i = 0; i < keysx.dim; i++) { auto ekey = (*keysx)[i]; auto evalue = (*valuesx)[i]; auto ek = interpret(ekey, istate); if (exceptionOrCant(ek)) return; auto ev = interpret(evalue, istate); if (exceptionOrCant(ev)) return; /* If any changes, do Copy On Write */ if (ek !is ekey || ev !is evalue) { keysx = copyArrayOnWrite(keysx, e.keys); valuesx = copyArrayOnWrite(valuesx, e.values); (*keysx)[i] = ek; (*valuesx)[i] = ev; } } if (keysx !is e.keys) expandTuples(keysx); if (valuesx !is e.values) expandTuples(valuesx); if (keysx.dim != valuesx.dim) { e.error("CTFE internal error: invalid AA"); result = CTFEExp.cantexp; return; } /* Remove duplicate keys */ for (size_t i = 1; i < keysx.dim; i++) { auto ekey = (*keysx)[i - 1]; for (size_t j = i; j < keysx.dim; j++) { auto ekey2 = (*keysx)[j]; if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2)) continue; // Remove ekey keysx = copyArrayOnWrite(keysx, e.keys); valuesx = copyArrayOnWrite(valuesx, e.values); keysx.remove(i - 1); valuesx.remove(i - 1); i -= 1; // redo the i'th iteration break; } } if (keysx !is e.keys || valuesx !is e.values) { assert(keysx !is e.keys && valuesx !is e.values); auto aae = new AssocArrayLiteralExp(e.loc, keysx, valuesx); aae.type = e.type; aae.ownedByCtfe = OwnedBy.ctfe; result = aae; } else result = copyLiteral(e).copy(); } override void visit(StructLiteralExp e) { debug (LOG) { printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe); } if (e.ownedByCtfe >= OwnedBy.ctfe) { result = e; return; } size_t dim = e.elements ? e.elements.dim : 0; auto expsx = e.elements; if (dim != e.sd.fields.dim) { // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral assert(e.sd.isNested() && dim == e.sd.fields.dim - 1); /* If a nested struct has no initialized hidden pointer, * set it to null to match the runtime behaviour. */ auto ne = new NullExp(e.loc); ne.type = e.sd.vthis.type; expsx = copyArrayOnWrite(expsx, e.elements); expsx.push(ne); ++dim; } assert(dim == e.sd.fields.dim); foreach (i; 0 .. dim) { auto v = e.sd.fields[i]; Expression exp = (*expsx)[i]; Expression ex; if (!exp) { ex = voidInitLiteral(v.type, v).copy(); } else { ex = interpret(exp, istate); if (exceptionOrCant(ex)) return; if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray) { // Block assignment from inside struct literals auto tsa = cast(TypeSArray)v.type; auto len = cast(size_t)tsa.dim.toInteger(); ex = createBlockDuplicatedArrayLiteral(ex.loc, v.type, ex, len); } } /* If any changes, do Copy On Write */ if (ex !is exp) { expsx = copyArrayOnWrite(expsx, e.elements); (*expsx)[i] = ex; } } if (expsx !is e.elements) { expandTuples(expsx); if (expsx.dim != e.sd.fields.dim) { e.error("CTFE internal error: invalid struct literal"); result = CTFEExp.cantexp; return; } emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx); auto sle = cast(StructLiteralExp)pue.exp(); sle.type = e.type; sle.ownedByCtfe = OwnedBy.ctfe; sle.origin = e.origin; result = sle; } else result = copyLiteral(e).copy(); } // Create an array literal of type 'newtype' with dimensions given by // 'arguments'[argnum..$] static Expression recursivelyCreateArrayLiteral(const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum) { Expression lenExpr = interpret((*arguments)[argnum], istate); if (exceptionOrCantInterpret(lenExpr)) return lenExpr; size_t len = cast(size_t)lenExpr.toInteger(); Type elemType = (cast(TypeArray)newtype).next; if (elemType.ty == Tarray && argnum < arguments.dim - 1) { Expression elem = recursivelyCreateArrayLiteral(loc, elemType, istate, arguments, argnum + 1); if (exceptionOrCantInterpret(elem)) return elem; auto elements = new Expressions(len); for (size_t i = 0; i < len; i++) (*elements)[i] = copyLiteral(elem).copy(); auto ae = new ArrayLiteralExp(loc, newtype, elements); ae.ownedByCtfe = OwnedBy.ctfe; return ae; } assert(argnum == arguments.dim - 1); if (elemType.ty == Tchar || elemType.ty == Twchar || elemType.ty == Tdchar) { const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger(); const sz = cast(ubyte)elemType.size(); return createBlockDuplicatedStringLiteral(loc, newtype, ch, len, sz); } else { auto el = interpret(elemType.defaultInitLiteral(loc), istate); return createBlockDuplicatedArrayLiteral(loc, newtype, el, len); } } override void visit(NewExp e) { debug (LOG) { printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.allocator) { e.error("member allocators not supported by CTFE"); result = CTFEExp.cantexp; return; } result = interpret(e.argprefix, istate, ctfeNeedNothing); if (exceptionOrCant(result)) return; if (e.newtype.ty == Tarray && e.arguments) { result = recursivelyCreateArrayLiteral(e.loc, e.newtype, istate, e.arguments, 0); return; } if (e.newtype.toBasetype().ty == Tstruct) { if (e.member) { Expression se = e.newtype.defaultInitLiteral(e.loc); se = interpret(se, istate); if (exceptionOrCant(se)) return; result = interpretFunction(e.member, istate, e.arguments, se); // Repaint as same as CallExp::interpret() does. result.loc = e.loc; } else { StructDeclaration sd = (cast(TypeStruct)e.newtype.toBasetype()).sym; auto exps = new Expressions(); exps.reserve(sd.fields.dim); if (e.arguments) { exps.setDim(e.arguments.dim); for (size_t i = 0; i < exps.dim; i++) { Expression ex = (*e.arguments)[i]; ex = interpret(ex, istate); if (exceptionOrCant(ex)) return; (*exps)[i] = ex; } } sd.fill(e.loc, exps, false); auto se = new StructLiteralExp(e.loc, sd, exps, e.newtype); se.type = e.newtype; se.ownedByCtfe = OwnedBy.ctfe; result = interpret(se, istate); } if (exceptionOrCant(result)) return; emplaceExp!(AddrExp)(pue, e.loc, result, e.type); result = pue.exp(); return; } if (e.newtype.toBasetype().ty == Tclass) { ClassDeclaration cd = (cast(TypeClass)e.newtype.toBasetype()).sym; size_t totalFieldCount = 0; for (ClassDeclaration c = cd; c; c = c.baseClass) totalFieldCount += c.fields.dim; auto elems = new Expressions(totalFieldCount); size_t fieldsSoFar = totalFieldCount; for (ClassDeclaration c = cd; c; c = c.baseClass) { fieldsSoFar -= c.fields.dim; for (size_t i = 0; i < c.fields.dim; i++) { VarDeclaration v = c.fields[i]; if (v.inuse) { e.error("circular reference to `%s`", v.toPrettyChars()); result = CTFEExp.cantexp; return; } Expression m; if (v._init) { if (v._init.isVoidInitializer()) m = voidInitLiteral(v.type, v).copy(); else m = v.getConstInitializer(true); } else m = v.type.defaultInitLiteral(e.loc); if (exceptionOrCant(m)) return; (*elems)[fieldsSoFar + i] = copyLiteral(m).copy(); } } // Hack: we store a ClassDeclaration instead of a StructDeclaration. // We probably won't get away with this. auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype); se.ownedByCtfe = OwnedBy.ctfe; Expression eref = new ClassReferenceExp(e.loc, se, e.type); if (e.member) { // Call constructor if (!e.member.fbody) { Expression ctorfail = evaluateIfBuiltin(istate, e.loc, e.member, e.arguments, eref); if (ctorfail) { if (exceptionOrCant(ctorfail)) return; result = eref; return; } e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars()); result = CTFEExp.cantexp; return; } Expression ctorfail = interpretFunction(e.member, istate, e.arguments, eref); if (exceptionOrCant(ctorfail)) return; /* https://issues.dlang.org/show_bug.cgi?id=14465 * Repaint the loc, because a super() call * in the constructor modifies the loc of ClassReferenceExp * in CallExp::interpret(). */ eref.loc = e.loc; } result = eref; return; } if (e.newtype.toBasetype().isscalar()) { Expression newval; if (e.arguments && e.arguments.dim) newval = (*e.arguments)[0]; else newval = e.newtype.defaultInitLiteral(e.loc); newval = interpret(newval, istate); if (exceptionOrCant(newval)) return; // Create a CTFE pointer &[newval][0] auto elements = new Expressions(1); (*elements)[0] = newval; auto ae = new ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements); ae.ownedByCtfe = OwnedBy.ctfe; auto ei = new IndexExp(e.loc, ae, new IntegerExp(Loc.initial, 0, Type.tsize_t)); ei.type = e.newtype; emplaceExp!(AddrExp)(pue, e.loc, ei, e.type); result = pue.exp(); return; } e.error("cannot interpret `%s` at compile time", e.toChars()); result = CTFEExp.cantexp; } override void visit(UnaExp e) { debug (LOG) { printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } UnionExp ue = void; Expression e1 = interpret(&ue, e.e1, istate); if (exceptionOrCant(e1)) return; switch (e.op) { case TOK.negate: *pue = Neg(e.type, e1); break; case TOK.tilde: *pue = Com(e.type, e1); break; case TOK.not: *pue = Not(e.type, e1); break; case TOK.vector: result = e; return; // do nothing default: assert(0); } result = (*pue).exp(); } override void visit(DotTypeExp e) { debug (LOG) { printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } UnionExp ue = void; Expression e1 = interpret(&ue, e.e1, istate); if (exceptionOrCant(e1)) return; if (e1 == e.e1) result = e; // optimize: reuse this CTFE reference else { auto edt = cast(DotTypeExp)e.copy(); edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue result = edt; } } extern (D) private void interpretCommon(BinExp e, fp_t fp) { debug (LOG) { printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars()); } if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == TOK.min) { UnionExp ue1 = void; Expression e1 = interpret(&ue1, e.e1, istate); if (exceptionOrCant(e1)) return; UnionExp ue2 = void; Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; *pue = pointerDifference(e.loc, e.type, e1, e2); result = (*pue).exp(); return; } if (e.e1.type.ty == Tpointer && e.e2.type.isintegral()) { UnionExp ue1 = void; Expression e1 = interpret(&ue1, e.e1, istate); if (exceptionOrCant(e1)) return; UnionExp ue2 = void; Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2); result = (*pue).exp(); return; } if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add) { UnionExp ue1 = void; Expression e1 = interpret(&ue1, e.e1, istate); if (exceptionOrCant(e1)) return; UnionExp ue2 = void; Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1); result = (*pue).exp(); return; } if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer) { e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars()); result = CTFEExp.cantexp; return; } bool evalOperand(UnionExp* pue, Expression ex, out Expression er) { er = interpret(pue, ex, istate); if (exceptionOrCant(er)) return false; if (er.isConst() != 1) { if (er.op == TOK.arrayLiteral) // Until we get it to work, issue a reasonable error message e.error("cannot interpret array literal expression `%s` at compile time", e.toChars()); else e.error("CTFE internal error: non-constant value `%s`", ex.toChars()); result = CTFEExp.cantexp; return false; } return true; } UnionExp ue1 = void; Expression e1; if (!evalOperand(&ue1, e.e1, e1)) return; UnionExp ue2 = void; Expression e2; if (!evalOperand(&ue2, e.e2, e2)) return; if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift) { const sinteger_t i2 = e2.toInteger(); const d_uns64 sz = e1.type.size() * 8; if (i2 < 0 || i2 >= sz) { e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1); result = CTFEExp.cantexp; return; } } *pue = (*fp)(e.loc, e.type, e1, e2); result = (*pue).exp(); if (CTFEExp.isCantExp(result)) e.error("`%s` cannot be interpreted at compile time", e.toChars()); } extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp) { debug (LOG) { printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars()); } UnionExp ue1 = void; UnionExp ue2 = void; if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer) { Expression e1 = interpret(&ue1, e.e1, istate); if (exceptionOrCant(e1)) return; Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars()); dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(e1, &ofs1); Expression agg2 = getAggregateFromPointer(e2, &ofs2); //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars()); const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2); if (cmp == -1) { char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>'; e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars()); result = CTFEExp.cantexp; return; } emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type); result = (*pue).exp(); return; } Expression e1 = interpret(&ue1, e.e1, istate); if (exceptionOrCant(e1)) return; if (!isCtfeComparable(e1)) { e.error("cannot compare `%s` at compile time", e1.toChars()); result = CTFEExp.cantexp; return; } Expression e2 = interpret(&ue2, e.e2, istate); if (exceptionOrCant(e2)) return; if (!isCtfeComparable(e2)) { e.error("cannot compare `%s` at compile time", e2.toChars()); result = CTFEExp.cantexp; return; } const cmp = (*fp)(e.loc, e.op, e1, e2); emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type); result = (*pue).exp(); } override void visit(BinExp e) { switch (e.op) { case TOK.add: interpretCommon(e, &Add); return; case TOK.min: interpretCommon(e, &Min); return; case TOK.mul: interpretCommon(e, &Mul); return; case TOK.div: interpretCommon(e, &Div); return; case TOK.mod: interpretCommon(e, &Mod); return; case TOK.leftShift: interpretCommon(e, &Shl); return; case TOK.rightShift: interpretCommon(e, &Shr); return; case TOK.unsignedRightShift: interpretCommon(e, &Ushr); return; case TOK.and: interpretCommon(e, &And); return; case TOK.or: interpretCommon(e, &Or); return; case TOK.xor: interpretCommon(e, &Xor); return; case TOK.pow: interpretCommon(e, &Pow); return; case TOK.equal: case TOK.notEqual: interpretCompareCommon(e, &ctfeEqual); return; case TOK.identity: case TOK.notIdentity: interpretCompareCommon(e, &ctfeIdentity); return; case TOK.lessThan: case TOK.lessOrEqual: case TOK.greaterThan: case TOK.greaterOrEqual: interpretCompareCommon(e, &ctfeCmp); return; default: printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars()); assert(0); } } /* Helper functions for BinExp::interpretAssignCommon */ // Returns the variable which is eventually modified, or NULL if an rvalue. // thisval is the current value of 'this'. static VarDeclaration findParentVar(Expression e) { for (;;) { if (e.op == TOK.variable) break; if (e.op == TOK.index) e = (cast(IndexExp)e).e1; else if (e.op == TOK.dotVariable) e = (cast(DotVarExp)e).e1; else if (e.op == TOK.dotTemplateInstance) e = (cast(DotTemplateInstanceExp)e).e1; else if (e.op == TOK.slice) e = (cast(SliceExp)e).e1; else return null; } VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); assert(v); return v; } extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0) { debug (LOG) { printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars()); } result = CTFEExp.cantexp; Expression e1 = e.e1; if (!istate) { e.error("value of `%s` is not known at compile time", e1.toChars()); return; } ++CtfeStatus.numAssignments; /* Before we begin, we need to know if this is a reference assignment * (dynamic array, AA, or class) or a value assignment. * Determining this for slice assignments are tricky: we need to know * if it is a block assignment (a[] = e) rather than a direct slice * assignment (a[] = b[]). Note that initializers of multi-dimensional * static arrays can have 2D block assignments (eg, int[7][7] x = 6;). * So we need to recurse to determine if it is a block assignment. */ bool isBlockAssignment = false; if (e1.op == TOK.slice) { // a[] = e can have const e. So we compare the naked types. Type tdst = e1.type.toBasetype(); Type tsrc = e.e2.type.toBasetype(); while (tdst.ty == Tsarray || tdst.ty == Tarray) { tdst = (cast(TypeArray)tdst).next.toBasetype(); if (tsrc.equivalent(tdst)) { isBlockAssignment = true; break; } } } // --------------------------------------- // Deal with reference assignment // --------------------------------------- // If it is a construction of a ref variable, it is a ref assignment if ((e.op == TOK.construct || e.op == TOK.blit) && ((cast(AssignExp)e).memset & MemorySet.referenceInit)) { assert(!fp); Expression newval = interpret(e.e2, istate, ctfeNeedLvalue); if (exceptionOrCant(newval)) return; VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration(); setValue(v, newval); // Get the value to return. Note that 'newval' is an Lvalue, // so if we need an Rvalue, we have to interpret again. if (goal == ctfeNeedRvalue) result = interpret(newval, istate); else result = e1; // VarExp is a CTFE reference return; } if (fp) { while (e1.op == TOK.cast_) { CastExp ce = cast(CastExp)e1; e1 = ce.e1; } } // --------------------------------------- // Interpret left hand side // --------------------------------------- AssocArrayLiteralExp existingAA = null; Expression lastIndex = null; Expression oldval = null; if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { // --------------------------------------- // Deal with AA index assignment // --------------------------------------- /* This needs special treatment if the AA doesn't exist yet. * There are two special cases: * (1) If the AA is itself an index of another AA, we may need to create * multiple nested AA literals before we can insert the new value. * (2) If the ultimate AA is null, no insertion happens at all. Instead, * we create nested AA literals, and change it into a assignment. */ IndexExp ie = cast(IndexExp)e1; int depth = 0; // how many nested AA indices are there? while (ie.e1.op == TOK.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray) { assert(ie.modifiable); ie = cast(IndexExp)ie.e1; ++depth; } // Get the AA value to be modified. Expression aggregate = interpret(ie.e1, istate); if (exceptionOrCant(aggregate)) return; if (aggregate.op == TOK.assocArrayLiteral) { existingAA = cast(AssocArrayLiteralExp)aggregate; // Normal case, ultimate parent AA already exists // We need to walk from the deepest index up, checking that an AA literal // already exists on each level. lastIndex = interpret((cast(IndexExp)e1).e2, istate); lastIndex = resolveSlice(lastIndex); // only happens with AA assignment if (exceptionOrCant(lastIndex)) return; while (depth > 0) { // Walk the syntax tree to find the indexExp at this depth IndexExp xe = cast(IndexExp)e1; for (int d = 0; d < depth; ++d) xe = cast(IndexExp)xe.e1; Expression ekey = interpret(xe.e2, istate); if (exceptionOrCant(ekey)) return; UnionExp ekeyTmp = void; ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment // Look up this index in it up in the existing AA, to get the next level of AA. AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey); if (exceptionOrCant(newAA)) return; if (!newAA) { // Doesn't exist yet, create an empty AA... auto keysx = new Expressions(); auto valuesx = new Expressions(); newAA = new AssocArrayLiteralExp(e.loc, keysx, valuesx); newAA.type = xe.type; newAA.ownedByCtfe = OwnedBy.ctfe; //... and insert it into the existing AA. existingAA.keys.push(ekey); existingAA.values.push(newAA); } existingAA = newAA; --depth; } if (fp) { oldval = findKeyInAA(e.loc, existingAA, lastIndex); if (!oldval) oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy(); } } else { /* The AA is currently null. 'aggregate' is actually a reference to * whatever contains it. It could be anything: var, dotvarexp, ... * We rewrite the assignment from: * aa[i][j] op= newval; * into: * aa = [i:[j:T.init]]; * aa[j] op= newval; */ oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy(); Expression newaae = oldval; while (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { Expression ekey = interpret((cast(IndexExp)e1).e2, istate); if (exceptionOrCant(ekey)) return; ekey = resolveSlice(ekey); // only happens with AA assignment auto keysx = new Expressions(); auto valuesx = new Expressions(); keysx.push(ekey); valuesx.push(newaae); auto aae = new AssocArrayLiteralExp(e.loc, keysx, valuesx); aae.type = (cast(IndexExp)e1).e1.type; aae.ownedByCtfe = OwnedBy.ctfe; if (!existingAA) { existingAA = aae; lastIndex = ekey; } newaae = aae; e1 = (cast(IndexExp)e1).e1; } // We must set to aggregate with newaae e1 = interpret(e1, istate, ctfeNeedLvalue); if (exceptionOrCant(e1)) return; e1 = assignToLvalue(e, e1, newaae); if (exceptionOrCant(e1)) return; } assert(existingAA && lastIndex); e1 = null; // stomp } else if (e1.op == TOK.arrayLength) { oldval = interpret(e1, istate); if (exceptionOrCant(oldval)) return; } else if (e.op == TOK.construct || e.op == TOK.blit) { // Unless we have a simple var assignment, we're // only modifying part of the variable. So we need to make sure // that the parent variable exists. VarDeclaration ultimateVar = findParentVar(e1); if (e1.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration(); assert(v); if (v.storage_class & STC.out_) goto L1; } else if (ultimateVar && !getValue(ultimateVar)) { Expression ex = interpret(ultimateVar.type.defaultInitLiteral(e.loc), istate); if (exceptionOrCant(ex)) return; setValue(ultimateVar, ex); } else goto L1; } else { L1: e1 = interpret(e1, istate, ctfeNeedLvalue); if (exceptionOrCant(e1)) return; if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { IndexExp ie = cast(IndexExp)e1; assert(ie.e1.op == TOK.assocArrayLiteral); existingAA = cast(AssocArrayLiteralExp)ie.e1; lastIndex = ie.e2; } } // --------------------------------------- // Interpret right hand side // --------------------------------------- Expression newval = interpret(e.e2, istate); if (exceptionOrCant(newval)) return; if (e.op == TOK.blit && newval.op == TOK.int64) { Type tbn = e.type.baseElemOf(); if (tbn.ty == Tstruct) { /* Look for special case of struct being initialized with 0. */ newval = e.type.defaultInitLiteral(e.loc); if (newval.op == TOK.error) { result = CTFEExp.cantexp; return; } newval = interpret(newval, istate); // copy and set ownedByCtfe flag if (exceptionOrCant(newval)) return; } } // ---------------------------------------------------- // Deal with read-modify-write assignments. // Set 'newval' to the final assignment value // Also determine the return value (except for slice // assignments, which are more complicated) // ---------------------------------------------------- if (fp) { if (!oldval) { // Load the left hand side after interpreting the right hand side. oldval = interpret(e1, istate); if (exceptionOrCant(oldval)) return; } if (e.e1.type.ty != Tpointer) { // ~= can create new values (see bug 6052) if (e.op == TOK.concatenateAssign || e.op == TOK.concatenateElemAssign || e.op == TOK.concatenateDcharAssign) { // We need to dup it and repaint the type. For a dynamic array // we can skip duplication, because it gets copied later anyway. if (newval.type.ty != Tarray) { newval = copyLiteral(newval).copy(); newval.type = e.e2.type; // repaint type } else { newval = paintTypeOntoLiteral(e.e2.type, newval); newval = resolveSlice(newval); } } oldval = resolveSlice(oldval); newval = (*fp)(e.loc, e.type, oldval, newval).copy(); } else if (e.e2.type.isintegral() && (e.op == TOK.addAssign || e.op == TOK.minAssign || e.op == TOK.plusPlus || e.op == TOK.minusMinus)) { newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy(); } else { e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars()); result = CTFEExp.cantexp; return; } if (exceptionOrCant(newval)) { if (CTFEExp.isCantExp(newval)) e.error("cannot interpret `%s` at compile time", e.toChars()); return; } } if (existingAA) { if (existingAA.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only constant `%s`", existingAA.toChars()); result = CTFEExp.cantexp; return; } //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n", // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars()); assignAssocArrayElement(e.loc, existingAA, lastIndex, newval); // Determine the return value result = ctfeCast(e.loc, e.type, e.type, fp && post ? oldval : newval); return; } if (e1.op == TOK.arrayLength) { /* Change the assignment from: * arr.length = n; * into: * arr = new_length_array; (result is n) */ // Determine the return value result = ctfeCast(e.loc, e.type, e.type, fp && post ? oldval : newval); if (exceptionOrCant(result)) return; size_t oldlen = cast(size_t)oldval.toInteger(); size_t newlen = cast(size_t)newval.toInteger(); if (oldlen == newlen) // no change required -- we're done! return; // We have changed it into a reference assignment // Note that returnValue is still the new length. e1 = (cast(ArrayLengthExp)e1).e1; Type t = e1.type.toBasetype(); if (t.ty != Tarray) { e.error("`%s` is not yet supported at compile time", e.toChars()); result = CTFEExp.cantexp; return; } e1 = interpret(e1, istate, ctfeNeedLvalue); if (exceptionOrCant(e1)) return; if (oldlen != 0) // Get the old array literal. oldval = interpret(e1, istate); newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy(); e1 = assignToLvalue(e, e1, newval); if (exceptionOrCant(e1)) return; return; } if (!isBlockAssignment) { newval = ctfeCast(e.loc, e.type, e.type, newval); if (exceptionOrCant(newval)) return; // Determine the return value if (goal == ctfeNeedLvalue) // https://issues.dlang.org/show_bug.cgi?id=14371 result = e1; else result = ctfeCast(e.loc, e.type, e.type, fp && post ? oldval : newval); if (exceptionOrCant(result)) return; } if (exceptionOrCant(newval)) return; debug (LOGASSIGN) { printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars()); showCtfeExpr(newval); } /* Block assignment or element-wise assignment. */ if (e1.op == TOK.slice || e1.op == TOK.vector || e1.op == TOK.arrayLiteral || e1.op == TOK.string_ || e1.op == TOK.null_ && e1.type.toBasetype().ty == Tarray) { // Note that slice assignments don't support things like ++, so // we don't need to remember 'returnValue'. result = interpretAssignToSlice(e, e1, newval, isBlockAssignment); if (exceptionOrCant(result)) return; if (e.e1.op == TOK.slice) { Expression e1x = interpret((cast(SliceExp)e.e1).e1, istate, ctfeNeedLvalue); if (e1x.op == TOK.dotVariable) { auto dve = cast(DotVarExp)e1x; auto ex = dve.e1; auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex) : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value : null; auto v = dve.var.isVarDeclaration(); if (!sle || !v) { e.error("CTFE internal error: dotvar slice assignment"); result = CTFEExp.cantexp; return; } stompOverlappedFields(sle, v); } } return; } assert(result); /* Assignment to a CTFE reference. */ if (Expression ex = assignToLvalue(e, e1, newval)) result = ex; return; } /* Set all sibling fields which overlap with v to VoidExp. */ private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v) { if (!v.overlapped) return; foreach (size_t i, v2; sle.sd.fields) { if (v is v2 || !v.isOverlappedWith(v2)) continue; auto e = (*sle.elements)[i]; if (e.op != TOK.void_) (*sle.elements)[i] = voidInitLiteral(e.type, v).copy(); } } private Expression assignToLvalue(BinExp e, Expression e1, Expression newval) { VarDeclaration vd = null; Expression* payload = null; // dead-store to prevent spurious warning Expression oldval; if (e1.op == TOK.variable) { vd = (cast(VarExp)e1).var.isVarDeclaration(); oldval = getValue(vd); } else if (e1.op == TOK.dotVariable) { /* Assignment to member variable of the form: * e.v = newval */ auto ex = (cast(DotVarExp)e1).e1; auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex) : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value : null; auto v = (cast(DotVarExp)e1).var.isVarDeclaration(); if (!sle || !v) { e.error("CTFE internal error: dotvar assignment"); return CTFEExp.cantexp; } if (sle.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only constant `%s`", sle.toChars()); return CTFEExp.cantexp; } int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v) : (cast(ClassReferenceExp)ex).findFieldIndexByName(v); if (fieldi == -1) { e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars()); return CTFEExp.cantexp; } assert(0 <= fieldi && fieldi < sle.elements.dim); // If it's a union, set all other members of this union to void stompOverlappedFields(sle, v); payload = &(*sle.elements)[fieldi]; oldval = *payload; } else if (e1.op == TOK.index) { IndexExp ie = cast(IndexExp)e1; assert(ie.e1.type.toBasetype().ty != Taarray); Expression aggregate; uinteger_t indexToModify; if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true)) { return CTFEExp.cantexp; } size_t index = cast(size_t)indexToModify; if (aggregate.op == TOK.string_) { StringExp existingSE = cast(StringExp)aggregate; if (existingSE.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only string literal `%s`", ie.e1.toChars()); return CTFEExp.cantexp; } existingSE.setCodeUnit(index, cast(dchar)newval.toInteger()); return null; } if (aggregate.op != TOK.arrayLiteral) { e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars()); return CTFEExp.cantexp; } ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate; if (existingAE.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only constant `%s`", existingAE.toChars()); return CTFEExp.cantexp; } payload = &(*existingAE.elements)[index]; oldval = *payload; } else { e.error("`%s` cannot be evaluated at compile time", e.toChars()); return CTFEExp.cantexp; } Type t1b = e1.type.toBasetype(); bool wantCopy = t1b.baseElemOf().ty == Tstruct; if (newval.op == TOK.structLiteral && oldval) { newval = copyLiteral(newval).copy(); assignInPlace(oldval, newval); } else if (wantCopy && e.op == TOK.assign) { // Currently postblit/destructor calls on static array are done // in the druntime internal functions so they don't appear in AST. // Therefore interpreter should handle them specially. assert(oldval); version (all) // todo: instead we can directly access to each elements of the slice { newval = resolveSlice(newval); if (CTFEExp.isCantExp(newval)) { e.error("CTFE internal error: assignment `%s`", e.toChars()); return CTFEExp.cantexp; } } assert(oldval.op == TOK.arrayLiteral); assert(newval.op == TOK.arrayLiteral); Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements; Expressions* newelems = (cast(ArrayLiteralExp)newval).elements; assert(oldelems.dim == newelems.dim); Type elemtype = oldval.type.nextOf(); for (size_t i = 0; i < newelems.dim; i++) { Expression oldelem = (*oldelems)[i]; Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]); // https://issues.dlang.org/show_bug.cgi?id=9245 if (e.e2.isLvalue()) { if (Expression ex = evaluatePostblit(istate, newelem)) return ex; } // https://issues.dlang.org/show_bug.cgi?id=13661 if (Expression ex = evaluateDtor(istate, oldelem)) return ex; (*oldelems)[i] = newelem; } } else { // e1 has its own payload, so we have to create a new literal. if (wantCopy) newval = copyLiteral(newval).copy(); if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=9245 if (Expression ex = evaluatePostblit(istate, newval)) return ex; } oldval = newval; } if (vd) setValue(vd, oldval); else *payload = oldval; // Blit assignment should return the newly created value. if (e.op == TOK.blit) return oldval; return null; } /************* * Deal with assignments of the form: * dest[] = newval * dest[low..upp] = newval * where newval has already been interpreted * * This could be a slice assignment or a block assignment, and * dest could be either an array literal, or a string. * * Returns TOK.cantExpression on failure. If there are no errors, * it returns aggregate[low..upp], except that as an optimisation, * if goal == ctfeNeedNothing, it will return NULL */ private Expression interpretAssignToSlice(BinExp e, Expression e1, Expression newval, bool isBlockAssignment) { dinteger_t lowerbound; dinteger_t upperbound; dinteger_t firstIndex; Expression aggregate; if (e1.op == TOK.vector) e1 = (cast(VectorExp)e1).e1; if (e1.op == TOK.slice) { // ------------------------------ // aggregate[] = newval // aggregate[low..upp] = newval // ------------------------------ SliceExp se = cast(SliceExp)e1; version (all) // should be move in interpretAssignCommon as the evaluation of e1 { Expression oldval = interpret(se.e1, istate); // Set the $ variable uinteger_t dollar = resolveArrayLength(oldval); if (se.lengthVar) { Expression dollarExp = new IntegerExp(e1.loc, dollar, Type.tsize_t); ctfeStack.push(se.lengthVar); setValue(se.lengthVar, dollarExp); } Expression lwr = interpret(se.lwr, istate); if (exceptionOrCantInterpret(lwr)) { if (se.lengthVar) ctfeStack.pop(se.lengthVar); return lwr; } Expression upr = interpret(se.upr, istate); if (exceptionOrCantInterpret(upr)) { if (se.lengthVar) ctfeStack.pop(se.lengthVar); return upr; } if (se.lengthVar) ctfeStack.pop(se.lengthVar); // $ is defined only in [L..U] const dim = dollar; lowerbound = lwr ? lwr.toInteger() : 0; upperbound = upr ? upr.toInteger() : dim; if (lowerbound < 0 || dim < upperbound) { e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`", ulong(dim), ulong(lowerbound), ulong(upperbound)); return CTFEExp.cantexp; } } aggregate = oldval; firstIndex = lowerbound; if (aggregate.op == TOK.slice) { // Slice of a slice --> change the bounds SliceExp oldse = cast(SliceExp)aggregate; if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger()) { e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger()); return CTFEExp.cantexp; } aggregate = oldse.e1; firstIndex = lowerbound + oldse.lwr.toInteger(); } } else { if (e1.op == TOK.arrayLiteral) { lowerbound = 0; upperbound = (cast(ArrayLiteralExp)e1).elements.dim; } else if (e1.op == TOK.string_) { lowerbound = 0; upperbound = (cast(StringExp)e1).len; } else if (e1.op == TOK.null_) { lowerbound = 0; upperbound = 0; } else assert(0); aggregate = e1; firstIndex = lowerbound; } if (upperbound == lowerbound) return newval; // For slice assignment, we check that the lengths match. if (!isBlockAssignment) { const srclen = resolveArrayLength(newval); if (srclen != (upperbound - lowerbound)) { e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`", ulong(srclen), ulong(lowerbound), ulong(upperbound)); return CTFEExp.cantexp; } } if (aggregate.op == TOK.string_) { StringExp existingSE = cast(StringExp)aggregate; if (existingSE.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only string literal `%s`", existingSE.toChars()); return CTFEExp.cantexp; } if (newval.op == TOK.slice) { auto se = cast(SliceExp)newval; auto aggr2 = se.e1; const srclower = se.lwr.toInteger(); const srcupper = se.upr.toInteger(); if (aggregate == aggr2 && lowerbound < srcupper && srclower < upperbound) { e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`", ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper)); return CTFEExp.cantexp; } version (all) // todo: instead we can directly access to each elements of the slice { Expression orignewval = newval; newval = resolveSlice(newval); if (CTFEExp.isCantExp(newval)) { e.error("CTFE internal error: slice `%s`", orignewval.toChars()); return CTFEExp.cantexp; } } assert(newval.op != TOK.slice); } if (newval.op == TOK.string_) { sliceAssignStringFromString(existingSE, cast(StringExp)newval, cast(size_t)firstIndex); return newval; } if (newval.op == TOK.arrayLiteral) { /* Mixed slice: it was initialized as a string literal. * Now a slice of it is being set with an array literal. */ sliceAssignStringFromArrayLiteral(existingSE, cast(ArrayLiteralExp)newval, cast(size_t)firstIndex); return newval; } // String literal block slice assign const value = cast(dchar)newval.toInteger(); foreach (i; 0 .. upperbound - lowerbound) { existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value); } if (goal == ctfeNeedNothing) return null; // avoid creating an unused literal auto retslice = new SliceExp(e.loc, existingSE, new IntegerExp(e.loc, firstIndex, Type.tsize_t), new IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t)); retslice.type = e.type; return interpret(retslice, istate); } if (aggregate.op == TOK.arrayLiteral) { ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate; if (existingAE.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only constant `%s`", existingAE.toChars()); return CTFEExp.cantexp; } if (newval.op == TOK.slice && !isBlockAssignment) { auto se = cast(SliceExp)newval; auto aggr2 = se.e1; const srclower = se.lwr.toInteger(); const srcupper = se.upr.toInteger(); const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct); //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n", // aggregate, aggregate.toChars(), lowerbound, upperbound, // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy); if (wantCopy) { // Currently overlapping for struct array is allowed. // The order of elements processing depends on the overlapping. // https://issues.dlang.org/show_bug.cgi?id=14024 assert(aggr2.op == TOK.arrayLiteral); Expressions* oldelems = existingAE.elements; Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements; Type elemtype = aggregate.type.nextOf(); bool needsPostblit = e.e2.isLvalue(); if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper) { // reverse order for (auto i = upperbound - lowerbound; 0 < i--;) { Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)]; Expression newelem = (*newelems)[cast(size_t)(i + srclower)]; newelem = copyLiteral(newelem).copy(); newelem.type = elemtype; if (needsPostblit) { if (Expression x = evaluatePostblit(istate, newelem)) return x; } if (Expression x = evaluateDtor(istate, oldelem)) return x; (*oldelems)[cast(size_t)(lowerbound + i)] = newelem; } } else { // normal order for (auto i = 0; i < upperbound - lowerbound; i++) { Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)]; Expression newelem = (*newelems)[cast(size_t)(i + srclower)]; newelem = copyLiteral(newelem).copy(); newelem.type = elemtype; if (needsPostblit) { if (Expression x = evaluatePostblit(istate, newelem)) return x; } if (Expression x = evaluateDtor(istate, oldelem)) return x; (*oldelems)[cast(size_t)(lowerbound + i)] = newelem; } } //assert(0); return newval; // oldval? } if (aggregate == aggr2 && lowerbound < srcupper && srclower < upperbound) { e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`", ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper)); return CTFEExp.cantexp; } version (all) // todo: instead we can directly access to each elements of the slice { Expression orignewval = newval; newval = resolveSlice(newval); if (CTFEExp.isCantExp(newval)) { e.error("CTFE internal error: slice `%s`", orignewval.toChars()); return CTFEExp.cantexp; } } // no overlapping //length? assert(newval.op != TOK.slice); } if (newval.op == TOK.string_ && !isBlockAssignment) { /* Mixed slice: it was initialized as an array literal of chars/integers. * Now a slice of it is being set with a string. */ sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex); return newval; } if (newval.op == TOK.arrayLiteral && !isBlockAssignment) { Expressions* oldelems = existingAE.elements; Expressions* newelems = (cast(ArrayLiteralExp)newval).elements; Type elemtype = existingAE.type.nextOf(); bool needsPostblit = e.op != TOK.blit && e.e2.isLvalue(); for (size_t j = 0; j < newelems.dim; j++) { Expression newelem = (*newelems)[j]; newelem = paintTypeOntoLiteral(elemtype, newelem); if (needsPostblit) { Expression x = evaluatePostblit(istate, newelem); if (exceptionOrCantInterpret(x)) return x; } (*oldelems)[cast(size_t)(j + firstIndex)] = newelem; } return newval; } /* Block assignment, initialization of static arrays * x[] = newval * x may be a multidimensional static array. (Note that this * only happens with array literals, never with strings). */ struct RecursiveBlock { InterState* istate; Expression newval; bool refCopy; bool needsPostblit; bool needsDtor; extern (C++) Expression assignTo(ArrayLiteralExp ae) { return assignTo(ae, 0, ae.elements.dim); } extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr) { Expressions* w = ae.elements; assert(ae.type.ty == Tsarray || ae.type.ty == Tarray); bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type); for (size_t k = lwr; k < upr; k++) { if (!directblk && (*w)[k].op == TOK.arrayLiteral) { // Multidimensional array block assign if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k])) return ex; } else if (refCopy) { (*w)[k] = newval; } else if (!needsPostblit && !needsDtor) { assignInPlace((*w)[k], newval); } else { Expression oldelem = (*w)[k]; Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null; assignInPlace(oldelem, newval); if (needsPostblit) { if (Expression ex = evaluatePostblit(istate, oldelem)) return ex; } if (needsDtor) { // https://issues.dlang.org/show_bug.cgi?id=14860 if (Expression ex = evaluateDtor(istate, tmpelem)) return ex; } } } return null; } } Type tn = newval.type.toBasetype(); bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass); bool cow = newval.op != TOK.structLiteral && newval.op != TOK.arrayLiteral && newval.op != TOK.string_; Type tb = tn.baseElemOf(); StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null); RecursiveBlock rb; rb.istate = istate; rb.newval = newval; rb.refCopy = wantRef || cow; rb.needsPostblit = sd && sd.postblit && e.op != TOK.blit && e.e2.isLvalue(); rb.needsDtor = sd && sd.dtor && e.op == TOK.assign; if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound)) return ex; if (goal == ctfeNeedNothing) return null; // avoid creating an unused literal auto retslice = new SliceExp(e.loc, existingAE, new IntegerExp(e.loc, firstIndex, Type.tsize_t), new IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t)); retslice.type = e.type; return interpret(retslice, istate); } e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars()); return CTFEExp.cantexp; } override void visit(AssignExp e) { interpretAssignCommon(e, null); } override void visit(BinAssignExp e) { switch (e.op) { case TOK.addAssign: interpretAssignCommon(e, &Add); return; case TOK.minAssign: interpretAssignCommon(e, &Min); return; case TOK.concatenateAssign: case TOK.concatenateElemAssign: case TOK.concatenateDcharAssign: interpretAssignCommon(e, &ctfeCat); return; case TOK.mulAssign: interpretAssignCommon(e, &Mul); return; case TOK.divAssign: interpretAssignCommon(e, &Div); return; case TOK.modAssign: interpretAssignCommon(e, &Mod); return; case TOK.leftShiftAssign: interpretAssignCommon(e, &Shl); return; case TOK.rightShiftAssign: interpretAssignCommon(e, &Shr); return; case TOK.unsignedRightShiftAssign: interpretAssignCommon(e, &Ushr); return; case TOK.andAssign: interpretAssignCommon(e, &And); return; case TOK.orAssign: interpretAssignCommon(e, &Or); return; case TOK.xorAssign: interpretAssignCommon(e, &Xor); return; case TOK.powAssign: interpretAssignCommon(e, &Pow); return; default: assert(0); } } override void visit(PostExp e) { debug (LOG) { printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.op == TOK.plusPlus) interpretAssignCommon(e, &Add, 1); else interpretAssignCommon(e, &Min, 1); debug (LOG) { if (CTFEExp.isCantExp(result)) printf("PostExp::interpret() CANT\n"); } } /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison; * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison; * 0 otherwise */ static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2) { int ret = 1; while (e.op == TOK.not) { ret *= -1; e = (cast(NotExp)e).e1; } switch (e.op) { case TOK.lessThan: case TOK.lessOrEqual: ret *= -1; goto case; /+ fall through +/ case TOK.greaterThan: case TOK.greaterOrEqual: *p1 = (cast(BinExp)e).e1; *p2 = (cast(BinExp)e).e2; if (!(isPointer((*p1).type) && isPointer((*p2).type))) ret = 0; break; default: ret = 0; break; } return ret; } /** Negate a relational operator, eg >= becomes < */ static TOK reverseRelation(TOK op) { switch (op) { case TOK.greaterOrEqual: return TOK.lessThan; case TOK.greaterThan: return TOK.lessOrEqual; case TOK.lessOrEqual: return TOK.greaterThan; case TOK.lessThan: return TOK.greaterOrEqual; default: assert(0); } } /** If this is a four pointer relation, evaluate it, else return NULL. * * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2) * where p1, p2 are expressions yielding pointers to memory block p, * and q1, q2 are expressions yielding pointers to memory block q. * This expression is valid even if p and q are independent memory * blocks and are therefore not normally comparable; the && form returns true * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns * true if [p1..p2] lies outside [q1..q2], and false otherwise. * * Within the expression, any ordering of p1, p2, q1, q2 is permissible; * the comparison operators can be any of >, <, <=, >=, provided that * both directions (p > q and p < q) are checked. Additionally the * relational sub-expressions can be negated, eg * (!(q1 < p1) && p2 <= q2) is valid. */ private void interpretFourPointerRelation(BinExp e) { assert(e.op == TOK.andAnd || e.op == TOK.orOr); /* It can only be an isInside expression, if both e1 and e2 are * directional pointer comparisons. * Note that this check can be made statically; it does not depends on * any runtime values. This allows a JIT implementation to compile a * special AndAndPossiblyInside, keeping the normal AndAnd case efficient. */ // Save the pointer expressions and the comparison directions, // so we can use them later. Expression p1 = null; Expression p2 = null; Expression p3 = null; Expression p4 = null; int dir1 = isPointerCmpExp(e.e1, &p1, &p2); int dir2 = isPointerCmpExp(e.e2, &p3, &p4); if (dir1 == 0 || dir2 == 0) { result = null; return; } //printf("FourPointerRelation %s\n", toChars()); // Evaluate the first two pointers p1 = interpret(p1, istate); if (exceptionOrCant(p1)) return; p2 = interpret(p2, istate); if (exceptionOrCant(p2)) return; dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(p1, &ofs1); Expression agg2 = getAggregateFromPointer(p2, &ofs2); if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_) { // Here it is either CANT_INTERPRET, // or an IsInside comparison returning false. p3 = interpret(p3, istate); if (CTFEExp.isCantExp(p3)) return; // Note that it is NOT legal for it to throw an exception! Expression except = null; if (exceptionOrCantInterpret(p3)) except = p3; else { p4 = interpret(p4, istate); if (CTFEExp.isCantExp(p4)) { result = p4; return; } if (exceptionOrCantInterpret(p4)) except = p4; } if (except) { e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars()); result = CTFEExp.cantexp; return; } dinteger_t ofs3, ofs4; Expression agg3 = getAggregateFromPointer(p3, &ofs3); Expression agg4 = getAggregateFromPointer(p4, &ofs4); // The valid cases are: // p1 > p2 && p3 > p4 (same direction, also for < && <) // p1 > p2 && p3 < p4 (different direction, also < && >) // Changing any > into >= doesn't affect the result if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4))) { // it's a legal two-sided comparison result = new IntegerExp(e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type); return; } // It's an invalid four-pointer comparison. Either the second // comparison is in the same direction as the first, or else // more than two memory blocks are involved (either two independent // invalid comparisons are present, or else agg3 == agg4). e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars()); result = CTFEExp.cantexp; return; } // The first pointer expression didn't need special treatment, so we // we need to interpret the entire expression exactly as a normal && or ||. // This is easy because we haven't evaluated e2 at all yet, and we already // know it will return a bool. // But we mustn't evaluate the pointer expressions in e1 again, in case // they have side-effects. bool nott = false; Expression ex = e.e1; while (ex.op == TOK.not) { nott = !nott; ex = (cast(NotExp)ex).e1; } TOK cmpop = ex.op; if (nott) cmpop = reverseRelation(cmpop); int cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2); // We already know this is a valid comparison. assert(cmp >= 0); if (e.op == TOK.andAnd && cmp == 1 || e.op == TOK.orOr && cmp == 0) { result = interpret(e.e2, istate); return; } result = new IntegerExp(e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type); } override void visit(LogicalExp e) { debug (LOG) { printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } // Check for an insidePointer expression, evaluate it if so interpretFourPointerRelation(e); if (result) return; result = interpret(e.e1, istate); if (exceptionOrCant(result)) return; int res; const andand = e.op == TOK.andAnd; if (andand ? result.isBool(false) : isTrueBool(result)) res = !andand; else if (andand ? isTrueBool(result) : result.isBool(false)) { UnionExp ue2; result = interpret(&ue2, e.e2, istate); if (exceptionOrCant(result)) return; if (result.op == TOK.voidExpression) { assert(e.type.ty == Tvoid); result = null; return; } if (result.isBool(false)) res = 0; else if (isTrueBool(result)) res = 1; else { result.error("`%s` does not evaluate to a `bool`", result.toChars()); result = CTFEExp.cantexp; return; } } else { result.error("`%s` cannot be interpreted as a `bool`", result.toChars()); result = CTFEExp.cantexp; return; } if (goal != ctfeNeedNothing) { emplaceExp!(IntegerExp)(pue, e.loc, res, e.type); result = pue.exp(); } } // Print a stack trace, starting from callingExp which called fd. // To shorten the stack trace, try to detect recursion. private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd) { if (CtfeStatus.stackTraceCallsToSuppress > 0) { --CtfeStatus.stackTraceCallsToSuppress; return; } errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars()); // Quit if it's not worth trying to compress the stack trace if (CtfeStatus.callDepth < 6 || global.params.verbose) return; // Recursion happens if the current function already exists in the call stack. int numToSuppress = 0; int recurseCount = 0; int depthSoFar = 0; InterState* lastRecurse = istate; for (InterState* cur = istate; cur; cur = cur.caller) { if (cur.fd == fd) { ++recurseCount; numToSuppress = depthSoFar; lastRecurse = cur; } ++depthSoFar; } // We need at least three calls to the same function, to make compression worthwhile if (recurseCount < 2) return; // We found a useful recursion. Print all the calls involved in the recursion errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars()); for (InterState* cur = istate; cur.fd != fd; cur = cur.caller) { errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars()); } // We probably didn't enter the recursion in this function. // Go deeper to find the real beginning. InterState* cur = istate; while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd) { cur = cur.caller; lastRecurse = lastRecurse.caller; ++numToSuppress; } CtfeStatus.stackTraceCallsToSuppress = numToSuppress; } override void visit(CallExp e) { debug (LOG) { printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression pthis = null; FuncDeclaration fd = null; Expression ecall = interpret(e.e1, istate); if (exceptionOrCant(ecall)) return; if (ecall.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)ecall; // Calling a member function pthis = dve.e1; fd = dve.var.isFuncDeclaration(); assert(fd); if (pthis.op == TOK.dotType) pthis = (cast(DotTypeExp)dve.e1).e1; } else if (ecall.op == TOK.variable) { fd = (cast(VarExp)ecall).var.isFuncDeclaration(); assert(fd); if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor) { assert(e.arguments.dim == 1); Expression ea = (*e.arguments)[0]; // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars()); if (ea.op == TOK.slice) ea = (cast(SliceExp)ea).e1; if (ea.op == TOK.cast_) ea = (cast(CastExp)ea).e1; // printf("2 ea = %s, %s %s\n", ea.type.toChars(), Token.toChars(ea.op), ea.toChars()); if (ea.op == TOK.variable || ea.op == TOK.symbolOffset) result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, ctfeNeedRvalue); else if (ea.op == TOK.address) result = interpret((cast(AddrExp)ea).e1, istate); // https://issues.dlang.org/show_bug.cgi?id=18871 // https://issues.dlang.org/show_bug.cgi?id=18819 else if (ea.op == TOK.arrayLiteral) result = interpret(cast(ArrayLiteralExp)ea, istate); else assert(0); if (CTFEExp.isCantExp(result)) return; if (fd.ident == Id.__ArrayPostblit) result = evaluatePostblit(istate, result); else result = evaluateDtor(istate, result); if (!result) result = CTFEExp.voidexp; return; } } else if (ecall.op == TOK.symbolOffset) { SymOffExp soe = cast(SymOffExp)ecall; fd = soe.var.isFuncDeclaration(); assert(fd && soe.offset == 0); } else if (ecall.op == TOK.delegate_) { // Calling a delegate fd = (cast(DelegateExp)ecall).func; pthis = (cast(DelegateExp)ecall).e1; // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc) if (pthis.op == TOK.variable && (cast(VarExp)pthis).var == fd) pthis = null; // context is not necessary for CTFE } else if (ecall.op == TOK.function_) { // Calling a delegate literal fd = (cast(FuncExp)ecall).fd; } else { // delegate.funcptr() // others e.error("cannot call `%s` at compile time", e.toChars()); result = CTFEExp.cantexp; return; } if (!fd) { e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars()); result = CTFEExp.cantexp; return; } if (pthis) { // Member function call // Currently this is satisfied because closure is not yet supported. assert(!fd.isNested()); if (pthis.op == TOK.typeid_) { pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars()); result = CTFEExp.cantexp; return; } assert(pthis); if (pthis.op == TOK.null_) { assert(pthis.type.toBasetype().ty == Tclass); e.error("function call through null class reference `%s`", pthis.toChars()); result = CTFEExp.cantexp; return; } assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference); if (fd.isVirtual() && !e.directcall) { // Make a virtual function call. // Get the function from the vtable of the original class assert(pthis.op == TOK.classReference); ClassDeclaration cd = (cast(ClassReferenceExp)pthis).originalClass(); // We can't just use the vtable index to look it up, because // vtables for interfaces don't get populated until the glue layer. fd = cd.findFunc(fd.ident, cast(TypeFunction)fd.type); assert(fd); } } if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors) { e.error("CTFE failed because of previous errors in `%s`", fd.toChars()); result = CTFEExp.cantexp; return; } // Check for built-in functions result = evaluateIfBuiltin(istate, e.loc, fd, e.arguments, pthis); if (result) return; if (!fd.fbody) { e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars()); result = CTFEExp.showcontext; return; } result = interpretFunction(fd, istate, e.arguments, pthis); if (result.op == TOK.voidExpression) return; if (!exceptionOrCantInterpret(result)) { if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnesessary result = interpret(result, istate); } if (!exceptionOrCantInterpret(result)) { result = paintTypeOntoLiteral(e.type, result); result.loc = e.loc; } else if (CTFEExp.isCantExp(result) && !global.gag) showCtfeBackTrace(e, fd); // Print a stack trace. } override void visit(CommaExp e) { debug (LOG) { printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } // If it creates a variable, and there's no context for // the variable to be created in, we need to create one now. InterState istateComma; if (!istate && firstComma(e.e1).op == TOK.declaration) { ctfeStack.startFrame(null); istate = &istateComma; } void endTempStackFrame() { // If we created a temporary stack frame, end it now. if (istate == &istateComma) ctfeStack.endFrame(); } result = CTFEExp.cantexp; // If the comma returns a temporary variable, it needs to be an lvalue // (this is particularly important for struct constructors) if (e.e1.op == TOK.declaration && e.e2.op == TOK.variable && (cast(DeclarationExp)e.e1).declaration == (cast(VarExp)e.e2).var && (cast(VarExp)e.e2).var.storage_class & STC.ctfe) { VarExp ve = cast(VarExp)e.e2; VarDeclaration v = ve.var.isVarDeclaration(); ctfeStack.push(v); if (!v._init && !getValue(v)) { setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy()); } if (!getValue(v)) { Expression newval = v._init.initializerToExpression(); // Bug 4027. Copy constructors are a weird case where the // initializer is a void function (the variable is modified // through a reference parameter instead). newval = interpret(newval, istate); if (exceptionOrCant(newval)) return endTempStackFrame(); if (newval.op != TOK.voidExpression) { // v isn't necessarily null. setValueWithoutChecking(v, copyLiteral(newval).copy()); } } } else { UnionExp ue = void; auto e1 = interpret(&ue, e.e1, istate, ctfeNeedNothing); if (exceptionOrCant(e1)) return endTempStackFrame(); } result = interpret(pue, e.e2, istate, goal); return endTempStackFrame(); } override void visit(CondExp e) { debug (LOG) { printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } UnionExp uecond = void; Expression econd; econd = interpret(&uecond, e.econd, istate); if (exceptionOrCant(econd)) return; if (isPointer(e.econd.type)) { if (econd.op != TOK.null_) { emplaceExp!(IntegerExp)(&uecond, e.loc, 1, Type.tbool); econd = uecond.exp(); } } if (isTrueBool(econd)) result = interpret(pue, e.e1, istate, goal); else if (econd.isBool(false)) result = interpret(pue, e.e2, istate, goal); else { e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars()); result = CTFEExp.cantexp; } } override void visit(ArrayLengthExp e) { debug (LOG) { printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } UnionExp ue1; Expression e1 = interpret(&ue1, e.e1, istate); assert(e1); if (exceptionOrCant(e1)) return; if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_) { e.error("`%s` cannot be evaluated at compile time", e.toChars()); result = CTFEExp.cantexp; return; } emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type); result = pue.exp(); } override void visit(DelegatePtrExp e) { debug (LOG) { printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression e1 = interpret(pue, e.e1, istate); assert(e1); if (exceptionOrCant(e1)) return; e.error("`%s` cannot be evaluated at compile time", e.toChars()); result = CTFEExp.cantexp; } override void visit(DelegateFuncptrExp e) { debug (LOG) { printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression e1 = interpret(pue, e.e1, istate); assert(e1); if (exceptionOrCant(e1)) return; e.error("`%s` cannot be evaluated at compile time", e.toChars()); result = CTFEExp.cantexp; } static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify) { assert(e.e1.type.toBasetype().ty != Taarray); if (e.e1.type.toBasetype().ty == Tpointer) { // Indexing a pointer. Note that there is no $ in this case. Expression e1 = interpret(e.e1, istate); if (exceptionOrCantInterpret(e1)) return false; Expression e2 = interpret(e.e2, istate); if (exceptionOrCantInterpret(e2)) return false; sinteger_t indx = e2.toInteger(); dinteger_t ofs; Expression agg = getAggregateFromPointer(e1, &ofs); if (agg.op == TOK.null_) { e.error("cannot index through null pointer `%s`", e.e1.toChars()); return false; } if (agg.op == TOK.int64) { e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars()); return false; } // Pointer to a non-array variable if (agg.op == TOK.symbolOffset) { e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars()); return false; } if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_) { dinteger_t len = resolveArrayLength(agg); if (ofs + indx >= len) { e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len); return false; } } else { if (ofs + indx != 0) { e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx); return false; } } *pagg = agg; *pidx = ofs + indx; return true; } Expression e1 = interpret(e.e1, istate); if (exceptionOrCantInterpret(e1)) return false; if (e1.op == TOK.null_) { e.error("cannot index null array `%s`", e.e1.toChars()); return false; } if (e1.op == TOK.vector) e1 = (cast(VectorExp)e1).e1; // Set the $ variable, and find the array literal to modify if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.slice) { e.error("cannot determine length of `%s` at compile time", e.e1.toChars()); return false; } dinteger_t len = resolveArrayLength(e1); if (e.lengthVar) { Expression dollarExp = new IntegerExp(e.loc, len, Type.tsize_t); ctfeStack.push(e.lengthVar); setValue(e.lengthVar, dollarExp); } Expression e2 = interpret(e.e2, istate); if (e.lengthVar) ctfeStack.pop(e.lengthVar); // $ is defined only inside [] if (exceptionOrCantInterpret(e2)) return false; if (e2.op != TOK.int64) { e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars()); return false; } if (e1.op == TOK.slice) { // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx'] uinteger_t index = e2.toInteger(); uinteger_t ilwr = (cast(SliceExp)e1).lwr.toInteger(); uinteger_t iupr = (cast(SliceExp)e1).upr.toInteger(); if (index > iupr - ilwr) { e.error("index %llu exceeds array length %llu", index, iupr - ilwr); return false; } *pagg = (cast(SliceExp)e1).e1; *pidx = index + ilwr; } else { *pagg = e1; *pidx = e2.toInteger(); if (len <= *pidx) { e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len); return false; } } return true; } override void visit(IndexExp e) { debug (LOG) { printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal); } if (e.e1.type.toBasetype().ty == Tpointer) { Expression agg; uinteger_t indexToAccess; if (!resolveIndexing(e, istate, &agg, &indexToAccess, false)) { result = CTFEExp.cantexp; return; } if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_) { if (goal == ctfeNeedLvalue) { // if we need a reference, IndexExp shouldn't be interpreting // the expression to a value, it should stay as a reference emplaceExp!(IndexExp)(pue, e.loc, agg, new IntegerExp(e.e2.loc, indexToAccess, e.e2.type)); result = pue.exp(); result.type = e.type; return; } result = ctfeIndex(e.loc, e.type, agg, indexToAccess); return; } else { assert(indexToAccess == 0); result = interpret(agg, istate, goal); if (exceptionOrCant(result)) return; result = paintTypeOntoLiteral(e.type, result); return; } } if (e.e1.type.toBasetype().ty == Taarray) { Expression e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; if (e1.op == TOK.null_) { if (goal == ctfeNeedLvalue && e1.type.ty == Taarray && e.modifiable) { assert(0); // does not reach here? } e.error("cannot index null array `%s`", e.e1.toChars()); result = CTFEExp.cantexp; return; } Expression e2 = interpret(e.e2, istate); if (exceptionOrCant(e2)) return; if (goal == ctfeNeedLvalue) { // Pointer or reference of a scalar type if (e1 == e.e1 && e2 == e.e2) result = e; else { emplaceExp!(IndexExp)(pue, e.loc, e1, e2); result = pue.exp(); result.type = e.type; } return; } assert(e1.op == TOK.assocArrayLiteral); UnionExp e2tmp = void; e2 = resolveSlice(e2, &e2tmp); result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2); if (!result) { e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars()); result = CTFEExp.cantexp; } return; } Expression agg; uinteger_t indexToAccess; if (!resolveIndexing(e, istate, &agg, &indexToAccess, false)) { result = CTFEExp.cantexp; return; } if (goal == ctfeNeedLvalue) { Expression e2 = new IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t); emplaceExp!(IndexExp)(pue, e.loc, agg, e2); result = pue.exp(); result.type = e.type; return; } result = ctfeIndex(e.loc, e.type, agg, indexToAccess); if (exceptionOrCant(result)) return; if (result.op == TOK.void_) { e.error("`%s` is used before initialized", e.toChars()); errorSupplemental(result.loc, "originally uninitialized here"); result = CTFEExp.cantexp; return; } result = paintTypeOntoLiteral(e.type, result); } override void visit(SliceExp e) { debug (LOG) { printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } if (e.e1.type.toBasetype().ty == Tpointer) { // Slicing a pointer. Note that there is no $ in this case. Expression e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; if (e1.op == TOK.int64) { e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars()); result = CTFEExp.cantexp; return; } /* Evaluate lower and upper bounds of slice */ Expression lwr = interpret(e.lwr, istate); if (exceptionOrCant(lwr)) return; Expression upr = interpret(e.upr, istate); if (exceptionOrCant(upr)) return; uinteger_t ilwr = lwr.toInteger(); uinteger_t iupr = upr.toInteger(); dinteger_t ofs; Expression agg = getAggregateFromPointer(e1, &ofs); ilwr += ofs; iupr += ofs; if (agg.op == TOK.null_) { if (iupr == ilwr) { result = new NullExp(e.loc); result.type = e.type; return; } e.error("cannot slice null pointer `%s`", e.e1.toChars()); result = CTFEExp.cantexp; return; } if (agg.op == TOK.symbolOffset) { e.error("slicing pointers to static variables is not supported in CTFE"); result = CTFEExp.cantexp; return; } if (agg.op != TOK.arrayLiteral && agg.op != TOK.string_) { e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars()); result = CTFEExp.cantexp; return; } assert(agg.op == TOK.arrayLiteral || agg.op == TOK.string_); dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger(); //Type *pointee = ((TypePointer *)agg.type)->next; if (iupr > (len + 1) || iupr < ilwr) { e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len); result = CTFEExp.cantexp; return; } if (ofs != 0) { lwr = new IntegerExp(e.loc, ilwr, lwr.type); upr = new IntegerExp(e.loc, iupr, upr.type); } emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr); result = pue.exp(); result.type = e.type; return; } Expression e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; if (!e.lwr) { result = paintTypeOntoLiteral(e.type, e1); return; } /* Set the $ variable */ if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.null_ && e1.op != TOK.slice) { e.error("cannot determine length of `%s` at compile time", e1.toChars()); result = CTFEExp.cantexp; return; } uinteger_t dollar = resolveArrayLength(e1); if (e.lengthVar) { auto dollarExp = new IntegerExp(e.loc, dollar, Type.tsize_t); ctfeStack.push(e.lengthVar); setValue(e.lengthVar, dollarExp); } /* Evaluate lower and upper bounds of slice */ Expression lwr = interpret(e.lwr, istate); if (exceptionOrCant(lwr)) { if (e.lengthVar) ctfeStack.pop(e.lengthVar); return; } Expression upr = interpret(e.upr, istate); if (exceptionOrCant(upr)) { if (e.lengthVar) ctfeStack.pop(e.lengthVar); return; } if (e.lengthVar) ctfeStack.pop(e.lengthVar); // $ is defined only inside [L..U] uinteger_t ilwr = lwr.toInteger(); uinteger_t iupr = upr.toInteger(); if (e1.op == TOK.null_) { if (ilwr == 0 && iupr == 0) { result = e1; return; } e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr); result = CTFEExp.cantexp; return; } if (e1.op == TOK.slice) { SliceExp se = cast(SliceExp)e1; // Simplify slice of slice: // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] uinteger_t lo1 = se.lwr.toInteger(); uinteger_t up1 = se.upr.toInteger(); if (ilwr > iupr || iupr > up1 - lo1) { e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1); result = CTFEExp.cantexp; return; } ilwr += lo1; iupr += lo1; emplaceExp!(SliceExp)(pue, e.loc, se.e1, new IntegerExp(e.loc, ilwr, lwr.type), new IntegerExp(e.loc, iupr, upr.type)); result = pue.exp(); result.type = e.type; return; } if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_) { if (iupr < ilwr || dollar < iupr) { e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar); result = CTFEExp.cantexp; return; } } emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr); result = pue.exp(); result.type = e.type; } override void visit(InExp e) { debug (LOG) { printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; Expression e2 = interpret(e.e2, istate); if (exceptionOrCant(e2)) return; if (e2.op == TOK.null_) { emplaceExp!(NullExp)(pue, e.loc, e.type); result = pue.exp(); return; } if (e2.op != TOK.assocArrayLiteral) { e.error("`%s` cannot be interpreted at compile time", e.toChars()); result = CTFEExp.cantexp; return; } e1 = resolveSlice(e1); result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1); if (exceptionOrCant(result)) return; if (!result) { emplaceExp!(NullExp)(pue, e.loc, e.type); result = pue.exp(); } else { // Create a CTFE pointer &aa[index] result = new IndexExp(e.loc, e2, e1); result.type = e.type.nextOf(); emplaceExp!(AddrExp)(pue, e.loc, result, e.type); result = pue.exp(); } } override void visit(CatExp e) { debug (LOG) { printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } { Expression e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; Expression e2 = interpret(e.e2, istate); if (exceptionOrCant(e2)) return; UnionExp e1tmp = void; e1 = resolveSlice(e1, &e1tmp); UnionExp e2tmp = void; e2 = resolveSlice(e2, &e2tmp); result = ctfeCat(e.loc, e.type, e1, e2).copy(); } if (CTFEExp.isCantExp(result)) { e.error("`%s` cannot be interpreted at compile time", e.toChars()); return; } // We know we still own it, because we interpreted both e1 and e2 if (result.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)result; ale.ownedByCtfe = OwnedBy.ctfe; // https://issues.dlang.org/show_bug.cgi?id=14686 for (size_t i = 0; i < ale.elements.dim; i++) { Expression ex = evaluatePostblit(istate, (*ale.elements)[i]); if (exceptionOrCant(ex)) return; } } if (result.op == TOK.string_) (cast(StringExp)result).ownedByCtfe = OwnedBy.ctfe; } override void visit(DeleteExp e) { debug (LOG) { printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } result = interpret(e.e1, istate); if (exceptionOrCant(result)) return; if (result.op == TOK.null_) { result = CTFEExp.voidexp; return; } auto tb = e.e1.type.toBasetype(); switch (tb.ty) { case Tclass: if (result.op != TOK.classReference) { e.error("`delete` on invalid class reference `%s`", result.toChars()); result = CTFEExp.cantexp; return; } auto cre = cast(ClassReferenceExp)result; auto cd = cre.originalClass(); if (cd.aggDelete) { e.error("member deallocators not supported by CTFE"); result = CTFEExp.cantexp; return; } if (cd.dtor) { result = interpretFunction(cd.dtor, istate, null, cre); if (exceptionOrCant(result)) return; } break; case Tpointer: tb = (cast(TypePointer)tb).next.toBasetype(); if (tb.ty == Tstruct) { if (result.op != TOK.address || (cast(AddrExp)result).e1.op != TOK.structLiteral) { e.error("`delete` on invalid struct pointer `%s`", result.toChars()); result = CTFEExp.cantexp; return; } auto sd = (cast(TypeStruct)tb).sym; auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1; if (sd.aggDelete) { e.error("member deallocators not supported by CTFE"); result = CTFEExp.cantexp; return; } if (sd.dtor) { result = interpretFunction(sd.dtor, istate, null, sle); if (exceptionOrCant(result)) return; } } break; case Tarray: auto tv = tb.nextOf().baseElemOf(); if (tv.ty == Tstruct) { if (result.op != TOK.arrayLiteral) { e.error("`delete` on invalid struct array `%s`", result.toChars()); result = CTFEExp.cantexp; return; } auto sd = (cast(TypeStruct)tv).sym; if (sd.aggDelete) { e.error("member deallocators not supported by CTFE"); result = CTFEExp.cantexp; return; } if (sd.dtor) { auto ale = cast(ArrayLiteralExp)result; foreach (el; *ale.elements) { result = interpretFunction(sd.dtor, istate, null, el); if (exceptionOrCant(result)) return; } } } break; default: assert(0); } result = CTFEExp.voidexp; } override void visit(CastExp e) { debug (LOG) { printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression e1 = interpret(e.e1, istate, goal); if (exceptionOrCant(e1)) return; // If the expression has been cast to void, do nothing. if (e.to.ty == Tvoid) { result = CTFEExp.voidexp; return; } if (e.to.ty == Tpointer && e1.op != TOK.null_) { Type pointee = (cast(TypePointer)e.type).next; // Implement special cases of normally-unsafe casts if (e1.op == TOK.int64) { // Happens with Windows HANDLEs, for example. result = paintTypeOntoLiteral(e.to, e1); return; } bool castToSarrayPointer = false; bool castBackFromVoid = false; if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer) { // Check for unsupported type painting operations // For slices, we need the type being sliced, // since it may have already been type painted Type elemtype = e1.type.nextOf(); if (e1.op == TOK.slice) elemtype = (cast(SliceExp)e1).e1.type.nextOf(); // Allow casts from X* to void *, and X** to void** for any X. // But don't allow cast from X* to void**. // So, we strip all matching * from source and target to find X. // Allow casts to X* from void* only if the 'void' was originally an X; // we check this later on. Type ultimatePointee = pointee; Type ultimateSrc = elemtype; while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer) { ultimatePointee = ultimatePointee.nextOf(); ultimateSrc = ultimateSrc.nextOf(); } if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc)) { castToSarrayPointer = true; } else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee)) { e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars()); result = CTFEExp.cantexp; return; } if (ultimateSrc.ty == Tvoid) castBackFromVoid = true; } if (e1.op == TOK.slice) { if ((cast(SliceExp)e1).e1.op == TOK.null_) { result = paintTypeOntoLiteral(e.type, (cast(SliceExp)e1).e1); return; } // Create a CTFE pointer &aggregate[1..2] auto ei = new IndexExp(e.loc, (cast(SliceExp)e1).e1, (cast(SliceExp)e1).lwr); ei.type = e.type.nextOf(); emplaceExp!(AddrExp)(pue, e.loc, ei, e.type); result = pue.exp(); return; } if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_) { // Create a CTFE pointer &[1,2,3][0] or &"abc"[0] auto ei = new IndexExp(e.loc, e1, new IntegerExp(e.loc, 0, Type.tsize_t)); ei.type = e.type.nextOf(); emplaceExp!(AddrExp)(pue, e.loc, ei, e.type); result = pue.exp(); return; } if (e1.op == TOK.index && !(cast(IndexExp)e1).e1.type.equals(e1.type)) { // type painting operation IndexExp ie = cast(IndexExp)e1; result = new IndexExp(e1.loc, ie.e1, ie.e2); if (castBackFromVoid) { // get the original type. For strings, it's just the type... Type origType = ie.e1.type.nextOf(); // ..but for arrays of type void*, it's the type of the element if (ie.e1.op == TOK.arrayLiteral && ie.e2.op == TOK.int64) { ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1; size_t indx = cast(size_t)ie.e2.toInteger(); if (indx < ale.elements.dim) { if (Expression xx = (*ale.elements)[indx]) { if (xx.op == TOK.index) origType = (cast(IndexExp)xx).e1.type.nextOf(); else if (xx.op == TOK.address) origType = (cast(AddrExp)xx).e1.type; else if (xx.op == TOK.variable) origType = (cast(VarExp)xx).var.type; } } } if (!isSafePointerCast(origType, pointee)) { e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars()); result = CTFEExp.cantexp; return; } } result.type = e.type; return; } if (e1.op == TOK.address) { Type origType = (cast(AddrExp)e1).e1.type; if (isSafePointerCast(origType, pointee)) { emplaceExp!(AddrExp)(pue, e.loc, (cast(AddrExp)e1).e1, e.type); result = pue.exp(); return; } if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && (cast(AddrExp)e1).e1.op == TOK.index) { // &val[idx] dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger(); IndexExp ie = cast(IndexExp)(cast(AddrExp)e1).e1; Expression lwr = ie.e2; Expression upr = new IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t); // Create a CTFE pointer &val[idx..idx+dim] auto er = new SliceExp(e.loc, ie.e1, lwr, upr); er.type = pointee; emplaceExp!(AddrExp)(pue, e.loc, er, e.type); result = pue.exp(); return; } } if (e1.op == TOK.variable || e1.op == TOK.symbolOffset) { // type painting operation Type origType = (cast(SymbolExp)e1).var.type; if (castBackFromVoid && !isSafePointerCast(origType, pointee)) { e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars()); result = CTFEExp.cantexp; return; } if (e1.op == TOK.variable) emplaceExp!(VarExp)(pue, e.loc, (cast(VarExp)e1).var); else emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset); result = pue.exp(); result.type = e.to; return; } // Check if we have a null pointer (eg, inside a struct) e1 = interpret(e1, istate); if (e1.op != TOK.null_) { e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); result = CTFEExp.cantexp; return; } } if (e.to.ty == Tsarray && e.e1.type.ty == Tvector) { // Special handling for: cast(float[4])__vector([w, x, y, z]) e1 = interpret(e.e1, istate); if (exceptionOrCant(e1)) return; assert(e1.op == TOK.vector); e1 = (cast(VectorExp)e1).e1; } if (e.to.ty == Tarray && e1.op == TOK.slice) { // Note that the slice may be void[], so when checking for dangerous // casts, we need to use the original type, which is se.e1. SliceExp se = cast(SliceExp)e1; if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf())) { e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars()); result = CTFEExp.cantexp; return; } emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr); result = pue.exp(); result.type = e.to; return; } // Disallow array type painting, except for conversions between built-in // types of identical size. if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) { e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); result = CTFEExp.cantexp; return; } if (e.to.ty == Tsarray) e1 = resolveSlice(e1); if (e.to.toBasetype().ty == Tbool && e1.type.ty == Tpointer) { emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to); result = pue.exp(); return; } result = ctfeCast(e.loc, e.type, e.to, e1); } override void visit(AssertExp e) { debug (LOG) { printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression e1 = interpret(pue, e.e1, istate); if (exceptionOrCant(e1)) return; if (isTrueBool(e1)) { } else if (e1.isBool(false)) { if (e.msg) { UnionExp ue = void; result = interpret(&ue, e.msg, istate); if (exceptionOrCant(result)) return; e.error("`%s`", result.toChars()); } else e.error("`%s` failed", e.toChars()); result = CTFEExp.cantexp; return; } else { e.error("`%s` is not a compile time boolean expression", e1.toChars()); result = CTFEExp.cantexp; return; } result = e1; return; } override void visit(PtrExp e) { debug (LOG) { printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } // Check for int<->float and long<->double casts. if (e.e1.op == TOK.symbolOffset && (cast(SymOffExp)e.e1).offset == 0 && (cast(SymOffExp)e.e1).var.isVarDeclaration() && isFloatIntPaint(e.type, (cast(SymOffExp)e.e1).var.type)) { // *(cast(int*)&v), where v is a float variable result = paintFloatInt(getVarExp(e.loc, istate, (cast(SymOffExp)e.e1).var, ctfeNeedRvalue), e.type); return; } if (e.e1.op == TOK.cast_ && (cast(CastExp)e.e1).e1.op == TOK.address) { // *(cast(int*)&x), where x is a float expression Expression x = (cast(AddrExp)(cast(CastExp)e.e1).e1).e1; if (isFloatIntPaint(e.type, x.type)) { result = paintFloatInt(interpret(x, istate), e.type); return; } } // Constant fold *(&structliteral + offset) if (e.e1.op == TOK.add) { AddExp ae = cast(AddExp)e.e1; if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64) { AddrExp ade = cast(AddrExp)ae.e1; Expression ex = interpret(ade.e1, istate); if (exceptionOrCant(ex)) return; if (ex.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)ex; dinteger_t offset = ae.e2.toInteger(); result = se.getField(e.type, cast(uint)offset); if (result) return; } } } // It's possible we have an array bounds error. We need to make sure it // errors with this line number, not the one where the pointer was set. result = interpret(e.e1, istate); if (exceptionOrCant(result)) return; if (result.op == TOK.function_) return; if (result.op == TOK.symbolOffset) { SymOffExp soe = cast(SymOffExp)result; if (soe.offset == 0 && soe.var.isFuncDeclaration()) return; e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars()); result = CTFEExp.cantexp; return; } if (result.op != TOK.address) { if (result.op == TOK.null_) e.error("dereference of null pointer `%s`", e.e1.toChars()); else e.error("dereference of invalid pointer `%s`", result.toChars()); result = CTFEExp.cantexp; return; } // *(&x) ==> x result = (cast(AddrExp)result).e1; if (result.op == TOK.slice && e.type.toBasetype().ty == Tsarray) { /* aggr[lwr..upr] * upr may exceed the upper boundary of aggr, but the check is deferred * until those out-of-bounds elements will be touched. */ return; } result = interpret(result, istate, goal); if (exceptionOrCant(result)) return; debug (LOG) { if (CTFEExp.isCantExp(result)) printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars()); } } override void visit(DotVarExp e) { debug (LOG) { printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal); } Expression ex = interpret(e.e1, istate); if (exceptionOrCant(ex)) return; if (FuncDeclaration f = e.var.isFuncDeclaration()) { if (ex == e.e1) result = e; // optimize: reuse this CTFE reference else { emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false); result = pue.exp(); result.type = e.type; } return; } VarDeclaration v = e.var.isVarDeclaration(); if (!v) { e.error("CTFE internal error: `%s`", e.toChars()); result = CTFEExp.cantexp; return; } if (ex.op == TOK.null_) { if (ex.type.toBasetype().ty == Tclass) e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars()); else e.error("CTFE internal error: null this `%s`", e.e1.toChars()); result = CTFEExp.cantexp; return; } if (ex.op != TOK.structLiteral && ex.op != TOK.classReference) { e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars()); result = CTFEExp.cantexp; return; } StructLiteralExp se; int i; // We can't use getField, because it makes a copy if (ex.op == TOK.classReference) { se = (cast(ClassReferenceExp)ex).value; i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v); } else { se = cast(StructLiteralExp)ex; i = findFieldIndexByName(se.sd, v); } if (i == -1) { e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars()); result = CTFEExp.cantexp; return; } if (goal == ctfeNeedLvalue) { Expression ev = (*se.elements)[i]; if (!ev || ev.op == TOK.void_) (*se.elements)[i] = voidInitLiteral(e.type, v).copy(); // just return the (simplified) dotvar expression as a CTFE reference if (e.e1 == ex) result = e; else { emplaceExp!(DotVarExp)(pue, e.loc, ex, v); result = pue.exp(); result.type = e.type; } return; } result = (*se.elements)[i]; if (!result) { e.error("Internal Compiler Error: null field `%s`", v.toChars()); result = CTFEExp.cantexp; return; } if (result.op == TOK.void_) { VoidInitExp ve = cast(VoidInitExp)result; const(char)* s = ve.var.toChars(); if (v.overlapped) { e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s); result = CTFEExp.cantexp; return; } e.error("cannot read uninitialized variable `%s` in CTFE", s); result = CTFEExp.cantexp; return; } if (v.type.ty != result.type.ty && v.type.ty == Tsarray) { // Block assignment from inside struct literals auto tsa = cast(TypeSArray)v.type; auto len = cast(size_t)tsa.dim.toInteger(); result = createBlockDuplicatedArrayLiteral(ex.loc, v.type, ex, len); (*se.elements)[i] = result; } debug (LOG) { if (CTFEExp.isCantExp(result)) printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars()); } } override void visit(RemoveExp e) { debug (LOG) { printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } Expression agg = interpret(e.e1, istate); if (exceptionOrCant(agg)) return; Expression index = interpret(e.e2, istate); if (exceptionOrCant(index)) return; if (agg.op == TOK.null_) { result = CTFEExp.voidexp; return; } assert(agg.op == TOK.assocArrayLiteral); AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)agg; Expressions* keysx = aae.keys; Expressions* valuesx = aae.values; size_t removed = 0; for (size_t j = 0; j < valuesx.dim; ++j) { Expression ekey = (*keysx)[j]; int eq = ctfeEqual(e.loc, TOK.equal, ekey, index); if (eq) ++removed; else if (removed != 0) { (*keysx)[j - removed] = ekey; (*valuesx)[j - removed] = (*valuesx)[j]; } } valuesx.dim = valuesx.dim - removed; keysx.dim = keysx.dim - removed; emplaceExp!(IntegerExp)(pue, e.loc, removed ? 1 : 0, Type.tbool); result = pue.exp(); } override void visit(ClassReferenceExp e) { //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars()); result = e; } override void visit(VoidInitExp e) { e.error("CTFE internal error: trying to read uninitialized variable"); assert(0); } override void visit(ThrownExceptionExp e) { assert(0); // This should never be interpreted } } /******************************************** * Interpret the expression. * Params: * pue = non-null pointer to temporary storage that can be used to store the return value * e = Expression to interpret * istate = context * goal = what the result will be used for * Returns: * resulting expression */ Expression interpret(UnionExp* pue, Expression e, InterState* istate, CtfeGoal goal = ctfeNeedRvalue) { if (!e) return null; scope Interpreter v = new Interpreter(pue, istate, goal); e.accept(v); Expression ex = v.result; assert(goal == ctfeNeedNothing || ex !is null); return ex; } /// Expression interpret(Expression e, InterState* istate, CtfeGoal goal = ctfeNeedRvalue) { UnionExp ue = void; auto result = interpret(&ue, e, istate, goal); if (result == ue.exp()) result = ue.copy(); return result; } /*********************************** * Interpret the statement. * Params: * pue = non-null pointer to temporary storage that can be used to store the return value * s = Statement to interpret * istate = context * Returns: * NULL continue to next statement * TOK.cantExpression cannot interpret statement at compile time * !NULL expression from return statement, or thrown exception */ Expression interpret(UnionExp* pue, Statement s, InterState* istate) { if (!s) return null; scope Interpreter v = new Interpreter(pue, istate, ctfeNeedNothing); s.accept(v); return v.result; } /// Expression interpret(Statement s, InterState* istate) { UnionExp ue = void; auto result = interpret(&ue, s, istate); if (result == ue.exp()) result = ue.copy(); return result; } /* All results destined for use outside of CTFE need to have their CTFE-specific * features removed. * In particular, all slices must be resolved. */ private Expression scrubReturnValue(const ref Loc loc, Expression e) { if (e.op == TOK.classReference) { StructLiteralExp se = (cast(ClassReferenceExp)e).value; se.ownedByCtfe = OwnedBy.code; if (!(se.stageflags & stageScrub)) { int old = se.stageflags; se.stageflags |= stageScrub; if (Expression ex = scrubArray(loc, se.elements, true)) return ex; se.stageflags = old; } } if (e.op == TOK.void_) { error(loc, "uninitialized variable `%s` cannot be returned from CTFE", (cast(VoidInitExp)e).var.toChars()); return new ErrorExp(); } e = resolveSlice(e); if (e.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)e; se.ownedByCtfe = OwnedBy.code; if (!(se.stageflags & stageScrub)) { int old = se.stageflags; se.stageflags |= stageScrub; if (Expression ex = scrubArray(loc, se.elements, true)) return ex; se.stageflags = old; } } if (e.op == TOK.string_) { (cast(StringExp)e).ownedByCtfe = OwnedBy.code; } if (e.op == TOK.arrayLiteral) { (cast(ArrayLiteralExp)e).ownedByCtfe = OwnedBy.code; if (Expression ex = scrubArray(loc, (cast(ArrayLiteralExp)e).elements)) return ex; } if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)e; aae.ownedByCtfe = OwnedBy.code; if (Expression ex = scrubArray(loc, aae.keys)) return ex; if (Expression ex = scrubArray(loc, aae.values)) return ex; aae.type = toBuiltinAAType(aae.type); } return e; } // Return true if every element is either void, // or is an array literal or struct literal of void elements. private bool isEntirelyVoid(Expressions* elems) { for (size_t i = 0; i < elems.dim; i++) { Expression m = (*elems)[i]; // It can be NULL for performance reasons, // see StructLiteralExp::interpret(). if (!m) continue; if (!(m.op == TOK.void_) && !(m.op == TOK.arrayLiteral && isEntirelyVoid((cast(ArrayLiteralExp)m).elements)) && !(m.op == TOK.structLiteral && isEntirelyVoid((cast(StructLiteralExp)m).elements))) { return false; } } return true; } // Scrub all members of an array. Return false if error private Expression scrubArray(const ref Loc loc, Expressions* elems, bool structlit = false) { for (size_t i = 0; i < elems.dim; i++) { Expression m = (*elems)[i]; // It can be NULL for performance reasons, // see StructLiteralExp::interpret(). if (!m) continue; // A struct .init may contain void members. // Static array members are a weird special case (bug 10994). if (structlit && ((m.op == TOK.void_) || (m.op == TOK.arrayLiteral && m.type.ty == Tsarray && isEntirelyVoid((cast(ArrayLiteralExp)m).elements)) || (m.op == TOK.structLiteral && isEntirelyVoid((cast(StructLiteralExp)m).elements)))) { m = null; } else { m = scrubReturnValue(loc, m); if (CTFEExp.isCantExp(m) || m.op == TOK.error) return m; } (*elems)[i] = m; } return null; } private Expression scrubCacheValue(const ref Loc loc, Expression e) { if (e.op == TOK.classReference) { StructLiteralExp sle = (cast(ClassReferenceExp)e).value; sle.ownedByCtfe = OwnedBy.cache; if (!(sle.stageflags & stageScrub)) { int old = sle.stageflags; sle.stageflags |= stageScrub; if (Expression ex = scrubArrayCache(loc, sle.elements)) return ex; sle.stageflags = old; } } if (e.op == TOK.structLiteral) { StructLiteralExp sle = cast(StructLiteralExp)e; sle.ownedByCtfe = OwnedBy.cache; if (!(sle.stageflags & stageScrub)) { int old = sle.stageflags; sle.stageflags |= stageScrub; if (Expression ex = scrubArrayCache(loc, sle.elements)) return ex; sle.stageflags = old; } } if (e.op == TOK.string_) { (cast(StringExp)e).ownedByCtfe = OwnedBy.cache; } if (e.op == TOK.arrayLiteral) { (cast(ArrayLiteralExp)e).ownedByCtfe = OwnedBy.cache; if (Expression ex = scrubArrayCache(loc, (cast(ArrayLiteralExp)e).elements)) return ex; } if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)e; aae.ownedByCtfe = OwnedBy.cache; if (Expression ex = scrubArrayCache(loc, aae.keys)) return ex; if (Expression ex = scrubArrayCache(loc, aae.values)) return ex; } return e; } private Expression scrubArrayCache(const ref Loc loc, Expressions* elems) { for (size_t i = 0; i < elems.dim; i++) { Expression m = (*elems)[i]; if (!m) continue; (*elems)[i] = scrubCacheValue(loc, m); } return null; } /******************************* Special Functions ***************************/ private Expression interpret_length(InterState* istate, Expression earg) { //printf("interpret_length()\n"); earg = interpret(earg, istate); if (exceptionOrCantInterpret(earg)) return earg; dinteger_t len = 0; if (earg.op == TOK.assocArrayLiteral) len = (cast(AssocArrayLiteralExp)earg).keys.dim; else assert(earg.op == TOK.null_); Expression e = new IntegerExp(earg.loc, len, Type.tsize_t); return e; } private Expression interpret_keys(InterState* istate, Expression earg, Type returnType) { debug (LOG) { printf("interpret_keys()\n"); } earg = interpret(earg, istate); if (exceptionOrCantInterpret(earg)) return earg; if (earg.op == TOK.null_) return new NullExp(earg.loc, returnType); if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; assert(earg.op == TOK.assocArrayLiteral); AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)earg; auto ae = new ArrayLiteralExp(aae.loc, returnType, aae.keys); ae.ownedByCtfe = aae.ownedByCtfe; return copyLiteral(ae).copy(); } private Expression interpret_values(InterState* istate, Expression earg, Type returnType) { debug (LOG) { printf("interpret_values()\n"); } earg = interpret(earg, istate); if (exceptionOrCantInterpret(earg)) return earg; if (earg.op == TOK.null_) return new NullExp(earg.loc, returnType); if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; assert(earg.op == TOK.assocArrayLiteral); AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)earg; auto ae = new ArrayLiteralExp(aae.loc, returnType, aae.values); ae.ownedByCtfe = aae.ownedByCtfe; //printf("result is %s\n", e.toChars()); return copyLiteral(ae).copy(); } private Expression interpret_dup(InterState* istate, Expression earg) { debug (LOG) { printf("interpret_dup()\n"); } earg = interpret(earg, istate); if (exceptionOrCantInterpret(earg)) return earg; if (earg.op == TOK.null_) return new NullExp(earg.loc, earg.type); if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; assert(earg.op == TOK.assocArrayLiteral); AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)copyLiteral(earg).copy(); for (size_t i = 0; i < aae.keys.dim; i++) { if (Expression e = evaluatePostblit(istate, (*aae.keys)[i])) return e; if (Expression e = evaluatePostblit(istate, (*aae.values)[i])) return e; } aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int] //printf("result is %s\n", aae.toChars()); return aae; } // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) private Expression interpret_aaApply(InterState* istate, Expression aa, Expression deleg) { aa = interpret(aa, istate); if (exceptionOrCantInterpret(aa)) return aa; if (aa.op != TOK.assocArrayLiteral) return new IntegerExp(deleg.loc, 0, Type.tsize_t); FuncDeclaration fd = null; Expression pthis = null; if (deleg.op == TOK.delegate_) { fd = (cast(DelegateExp)deleg).func; pthis = (cast(DelegateExp)deleg).e1; } else if (deleg.op == TOK.function_) fd = (cast(FuncExp)deleg).fd; assert(fd && fd.fbody); assert(fd.parameters); size_t numParams = fd.parameters.dim; assert(numParams == 1 || numParams == 2); Parameter fparam = Parameter.getNth((cast(TypeFunction)fd.type).parameters, numParams - 1); bool wantRefValue = 0 != (fparam.storageClass & (STC.out_ | STC.ref_)); Expressions args = Expressions(numParams); AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa; if (!ae.keys || ae.keys.dim == 0) return new IntegerExp(deleg.loc, 0, Type.tsize_t); Expression eresult; for (size_t i = 0; i < ae.keys.dim; ++i) { Expression ekey = (*ae.keys)[i]; Expression evalue = (*ae.values)[i]; if (wantRefValue) { Type t = evalue.type; evalue = new IndexExp(deleg.loc, ae, ekey); evalue.type = t; } args[numParams - 1] = evalue; if (numParams == 2) args[0] = ekey; eresult = interpretFunction(fd, istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) return eresult; assert(eresult.op == TOK.int64); if ((cast(IntegerExp)eresult).getInteger() != 0) return eresult; } return eresult; } /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ private Expression foreachApplyUtf(InterState* istate, Expression str, Expression deleg, bool rvs) { debug (LOG) { printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars()); } FuncDeclaration fd = null; Expression pthis = null; if (deleg.op == TOK.delegate_) { fd = (cast(DelegateExp)deleg).func; pthis = (cast(DelegateExp)deleg).e1; } else if (deleg.op == TOK.function_) fd = (cast(FuncExp)deleg).fd; assert(fd && fd.fbody); assert(fd.parameters); size_t numParams = fd.parameters.dim; assert(numParams == 1 || numParams == 2); Type charType = (*fd.parameters)[numParams - 1].type; Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t; size_t len = cast(size_t)resolveArrayLength(str); if (len == 0) return new IntegerExp(deleg.loc, 0, indexType); str = resolveSlice(str); StringExp se = null; ArrayLiteralExp ale = null; if (str.op == TOK.string_) se = cast(StringExp)str; else if (str.op == TOK.arrayLiteral) ale = cast(ArrayLiteralExp)str; else { str.error("CTFE internal error: cannot foreach `%s`", str.toChars()); return CTFEExp.cantexp; } Expressions args = Expressions(numParams); Expression eresult = null; // ded-store to prevent spurious warning // Buffers for encoding; also used for decoding array literals char[4] utf8buf; wchar[2] utf16buf; size_t start = rvs ? len : 0; size_t end = rvs ? 0 : len; for (size_t indx = start; indx != end;) { // Step 1: Decode the next dchar from the string. const(char)* errmsg = null; // Used for reporting decoding errors dchar rawvalue; // Holds the decoded dchar size_t currentIndex = indx; // The index of the decoded character if (ale) { // If it is an array literal, copy the code points into the buffer size_t buflen = 1; // #code points in the buffer size_t n = 1; // #code points in this char size_t sz = cast(size_t)ale.type.nextOf().size(); switch (sz) { case 1: if (rvs) { // find the start of the string --indx; buflen = 1; while (indx > 0 && buflen < 4) { Expression r = (*ale.elements)[indx]; assert(r.op == TOK.int64); char x = cast(char)(cast(IntegerExp)r).getInteger(); if ((x & 0xC0) != 0x80) break; ++buflen; } } else buflen = (indx + 4 > len) ? len - indx : 4; for (size_t i = 0; i < buflen; ++i) { Expression r = (*ale.elements)[indx + i]; assert(r.op == TOK.int64); utf8buf[i] = cast(char)(cast(IntegerExp)r).getInteger(); } n = 0; errmsg = utf_decodeChar(&utf8buf[0], buflen, n, rawvalue); break; case 2: if (rvs) { // find the start of the string --indx; buflen = 1; Expression r = (*ale.elements)[indx]; assert(r.op == TOK.int64); ushort x = cast(ushort)(cast(IntegerExp)r).getInteger(); if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) { --indx; ++buflen; } } else buflen = (indx + 2 > len) ? len - indx : 2; for (size_t i = 0; i < buflen; ++i) { Expression r = (*ale.elements)[indx + i]; assert(r.op == TOK.int64); utf16buf[i] = cast(ushort)(cast(IntegerExp)r).getInteger(); } n = 0; errmsg = utf_decodeWchar(&utf16buf[0], buflen, n, rawvalue); break; case 4: { if (rvs) --indx; Expression r = (*ale.elements)[indx]; assert(r.op == TOK.int64); rawvalue = cast(dchar)(cast(IntegerExp)r).getInteger(); n = 1; } break; default: assert(0); } if (!rvs) indx += n; } else { // String literals size_t saveindx; // used for reverse iteration switch (se.sz) { case 1: if (rvs) { // find the start of the string --indx; while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80)) --indx; saveindx = indx; } errmsg = utf_decodeChar(se.string, se.len, indx, rawvalue); if (rvs) indx = saveindx; break; case 2: if (rvs) { // find the start --indx; auto wc = se.getCodeUnit(indx); if (wc >= 0xDC00 && wc <= 0xDFFF) --indx; saveindx = indx; } errmsg = utf_decodeWchar(se.wstring, se.len, indx, rawvalue); if (rvs) indx = saveindx; break; case 4: if (rvs) --indx; rawvalue = se.getCodeUnit(indx); if (!rvs) ++indx; break; default: assert(0); } } if (errmsg) { deleg.error("`%s`", errmsg); return CTFEExp.cantexp; } // Step 2: encode the dchar in the target encoding int charlen = 1; // How many codepoints are involved? switch (charType.size()) { case 1: charlen = utf_codeLengthChar(rawvalue); utf_encodeChar(&utf8buf[0], rawvalue); break; case 2: charlen = utf_codeLengthWchar(rawvalue); utf_encodeWchar(&utf16buf[0], rawvalue); break; case 4: break; default: assert(0); } if (rvs) currentIndex = indx; // Step 3: call the delegate once for each code point // The index only needs to be set once if (numParams == 2) args[0] = new IntegerExp(deleg.loc, currentIndex, indexType); Expression val = null; for (int k = 0; k < charlen; ++k) { dchar codepoint; switch (charType.size()) { case 1: codepoint = utf8buf[k]; break; case 2: codepoint = utf16buf[k]; break; case 4: codepoint = rawvalue; break; default: assert(0); } val = new IntegerExp(str.loc, codepoint, charType); args[numParams - 1] = val; eresult = interpretFunction(fd, istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) return eresult; assert(eresult.op == TOK.int64); if ((cast(IntegerExp)eresult).getInteger() != 0) return eresult; } } return eresult; } /* If this is a built-in function, return the interpreted result, * Otherwise, return NULL. */ private Expression evaluateIfBuiltin(InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis) { Expression e = null; size_t nargs = arguments ? arguments.dim : 0; if (!pthis) { if (isBuiltin(fd) == BUILTIN.yes) { Expressions args = Expressions(nargs); for (size_t i = 0; i < args.dim; i++) { Expression earg = (*arguments)[i]; earg = interpret(earg, istate); if (exceptionOrCantInterpret(earg)) return earg; args[i] = earg; } e = eval_builtin(loc, fd, &args); if (!e) { error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars()); e = CTFEExp.cantexp; } } } if (!pthis) { Expression firstarg = nargs > 0 ? (*arguments)[0] : null; if (firstarg && firstarg.type.toBasetype().ty == Taarray) { TypeAArray firstAAtype = cast(TypeAArray)firstarg.type; const id = fd.ident.toChars(); if (nargs == 1 && fd.ident == Id.aaLen) return interpret_length(istate, firstarg); if (nargs == 3 && !strcmp(id, "_aaApply")) return interpret_aaApply(istate, firstarg, arguments.data[2]); if (nargs == 3 && !strcmp(id, "_aaApply2")) return interpret_aaApply(istate, firstarg, arguments.data[2]); if (nargs == 1 && !strcmp(id, "keys") && !strcmp(fd.toParent2().ident.toChars(), "object")) return interpret_keys(istate, firstarg, firstAAtype.index.arrayOf()); if (nargs == 1 && !strcmp(id, "values") && !strcmp(fd.toParent2().ident.toChars(), "object")) return interpret_values(istate, firstarg, firstAAtype.nextOf().arrayOf()); if (nargs == 1 && !strcmp(id, "rehash") && !strcmp(fd.toParent2().ident.toChars(), "object")) return interpret(firstarg, istate); if (nargs == 1 && !strcmp(id, "dup") && !strcmp(fd.toParent2().ident.toChars(), "object")) return interpret_dup(istate, firstarg); } } if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object) { if (pthis.op == TOK.classReference && fd.parent.ident == Id.Throwable) { // At present, the constructors just copy their arguments into the struct. // But we might need some magic if stack tracing gets added to druntime. StructLiteralExp se = (cast(ClassReferenceExp)pthis).value; assert(arguments.dim <= se.elements.dim); for (size_t i = 0; i < arguments.dim; ++i) { e = interpret((*arguments)[i], istate); if (exceptionOrCantInterpret(e)) return e; (*se.elements)[i] = e; } return CTFEExp.voidexp; } } if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit)) { // Support synchronized{} as a no-op return CTFEExp.voidexp; } if (!pthis) { const idlen = fd.ident.toString().length; const id = fd.ident.toChars(); if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7)) { // Functions from aApply.d and aApplyR.d in the runtime bool rvs = (idlen == 11); // true if foreach_reverse char c = id[idlen - 3]; // char width: 'c', 'w', or 'd' char s = id[idlen - 2]; // string width: 'c', 'w', or 'd' char n = id[idlen - 1]; // numParams: 1 or 2. // There are 12 combinations if ((n == '1' || n == '2') && (c == 'c' || c == 'w' || c == 'd') && (s == 'c' || s == 'w' || s == 'd') && c != s) { Expression str = (*arguments)[0]; str = interpret(str, istate); if (exceptionOrCantInterpret(str)) return str; return foreachApplyUtf(istate, str, (*arguments)[1], rvs); } } } return e; } private Expression evaluatePostblit(InterState* istate, Expression e) { Type tb = e.type.baseElemOf(); if (tb.ty != Tstruct) return null; StructDeclaration sd = (cast(TypeStruct)tb).sym; if (!sd.postblit) return null; if (e.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e; for (size_t i = 0; i < ale.elements.dim; i++) { e = evaluatePostblit(istate, (*ale.elements)[i]); if (e) return e; } return null; } if (e.op == TOK.structLiteral) { // e.__postblit() e = interpretFunction(sd.postblit, istate, null, e); if (exceptionOrCantInterpret(e)) return e; return null; } assert(0); } private Expression evaluateDtor(InterState* istate, Expression e) { Type tb = e.type.baseElemOf(); if (tb.ty != Tstruct) return null; StructDeclaration sd = (cast(TypeStruct)tb).sym; if (!sd.dtor) return null; if (e.op == TOK.arrayLiteral) { ArrayLiteralExp alex = cast(ArrayLiteralExp)e; for (size_t i = alex.elements.dim; 0 < i--;) e = evaluateDtor(istate, (*alex.elements)[i]); } else if (e.op == TOK.structLiteral) { // e.__dtor() e = interpretFunction(sd.dtor, istate, null, e); } else assert(0); if (exceptionOrCantInterpret(e)) return e; return null; } /*************************** CTFE Sanity Checks ***************************/ /* Setter functions for CTFE variable values. * These functions exist to check for compiler CTFE bugs. */ private bool hasValue(VarDeclaration vd) { if (vd.ctfeAdrOnStack == cast(size_t)-1) return false; return null !is getValue(vd); } // Don't check for validity private void setValueWithoutChecking(VarDeclaration vd, Expression newval) { ctfeStack.setValue(vd, newval); } private void setValue(VarDeclaration vd, Expression newval) { version (none) { if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval))) { printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars()); } } assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)); ctfeStack.setValue(vd, newval); } ================================================ FILE: gcc/d/dmd/dmacro.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dmacro.d, _dmacro.d) * Documentation: https://dlang.org/phobos/dmd_dmacro.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmacro.d */ module dmd.dmacro; import core.stdc.ctype; import core.stdc.string; import dmd.doc; import dmd.errors; import dmd.globals; import dmd.root.outbuffer; import dmd.root.rmem; struct Macro { private: Macro* next; // next in list const(char)[] name; // macro name const(char)[] text; // macro replacement text int inuse; // macro is in use (don't expand) this(const(char)[] name, const(char)[] text) { this.name = name; this.text = text; } Macro* search(const(char)[] name) { Macro* table; //printf("Macro::search(%.*s)\n", name.length, name.ptr); for (table = &this; table; table = table.next) { if (table.name == name) { //printf("\tfound %d\n", table.textlen); break; } } return table; } public: static Macro* define(Macro** ptable, const(char)[] name, const(char)[] text) { //printf("Macro::define('%.*s' = '%.*s')\n", name.length, name.ptr, text.length, text.ptr); Macro* table; //assert(ptable); for (table = *ptable; table; table = table.next) { if (table.name == name) { table.text = text; return table; } } table = new Macro(name, text); table.next = *ptable; *ptable = table; return table; } /***************************************************** * Expand macro in place in buf. * Only look at the text in buf from start to end. */ void expand(OutBuffer* buf, size_t start, size_t* pend, const(char)[] arg) { version (none) { printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, cast(int)arg.length, arg.ptr); printf("Buf is: '%.*s'\n", *pend - start, buf.data + start); } // limit recursive expansion __gshared int nest; __gshared const(int) nestLimit = 1000; if (nest > nestLimit) { error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", nestLimit); return; } nest++; size_t end = *pend; assert(start <= end); assert(end <= buf.offset); /* First pass - replace $0 */ arg = memdup(arg); for (size_t u = start; u + 1 < end;) { char* p = cast(char*)buf.data; // buf.data is not loop invariant /* Look for $0, but not $$0, and replace it with arg. */ if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) { if (u > start && p[u - 1] == '$') { // Don't expand $$0, but replace it with $0 buf.remove(u - 1, 1); end--; u += 1; // now u is one past the closing '1' continue; } char c = p[u + 1]; int n = (c == '+') ? -1 : c - '0'; const(char)[] marg; if (n == 0) { marg = arg; } else extractArgN(arg, marg, n); if (marg.length == 0) { // Just remove macro invocation //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr); buf.remove(u, 2); end -= 2; } else if (c == '+') { // Replace '$+' with 'arg' //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr); buf.remove(u, 2); buf.insert(u, marg); end += marg.length - 2; // Scan replaced text for further expansion size_t mend = u + marg.length; expand(buf, u, &mend, null); end += mend - (u + marg.length); u = mend; } else { // Replace '$1' with '\xFF{arg\xFF}' //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], cast(int)marg.length, marg.ptr); buf.data[u] = 0xFF; buf.data[u + 1] = '{'; buf.insert(u + 2, marg); buf.insert(u + 2 + marg.length, "\xFF}"); end += -2 + 2 + marg.length + 2; // Scan replaced text for further expansion size_t mend = u + 2 + marg.length; expand(buf, u + 2, &mend, null); end += mend - (u + 2 + marg.length); u = mend; } //printf("u = %d, end = %d\n", u, end); //printf("#%.*s#\n", end, &buf.data[0]); continue; } u++; } /* Second pass - replace other macros */ for (size_t u = start; u + 4 < end;) { char* p = cast(char*)buf.data; // buf.data is not loop invariant /* A valid start of macro expansion is $(c, where c is * an id start character, and not $$(c. */ if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p + u + 2)) { //printf("\tfound macro start '%c'\n", p[u + 2]); char* name = p + u + 2; size_t namelen = 0; const(char)[] marg; size_t v; /* Scan forward to find end of macro name and * beginning of macro argument (marg). */ for (v = u + 2; v < end; v += utfStride(p + v)) { if (!isIdTail(p + v)) { // We've gone past the end of the macro name. namelen = v - (u + 2); break; } } v += extractArgN(p[v .. end], marg, 0); assert(v <= end); if (v < end) { // v is on the closing ')' if (u > start && p[u - 1] == '$') { // Don't expand $$(NAME), but replace it with $(NAME) buf.remove(u - 1, 1); end--; u = v; // now u is one past the closing ')' continue; } Macro* m = search(name[0 .. namelen]); if (!m) { immutable undef = "DDOC_UNDEFINED_MACRO"; m = search(undef); if (m) { // Macro was not defined, so this is an expansion of // DDOC_UNDEFINED_MACRO. Prepend macro name to args. // marg = name[ ] ~ "," ~ marg[ ]; if (marg.length) { char* q = cast(char*)mem.xmalloc(namelen + 1 + marg.length); assert(q); memcpy(q, name, namelen); q[namelen] = ','; memcpy(q + namelen + 1, marg.ptr, marg.length); marg = q[0 .. marg.length + namelen + 1]; } else { marg = name[0 .. namelen]; } } } if (m) { if (m.inuse && marg.length == 0) { // Remove macro invocation buf.remove(u, v + 1 - u); end -= v + 1 - u; } else if (m.inuse && ((arg.length == marg.length && memcmp(arg.ptr, marg.ptr, arg.length) == 0) || (arg.length + 4 == marg.length && marg[0] == 0xFF && marg[1] == '{' && memcmp(arg.ptr, marg.ptr + 2, arg.length) == 0 && marg[marg.length - 2] == 0xFF && marg[marg.length - 1] == '}'))) { /* Recursive expansion: * marg is same as arg (with blue paint added) * Just leave in place. */ } else { //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", cast(int)m.namelen, m.name, cast(int)marg.length, marg.ptr, cast(int)m.textlen, m.text); marg = memdup(marg); // Insert replacement text buf.spread(v + 1, 2 + m.text.length + 2); buf.data[v + 1] = 0xFF; buf.data[v + 2] = '{'; buf.data[v + 3 .. v + 3 + m.text.length] = cast(ubyte[])m.text[]; buf.data[v + 3 + m.text.length] = 0xFF; buf.data[v + 3 + m.text.length + 1] = '}'; end += 2 + m.text.length + 2; // Scan replaced text for further expansion m.inuse++; size_t mend = v + 1 + 2 + m.text.length + 2; expand(buf, v + 1, &mend, marg); end += mend - (v + 1 + 2 + m.text.length + 2); m.inuse--; buf.remove(u, v + 1 - u); end -= v + 1 - u; u += mend - (v + 1); mem.xfree(cast(char*)marg.ptr); //printf("u = %d, end = %d\n", u, end); //printf("#%.*s#\n", end - u, &buf.data[u]); continue; } } else { // Replace $(NAME) with nothing buf.remove(u, v + 1 - u); end -= (v + 1 - u); continue; } } } u++; } mem.xfree(cast(char*)arg); *pend = end; nest--; } } /************************ * Make mutable copy of slice p. * Params: * p = slice * Returns: * copy allocated with mem.xmalloc() */ private char[] memdup(const(char)[] p) { size_t len = p.length; return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len]; } /********************************************************** * Given buffer buf[], extract argument marg[]. * Params: * buf = source string * marg = set to slice of buf[] * n = 0: get entire argument * 1..9: get nth argument * -1: get 2nd through end */ private size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) { /* Scan forward for matching right parenthesis. * Nest parentheses. * Skip over "..." and '...' strings inside HTML tags. * Skip over comments. * Skip over previous macro insertions * Set marg. */ uint parens = 1; ubyte instring = 0; uint incomment = 0; uint intag = 0; uint inexp = 0; uint argn = 0; size_t v = 0; const p = buf.ptr; const end = buf.length; Largstart: // Skip first space, if any, to find the start of the macro argument if (n != 1 && v < end && isspace(p[v])) v++; size_t vstart = v; for (; v < end; v++) { char c = p[v]; switch (c) { case ',': if (!inexp && !instring && !incomment && parens == 1) { argn++; if (argn == 1 && n == -1) { v++; goto Largstart; } if (argn == n) break; if (argn + 1 == n) { v++; goto Largstart; } } continue; case '(': if (!inexp && !instring && !incomment) parens++; continue; case ')': if (!inexp && !instring && !incomment && --parens == 0) { break; } continue; case '"': case '\'': if (!inexp && !incomment && intag) { if (c == instring) instring = 0; else if (!instring) instring = c; } continue; case '<': if (!inexp && !instring && !incomment) { if (v + 6 < end && p[v + 1] == '!' && p[v + 2] == '-' && p[v + 3] == '-') { incomment = 1; v += 3; } else if (v + 2 < end && isalpha(p[v + 1])) intag = 1; } continue; case '>': if (!inexp) intag = 0; continue; case '-': if (!inexp && !instring && incomment && v + 2 < end && p[v + 1] == '-' && p[v + 2] == '>') { incomment = 0; v += 2; } continue; case 0xFF: if (v + 1 < end) { if (p[v + 1] == '{') inexp++; else if (p[v + 1] == '}') inexp--; } continue; default: continue; } break; } if (argn == 0 && n == -1) marg = p[v .. v]; else marg = p[vstart .. v]; //printf("extractArg%d('%.*s') = '%.*s'\n", n, cast(int)end, p, cast(int)marg.length, marg.ptr); return v; } ================================================ FILE: gcc/d/dmd/dmangle.d ================================================ /** * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) * * Copyright: Copyright (C) 1999-2018 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/dmangle.d, _dmangle.d) * Documentation: https://dlang.org/phobos/dmd_dmangle.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d * References: https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/ */ module dmd.dmangle; import core.stdc.ctype; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import 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.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.aav; import dmd.target; import dmd.tokens; import dmd.utf; import dmd.visitor; private immutable char[TMAX] mangleChar = [ Tchar : 'a', Tbool : 'b', Tcomplex80 : 'c', Tfloat64 : 'd', Tfloat80 : 'e', Tfloat32 : 'f', Tint8 : 'g', Tuns8 : 'h', Tint32 : 'i', Timaginary80 : 'j', Tuns32 : 'k', Tint64 : 'l', Tuns64 : 'm', Tnone : 'n', Tnull : 'n', // yes, same as TypeNone Timaginary32 : 'o', Timaginary64 : 'p', Tcomplex32 : 'q', Tcomplex64 : 'r', Tint16 : 's', Tuns16 : 't', Twchar : 'u', Tvoid : 'v', Tdchar : 'w', // x // const // y // immutable Tint128 : 'z', // zi Tuns128 : 'z', // zk Tarray : 'A', Ttuple : 'B', Tclass : 'C', Tdelegate : 'D', Tenum : 'E', Tfunction : 'F', // D function Tsarray : 'G', Taarray : 'H', Tident : 'I', // J // out // K // ref // L // lazy // M // has this, or scope // N // Nh:vector Ng:wild // O // shared Tpointer : 'P', // Q // Type/symbol/identifier backward reference Treference : 'R', Tstruct : 'S', // T // Ttypedef // U // C function // V // Pascal function // W // Windows function // X // variadic T t...) // Y // variadic T t,...) // Z // not variadic, end of parameters // '@' shouldn't appear anywhere in the deco'd names Tinstance : '@', Terror : '@', Ttypeof : '@', Tslice : '@', Treturn : '@', Tvector : '@', ]; unittest { foreach (i, mangle; mangleChar) { if (mangle == char.init) { fprintf(stderr, "ty = %u\n", cast(uint)i); assert(0); } } } /*********************** * Mangle basic type ty to buf. */ private void tyToDecoBuffer(OutBuffer* buf, int ty) { const c = mangleChar[ty]; buf.writeByte(c); if (c == 'z') buf.writeByte(ty == Tint128 ? 'i' : 'k'); } /********************************* * Mangling for mod. */ private void MODtoDecoBuffer(OutBuffer* buf, MOD mod) { switch (mod) { case 0: break; case MODFlags.const_: buf.writeByte('x'); break; case MODFlags.immutable_: buf.writeByte('y'); break; case MODFlags.shared_: buf.writeByte('O'); break; case MODFlags.shared_ | MODFlags.const_: buf.writestring("Ox"); break; case MODFlags.wild: buf.writestring("Ng"); break; case MODFlags.wildconst: buf.writestring("Ngx"); break; case MODFlags.shared_ | MODFlags.wild: buf.writestring("ONg"); break; case MODFlags.shared_ | MODFlags.wildconst: buf.writestring("ONgx"); break; default: assert(0); } } private extern (C++) final class Mangler : Visitor { alias visit = Visitor.visit; public: static assert(Key.sizeof == size_t.sizeof); AssocArray!(Type, size_t) types; AssocArray!(Identifier, size_t) idents; OutBuffer* buf; extern (D) this(OutBuffer* buf) { this.buf = buf; } /** * writes a back reference with the relative position encoded with base 26 * using upper case letters for all digits but the last digit which uses * a lower case letter. * The decoder has to look up the referenced position to determine * whether the back reference is an identifer (starts with a digit) * or a type (starts with a letter). * * Params: * pos = relative position to encode */ void writeBackRef(size_t pos) { buf.writeByte('Q'); enum base = 26; size_t mul = 1; while (pos >= mul * base) mul *= base; while (mul >= base) { auto dig = cast(ubyte)(pos / mul); buf.writeByte('A' + dig); pos -= dig * mul; mul /= base; } buf.writeByte('a' + cast(ubyte)pos); } /** * Back references a non-basic type * * The encoded mangling is * 'Q' * * Params: * t = the type to encode via back referencing * * Returns: * true if the type was found. A back reference has been encoded. * false if the type was not found. The current position is saved for later back references. */ bool backrefType(Type t) { if (!t.isTypeBasic()) { auto p = types.getLvalue(t); if (*p) { writeBackRef(buf.offset - *p); return true; } *p = buf.offset; } return false; } /** * Back references a single identifier * * The encoded mangling is * 'Q' * * Params: * id = the identifier to encode via back referencing * * Returns: * true if the identifier was found. A back reference has been encoded. * false if the identifier was not found. The current position is saved for later back references. */ bool backrefIdentifier(Identifier id) { auto p = idents.getLvalue(id); if (*p) { writeBackRef(buf.offset - *p); return true; } *p = buf.offset; return false; } void mangleSymbol(Dsymbol s) { s.accept(this); } void mangleType(Type t) { if (!backrefType(t)) t.accept(this); } void mangleIdentifier(Identifier id, Dsymbol s) { if (!backrefIdentifier(id)) toBuffer(id.toString(), s); } //////////////////////////////////////////////////////////////////////////// /************************************************** * Type mangling */ void visitWithMask(Type t, ubyte modMask) { if (modMask != t.mod) { MODtoDecoBuffer(buf, t.mod); } mangleType(t); } override void visit(Type t) { tyToDecoBuffer(buf, t.ty); } override void visit(TypeNext t) { visit(cast(Type)t); visitWithMask(t.next, t.mod); } override void visit(TypeVector t) { buf.writestring("Nh"); visitWithMask(t.basetype, t.mod); } override void visit(TypeSArray t) { visit(cast(Type)t); if (t.dim) buf.print(t.dim.toInteger()); if (t.next) visitWithMask(t.next, t.mod); } override void visit(TypeDArray t) { visit(cast(Type)t); if (t.next) visitWithMask(t.next, t.mod); } override void visit(TypeAArray t) { visit(cast(Type)t); visitWithMask(t.index, 0); visitWithMask(t.next, t.mod); } override void visit(TypeFunction t) { //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars()); //static int nest; if (++nest == 50) *(char*)0=0; mangleFuncType(t, t, t.mod, t.next); } void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret) { //printf("mangleFuncType() %s\n", t.toChars()); if (t.inuse && tret) { // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars()); t.inuse = 2; // flag error to caller return; } t.inuse++; if (modMask != t.mod) MODtoDecoBuffer(buf, t.mod); char mc; final switch (t.linkage) { case LINK.default_: case LINK.system: case LINK.d: mc = 'F'; break; case LINK.c: mc = 'U'; break; case LINK.windows: mc = 'W'; break; case LINK.pascal: mc = 'V'; break; case LINK.cpp: mc = 'R'; break; case LINK.objc: mc = 'Y'; break; } buf.writeByte(mc); if (ta.purity) buf.writestring("Na"); if (ta.isnothrow) buf.writestring("Nb"); if (ta.isref) buf.writestring("Nc"); if (ta.isproperty) buf.writestring("Nd"); if (ta.isnogc) buf.writestring("Ni"); if (ta.isreturn) buf.writestring("Nj"); else if (ta.isscope && !ta.isscopeinferred) buf.writestring("Nl"); switch (ta.trust) { case TRUST.trusted: buf.writestring("Ne"); break; case TRUST.safe: buf.writestring("Nf"); break; default: break; } // Write argument types paramsToDecoBuffer(t.parameters); //if (buf.data[buf.offset - 1] == '@') assert(0); buf.writeByte('Z' - t.varargs); // mark end of arg list if (tret !is null) visitWithMask(tret, 0); t.inuse--; } override void visit(TypeIdentifier t) { visit(cast(Type)t); auto name = t.ident.toString(); buf.print(cast(int)name.length); buf.writestring(name); } override void visit(TypeEnum t) { visit(cast(Type)t); mangleSymbol(t.sym); } override void visit(TypeStruct t) { //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name); visit(cast(Type)t); mangleSymbol(t.sym); } override void visit(TypeClass t) { //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name); visit(cast(Type)t); mangleSymbol(t.sym); } override void visit(TypeTuple t) { //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars()); visit(cast(Type)t); paramsToDecoBuffer(t.arguments); buf.writeByte('Z'); } override void visit(TypeNull t) { visit(cast(Type)t); } //////////////////////////////////////////////////////////////////////////// void mangleDecl(Declaration sthis) { mangleParent(sthis); assert(sthis.ident); mangleIdentifier(sthis.ident, sthis); if (FuncDeclaration fd = sthis.isFuncDeclaration()) { mangleFunc(fd, false); } else if (sthis.type) { visitWithMask(sthis.type, 0); } else assert(0); } void mangleParent(Dsymbol s) { Dsymbol p; if (TemplateInstance ti = s.isTemplateInstance()) p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent; else p = s.parent; if (p) { mangleParent(p); auto ti = p.isTemplateInstance(); if (ti && !ti.isTemplateMixin()) { mangleTemplateInstance(ti); } else if (p.getIdent()) { mangleIdentifier(p.ident, s); if (FuncDeclaration f = p.isFuncDeclaration()) mangleFunc(f, true); } else buf.writeByte('0'); } } void mangleFunc(FuncDeclaration fd, bool inParent) { //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null"); //printf("fd.type = %s\n", fd.type.toChars()); if (fd.needThis() || fd.isNested()) buf.writeByte('M'); if (!fd.type || fd.type.ty == Terror) { // never should have gotten here, but could be the result of // failed speculative compilation buf.writestring("9__error__FZ"); //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars()); //assert(0); // don't mangle function until semantic3 done. } else if (inParent) { TypeFunction tf = cast(TypeFunction)fd.type; TypeFunction tfo = cast(TypeFunction)fd.originalType; mangleFuncType(tf, tfo, 0, null); } else { visitWithMask(fd.type, 0); } } /************************************************************ * Write length prefixed string to buf. */ extern (D) void toBuffer(const(char)[] id, Dsymbol s) { const len = id.length; if (buf.offset + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.offset + len)); else { buf.print(len); buf.writestring(id); } } extern (D) static const(char)[] externallyMangledIdentifier(Declaration d) { if (!d.parent || d.parent.isModule() || d.linkage == LINK.cpp) // if at global scope { final switch (d.linkage) { case LINK.d: break; case LINK.c: case LINK.windows: case LINK.pascal: case LINK.objc: return d.ident.toString(); case LINK.cpp: { const p = Target.toCppMangle(d); return p[0 .. strlen(p)]; } case LINK.default_: case LINK.system: d.error("forward declaration"); return d.ident.toString(); } } return null; } override void visit(Declaration d) { //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage); if (const id = externallyMangledIdentifier(d)) { buf.writestring(id); return; } buf.writestring("_D"); mangleDecl(d); debug { const slice = buf.peekSlice(); assert(slice.length); foreach (const char c; slice) { assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~ "contains an invalid character: " ~ c); } } } /****************************************************************************** * Normally FuncDeclaration and FuncAliasDeclaration have overloads. * If and only if there is no overloads, mangle() could return * exact mangled name. * * module test; * void foo(long) {} // _D4test3fooFlZv * void foo(string) {} // _D4test3fooFAyaZv * * // from FuncDeclaration.mangle(). * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo" * // by calling Dsymbol.mangle() * * // from FuncAliasDeclaration.mangle() * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv" * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv" * * If a function has no overloads, .mangleof property still returns exact mangled name. * * void bar() {} * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv" * // by calling FuncDeclaration.mangleExact(). */ override void visit(FuncDeclaration fd) { if (fd.isUnique()) mangleExact(fd); else visit(cast(Dsymbol)fd); } // ditto override void visit(FuncAliasDeclaration fd) { FuncDeclaration f = fd.toAliasFunc(); FuncAliasDeclaration fa = f.isFuncAliasDeclaration(); if (!fd.hasOverloads && !fa) { mangleExact(f); return; } if (fa) { mangleSymbol(fa); return; } visit(cast(Dsymbol)fd); } override void visit(OverDeclaration od) { if (od.overnext) { visit(cast(Dsymbol)od); return; } if (FuncDeclaration fd = od.aliassym.isFuncDeclaration()) { if (!od.hasOverloads || fd.isUnique()) { mangleExact(fd); return; } } if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration()) { if (!od.hasOverloads || td.overnext is null) { mangleSymbol(td); return; } } visit(cast(Dsymbol)od); } void mangleExact(FuncDeclaration fd) { assert(!fd.isFuncAliasDeclaration()); if (fd.mangleOverride) { buf.writestring(fd.mangleOverride); return; } if (fd.isMain()) { buf.writestring("_Dmain"); return; } if (fd.isWinMain() || fd.isDllMain() || fd.ident == Id.tls_get_addr) { buf.writestring(fd.ident.toChars()); return; } visit(cast(Declaration)fd); } override void visit(VarDeclaration vd) { if (vd.mangleOverride) { buf.writestring(vd.mangleOverride); return; } visit(cast(Declaration)vd); } override void visit(AggregateDeclaration ad) { ClassDeclaration cd = ad.isClassDeclaration(); Dsymbol parentsave = ad.parent; if (cd) { /* These are reserved to the compiler, so keep simple * names for them. */ if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0) { // Don't mangle parent ad.parent = null; } } visit(cast(Dsymbol)ad); ad.parent = parentsave; } override void visit(TemplateInstance ti) { version (none) { printf("TemplateInstance.mangle() %p %s", ti, ti.toChars()); if (ti.parent) printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars()); printf("\n"); } if (!ti.tempdecl) ti.error("is not defined"); else mangleParent(ti); if (ti.isTemplateMixin() && ti.ident) mangleIdentifier(ti.ident, ti); else mangleTemplateInstance(ti); } void mangleTemplateInstance(TemplateInstance ti) { TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration(); assert(tempdecl); // Use "__U" for the symbols declared inside template constraint. const char T = ti.members ? 'T' : 'U'; buf.printf("__%c", T); mangleIdentifier(tempdecl.ident, tempdecl); auto args = ti.tiargs; size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); for (size_t i = 0; i < args.dim; i++) { auto o = (*args)[i]; Type ta = isType(o); Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); Tuple va = isTuple(o); //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); if (i < nparams && (*tempdecl.parameters)[i].specialization()) buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574 if (ta) { buf.writeByte('T'); visitWithMask(ta, 0); } else if (ea) { // Don't interpret it yet, it might actually be an alias template parameter. // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339. enum keepLvalue = true; ea = ea.optimize(WANTvalue, keepLvalue); if (ea.op == TOK.variable) { sa = (cast(VarExp)ea).var; ea = null; goto Lsa; } if (ea.op == TOK.this_) { sa = (cast(ThisExp)ea).var; ea = null; goto Lsa; } if (ea.op == TOK.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; else sa = (cast(FuncExp)ea).fd; ea = null; goto Lsa; } buf.writeByte('V'); if (ea.op == TOK.tuple) { ea.error("tuple is not a valid template value argument"); continue; } // Now that we know it is not an alias, we MUST obtain a value uint olderr = global.errors; ea = ea.ctfeInterpret(); if (ea.op == TOK.error || olderr != global.errors) continue; /* Use type mangling that matches what it would be for a function parameter */ visitWithMask(ea.type, 0); ea.accept(this); } else if (sa) { Lsa: sa = sa.toAlias(); if (Declaration d = sa.isDeclaration()) { if (auto fad = d.isFuncAliasDeclaration()) d = fad.toAliasFunc(); if (d.mangleOverride) { buf.writeByte('X'); toBuffer(d.mangleOverride, d); continue; } if (const id = externallyMangledIdentifier(d)) { buf.writeByte('X'); toBuffer(id, d); continue; } if (!d.type || !d.type.deco) { ti.error("forward reference of %s `%s`", d.kind(), d.toChars()); continue; } } buf.writeByte('S'); mangleSymbol(sa); } else if (va) { assert(i + 1 == args.dim); // must be last one args = &va.objects; i = -cast(size_t)1; } else assert(0); } buf.writeByte('Z'); } override void visit(Dsymbol s) { version (none) { printf("Dsymbol.mangle() '%s'", s.toChars()); if (s.parent) printf(" parent = %s %s", s.parent.kind(), s.parent.toChars()); printf("\n"); } mangleParent(s); if (s.ident) mangleIdentifier(s.ident, s); else toBuffer(s.toString(), s); //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id); } //////////////////////////////////////////////////////////////////////////// override void visit(Expression e) { e.error("expression `%s` is not a valid template value argument", e.toChars()); } override void visit(IntegerExp e) { const v = e.toInteger(); if (cast(sinteger_t)v < 0) { buf.writeByte('N'); buf.print(-v); } else { buf.writeByte('i'); buf.print(v); } } override void visit(RealExp e) { buf.writeByte('e'); realToMangleBuffer(e.value); } void realToMangleBuffer(real_t value) { /* Rely on %A to get portable mangling. * Must munge result to get only identifier characters. * * Possible values from %A => mangled result * NAN => NAN * -INF => NINF * INF => INF * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 * 0X1.9P+2 => 19P2 */ if (CTFloat.isNaN(value)) buf.writestring("NAN"); // no -NAN bugs else if (CTFloat.isInfinity(value)) buf.writestring(value < CTFloat.zero ? "NINF" : "INF"); else { enum BUFFER_LEN = 36; char[BUFFER_LEN] buffer; const n = CTFloat.sprint(buffer.ptr, 'A', value); assert(n < BUFFER_LEN); for (int i = 0; i < n; i++) { char c = buffer[i]; switch (c) { case '-': buf.writeByte('N'); break; case '+': case 'X': case '.': break; case '0': if (i < 2) break; // skip leading 0X goto default; default: buf.writeByte(c); break; } } } } override void visit(ComplexExp e) { buf.writeByte('c'); realToMangleBuffer(e.toReal()); buf.writeByte('c'); // separate the two realToMangleBuffer(e.toImaginary()); } override void visit(NullExp e) { buf.writeByte('n'); } override void visit(StringExp e) { char m; OutBuffer tmp; const(char)[] q; /* Write string in UTF-8 format */ switch (e.sz) { case 1: m = 'a'; q = e.string[0 .. e.len]; break; case 2: m = 'w'; for (size_t u = 0; u < e.len;) { dchar c; const p = utf_decodeWchar(e.wstring, e.len, u, c); if (p) e.error("%s", p); else tmp.writeUTF8(c); } q = tmp.peekSlice(); break; case 4: m = 'd'; foreach (u; 0 .. e.len) { const c = (cast(uint*)e.string)[u]; if (!utf_isValidDchar(c)) e.error("invalid UCS-32 char \\U%08x", c); else tmp.writeUTF8(c); } q = tmp.peekSlice(); break; default: assert(0); } buf.reserve(1 + 11 + 2 * q.length); buf.writeByte(m); buf.print(q.length); buf.writeByte('_'); // nbytes <= 11 size_t qi = 0; for (char* p = cast(char*)buf.data + buf.offset, pend = p + 2 * q.length; p < pend; p += 2, ++qi) { char hi = (q[qi] >> 4) & 0xF; p[0] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a'); char lo = q[qi] & 0xF; p[1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a'); } buf.offset += 2 * q.length; } override void visit(ArrayLiteralExp e) { const dim = e.elements ? e.elements.dim : 0; buf.writeByte('A'); buf.print(dim); foreach (i; 0 .. dim) { e.getElement(i).accept(this); } } override void visit(AssocArrayLiteralExp e) { const dim = e.keys.dim; buf.writeByte('A'); buf.print(dim); foreach (i; 0 .. dim) { (*e.keys)[i].accept(this); (*e.values)[i].accept(this); } } override void visit(StructLiteralExp e) { const dim = e.elements ? e.elements.dim : 0; buf.writeByte('S'); buf.print(dim); foreach (i; 0 .. dim) { Expression ex = (*e.elements)[i]; if (ex) ex.accept(this); else buf.writeByte('v'); // 'v' for void } } //////////////////////////////////////////////////////////////////////////// void paramsToDecoBuffer(Parameters* parameters) { //printf("Parameter.paramsToDecoBuffer()\n"); int paramsToDecoBufferDg(size_t n, Parameter p) { p.accept(this); return 0; } Parameter._foreach(parameters, ¶msToDecoBufferDg); } override void visit(Parameter p) { if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred)) buf.writeByte('M'); // 'return inout ref' is the same as 'inout ref' if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_) buf.writestring("Nk"); switch (p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_)) { case 0: case STC.in_: break; case STC.out_: buf.writeByte('J'); break; case STC.ref_: buf.writeByte('K'); break; case STC.lazy_: buf.writeByte('L'); break; default: debug { printf("storageClass = x%llx\n", p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_)); } assert(0); } visitWithMask(p.type, 0); } } /// Returns: `true` if the given character is a valid mangled character package bool isValidMangling(dchar c) nothrow { return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c != 0 && strchr("$%().:?@[]_", c); } // valid mangled characters unittest { assert('a'.isValidMangling); assert('B'.isValidMangling); assert('2'.isValidMangling); assert('@'.isValidMangling); assert('_'.isValidMangling); } // invalid mangled characters unittest { assert(!'-'.isValidMangling); assert(!0.isValidMangling); assert(!'/'.isValidMangling); assert(!'\\'.isValidMangling); } /****************************************************************************** * Returns exact mangled name of function. */ extern (C++) const(char)* mangleExact(FuncDeclaration fd) { if (!fd.mangleString) { OutBuffer buf; scope Mangler v = new Mangler(&buf); v.mangleExact(fd); fd.mangleString = buf.extractString(); } return fd.mangleString; } extern (C++) void mangleToBuffer(Type t, OutBuffer* buf) { if (t.deco) buf.writestring(t.deco); else { scope Mangler v = new Mangler(buf); v.visitWithMask(t, 0); } } extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf) { scope Mangler v = new Mangler(buf); e.accept(v); } extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf) { scope Mangler v = new Mangler(buf); s.accept(v); } extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf) { scope Mangler v = new Mangler(buf); v.mangleTemplateInstance(ti); } /****************************************************************************** * Mangle function signatures ('this' qualifier, and parameter types) * to check conflicts in function overloads. * It's different from fd.type.deco. For example, fd.type.deco would be null * if fd is an auto function. * * Params: * buf = `OutBuffer` to write the mangled function signature to * fd = `FuncDeclaration` to mangle */ void mangleToFuncSignature(ref OutBuffer buf, FuncDeclaration fd) { assert(fd.type.ty == Tfunction); auto tf = cast(TypeFunction)fd.type; scope Mangler v = new Mangler(&buf); MODtoDecoBuffer(&buf, tf.mod); v.paramsToDecoBuffer(tf.parameters); buf.writeByte('Z' - tf.varargs); } ================================================ FILE: gcc/d/dmd/dmodule.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dmodule.d, _dmodule.d) * Documentation: https://dlang.org/phobos/dmd_dmodule.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmodule.d */ module dmd.dmodule; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.astcodegen; import dmd.compiler; import dmd.gluelayer; import dmd.dimport; import dmd.dmacro; import dmd.doc; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.parse; import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.port; import dmd.semantic2; import dmd.semantic3; import dmd.utils; import dmd.visitor; version(Windows) { extern (C) char* getcwd(char* buffer, size_t maxlen); } else { import core.sys.posix.unistd : getcwd; } /* =========================== ===================== */ /******************************************** * Look for the source file if it's different from filename. * Look for .di, .d, directory, and along global.path. * Does not open the file. * Input: * filename as supplied by the user * global.path * Returns: * NULL if it's not different from filename. */ private const(char)[] lookForSourceFile(const(char)[] filename) { /* Search along global.path for .di file, then .d file. */ const sdi = FileName.forceExt(filename, global.hdr_ext.toDString()); if (FileName.exists(sdi) == 1) return sdi; const sd = FileName.forceExt(filename, global.mars_ext.toDString()); if (FileName.exists(sd) == 1) return sd; if (FileName.exists(filename) == 2) { /* The filename exists and it's a directory. * Therefore, the result should be: filename/package.d * iff filename/package.d is a file */ const ni = FileName.combine(filename, "package.di"); if (FileName.exists(ni) == 1) return ni; FileName.free(ni.ptr); const n = FileName.combine(filename, "package.d"); if (FileName.exists(n) == 1) return n; FileName.free(n.ptr); } if (FileName.absolute(filename)) return null; if (!global.path) return null; for (size_t i = 0; i < global.path.dim; i++) { const p = (*global.path)[i].toDString(); const(char)[] n = FileName.combine(p, sdi); if (FileName.exists(n) == 1) { return n; } FileName.free(n.ptr); n = FileName.combine(p, sd); if (FileName.exists(n) == 1) { return n; } FileName.free(n.ptr); const b = FileName.removeExt(filename); n = FileName.combine(p, b); FileName.free(b.ptr); if (FileName.exists(n) == 2) { const n2i = FileName.combine(n, "package.di"); if (FileName.exists(n2i) == 1) return n2i; FileName.free(n2i.ptr); const n2 = FileName.combine(n, "package.d"); if (FileName.exists(n2) == 1) { return n2; } FileName.free(n2.ptr); } FileName.free(n.ptr); } return null; } // function used to call semantic3 on a module's dependencies void semantic3OnDependencies(Module m) { if (!m) return; if (m.semanticRun > PASS.semantic3) return; m.semantic3(null); foreach (i; 1 .. m.aimports.dim) semantic3OnDependencies(m.aimports[i]); } enum PKG : int { unknown, // not yet determined whether it's a package.d or not module_, // already determined that's an actual package.d package_, // already determined that's an actual package } /*********************************************************** */ extern (C++) class Package : ScopeDsymbol { PKG isPkgMod; uint tag; // auto incremented tag, used to mask package tree in scopes Module mod; // !=null if isPkgMod == PKG.module_ final extern (D) this(Identifier ident) { super(ident); this.isPkgMod = PKG.unknown; __gshared uint packageTag; this.tag = packageTag++; } override const(char)* kind() const { return "package"; } /**************************************************** * Input: * packages[] the pkg1.pkg2 of pkg1.pkg2.mod * Returns: * the symbol table that mod should be inserted into * Output: * *pparent the rightmost package, i.e. pkg2, or NULL if no packages * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages */ extern (D) static DsymbolTable resolve(Identifiers* packages, Dsymbol* pparent, Package* ppkg) { DsymbolTable dst = Module.modules; Dsymbol parent = null; //printf("Package::resolve()\n"); if (ppkg) *ppkg = null; if (packages) { for (size_t i = 0; i < packages.dim; i++) { Identifier pid = (*packages)[i]; Package pkg; Dsymbol p = dst.lookup(pid); if (!p) { pkg = new Package(pid); dst.insert(pkg); pkg.parent = parent; pkg.symtab = new DsymbolTable(); } else { pkg = p.isPackage(); assert(pkg); // It might already be a module, not a package, but that needs // to be checked at a higher level, where a nice error message // can be generated. // dot net needs modules and packages with same name // But we still need a symbol table for it if (!pkg.symtab) pkg.symtab = new DsymbolTable(); } parent = pkg; dst = pkg.symtab; if (ppkg && !*ppkg) *ppkg = pkg; if (pkg.isModule()) { // Return the module so that a nice error message can be generated if (ppkg) *ppkg = cast(Package)p; break; } } } if (pparent) *pparent = parent; return dst; } override final inout(Package) isPackage() inout { return this; } /** * Checks if pkg is a sub-package of this * * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3', * this function returns 'true'. If it is other way around or qualified * package paths conflict function returns 'false'. * * Params: * pkg = possible subpackage * * Returns: * see description */ final bool isAncestorPackageOf(const Package pkg) const { if (this == pkg) return true; if (!pkg || !pkg.parent) return false; return isAncestorPackageOf(pkg.parent.isPackage()); } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); flags &= ~SearchLocalsOnly; // searching an import is always transitive if (!isModule() && mod) { // Prefer full package name. Dsymbol s = symtab ? symtab.lookup(ident) : null; if (s) return s; //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); return mod.search(loc, ident, flags); } return ScopeDsymbol.search(loc, ident, flags); } override void accept(Visitor v) { v.visit(this); } final Module isPackageMod() { if (isPkgMod == PKG.module_) { return mod; } return null; } } /*********************************************************** */ extern (C++) final class Module : Package { extern (C++) __gshared Module rootModule; extern (C++) __gshared DsymbolTable modules; // symbol table of all modules extern (C++) __gshared Modules amodules; // array of all modules extern (C++) __gshared Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them extern (C++) __gshared Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them extern (C++) __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them extern (C++) __gshared uint dprogress; // progress resolving the deferred list static void _init() { modules = new DsymbolTable(); } extern (C++) __gshared AggregateDeclaration moduleinfo; const(char)* arg; // original argument name ModuleDeclaration* md; // if !=null, the contents of the ModuleDeclaration declaration File* srcfile; // input source file File* objfile; // output .obj file File* hdrfile; // 'header' file File* docfile; // output documentation file uint errors; // if any errors in file uint numlines; // number of lines in source file int isDocFile; // if it is a documentation input file, not D source bool isPackageFile; // if it is a package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does /************************************* * Return true if module imports itself. */ bool selfImports() { //printf("Module::selfImports() %s\n", toChars()); if (selfimports == 0) { for (size_t i = 0; i < amodules.dim; i++) amodules[i].insearch = 0; selfimports = imports(this) + 1; for (size_t i = 0; i < amodules.dim; i++) amodules[i].insearch = 0; } return selfimports == 2; } int rootimports; // 0: don't know, 1: does not, 2: does /************************************* * Return true if module imports root module. */ bool rootImports() { //printf("Module::rootImports() %s\n", toChars()); if (rootimports == 0) { for (size_t i = 0; i < amodules.dim; i++) amodules[i].insearch = 0; rootimports = 1; for (size_t i = 0; i < amodules.dim; ++i) { Module m = amodules[i]; if (m.isRoot() && imports(m)) { rootimports = 2; break; } } for (size_t i = 0; i < amodules.dim; i++) amodules[i].insearch = 0; } return rootimports == 2; } int insearch; Identifier searchCacheIdent; Dsymbol searchCacheSymbol; // cached value of search int searchCacheFlags; // cached flags /** * A root module is one that will be compiled all the way to * object code. This field holds the root module that caused * this module to be loaded. If this module is a root module, * then it will be set to `this`. This is used to determine * ownership of template instantiation. */ Module importedFrom; Dsymbols* decldefs; // top level declarations for this Module Modules aimports; // all imported modules uint debuglevel; // debug level Identifiers* debugids; // debug identifiers Identifiers* debugidsNot; // forward referenced debug identifiers uint versionlevel; // version level Identifiers* versionids; // version identifiers Identifiers* versionidsNot; // forward referenced version identifiers Macro* macrotable; // document comment macros Escape* escapetable; // document comment escapes size_t nameoffset; // offset of module name from start of ModuleInfo size_t namelen; // length of module name in characters extern (D) this(const(char)* filename, Identifier ident, int doDocComment, int doHdrGen) { super(ident); const(char)* srcfilename; //printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident.toChars()); this.arg = filename; srcfilename = FileName.defaultExt(filename, global.mars_ext); if (global.run_noext && global.params.run && !FileName.ext(filename) && FileName.exists(srcfilename) == 0 && FileName.exists(filename) == 1) { FileName.free(srcfilename); srcfilename = FileName.removeExt(filename); // just does a mem.strdup(filename) } else if (!FileName.equalsExt(srcfilename, global.mars_ext) && !FileName.equalsExt(srcfilename, global.hdr_ext) && !FileName.equalsExt(srcfilename, "dd")) { error("source file name '%s' must have .%s extension", srcfilename, global.mars_ext); fatal(); } srcfile = new File(srcfilename); objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext); if (doDocComment) setDocfile(); if (doHdrGen) hdrfile = setOutfile(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext); //objfile = new File(objfilename); } static Module create(const(char)* filename, Identifier ident, int doDocComment, int doHdrGen) { return new Module(filename, ident, doDocComment, doHdrGen); } static Module load(Loc loc, Identifiers* packages, Identifier ident) { //printf("Module::load(ident = '%s')\n", ident.toChars()); // Build module filename by turning: // foo.bar.baz // into: // foo\bar\baz const(char)[] filename = ident.toString(); if (packages && packages.dim) { OutBuffer buf; OutBuffer dotmods; auto ms = global.params.modFileAliasStrings; const msdim = ms ? ms.dim : 0; void checkModFileAlias(const(char)[] p) { /* Check and replace the contents of buf[] with * an alias string from global.params.modFileAliasStrings[] */ dotmods.writestring(p); Lmain: for (size_t j = msdim; j--;) { const m = (*ms)[j]; const q = strchr(m, '='); assert(q); if (dotmods.offset == q - m && memcmp(dotmods.peekString(), m, q - m) == 0) { buf.reset(); auto qlen = strlen(q + 1); if (qlen && (q[qlen] == '/' || q[qlen] == '\\')) --qlen; // remove trailing separator buf.writestring(q[1 .. qlen + 1]); break Lmain; // last matching entry in ms[] wins } } dotmods.writeByte('.'); } foreach (pid; *packages) { const p = pid.toString(); buf.writestring(p); if (msdim) checkModFileAlias(p); version (Windows) { buf.writeByte('\\'); } else { buf.writeByte('/'); } } buf.writestring(filename); if (msdim) checkModFileAlias(filename); buf.writeByte(0); filename = buf.extractData().toDString(); } auto m = new Module(filename.ptr, ident, 0, 0); m.loc = loc; /* Look for the source file */ if (const result = lookForSourceFile(filename)) m.srcfile = new File(result); if (!m.read(loc)) return null; if (global.params.verbose) { OutBuffer buf; if (packages) { foreach (pid; *packages) { buf.writestring(pid.toString()); buf.writeByte('.'); } } buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars()); message("import %s", buf.peekString()); } m = m.parse(); // Call onImport here because if the module is going to be compiled then we // need to determine it early because it affects semantic analysis. This is // being done after parsing the module so the full module name can be taken // from whatever was declared in the file. if (!m.isRoot() && Compiler.onImport(m)) { m.importedFrom = m; assert(m.isRoot()); } Compiler.loadModule(m); return m; } override const(char)* kind() const { return "module"; } /********************************************* * Combines things into output file name for .html and .di files. * Input: * name Command line name given for the file, NULL if none * dir Command line directory given for the file, NULL if none * arg Name of the source file * ext File name extension to use if 'name' is NULL * global.params.preservePaths get output path from arg * srcfile Input file - output file name must not match input file */ File* setOutfile(const(char)* name, const(char)* dir, const(char)* arg, const(char)* ext) { return setOutfile(name.toDString(), dir.toDString(), arg.toDString(), ext.toDString()); } /// Ditto extern(D) File* setOutfile(const(char)[] name, const(char)[] dir, const(char)[] arg, const(char)[] ext) { const(char)[] docfilename; if (name) { docfilename = name; } else { const(char)[] argdoc; OutBuffer buf; if (arg == "__stdin.d") { version (Posix) import core.sys.posix.unistd : getpid; else version (Windows) import core.sys.windows.windows : getpid = GetCurrentProcessId; buf.printf("__stdin_%d.d", getpid()); arg = buf.peekSlice(); } if (global.params.preservePaths) argdoc = arg; else argdoc = FileName.name(arg); // If argdoc doesn't have an absolute path, make it relative to dir if (!FileName.absolute(argdoc)) { //FileName::ensurePathExists(dir); argdoc = FileName.combine(dir, argdoc); } docfilename = FileName.forceExt(argdoc, ext); } if (FileName.equals(docfilename, srcfile.name.toString())) { error("source file and output file have same name '%s'", srcfile.name.toChars()); fatal(); } return new File(docfilename); } void setDocfile() { docfile = setOutfile(global.params.docname, global.params.docdir, arg, global.doc_ext); } // read file, returns 'true' if succeed, 'false' otherwise. bool read(Loc loc) { //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); if (!srcfile.read()) return true; if (FileName.equals(srcfile.toString(), "object.d")) { .error(loc, "cannot find source code for runtime library file 'object.d'"); errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); const dmdConfFile = FileName.canonicalName(global.inifilename); errorSupplemental(loc, "config file: %s", dmdConfFile ? dmdConfFile : "not found".ptr); } else { // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name.name(), "package.d") == 0 || (strcmp(srcfile.name.name(), "package.di") == 0)); if (isPackageMod) .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars()); else error(loc, "is in file '%s' which cannot be read", srcfile.toChars()); } if (!global.gag) { /* Print path */ if (global.path) { foreach (i, p; *global.path) fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p); } else fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile.toChars()); fatal(); } return false; } // syntactic parse Module parse() { //printf("Module::parse(srcfile='%s') this=%p\n", srcfile.name.toChars(), this); const(char)* srcname = srcfile.name.toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); isPackageFile = (strcmp(srcfile.name.name(), "package.d") == 0 || strcmp(srcfile.name.name(), "package.di") == 0); char* buf = cast(char*)srcfile.buffer; size_t buflen = srcfile.len; if (buflen >= 2) { /* Convert all non-UTF-8 formats to UTF-8. * BOM : http://www.unicode.org/faq/utf_bom.html * 00 00 FE FF UTF-32BE, big-endian * FF FE 00 00 UTF-32LE, little-endian * FE FF UTF-16BE, big-endian * FF FE UTF-16LE, little-endian * EF BB BF UTF-8 */ uint le; uint bom = 1; // assume there's a BOM if (buf[0] == 0xFF && buf[1] == 0xFE) { if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; Lutf32: OutBuffer dbuf; uint* pu = cast(uint*)buf; uint* pumax = &pu[buflen / 4]; if (buflen & 3) { error("odd length of UTF-32 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 4); for (pu += bom; pu < pumax; pu++) { uint u; u = le ? Port.readlongLE(pu) : Port.readlongBE(pu); if (u & ~0x7F) { if (u > 0x10FFFF) { error("UTF-32 value %08x greater than 0x10FFFF", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = dbuf.extractData(); } else { // UTF-16LE (X86) // Convert it to UTF-8 le = 1; Lutf16: OutBuffer dbuf; ushort* pu = cast(ushort*)buf; ushort* pumax = &pu[buflen / 2]; if (buflen & 1) { error("odd length of UTF-16 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 2); for (pu += bom; pu < pumax; pu++) { uint u; u = le ? Port.readwordLE(pu) : Port.readwordBE(pu); if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) { uint u2; if (++pu > pumax) { error("surrogate UTF-16 high value %04x at end of file", u); fatal(); } u2 = le ? Port.readwordLE(pu) : Port.readwordBE(pu); if (u2 < 0xDC00 || u2 > 0xDFFF) { error("surrogate UTF-16 low value %04x out of range", u2); fatal(); } u = (u - 0xD7C0) << 10; u |= (u2 - 0xDC00); } else if (u >= 0xDC00 && u <= 0xDFFF) { error("unpaired surrogate UTF-16 value %04x", u); fatal(); } else if (u == 0xFFFE || u == 0xFFFF) { error("illegal UTF-16 value %04x", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = dbuf.extractData(); } } else if (buf[0] == 0xFE && buf[1] == 0xFF) { // UTF-16BE le = 0; goto Lutf16; } else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) { // UTF-32BE le = 0; goto Lutf32; } else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) { // UTF-8 buf += 3; buflen -= 3; } else { /* There is no BOM. Make use of Arcane Jill's insight that * the first char of D source must be ASCII to * figure out the encoding. */ bom = 0; if (buflen >= 4) { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; goto Lutf32; } else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) { // UTF-32BE le = 0; goto Lutf32; } } if (buflen >= 2) { if (buf[1] == 0) { // UTF-16LE le = 1; goto Lutf16; } else if (buf[0] == 0) { // UTF-16BE le = 0; goto Lutf16; } } // It's UTF-8 if (buf[0] >= 0x80) { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); fatal(); } } } /* If it starts with the string "Ddoc", then it's a documentation * source file. */ if (buflen >= 4 && memcmp(buf, cast(char*)"Ddoc", 4) == 0) { comment = buf + 4; isDocFile = 1; if (!docfile) setDocfile(); return this; } /* If it has the extension ".dd", it is also a documentation * source file. Documentation source files may begin with "Ddoc" * but do not have to if they have the .dd extension. * https://issues.dlang.org/show_bug.cgi?id=15465 */ if (FileName.equalsExt(arg, "dd")) { comment = buf; // the optional Ddoc, if present, is handled above. isDocFile = 1; if (!docfile) setDocfile(); return this; } { scope p = new Parser!ASTCodegen(this, buf[0 .. buflen], docfile !is null); p.nextToken(); members = p.parseModule(); md = p.md; numlines = p.scanloc.linnum; if (p.errors) ++global.errors; } if (srcfile._ref == 0) .free(srcfile.buffer); srcfile.buffer = null; srcfile.len = 0; /* The symbol table into which the module is to be inserted. */ DsymbolTable dst; if (md) { /* A ModuleDeclaration, md, was provided. * The ModuleDeclaration sets the packages this module appears in, and * the name of this module. */ this.ident = md.id; Package ppack = null; dst = Package.resolve(md.packages, &this.parent, &ppack); assert(dst); Module m = ppack ? ppack.isModule() : null; if (m && (strcmp(m.srcfile.name.name(), "package.d") != 0 && strcmp(m.srcfile.name.name(), "package.di") != 0)) { .error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars()); } } else { /* The name of the module is set to the source file name. * There are no packages. */ dst = modules; // and so this module goes into global module symbol table /* Check to see if module name is a valid identifier */ if (!Identifier.isValidIdentifier(this.ident.toChars())) error("has non-identifier characters in filename, use module declaration instead"); } // Insert module into the symbol table Dsymbol s = this; if (isPackageFile) { /* If the source tree is as follows: * pkg/ * +- package.d * +- common.d * the 'pkg' will be incorporated to the internal package tree in two ways: * import pkg; * and: * import pkg.common; * * If both are used in one compilation, 'pkg' as a module (== pkg/package.d) * and a package name 'pkg' will conflict each other. * * To avoid the conflict: * 1. If preceding package name insertion had occurred by Package::resolve, * later package.d loading will change Package::isPkgMod to PKG.module_ and set Package::mod. * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here. */ auto p = new Package(ident); p.parent = this.parent; p.isPkgMod = PKG.module_; p.mod = this; p.tag = this.tag; // reuse the same package tag p.symtab = new DsymbolTable(); s = p; } if (!dst.insert(s)) { /* It conflicts with a name that is already in the symbol table. * Figure out what went wrong, and issue error message. */ Dsymbol prev = dst.lookup(ident); assert(prev); if (Module mprev = prev.isModule()) { if (!FileName.equals(srcname, mprev.srcfile.toChars())) error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev.toChars(), mprev.srcfile.toChars()); else if (isRoot() && mprev.isRoot()) error(loc, "from file %s is specified twice on the command line", srcname); else error(loc, "from file %s must be imported with 'import %s;'", srcname, toPrettyChars()); // https://issues.dlang.org/show_bug.cgi?id=14446 // Return previously parsed module to avoid AST duplication ICE. return mprev; } else if (Package pkg = prev.isPackage()) { if (pkg.isPkgMod == PKG.unknown && isPackageFile) { /* If the previous inserted Package is not yet determined as package.d, * link it to the actual module. */ pkg.isPkgMod = PKG.module_; pkg.mod = this; pkg.tag = this.tag; // reuse the same package tag amodules.push(this); // Add to global array of all modules } else error(md ? md.loc : loc, "from file %s conflicts with package name %s", srcname, pkg.toChars()); } else assert(global.errors); } else { // Add to global array of all modules amodules.push(this); } return this; } override void importAll(Scope* prevsc) { //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); if (_scope) return; // already done if (isDocFile) { error("is a Ddoc file, cannot import it"); return; } if (md && md.msg) { if (StringExp se = md.msg.toStringExp()) md.msg = se; else md.msg.error("string expected, not '%s'", md.msg.toChars()); } /* Note that modules get their own scope, from scratch. * This is so regardless of where in the syntax a module * gets imported, it is unaffected by context. * Ignore prevsc. */ Scope* sc = Scope.createGlobal(this); // create root scope // Add import of "object", even for the "object" module. // If it isn't there, some compiler rewrites, like // classinst == classinst -> .object.opEquals(classinst, classinst) // would fail inside object.d. if (members.dim == 0 || (*members)[0].ident != Id.object) { auto im = new Import(Loc.initial, null, Id.object, null, 0); members.shift(im); } if (!symtab) { // Add all symbols into module's symbol table symtab = new DsymbolTable(); for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.addMember(sc, sc.scopesym); } } // anything else should be run after addMember, so version/debug symbols are defined /* Set scope for the symbols so that if we forward reference * a symbol, it can possibly be resolved on the spot. * If this works out well, it can be extended to all modules * before any semantic() on any of them. */ setScope(sc); // remember module scope for semantic for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.setScope(sc); } for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.importAll(sc); } sc = sc.pop(); sc.pop(); // 2 pops because Scope::createGlobal() created 2 } /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. */ int needModuleInfo() { //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); return needmoduleinfo || global.params.cov; } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { /* Since modules can be circularly referenced, * need to stop infinite recursive searches. * This is done with the cache. */ //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); if (insearch) return null; /* Qualified module searches always search their imports, * even if SearchLocalsOnly */ if (!(flags & SearchUnqualifiedModule)) flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); if (searchCacheIdent == ident && searchCacheFlags == flags) { //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); return searchCacheSymbol; } uint errors = global.errors; insearch = 1; Dsymbol s = ScopeDsymbol.search(loc, ident, flags); insearch = 0; if (errors == global.errors) { // https://issues.dlang.org/show_bug.cgi?id=10752 // Can cache the result only when it does not cause // access error so the side-effect should be reproduced in later search. searchCacheIdent = ident; searchCacheSymbol = s; searchCacheFlags = flags; } return s; } override bool isPackageAccessible(Package p, Prot protection, int flags = 0) { if (insearch) // don't follow import cycles return false; insearch = true; scope (exit) insearch = false; if (flags & IgnorePrivateImports) protection = Prot(Prot.Kind.public_); // only consider public imports return super.isPackageAccessible(p, protection); } override Dsymbol symtabInsert(Dsymbol s) { searchCacheIdent = null; // symbol is inserted, so invalidate cache return Package.symtabInsert(s); } void deleteObjFile() { if (global.params.obj) objfile.remove(); if (docfile) docfile.remove(); } /******************************************* * Can't run semantic on s now, try again later. */ static void addDeferredSemantic(Dsymbol s) { //printf("Module::addDeferredSemantic('%s')\n", s.toChars()); deferred.push(s); } static void addDeferredSemantic2(Dsymbol s) { //printf("Module::addDeferredSemantic2('%s')\n", s.toChars()); deferred2.push(s); } static void addDeferredSemantic3(Dsymbol s) { //printf("Module::addDeferredSemantic3('%s')\n", s.toChars()); deferred3.push(s); } /****************************************** * Run semantic() on deferred symbols. */ static void runDeferredSemantic() { if (dprogress == 0) return; __gshared int nested; if (nested) return; //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim); nested++; size_t len; do { dprogress = 0; len = deferred.dim; if (!len) break; Dsymbol* todo; Dsymbol* todoalloc = null; Dsymbol tmp; if (len == 1) { todo = &tmp; } else { todo = cast(Dsymbol*)malloc(len * Dsymbol.sizeof); assert(todo); todoalloc = todo; } memcpy(todo, deferred.tdata(), len * Dsymbol.sizeof); deferred.setDim(0); for (size_t i = 0; i < len; i++) { Dsymbol s = todo[i]; s.dsymbolSemantic(null); //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars()); } //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); if (todoalloc) free(todoalloc); } while (deferred.dim < len || dprogress); // while making progress nested--; //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim); } static void runDeferredSemantic2() { Module.runDeferredSemantic(); Dsymbols* a = &Module.deferred2; for (size_t i = 0; i < a.dim; i++) { Dsymbol s = (*a)[i]; //printf("[%d] %s semantic2a\n", i, s.toPrettyChars()); s.semantic2(null); if (global.errors) break; } a.setDim(0); } static void runDeferredSemantic3() { Module.runDeferredSemantic2(); Dsymbols* a = &Module.deferred3; for (size_t i = 0; i < a.dim; i++) { Dsymbol s = (*a)[i]; //printf("[%d] %s semantic3a\n", i, s.toPrettyChars()); s.semantic3(null); if (global.errors) break; } a.setDim(0); } static void clearCache() { for (size_t i = 0; i < amodules.dim; i++) { Module m = amodules[i]; m.searchCacheIdent = null; } } /************************************ * Recursively look at every module this module imports, * return true if it imports m. * Can be used to detect circular imports. */ int imports(Module m) { //printf("%s Module::imports(%s)\n", toChars(), m.toChars()); version (none) { for (size_t i = 0; i < aimports.dim; i++) { Module mi = cast(Module)aimports.data[i]; printf("\t[%d] %s\n", i, mi.toChars()); } } for (size_t i = 0; i < aimports.dim; i++) { Module mi = aimports[i]; if (mi == m) return true; if (!mi.insearch) { mi.insearch = 1; int r = mi.imports(m); if (r) return r; } } return false; } bool isRoot() { return this.importedFrom == this; } // true if the module source file is directly // listed in command line. bool isCoreModule(Identifier ident) { return this.ident == ident && parent && parent.ident == Id.core && !parent.parent; } // Back end int doppelganger; // sub-module Symbol* cov; // private uint[] __coverage; uint* covb; // bit array of valid code line numbers Symbol* sictor; // module order independent constructor Symbol* sctor; // module constructor Symbol* sdtor; // module destructor Symbol* ssharedctor; // module shared constructor Symbol* sshareddtor; // module shared destructor Symbol* stest; // module unit test Symbol* sfilename; // symbol for filename override inout(Module) isModule() inout { return this; } override void accept(Visitor v) { v.visit(this); } /*********************************************** * Writes this module's fully-qualified name to buf * Params: * buf = The buffer to write to */ void fullyQualifiedName(ref OutBuffer buf) { buf.writestring(ident.toString()); for (auto package_ = parent; package_ !is null; package_ = package_.parent) { buf.prependstring("."); buf.prependstring(package_.ident.toChars()); } } } /*********************************************************** */ struct ModuleDeclaration { Loc loc; Identifier id; Identifiers* packages; // array of Identifier's representing packages bool isdeprecated; // if it is a deprecated module Expression msg; extern (D) this(const ref Loc loc, Identifiers* packages, Identifier id, Expression msg, bool isdeprecated) { this.loc = loc; this.packages = packages; this.id = id; this.msg = msg; this.isdeprecated = isdeprecated; } extern (C++) const(char)* toChars() const { OutBuffer buf; if (packages && packages.dim) { foreach (pid; *packages) { buf.writestring(pid.toString()); buf.writeByte('.'); } } buf.writestring(id.toString()); return buf.extractString(); } /// Provide a human readable representation extern (D) const(char)[] toString() const { return this.toChars().toDString; } } ================================================ FILE: gcc/d/dmd/doc.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/doc.d, _doc.d) * Documentation: https://dlang.org/phobos/dmd_doc.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/doc.d */ module dmd.doc; import core.stdc.ctype; import core.stdc.stdlib; import core.stdc.stdio; import core.stdc.string; import core.stdc.time; import dmd.aggregate; import dmd.arraytypes; import dmd.attrib; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dmacro; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.lexer; import dmd.mtype; 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.tokens; import dmd.utf; import dmd.utils; import dmd.visitor; struct Escape { const(char)[][char.max] strings; /*************************************** * Find character string to replace c with. */ const(char)[] escapeChar(char c) { version (all) { //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c].ptr); return strings[c]; } else { const(char)[] s; switch (c) { case '<': s = "<"; break; case '>': s = ">"; break; case '&': s = "&"; break; default: s = null; break; } return s; } } } /*********************************************************** */ private class Section { const(char)* name; size_t namelen; const(char)* _body; size_t bodylen; int nooutput; void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) { assert(a.dim); if (namelen) { static immutable table = [ "AUTHORS", "BUGS", "COPYRIGHT", "DATE", "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", "VERSION", ]; foreach (entry; table) { if (iequals(entry, name[0 .. namelen])) { buf.printf("$(DDOC_%s ", entry.ptr); goto L1; } } buf.writestring("$(DDOC_SECTION "); // Replace _ characters with spaces buf.writestring("$(DDOC_SECTION_H "); size_t o = buf.offset; for (size_t u = 0; u < namelen; u++) { char c = name[u]; buf.writeByte((c == '_') ? ' ' : c); } escapeStrayParenthesis(loc, buf, o); buf.writestring(")"); } else { buf.writestring("$(DDOC_DESCRIPTION "); } L1: size_t o = buf.offset; buf.write(_body, bodylen); escapeStrayParenthesis(loc, buf, o); highlightText(sc, a, buf, o); buf.writestring(")"); } } /*********************************************************** */ private final class ParamSection : Section { override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) { assert(a.dim); Dsymbol s = (*a)[0]; // test const(char)* p = _body; size_t len = bodylen; const(char)* pend = p + len; const(char)* tempstart = null; size_t templen = 0; const(char)* namestart = null; size_t namelen = 0; // !=0 if line continuation const(char)* textstart = null; size_t textlen = 0; size_t paramcount = 0; buf.writestring("$(DDOC_PARAMS "); while (p < pend) { // Skip to start of macro while (1) { switch (*p) { case ' ': case '\t': p++; continue; case '\n': p++; goto Lcont; default: if (isIdStart(p) || isCVariadicArg(p[0 .. cast(size_t)(pend - p)])) break; if (namelen) goto Ltext; // continuation of prev macro goto Lskipline; } break; } tempstart = p; while (isIdTail(p)) p += utfStride(p); if (isCVariadicArg(p[0 .. cast(size_t)(pend - p)])) p += 3; templen = p - tempstart; while (*p == ' ' || *p == '\t') p++; if (*p != '=') { if (namelen) goto Ltext; // continuation of prev macro goto Lskipline; } p++; if (namelen) { // Output existing param L1: //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); ++paramcount; HdrGenState hgs; buf.writestring("$(DDOC_PARAM_ROW "); { buf.writestring("$(DDOC_PARAM_ID "); { size_t o = buf.offset; Parameter fparam = isFunctionParameter(a, namestart, namelen); if (!fparam) { // Comments on a template might refer to function parameters within. // Search the parameters of nested eponymous functions (with the same name.) fparam = isEponymousFunctionParameter(a, namestart, namelen); } bool isCVariadic = isCVariadicParameter(a, namestart[0 .. namelen]); if (isCVariadic) { buf.writestring("..."); } else if (fparam && fparam.type && fparam.ident) { .toCBuffer(fparam.type, buf, fparam.ident, &hgs); } else { if (isTemplateParameter(a, namestart, namelen)) { // 10236: Don't count template parameters for params check --paramcount; } else if (!fparam) { warning(s.loc, "Ddoc: function declaration has no parameter '%.*s'", namelen, namestart); } buf.write(namestart, namelen); } escapeStrayParenthesis(loc, buf, o); highlightCode(sc, a, buf, o); } buf.writestring(")"); buf.writestring("$(DDOC_PARAM_DESC "); { size_t o = buf.offset; buf.write(textstart, textlen); escapeStrayParenthesis(loc, buf, o); highlightText(sc, a, buf, o); } buf.writestring(")"); } buf.writestring(")"); namelen = 0; if (p >= pend) break; } namestart = tempstart; namelen = templen; while (*p == ' ' || *p == '\t') p++; textstart = p; Ltext: while (*p != '\n') p++; textlen = p - textstart; p++; Lcont: continue; Lskipline: // Ignore this line while (*p++ != '\n') { } } if (namelen) goto L1; // write out last one buf.writestring(")"); TypeFunction tf = a.dim == 1 ? isTypeFunction(s) : null; if (tf) { size_t pcount = (tf.parameters ? tf.parameters.dim : 0) + cast(int)(tf.varargs == 1); if (pcount != paramcount) { warning(s.loc, "Ddoc: parameter count mismatch"); } } } } /*********************************************************** */ private final class MacroSection : Section { override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf) { //printf("MacroSection::write()\n"); DocComment.parseMacros(dc.pescapetable, dc.pmacrotable, _body, bodylen); } } private alias Sections = Array!(Section); // Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one). private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) { foreach (member; *a) { TypeFunction tf = isTypeFunction(member); if (tf && tf.varargs == 1 && p == "...") return true; } return false; } private Dsymbol getEponymousMember(TemplateDeclaration td) { if (!td.onemember) return null; if (AggregateDeclaration ad = td.onemember.isAggregateDeclaration()) return ad; if (FuncDeclaration fd = td.onemember.isFuncDeclaration()) return fd; if (auto em = td.onemember.isEnumMember()) return null; // Keep backward compatibility. See compilable/ddoc9.d if (VarDeclaration vd = td.onemember.isVarDeclaration()) return td.constraint ? null : vd; return null; } private TemplateDeclaration getEponymousParent(Dsymbol s) { if (!s.parent) return null; TemplateDeclaration td = s.parent.isTemplateDeclaration(); return (td && getEponymousMember(td)) ? td : null; } private immutable ddoc_default = import("default_ddoc_theme.ddoc"); private immutable ddoc_decl_s = "$(DDOC_DECL "; private immutable ddoc_decl_e = ")\n"; private immutable ddoc_decl_dd_s = "$(DDOC_DECL_DD "; private immutable ddoc_decl_dd_e = ")\n"; /**************************************************** */ extern(C++) void gendocfile(Module m) { __gshared OutBuffer mbuf; __gshared int mbuf_done; OutBuffer buf; //printf("Module::gendocfile()\n"); if (!mbuf_done) // if not already read the ddoc files { mbuf_done = 1; // Use our internal default mbuf.writestring(ddoc_default); // Override with DDOCFILE specified in the sc.ini file char* p = getenv("DDOCFILE"); if (p) global.params.ddocfiles.shift(p); // Override with the ddoc macro files from the command line for (size_t i = 0; i < global.params.ddocfiles.dim; i++) { auto file = File(global.params.ddocfiles[i].toDString()); readFile(m.loc, &file); // BUG: convert file contents to UTF-8 before use //printf("file: '%.*s'\n", file.len, file.buffer); mbuf.write(file.buffer, file.len); } } DocComment.parseMacros(&m.escapetable, &m.macrotable, mbuf.peekSlice().ptr, mbuf.peekSlice().length); Scope* sc = Scope.createGlobal(m); // create root scope DocComment* dc = DocComment.parse(m, m.comment); dc.pmacrotable = &m.macrotable; dc.pescapetable = &m.escapetable; sc.lastdc = dc; // Generate predefined macros // Set the title to be the name of the module { const p = m.toPrettyChars().toDString; Macro.define(&m.macrotable, "TITLE", p); } // Set time macros { time_t t; time(&t); char* p = ctime(&t); p = mem.xstrdup(p); Macro.define(&m.macrotable, "DATETIME", p[0 .. strlen(p)]); Macro.define(&m.macrotable, "YEAR", p[20 .. 20 + 4]); } const srcfilename = m.srcfile.toString(); Macro.define(&m.macrotable, "SRCFILENAME", srcfilename); const docfilename = m.docfile.toString(); Macro.define(&m.macrotable, "DOCFILENAME", docfilename); if (dc.copyright) { dc.copyright.nooutput = 1; Macro.define(&m.macrotable, "COPYRIGHT", dc.copyright._body[0 .. dc.copyright.bodylen]); } if (m.isDocFile) { Loc loc = m.md ? m.md.loc : m.loc; size_t commentlen = strlen(cast(char*)m.comment); Dsymbols a; // https://issues.dlang.org/show_bug.cgi?id=9764 // Don't push m in a, to prevent emphasize ddoc file name. if (dc.macros) { commentlen = dc.macros.name - m.comment; dc.macros.write(loc, dc, sc, &a, &buf); } buf.write(m.comment, commentlen); highlightText(sc, &a, &buf, 0); } else { Dsymbols a; a.push(m); dc.writeSections(sc, &a, &buf); emitMemberComments(m, &buf, sc); } //printf("BODY= '%.*s'\n", buf.offset, buf.data); Macro.define(&m.macrotable, "BODY", buf.peekSlice()); OutBuffer buf2; buf2.writestring("$(DDOC)"); size_t end = buf2.offset; m.macrotable.expand(&buf2, 0, &end, null); version (all) { /* Remove all the escape sequences from buf2, * and make CR-LF the newline. */ { const slice = buf2.peekSlice(); buf.setsize(0); buf.reserve(slice.length); auto p = slice.ptr; for (size_t j = 0; j < slice.length; j++) { char c = p[j]; if (c == 0xFF && j + 1 < slice.length) { j++; continue; } if (c == '\n') buf.writeByte('\r'); else if (c == '\r') { buf.writestring("\r\n"); if (j + 1 < slice.length && p[j + 1] == '\n') { j++; } continue; } buf.writeByte(c); } } // Transfer image to file assert(m.docfile); m.docfile.setbuffer(cast(void*)buf.peekSlice().ptr, buf.peekSlice().length); m.docfile._ref = 1; ensurePathToNameExists(Loc.initial, m.docfile.toChars()); writeFile(m.loc, m.docfile); } else { /* Remove all the escape sequences from buf2 */ { size_t i = 0; char* p = buf2.data; for (size_t j = 0; j < buf2.offset; j++) { if (p[j] == 0xFF && j + 1 < buf2.offset) { j++; continue; } p[i] = p[j]; i++; } buf2.setsize(i); } // Transfer image to file m.docfile.setbuffer(buf2.data, buf2.offset); m.docfile._ref = 1; ensurePathToNameExists(Loc.initial, m.docfile.toChars()); writeFile(m.loc, m.docfile); } } /**************************************************** * Having unmatched parentheses can hose the output of Ddoc, * as the macros depend on properly nested parentheses. * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) * to preserve text literally. This also means macros in the * text won't be expanded. */ void escapeDdocString(OutBuffer* buf, size_t start) { for (size_t u = start; u < buf.offset; u++) { char c = buf.data[u]; switch (c) { case '$': buf.remove(u, 1); buf.insert(u, "$(DOLLAR)"); u += 8; break; case '(': buf.remove(u, 1); //remove the ( buf.insert(u, "$(LPAREN)"); //insert this instead u += 8; //skip over newly inserted macro break; case ')': buf.remove(u, 1); //remove the ) buf.insert(u, "$(RPAREN)"); //insert this instead u += 8; //skip over newly inserted macro break; default: break; } } } /**************************************************** * Having unmatched parentheses can hose the output of Ddoc, * as the macros depend on properly nested parentheses. * * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). */ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start) { uint par_open = 0; char inCode = 0; bool atLineStart = true; for (size_t u = start; u < buf.offset; u++) { char c = buf.data[u]; switch (c) { case '(': if (!inCode) par_open++; atLineStart = false; break; case ')': if (!inCode) { if (par_open == 0) { //stray ')' warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output. Use $(RPAREN) instead for unpaired right parentheses."); buf.remove(u, 1); //remove the ) buf.insert(u, "$(RPAREN)"); //insert this instead u += 8; //skip over newly inserted macro } else par_open--; } atLineStart = false; break; case '\n': atLineStart = true; version (none) { // For this to work, loc must be set to the beginning of the passed // text which is currently not possible // (loc is set to the Loc of the Dsymbol) loc.linnum++; } break; case ' ': case '\r': case '\t': break; case '-': case '`': // Issue 15465: don't try to escape unbalanced parens inside code // blocks. int numdash = 1; for (++u; u < buf.offset && buf.data[u] == '-'; ++u) ++numdash; --u; if (c == '`' || (atLineStart && numdash >= 3)) { if (inCode == c) inCode = 0; else if (!inCode) inCode = c; } atLineStart = false; break; default: atLineStart = false; break; } } if (par_open) // if any unmatched lparens { par_open = 0; for (size_t u = buf.offset; u > start;) { u--; char c = buf.data[u]; switch (c) { case ')': par_open++; break; case '(': if (par_open == 0) { //stray '(' warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses."); buf.remove(u, 1); //remove the ( buf.insert(u, "$(LPAREN)"); //insert this instead } else par_open--; break; default: break; } } } } // Basically, this is to skip over things like private{} blocks in a struct or // class definition that don't add any components to the qualified name. private Scope* skipNonQualScopes(Scope* sc) { while (sc && !sc.scopesym) sc = sc.enclosing; return sc; } private bool emitAnchorName(OutBuffer* buf, Dsymbol s, Scope* sc, bool includeParent) { if (!s || s.isPackage() || s.isModule()) return false; // Add parent names first bool dot = false; auto eponymousParent = getEponymousParent(s); if (includeParent && s.parent || eponymousParent) dot = emitAnchorName(buf, s.parent, sc, includeParent); else if (includeParent && sc) dot = emitAnchorName(buf, sc.scopesym, skipNonQualScopes(sc.enclosing), includeParent); // Eponymous template members can share the parent anchor name if (eponymousParent) return dot; if (dot) buf.writeByte('.'); // Use "this" not "__ctor" TemplateDeclaration td; if (s.isCtorDeclaration() || ((td = s.isTemplateDeclaration()) !is null && td.onemember && td.onemember.isCtorDeclaration())) { buf.writestring("this"); } else { /* We just want the identifier, not overloads like TemplateDeclaration::toChars. * We don't want the template parameter list and constraints. */ buf.writestring(s.Dsymbol.toChars()); } return true; } private void emitAnchor(OutBuffer* buf, Dsymbol s, Scope* sc, bool forHeader = false) { Identifier ident; { OutBuffer anc; emitAnchorName(&anc, s, skipNonQualScopes(sc), true); ident = Identifier.idPool(anc.peekSlice()); } auto pcount = cast(void*)ident in sc.anchorCounts; typeof(*pcount) count; if (!forHeader) { if (pcount) { // Existing anchor, // don't write an anchor for matching consecutive ditto symbols TemplateDeclaration td = getEponymousParent(s); if (sc.prevAnchor == ident && sc.lastdc && (isDitto(s.comment) || (td && isDitto(td.comment)))) return; count = ++*pcount; } else { sc.anchorCounts[cast(void*)ident] = 1; count = 1; } } // cache anchor name sc.prevAnchor = ident; auto macroName = forHeader ? "DDOC_HEADER_ANCHOR" : "DDOC_ANCHOR"; auto symbolName = ident.toString(); buf.printf("$(%.*s %.*s", cast(int) macroName.length, macroName.ptr, cast(int) symbolName.length, symbolName.ptr); // only append count once there's a duplicate if (count > 1) buf.printf(".%u", count); if (forHeader) { Identifier shortIdent; { OutBuffer anc; emitAnchorName(&anc, s, skipNonQualScopes(sc), false); shortIdent = Identifier.idPool(anc.peekSlice()); } auto shortName = shortIdent.toString(); buf.printf(", %.*s", cast(int) shortName.length, shortName.ptr); } buf.writeByte(')'); } /******************************* emitComment **********************************/ /** Get leading indentation from 'src' which represents lines of code. */ private size_t getCodeIndent(const(char)* src) { while (src && (*src == '\r' || *src == '\n')) ++src; // skip until we find the first non-empty line size_t codeIndent = 0; while (src && (*src == ' ' || *src == '\t')) { codeIndent++; src++; } return codeIndent; } /** Recursively expand template mixin member docs into the scope. */ private void expandTemplateMixinComments(TemplateMixin tm, OutBuffer* buf, Scope* sc) { if (!tm.semanticRun) tm.dsymbolSemantic(sc); TemplateDeclaration td = (tm && tm.tempdecl) ? tm.tempdecl.isTemplateDeclaration() : null; if (td && td.members) { for (size_t i = 0; i < td.members.dim; i++) { Dsymbol sm = (*td.members)[i]; TemplateMixin tmc = sm.isTemplateMixin(); if (tmc && tmc.comment) expandTemplateMixinComments(tmc, buf, sc); else emitComment(sm, buf, sc); } } } private void emitMemberComments(ScopeDsymbol sds, OutBuffer* buf, Scope* sc) { if (!sds.members) return; //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); const(char)[] m = "$(DDOC_MEMBERS "; if (sds.isTemplateDeclaration()) m = "$(DDOC_TEMPLATE_MEMBERS "; else if (sds.isClassDeclaration()) m = "$(DDOC_CLASS_MEMBERS "; else if (sds.isStructDeclaration()) m = "$(DDOC_STRUCT_MEMBERS "; else if (sds.isEnumDeclaration()) m = "$(DDOC_ENUM_MEMBERS "; else if (sds.isModule()) m = "$(DDOC_MODULE_MEMBERS "; size_t offset1 = buf.offset; // save starting offset buf.writestring(m); size_t offset2 = buf.offset; // to see if we write anything sc = sc.push(sds); for (size_t i = 0; i < sds.members.dim; i++) { Dsymbol s = (*sds.members)[i]; //printf("\ts = '%s'\n", s.toChars()); // only expand if parent is a non-template (semantic won't work) if (s.comment && s.isTemplateMixin() && s.parent && !s.parent.isTemplateDeclaration()) expandTemplateMixinComments(cast(TemplateMixin)s, buf, sc); emitComment(s, buf, sc); } emitComment(null, buf, sc); sc.pop(); if (buf.offset == offset2) { /* Didn't write out any members, so back out last write */ buf.offset = offset1; } else buf.writestring(")"); } private void emitProtection(OutBuffer* buf, Prot prot) { if (prot.kind != Prot.Kind.undefined && prot.kind != Prot.Kind.public_) { protectionToBuffer(buf, prot); buf.writeByte(' '); } } private void emitComment(Dsymbol s, OutBuffer* buf, Scope* sc) { extern (C++) final class EmitComment : Visitor { alias visit = Visitor.visit; public: OutBuffer* buf; Scope* sc; extern (D) this(OutBuffer* buf, Scope* sc) { this.buf = buf; this.sc = sc; } override void visit(Dsymbol) { } override void visit(InvariantDeclaration) { } override void visit(UnitTestDeclaration) { } override void visit(PostBlitDeclaration) { } override void visit(DtorDeclaration) { } override void visit(StaticCtorDeclaration) { } override void visit(StaticDtorDeclaration) { } override void visit(TypeInfoDeclaration) { } void emit(Scope* sc, Dsymbol s, const(char)* com) { if (s && sc.lastdc && isDitto(com)) { sc.lastdc.a.push(s); return; } // Put previous doc comment if exists if (DocComment* dc = sc.lastdc) { assert(dc.a.dim > 0, "Expects at least one declaration for a" ~ "documentation comment"); auto symbol = dc.a[0]; buf.writestring("$(DDOC_MEMBER"); buf.writestring("$(DDOC_MEMBER_HEADER"); emitAnchor(buf, symbol, sc, true); buf.writeByte(')'); // Put the declaration signatures as the document 'title' buf.writestring(ddoc_decl_s); for (size_t i = 0; i < dc.a.dim; i++) { Dsymbol sx = dc.a[i]; // the added linebreaks in here make looking at multiple // signatures more appealing if (i == 0) { size_t o = buf.offset; toDocBuffer(sx, buf, sc); highlightCode(sc, sx, buf, o); buf.writestring("$(DDOC_OVERLOAD_SEPARATOR)"); continue; } buf.writestring("$(DDOC_DITTO "); { size_t o = buf.offset; toDocBuffer(sx, buf, sc); highlightCode(sc, sx, buf, o); } buf.writestring("$(DDOC_OVERLOAD_SEPARATOR)"); buf.writeByte(')'); } buf.writestring(ddoc_decl_e); // Put the ddoc comment as the document 'description' buf.writestring(ddoc_decl_dd_s); { dc.writeSections(sc, &dc.a, buf); if (ScopeDsymbol sds = dc.a[0].isScopeDsymbol()) emitMemberComments(sds, buf, sc); } buf.writestring(ddoc_decl_dd_e); buf.writeByte(')'); //printf("buf.2 = [[%.*s]]\n", buf.offset - o0, buf.data + o0); } if (s) { DocComment* dc = DocComment.parse(s, com); dc.pmacrotable = &sc._module.macrotable; sc.lastdc = dc; } } override void visit(Declaration d) { //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d.toChars(), d.comment); //printf("type = %p\n", d.type); const(char)* com = d.comment; if (TemplateDeclaration td = getEponymousParent(d)) { if (isDitto(td.comment)) com = td.comment; else com = Lexer.combineComments(td.comment, com, true); } else { if (!d.ident) return; if (!d.type) { if (!d.isCtorDeclaration() && !d.isAliasDeclaration() && !d.isVarDeclaration()) { return; } } if (d.protection.kind == Prot.Kind.private_ || sc.protection.kind == Prot.Kind.private_) return; } if (!com) return; emit(sc, d, com); } override void visit(AggregateDeclaration ad) { //printf("AggregateDeclaration::emitComment() '%s'\n", ad.toChars()); const(char)* com = ad.comment; if (TemplateDeclaration td = getEponymousParent(ad)) { if (isDitto(td.comment)) com = td.comment; else com = Lexer.combineComments(td.comment, com, true); } else { if (ad.prot().kind == Prot.Kind.private_ || sc.protection.kind == Prot.Kind.private_) return; if (!ad.comment) return; } if (!com) return; emit(sc, ad, com); } override void visit(TemplateDeclaration td) { //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td.toChars(), td.kind()); if (td.prot().kind == Prot.Kind.private_ || sc.protection.kind == Prot.Kind.private_) return; if (!td.comment) return; if (Dsymbol ss = getEponymousMember(td)) { ss.accept(this); return; } emit(sc, td, td.comment); } override void visit(EnumDeclaration ed) { if (ed.prot().kind == Prot.Kind.private_ || sc.protection.kind == Prot.Kind.private_) return; if (ed.isAnonymous() && ed.members) { for (size_t i = 0; i < ed.members.dim; i++) { Dsymbol s = (*ed.members)[i]; emitComment(s, buf, sc); } return; } if (!ed.comment) return; if (ed.isAnonymous()) return; emit(sc, ed, ed.comment); } override void visit(EnumMember em) { //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em.toChars(), em.comment); if (em.prot().kind == Prot.Kind.private_ || sc.protection.kind == Prot.Kind.private_) return; if (!em.comment) return; emit(sc, em, em.comment); } override void visit(AttribDeclaration ad) { //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); /* A general problem with this, * illustrated by https://issues.dlang.org/show_bug.cgi?id=2516 * is that attributes are not transmitted through to the underlying * member declarations for template bodies, because semantic analysis * is not done for template declaration bodies * (only template instantiations). * Hence, Ddoc omits attributes from template members. */ Dsymbols* d = ad.include(null); if (d) { for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; //printf("AttribDeclaration::emitComment %s\n", s.toChars()); emitComment(s, buf, sc); } } } override void visit(ProtDeclaration pd) { if (pd.decl) { Scope* scx = sc; sc = sc.copy(); sc.protection = pd.protection; visit(cast(AttribDeclaration)pd); scx.lastdc = sc.lastdc; sc = sc.pop(); } } override void visit(ConditionalDeclaration cd) { //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); if (cd.condition.inc) { visit(cast(AttribDeclaration)cd); return; } /* If generating doc comment, be careful because if we're inside * a template, then include(null) will fail. */ Dsymbols* d = cd.decl ? cd.decl : cd.elsedecl; for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; emitComment(s, buf, sc); } } } scope EmitComment v = new EmitComment(buf, sc); if (!s) v.emit(sc, null, null); else s.accept(v); } private void toDocBuffer(Dsymbol s, OutBuffer* buf, Scope* sc) { extern (C++) final class ToDocBuffer : Visitor { alias visit = Visitor.visit; public: OutBuffer* buf; Scope* sc; extern (D) this(OutBuffer* buf, Scope* sc) { this.buf = buf; this.sc = sc; } override void visit(Dsymbol s) { //printf("Dsymbol::toDocbuffer() %s\n", s.toChars()); HdrGenState hgs; hgs.ddoc = true; .toCBuffer(s, buf, &hgs); } void prefix(Dsymbol s) { if (s.isDeprecated()) buf.writestring("deprecated "); if (Declaration d = s.isDeclaration()) { emitProtection(buf, d.protection); if (d.isStatic()) buf.writestring("static "); else if (d.isFinal()) buf.writestring("final "); else if (d.isAbstract()) buf.writestring("abstract "); if (d.isFuncDeclaration()) // functionToBufferFull handles this return; if (d.isImmutable()) buf.writestring("immutable "); if (d.storage_class & STC.shared_) buf.writestring("shared "); if (d.isWild()) buf.writestring("inout "); if (d.isConst()) buf.writestring("const "); if (d.isSynchronized()) buf.writestring("synchronized "); if (d.storage_class & STC.manifest) buf.writestring("enum "); // Add "auto" for the untyped variable in template members if (!d.type && d.isVarDeclaration() && !d.isImmutable() && !(d.storage_class & STC.shared_) && !d.isWild() && !d.isConst() && !d.isSynchronized()) { buf.writestring("auto "); } } } override void visit(Declaration d) { if (!d.ident) return; TemplateDeclaration td = getEponymousParent(d); //printf("Declaration::toDocbuffer() %s, originalType = %s, td = %s\n", d.toChars(), d.originalType ? d.originalType.toChars() : "--", td ? td.toChars() : "--"); HdrGenState hgs; hgs.ddoc = true; if (d.isDeprecated()) buf.writestring("$(DEPRECATED "); prefix(d); if (d.type) { Type origType = d.originalType ? d.originalType : d.type; if (origType.ty == Tfunction) { functionToBufferFull(cast(TypeFunction)origType, buf, d.ident, &hgs, td); } else .toCBuffer(origType, buf, d.ident, &hgs); } else buf.writestring(d.ident.toChars()); if (d.isVarDeclaration() && td) { buf.writeByte('('); if (td.origParameters && td.origParameters.dim) { for (size_t i = 0; i < td.origParameters.dim; i++) { if (i) buf.writestring(", "); toCBuffer((*td.origParameters)[i], buf, &hgs); } } buf.writeByte(')'); } // emit constraints if declaration is a templated declaration if (td && td.constraint) { bool noFuncDecl = td.isFuncDeclaration() is null; if (noFuncDecl) { buf.writestring("$(DDOC_CONSTRAINT "); } .toCBuffer(td.constraint, buf, &hgs); if (noFuncDecl) { buf.writestring(")"); } } if (d.isDeprecated()) buf.writestring(")"); buf.writestring(";\n"); } override void visit(AliasDeclaration ad) { //printf("AliasDeclaration::toDocbuffer() %s\n", ad.toChars()); if (!ad.ident) return; if (ad.isDeprecated()) buf.writestring("deprecated "); emitProtection(buf, ad.protection); buf.printf("alias %s = ", ad.toChars()); if (Dsymbol s = ad.aliassym) // ident alias { prettyPrintDsymbol(s, ad.parent); } else if (Type type = ad.getType()) // type alias { if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum) { if (Dsymbol s = type.toDsymbol(null)) // elaborate type prettyPrintDsymbol(s, ad.parent); else buf.writestring(type.toChars()); } else { // simple type buf.writestring(type.toChars()); } } buf.writestring(";\n"); } void parentToBuffer(Dsymbol s) { if (s && !s.isPackage() && !s.isModule()) { parentToBuffer(s.parent); buf.writestring(s.toChars()); buf.writestring("."); } } static bool inSameModule(Dsymbol s, Dsymbol p) { for (; s; s = s.parent) { if (s.isModule()) break; } for (; p; p = p.parent) { if (p.isModule()) break; } return s == p; } void prettyPrintDsymbol(Dsymbol s, Dsymbol parent) { if (s.parent && (s.parent == parent)) // in current scope -> naked name { buf.writestring(s.toChars()); } else if (!inSameModule(s, parent)) // in another module -> full name { buf.writestring(s.toPrettyChars()); } else // nested in a type in this module -> full name w/o module name { // if alias is nested in a user-type use module-scope lookup if (!parent.isModule() && !parent.isPackage()) buf.writestring("."); parentToBuffer(s.parent); buf.writestring(s.toChars()); } } override void visit(AggregateDeclaration ad) { if (!ad.ident) return; version (none) { emitProtection(buf, ad.protection); } buf.printf("%s %s", ad.kind(), ad.toChars()); buf.writestring(";\n"); } override void visit(StructDeclaration sd) { //printf("StructDeclaration::toDocbuffer() %s\n", sd.toChars()); if (!sd.ident) return; version (none) { emitProtection(buf, sd.protection); } if (TemplateDeclaration td = getEponymousParent(sd)) { toDocBuffer(td, buf, sc); } else { buf.printf("%s %s", sd.kind(), sd.toChars()); } buf.writestring(";\n"); } override void visit(ClassDeclaration cd) { //printf("ClassDeclaration::toDocbuffer() %s\n", cd.toChars()); if (!cd.ident) return; version (none) { emitProtection(buf, cd.protection); } if (TemplateDeclaration td = getEponymousParent(cd)) { toDocBuffer(td, buf, sc); } else { if (!cd.isInterfaceDeclaration() && cd.isAbstract()) buf.writestring("abstract "); buf.printf("%s %s", cd.kind(), cd.toChars()); } int any = 0; for (size_t i = 0; i < cd.baseclasses.dim; i++) { BaseClass* bc = (*cd.baseclasses)[i]; if (bc.sym && bc.sym.ident == Id.Object) continue; if (any) buf.writestring(", "); else { buf.writestring(": "); any = 1; } emitProtection(buf, Prot(Prot.Kind.public_)); if (bc.sym) { buf.printf("$(DDOC_PSUPER_SYMBOL %s)", bc.sym.toPrettyChars()); } else { HdrGenState hgs; .toCBuffer(bc.type, buf, null, &hgs); } } buf.writestring(";\n"); } override void visit(EnumDeclaration ed) { if (!ed.ident) return; buf.printf("%s %s", ed.kind(), ed.toChars()); if (ed.memtype) { buf.writestring(": $(DDOC_ENUM_BASETYPE "); HdrGenState hgs; .toCBuffer(ed.memtype, buf, null, &hgs); buf.writestring(")"); } buf.writestring(";\n"); } override void visit(EnumMember em) { if (!em.ident) return; buf.writestring(em.toChars()); } } scope ToDocBuffer v = new ToDocBuffer(buf, sc); s.accept(v); } /*********************************************************** */ struct DocComment { Sections sections; // Section*[] Section summary; Section copyright; Section macros; Macro** pmacrotable; Escape** pescapetable; Dsymbols a; static DocComment* parse(Dsymbol s, const(char)* comment) { //printf("parse(%s): '%s'\n", s.toChars(), comment); auto dc = new DocComment(); dc.a.push(s); if (!comment) return dc; dc.parseSections(comment); for (size_t i = 0; i < dc.sections.dim; i++) { Section sec = dc.sections[i]; if (iequals("copyright", sec.name[0 .. sec.namelen])) { dc.copyright = sec; } if (iequals("macros", sec.name[0 .. sec.namelen])) { dc.macros = sec; } } return dc; } /************************************************ * Parse macros out of Macros: section. * Macros are of the form: * name1 = value1 * * name2 = value2 */ static void parseMacros(Escape** pescapetable, Macro** pmacrotable, const(char)* m, size_t mlen) { const(char)* p = m; size_t len = mlen; const(char)* pend = p + len; const(char)* tempstart = null; size_t templen = 0; const(char)* namestart = null; size_t namelen = 0; // !=0 if line continuation const(char)* textstart = null; size_t textlen = 0; while (p < pend) { // Skip to start of macro while (1) { if (p >= pend) goto Ldone; switch (*p) { case ' ': case '\t': p++; continue; case '\r': case '\n': p++; goto Lcont; default: if (isIdStart(p)) break; if (namelen) goto Ltext; // continuation of prev macro goto Lskipline; } break; } tempstart = p; while (1) { if (p >= pend) goto Ldone; if (!isIdTail(p)) break; p += utfStride(p); } templen = p - tempstart; while (1) { if (p >= pend) goto Ldone; if (!(*p == ' ' || *p == '\t')) break; p++; } if (*p != '=') { if (namelen) goto Ltext; // continuation of prev macro goto Lskipline; } p++; if (p >= pend) goto Ldone; if (namelen) { // Output existing macro L1: //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); if (iequals("ESCAPES", namestart[0 .. namelen])) parseEscapes(pescapetable, textstart, textlen); else Macro.define(pmacrotable, namestart[0 ..namelen], textstart[0 .. textlen]); namelen = 0; if (p >= pend) break; } namestart = tempstart; namelen = templen; while (p < pend && (*p == ' ' || *p == '\t')) p++; textstart = p; Ltext: while (p < pend && *p != '\r' && *p != '\n') p++; textlen = p - textstart; p++; //printf("p = %p, pend = %p\n", p, pend); Lcont: continue; Lskipline: // Ignore this line while (p < pend && *p != '\r' && *p != '\n') p++; } Ldone: if (namelen) goto L1; // write out last one } /************************************** * Parse escapes of the form: * /c/string/ * where c is a single character. * Multiple escapes can be separated * by whitespace and/or commas. */ static void parseEscapes(Escape** pescapetable, const(char)* textstart, size_t textlen) { Escape* escapetable = *pescapetable; if (!escapetable) { escapetable = new Escape(); memset(escapetable, 0, Escape.sizeof); *pescapetable = escapetable; } //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable); const(char)* p = textstart; const(char)* pend = p + textlen; while (1) { while (1) { if (p + 4 >= pend) return; if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ',')) break; p++; } if (p[0] != '/' || p[2] != '/') return; char c = p[1]; p += 3; const(char)* start = p; while (1) { if (p >= pend) return; if (*p == '/') break; p++; } size_t len = p - start; char* s = cast(char*)memcpy(mem.xmalloc(len + 1), start, len); s[len] = 0; escapetable.strings[c] = s[0 .. len]; //printf("\t%c = '%s'\n", c, s); p++; } } /***************************************** * Parse next paragraph out of *pcomment. * Update *pcomment to point past paragraph. * Returns NULL if no more paragraphs. * If paragraph ends in 'identifier:', * then (*pcomment)[0 .. idlen] is the identifier. */ void parseSections(const(char)* comment) { const(char)* p; const(char)* pstart; const(char)* pend; const(char)* idstart = null; // dead-store to prevent spurious warning size_t idlen; const(char)* name = null; size_t namelen = 0; //printf("parseSections('%s')\n", comment); p = comment; while (*p) { const(char)* pstart0 = p; p = skipwhitespace(p); pstart = p; pend = p; /* Find end of section, which is ended by one of: * 'identifier:' (but not inside a code section) * '\0' */ idlen = 0; int inCode = 0; while (1) { // Check for start/end of a code section if (*p == '-') { if (!inCode) { // restore leading indentation while (pstart0 < pstart && isIndentWS(pstart - 1)) --pstart; } int numdash = 0; while (*p == '-') { ++numdash; p++; } // BUG: handle UTF PS and LS too if ((!*p || *p == '\r' || *p == '\n') && numdash >= 3) inCode ^= 1; pend = p; } if (!inCode && isIdStart(p)) { const(char)* q = p + utfStride(p); while (isIdTail(q)) q += utfStride(q); // Detected tag ends it if (*q == ':' && isupper(*p) && (isspace(q[1]) || q[1] == 0)) { idlen = q - p; idstart = p; for (pend = p; pend > pstart; pend--) { if (pend[-1] == '\n') break; } p = q + 1; break; } } while (1) { if (!*p) goto L1; if (*p == '\n') { p++; if (*p == '\n' && !summary && !namelen && !inCode) { pend = p; p++; goto L1; } break; } p++; pend = p; } p = skipwhitespace(p); } L1: if (namelen || pstart < pend) { Section s; if (iequals("Params", name[0 .. namelen])) s = new ParamSection(); else if (iequals("Macros", name[0 .. namelen])) s = new MacroSection(); else s = new Section(); s.name = name; s.namelen = namelen; s._body = pstart; s.bodylen = pend - pstart; s.nooutput = 0; //printf("Section: '%.*s' = '%.*s'\n", s.namelen, s.name, s.bodylen, s.body); sections.push(s); if (!summary && !namelen) summary = s; } if (idlen) { name = idstart; namelen = idlen; } else { name = null; namelen = 0; if (!*p) break; } } } void writeSections(Scope* sc, Dsymbols* a, OutBuffer* buf) { assert(a.dim); //printf("DocComment::writeSections()\n"); Loc loc = (*a)[0].loc; if (Module m = (*a)[0].isModule()) { if (m.md) loc = m.md.loc; } size_t offset1 = buf.offset; buf.writestring("$(DDOC_SECTIONS "); size_t offset2 = buf.offset; for (size_t i = 0; i < sections.dim; i++) { Section sec = sections[i]; if (sec.nooutput) continue; //printf("Section: '%.*s' = '%.*s'\n", sec.namelen, sec.name, sec.bodylen, sec.body); if (!sec.namelen && i == 0) { buf.writestring("$(DDOC_SUMMARY "); size_t o = buf.offset; buf.write(sec._body, sec.bodylen); escapeStrayParenthesis(loc, buf, o); highlightText(sc, a, buf, o); buf.writestring(")"); } else sec.write(loc, &this, sc, a, buf); } for (size_t i = 0; i < a.dim; i++) { Dsymbol s = (*a)[i]; if (Dsymbol td = getEponymousParent(s)) s = td; for (UnitTestDeclaration utd = s.ddocUnittest; utd; utd = utd.ddocUnittest) { if (utd.protection.kind == Prot.Kind.private_ || !utd.comment || !utd.fbody) continue; // Strip whitespaces to avoid showing empty summary const(char)* c = utd.comment; while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r') ++c; buf.writestring("$(DDOC_EXAMPLES "); size_t o = buf.offset; buf.writestring(cast(char*)c); if (utd.codedoc) { auto codedoc = utd.codedoc.stripLeadingNewlines; size_t n = getCodeIndent(codedoc); while (n--) buf.writeByte(' '); buf.writestring("----\n"); buf.writestring(codedoc); buf.writestring("----\n"); highlightText(sc, a, buf, o); } buf.writestring(")"); } } if (buf.offset == offset2) { /* Didn't write out any sections, so back out last write */ buf.offset = offset1; buf.writestring("\n"); } else buf.writestring(")"); } } /***************************************** * Return true if comment consists entirely of "ditto". */ private bool isDitto(const(char)* comment) { if (comment) { const(char)* p = skipwhitespace(comment); if (Port.memicmp(p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) return true; } return false; } /********************************************** * Skip white space. */ private const(char)* skipwhitespace(const(char)* p) { return skipwhitespace(p.toDString).ptr; } /// Ditto private const(char)[] skipwhitespace(const(char)[] p) { foreach (idx, char c; p) { switch (c) { case ' ': case '\t': case '\n': continue; default: return p[idx .. $]; } } return p[$ .. $]; } /************************************************ * Scan forward to one of: * start of identifier * beginning of next line * end of buf */ size_t skiptoident(OutBuffer* buf, size_t i) { const slice = buf.peekSlice(); while (i < slice.length) { dchar c; size_t oi = i; if (utf_decodeChar(slice.ptr, slice.length, i, c)) { /* Ignore UTF errors, but still consume input */ break; } if (c >= 0x80) { if (!isUniAlpha(c)) continue; } else if (!(isalpha(c) || c == '_' || c == '\n')) continue; i = oi; break; } return i; } /************************************************ * Scan forward past end of identifier. */ private size_t skippastident(OutBuffer* buf, size_t i) { const slice = buf.peekSlice(); while (i < slice.length) { dchar c; size_t oi = i; if (utf_decodeChar(slice.ptr, slice.length, i, c)) { /* Ignore UTF errors, but still consume input */ break; } if (c >= 0x80) { if (isUniAlpha(c)) continue; } else if (isalnum(c) || c == '_') continue; i = oi; break; } return i; } /************************************************ * Scan forward past URL starting at i. * We don't want to highlight parts of a URL. * Returns: * i if not a URL * index just past it if it is a URL */ private size_t skippastURL(OutBuffer* buf, size_t i) { const slice = buf.peekSlice()[i .. $]; size_t j; bool sawdot = false; if (slice.length > 7 && Port.memicmp(slice.ptr, "http://", 7) == 0) { j = 7; } else if (slice.length > 8 && Port.memicmp(slice.ptr, "https://", 8) == 0) { j = 8; } else goto Lno; for (; j < slice.length; j++) { const c = slice[j]; if (isalnum(c)) continue; if (c == '-' || c == '_' || c == '?' || c == '=' || c == '%' || c == '&' || c == '/' || c == '+' || c == '#' || c == '~') continue; if (c == '.') { sawdot = true; continue; } break; } if (sawdot) return i + j; Lno: return i; } /**************************************************** */ private bool isIdentifier(Dsymbols* a, const(char)* p, size_t len) { foreach (member; *a) { if (p[0 .. len] == member.ident.toString()) return true; } return false; } /**************************************************** */ private bool isKeyword(const(char)* p, size_t len) { immutable string[3] table = ["true", "false", "null"]; foreach (s; table) { if (p[0 .. len] == s) return true; } return false; } /**************************************************** */ private TypeFunction isTypeFunction(Dsymbol s) { FuncDeclaration f = s.isFuncDeclaration(); /* f.type may be NULL for template members. */ if (f && f.type) { Type t = f.originalType ? f.originalType : f.type; if (t.ty == Tfunction) return cast(TypeFunction)t; } return null; } /**************************************************** */ private Parameter isFunctionParameter(Dsymbol s, const(char)* p, size_t len) { TypeFunction tf = isTypeFunction(s); if (tf && tf.parameters) { foreach (fparam; *tf.parameters) { if (fparam.ident && p[0 .. len] == fparam.ident.toString()) { return fparam; } } } return null; } /**************************************************** */ private Parameter isFunctionParameter(Dsymbols* a, const(char)* p, size_t len) { for (size_t i = 0; i < a.dim; i++) { Parameter fparam = isFunctionParameter((*a)[i], p, len); if (fparam) { return fparam; } } return null; } /**************************************************** */ private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char) *p, size_t len) { for (size_t i = 0; i < a.dim; i++) { TemplateDeclaration td = (*a)[i].isTemplateDeclaration(); if (td && td.onemember) { /* Case 1: we refer to a template declaration inside the template /// ...ddoc... template case1(T) { void case1(R)() {} } */ td = td.onemember.isTemplateDeclaration(); } if (!td) { /* Case 2: we're an alias to a template declaration /// ...ddoc... alias case2 = case1!int; */ AliasDeclaration ad = (*a)[i].isAliasDeclaration(); if (ad && ad.aliassym) { td = ad.aliassym.isTemplateDeclaration(); } } while (td) { Dsymbol sym = getEponymousMember(td); if (sym) { Parameter fparam = isFunctionParameter(sym, p, len); if (fparam) { return fparam; } } td = td.overnext; } } return null; } /**************************************************** */ private TemplateParameter isTemplateParameter(Dsymbols* a, const(char)* p, size_t len) { for (size_t i = 0; i < a.dim; i++) { TemplateDeclaration td = (*a)[i].isTemplateDeclaration(); // Check for the parent, if the current symbol is not a template declaration. if (!td) td = getEponymousParent((*a)[i]); if (td && td.origParameters) { foreach (tp; *td.origParameters) { if (tp.ident && p[0 .. len] == tp.ident.toString()) { return tp; } } } } return null; } /**************************************************** * Return true if str is a reserved symbol name * that starts with a double underscore. */ private bool isReservedName(const(char)[] str) { immutable string[] table = [ "__ctor", "__dtor", "__postblit", "__invariant", "__unitTest", "__require", "__ensure", "__dollar", "__ctfe", "__withSym", "__result", "__returnLabel", "__vptr", "__monitor", "__gate", "__xopEquals", "__xopCmp", "__LINE__", "__FILE__", "__MODULE__", "__FUNCTION__", "__PRETTY_FUNCTION__", "__DATE__", "__TIME__", "__TIMESTAMP__", "__VENDOR__", "__VERSION__", "__EOF__", "__CXXLIB__", "__LOCAL_SIZE", "___tls_get_addr", "__entrypoint", ]; foreach (s; table) { if (str == s) return true; } return false; } /************************************************** * Highlight text section. */ private void highlightText(Scope* sc, Dsymbols* a, OutBuffer* buf, size_t offset) { Dsymbol s = a.dim ? (*a)[0] : null; // test //printf("highlightText()\n"); int leadingBlank = 1; int inCode = 0; int inBacktick = 0; //int inComment = 0; // in comment int inMacro = 0; size_t iCodeStart = 0; // start of code section size_t codeIndent = 0; size_t iLineStart = offset; for (size_t i = offset; i < buf.offset; i++) { char c = buf.data[i]; Lcont: switch (c) { case ' ': case '\t': break; case '\n': if (inBacktick) { // `inline code` is only valid if contained on a single line // otherwise, the backticks should be output literally. // // This lets things like `output from the linker' display // unmolested while keeping the feature consistent with GitHub. inBacktick = false; inCode = false; // the backtick also assumes we're in code // Nothing else is necessary since the DDOC_BACKQUOTED macro is // inserted lazily at the close quote, meaning the rest of the // text is already OK. } if (!inCode && i == iLineStart && i + 1 < buf.offset) // if "\n\n" { i = buf.insert(i, "$(DDOC_BLANKLINE)"); } leadingBlank = 1; iLineStart = i + 1; break; case '<': { leadingBlank = 0; if (inCode) break; const slice = buf.peekSlice(); auto p = &slice[i]; const se = sc._module.escapetable.escapeChar('<'); if (se == "<") { // Generating HTML // Skip over comments if (p[1] == '!' && p[2] == '-' && p[3] == '-') { size_t j = i + 4; p += 4; while (1) { if (j == slice.length) goto L1; if (p[0] == '-' && p[1] == '-' && p[2] == '>') { i = j + 2; // place on closing '>' break; } j++; p++; } break; } // Skip over HTML tag if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) { size_t j = i + 2; p += 2; while (1) { if (j == slice.length) break; if (p[0] == '>') { i = j; // place on closing '>' break; } j++; p++; } break; } } L1: // Replace '<' with '<' character entity if (se.length) { buf.remove(i, 1); i = buf.insert(i, se); i--; // point to ';' } break; } case '>': { leadingBlank = 0; if (inCode) break; // Replace '>' with '>' character entity const se = sc._module.escapetable.escapeChar('>'); if (se.length) { buf.remove(i, 1); i = buf.insert(i, se); i--; // point to ';' } break; } case '&': { leadingBlank = 0; if (inCode) break; char* p = cast(char*)&buf.data[i]; if (p[1] == '#' || isalpha(p[1])) break; // already a character entity // Replace '&' with '&' character entity const se = sc._module.escapetable.escapeChar('&'); if (se) { buf.remove(i, 1); i = buf.insert(i, se); i--; // point to ';' } break; } case '`': { if (inBacktick) { inBacktick = 0; inCode = 0; OutBuffer codebuf; codebuf.write(buf.peekSlice().ptr + iCodeStart + 1, i - (iCodeStart + 1)); // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL highlightCode(sc, a, &codebuf, 0); escapeStrayParenthesis(s ? s.loc : Loc.initial, &codebuf, 0); buf.remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current ` immutable pre = "$(DDOC_BACKQUOTED "; i = buf.insert(iCodeStart, pre); i = buf.insert(i, codebuf.peekSlice()); i = buf.insert(i, ")"); i--; // point to the ending ) so when the for loop does i++, it will see the next character break; } if (inCode) break; inCode = 1; inBacktick = 1; codeIndent = 0; // inline code is not indented // All we do here is set the code flags and record // the location. The macro will be inserted lazily // so we can easily cancel the inBacktick if we come // across a newline character. iCodeStart = i; break; } case '-': /* A line beginning with --- delimits a code section. * inCode tells us if it is start or end of a code section. */ if (leadingBlank) { size_t istart = i; size_t eollen = 0; leadingBlank = 0; while (1) { ++i; if (i >= buf.offset) break; c = buf.data[i]; if (c == '\n') { eollen = 1; break; } if (c == '\r') { eollen = 1; if (i + 1 >= buf.offset) break; if (buf.data[i + 1] == '\n') { eollen = 2; break; } } // BUG: handle UTF PS and LS too if (c != '-') goto Lcont; } if (i - istart < 3) goto Lcont; // We have the start/end of a code section // Remove the entire --- line, including blanks and \n buf.remove(iLineStart, i - iLineStart + eollen); i = iLineStart; if (inCode && (i <= iCodeStart)) { // Empty code section, just remove it completely. inCode = 0; break; } if (inCode) { inCode = 0; // The code section is from iCodeStart to i OutBuffer codebuf; codebuf.write(buf.data + iCodeStart, i - iCodeStart); codebuf.writeByte(0); // Remove leading indentations from all lines bool lineStart = true; char* endp = cast(char*)codebuf.data + codebuf.offset; for (char* p = cast(char*)codebuf.data; p < endp;) { if (lineStart) { size_t j = codeIndent; char* q = p; while (j-- > 0 && q < endp && isIndentWS(q)) ++q; codebuf.remove(p - cast(char*)codebuf.data, q - p); assert(cast(char*)codebuf.data <= p); assert(p < cast(char*)codebuf.data + codebuf.offset); lineStart = false; endp = cast(char*)codebuf.data + codebuf.offset; // update continue; } if (*p == '\n') lineStart = true; ++p; } highlightCode2(sc, a, &codebuf, 0); escapeStrayParenthesis(s ? s.loc : Loc.initial, &codebuf, 0); buf.remove(iCodeStart, i - iCodeStart); i = buf.insert(iCodeStart, codebuf.peekSlice()); i = buf.insert(i, ")\n"); i -= 2; // in next loop, c should be '\n' } else { __gshared const(char)* d_code = "$(D_CODE "; inCode = 1; codeIndent = istart - iLineStart; // save indent count i = buf.insert(i, d_code, strlen(d_code)); iCodeStart = i; i--; // place i on > leadingBlank = true; } } break; case '$': { /* Look for the start of a macro, '$(Identifier' */ leadingBlank = 0; if (inCode || inBacktick) break; const slice = buf.peekSlice(); auto p = &slice[i]; if (p[1] == '(' && isIdStart(&p[2])) ++inMacro; break; } case ')': { /* End of macro */ leadingBlank = 0; if (inCode || inBacktick) break; if (inMacro) --inMacro; break; } default: leadingBlank = 0; if (sc._module.isDocFile || inCode) break; const start = cast(char*)buf.data + i; if (isIdStart(start)) { size_t j = skippastident(buf, i); if (i < j) { size_t k = skippastURL(buf, i); if (i < k) { /* The URL is buf[i..k] */ if (inMacro) /* Leave alone if already in a macro */ i = k - 1; else { /* Replace URL with '$(DDOC_LINK_AUTODETECT URL)' */ i = buf.bracket(i, "$(DDOC_LINK_AUTODETECT ", k, ")") - 1; } break; } } else break; size_t len = j - i; // leading '_' means no highlight unless it's a reserved symbol name if (c == '_' && (i == 0 || !isdigit(*(start - 1))) && (i == buf.offset - 1 || !isReservedName(start[0 .. len]))) { buf.remove(i, 1); i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL_SUPPRESS ", j - 1, ")") - 1; break; } if (isIdentifier(a, start, len)) { i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL ", j, ")") - 1; break; } if (isKeyword(start, len)) { i = buf.bracket(i, "$(DDOC_AUTO_KEYWORD ", j, ")") - 1; break; } if (isFunctionParameter(a, start, len)) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); i = buf.bracket(i, "$(DDOC_AUTO_PARAM ", j, ")") - 1; break; } i = j - 1; } break; } } if (inCode) error(s ? s.loc : Loc.initial, "unmatched `---` in DDoc comment"); } /************************************************** * Highlight code for DDOC section. */ private void highlightCode(Scope* sc, Dsymbol s, OutBuffer* buf, size_t offset) { //printf("highlightCode(s = %s '%s')\n", s.kind(), s.toChars()); OutBuffer ancbuf; emitAnchor(&ancbuf, s, sc); buf.insert(offset, ancbuf.peekSlice()); offset += ancbuf.offset; Dsymbols a; a.push(s); highlightCode(sc, &a, buf, offset); } /**************************************************** */ private void highlightCode(Scope* sc, Dsymbols* a, OutBuffer* buf, size_t offset) { //printf("highlightCode(a = '%s')\n", a.toChars()); bool resolvedTemplateParameters = false; for (size_t i = offset; i < buf.offset; i++) { char c = buf.data[i]; const se = sc._module.escapetable.escapeChar(c); if (se.length) { buf.remove(i, 1); i = buf.insert(i, se); i--; // point to ';' continue; } char* start = cast(char*)buf.data + i; if (isIdStart(start)) { size_t j = skippastident(buf, i); if (i < j) { size_t len = j - i; if (isIdentifier(a, start, len)) { i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; continue; } if (isFunctionParameter(a, start, len)) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); i = buf.bracket(i, "$(DDOC_PARAM ", j, ")") - 1; continue; } i = j - 1; } } else if (!resolvedTemplateParameters) { size_t previ = i; // hunt for template declarations: foreach (symi; 0 .. a.dim) { FuncDeclaration fd = (*a)[symi].isFuncDeclaration(); if (!fd || !fd.parent || !fd.parent.isTemplateDeclaration()) { continue; } TemplateDeclaration td = fd.parent.isTemplateDeclaration(); // build the template parameters Array!(size_t) paramLens; paramLens.reserve(td.parameters.dim); OutBuffer parametersBuf; HdrGenState hgs; parametersBuf.writeByte('('); foreach (parami; 0 .. td.parameters.dim) { TemplateParameter tp = (*td.parameters)[parami]; if (parami) parametersBuf.writestring(", "); size_t lastOffset = parametersBuf.offset; .toCBuffer(tp, ¶metersBuf, &hgs); paramLens[parami] = parametersBuf.offset - lastOffset; } parametersBuf.writeByte(')'); const templateParams = parametersBuf.peekSlice(); //printf("templateDecl: %s\ntemplateParams: %s\nstart: %s\n", td.toChars(), templateParams, start); if (start[0 .. templateParams.length] == templateParams) { immutable templateParamListMacro = "$(DDOC_TEMPLATE_PARAM_LIST "; buf.bracket(i, templateParamListMacro.ptr, i + templateParams.length, ")"); // We have the parameter list. While we're here we might // as well wrap the parameters themselves as well // + 1 here to take into account the opening paren of the // template param list i += templateParamListMacro.length + 1; foreach (const len; paramLens) { i = buf.bracket(i, "$(DDOC_TEMPLATE_PARAM ", i + len, ")"); // increment two here for space + comma i += 2; } resolvedTemplateParameters = true; // reset i to be positioned back before we found the template // param list this assures that anything within the template // param list that needs to be escaped or otherwise altered // has an opportunity for that to happen outside of this context i = previ; continue; } } } } } /**************************************** */ private void highlightCode3(Scope* sc, OutBuffer* buf, const(char)* p, const(char)* pend) { for (; p < pend; p++) { const se = sc._module.escapetable.escapeChar(*p); if (se.length) buf.writestring(se); else buf.writeByte(*p); } } /************************************************** * Highlight code for CODE section. */ private void highlightCode2(Scope* sc, Dsymbols* a, OutBuffer* buf, size_t offset) { uint errorsave = global.errors; scope Lexer lex = new Lexer(null, cast(char*)buf.data, 0, buf.offset - 1, 0, 1); OutBuffer res; const(char)* lastp = cast(char*)buf.data; //printf("highlightCode2('%.*s')\n", buf.offset - 1, buf.data); res.reserve(buf.offset); while (1) { Token tok; lex.scan(&tok); highlightCode3(sc, &res, lastp, tok.ptr); const(char)* highlight = null; switch (tok.value) { case TOK.identifier: { if (!sc) break; size_t len = lex.p - tok.ptr; if (isIdentifier(a, tok.ptr, len)) { highlight = "$(D_PSYMBOL "; break; } if (isFunctionParameter(a, tok.ptr, len)) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); highlight = "$(D_PARAM "; break; } break; } case TOK.comment: highlight = "$(D_COMMENT "; break; case TOK.string_: highlight = "$(D_STRING "; break; default: if (tok.isKeyword()) highlight = "$(D_KEYWORD "; break; } if (highlight) { res.writestring(highlight); size_t o = res.offset; highlightCode3(sc, &res, tok.ptr, lex.p); if (tok.value == TOK.comment || tok.value == TOK.string_) /* https://issues.dlang.org/show_bug.cgi?id=7656 * https://issues.dlang.org/show_bug.cgi?id=7715 * https://issues.dlang.org/show_bug.cgi?id=10519 */ escapeDdocString(&res, o); res.writeByte(')'); } else highlightCode3(sc, &res, tok.ptr, lex.p); if (tok.value == TOK.endOfFile) break; lastp = lex.p; } buf.setsize(offset); buf.write(&res); global.errors = errorsave; } /**************************************** * Determine if p points to the start of a "..." parameter identifier. */ private bool isCVariadicArg(const(char)[] p) { return p.length >= 3 && p[0 .. 3] == "..."; } /**************************************** * Determine if p points to the start of an identifier. */ bool isIdStart(const(char)* p) { dchar c = *p; if (isalpha(c) || c == '_') return true; if (c >= 0x80) { size_t i = 0; if (utf_decodeChar(p, 4, i, c)) return false; // ignore errors if (isUniAlpha(c)) return true; } return false; } /**************************************** * Determine if p points to the rest of an identifier. */ bool isIdTail(const(char)* p) { dchar c = *p; if (isalnum(c) || c == '_') return true; if (c >= 0x80) { size_t i = 0; if (utf_decodeChar(p, 4, i, c)) return false; // ignore errors if (isUniAlpha(c)) return true; } return false; } /**************************************** * Determine if p points to the indentation space. */ private bool isIndentWS(const(char)* p) { return (*p == ' ') || (*p == '\t'); } /***************************************** * Return number of bytes in UTF character. */ int utfStride(const(char)* p) { dchar c = *p; if (c < 0x80) return 1; size_t i = 0; utf_decodeChar(p, 4, i, c); // ignore errors, but still consume input return cast(int)i; } private inout(char)* stripLeadingNewlines(inout(char)* s) { while (s && *s == '\n' || *s == '\r') s++; return s; } ================================================ FILE: gcc/d/dmd/doc.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/doc.h */ #pragma once class Module; void gendocfile(Module *m); ================================================ FILE: gcc/d/dmd/dscope.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dscope.d, _dscope.d) * Documentation: https://dlang.org/phobos/dmd_dscope.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d */ module dmd.dscope; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.attrib; import dmd.ctorflow; import dmd.dclass; import dmd.declaration; import dmd.dmodule; import dmd.doc; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.speller; import dmd.statement; import dmd.tokens; //version=LOGSEARCH; // Flags that would not be inherited beyond scope nesting enum SCOPE { ctor = 0x0001, /// constructor type noaccesscheck = 0x0002, /// don't do access checks condition = 0x0004, /// inside static if/assert condition debug_ = 0x0008, /// inside debug conditional constraint = 0x0010, /// inside template constraint invariant_ = 0x0020, /// inside invariant code require = 0x0040, /// inside in contract code ensure = 0x0060, /// inside out contract code contract = 0x0060, /// [mask] we're inside contract code ctfe = 0x0080, /// inside a ctfe-only expression compile = 0x0100, /// inside __traits(compile) ignoresymbolvisibility = 0x0200, /// ignore symbol visibility /// https://issues.dlang.org/show_bug.cgi?id=15907 onlysafeaccess = 0x0400, /// unsafe access is not allowed for @safe code free = 0x8000, /// is on free list fullinst = 0x10000, /// fully instantiate templates } // Flags that are carried along with a scope push() enum SCOPEpush = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | SCOPE.noaccesscheck | SCOPE.onlysafeaccess | SCOPE.ignoresymbolvisibility; struct Scope { Scope* enclosing; /// enclosing Scope Module _module; /// Root module ScopeDsymbol scopesym; /// current symbol FuncDeclaration func; /// function we are in Dsymbol parent; /// parent to use LabelStatement slabel; /// enclosing labelled statement SwitchStatement sw; /// enclosing switch statement TryFinallyStatement tf; /// enclosing try finally statement OnScopeStatement os; /// enclosing scope(xxx) statement Statement sbreak; /// enclosing statement that supports "break" Statement scontinue; /// enclosing statement that supports "continue" ForeachStatement fes; /// if nested function for ForeachStatement, this is it Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ bool inunion; /// true if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope). * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint). * If minst && tinst, it's in instantiated code scope without speculation. * If !minst && tinst, it's in instantiated code scope with speculation. */ Module minst; /// root module where the instantiated templates should belong to TemplateInstance tinst; /// enclosing template instance CtorFlow ctorflow; /// flow analysis for constructors /// alignment for struct members AlignDeclaration aligndecl; /// linkage for external functions LINK linkage = LINK.d; /// mangle type CPPMANGLE cppmangle = CPPMANGLE.def; /// inlining strategy for functions PINLINE inlining = PINLINE.default_; /// protection for class members Prot protection = Prot(Prot.Kind.public_); int explicitProtection; /// set if in an explicit protection attribute StorageClass stc; /// storage class DeprecatedDeclaration depdecl; /// customized deprecation message uint flags; // user defined attributes UserAttributeDeclaration userAttribDecl; DocComment* lastdc; /// documentation comment for last symbol at this scope uint[void*] anchorCounts; /// lookup duplicate anchor name count Identifier prevAnchor; /// qualified symbol name of last doc anchor extern (D) __gshared Scope* freelist; extern (D) static Scope* alloc() { if (freelist) { Scope* s = freelist; freelist = s.enclosing; //printf("freelist %p\n", s); assert(s.flags & SCOPE.free); s.flags &= ~SCOPE.free; return s; } return new Scope(); } extern (D) static Scope* createGlobal(Module _module) { Scope* sc = Scope.alloc(); *sc = Scope.init; sc._module = _module; sc.minst = _module; sc.scopesym = new ScopeDsymbol(); sc.scopesym.symtab = new DsymbolTable(); // Add top level package as member of this global scope Dsymbol m = _module; while (m.parent) m = m.parent; m.addMember(null, sc.scopesym); m.parent = null; // got changed by addMember() // Create the module scope underneath the global scope sc = sc.push(_module); sc.parent = _module; return sc; } extern (C++) Scope* copy() { Scope* sc = Scope.alloc(); *sc = this; /* https://issues.dlang.org/show_bug.cgi?id=11777 * The copied scope should not inherit fieldinit. */ sc.ctorflow.fieldinit = null; return sc; } extern (C++) Scope* push() { Scope* s = copy(); //printf("Scope::push(this = %p) new = %p\n", this, s); assert(!(flags & SCOPE.free)); s.scopesym = null; s.enclosing = &this; debug { if (enclosing) assert(!(enclosing.flags & SCOPE.free)); if (s == enclosing) { printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing); } assert(s != enclosing); } s.slabel = null; s.nofree = false; s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup; s.flags = (flags & SCOPEpush); s.lastdc = null; assert(&this != s); return s; } extern (C++) Scope* push(ScopeDsymbol ss) { //printf("Scope::push(%s)\n", ss.toChars()); Scope* s = push(); s.scopesym = ss; return s; } extern (C++) Scope* pop() { //printf("Scope::pop() %p nofree = %d\n", this, nofree); if (enclosing) enclosing.ctorflow.OR(ctorflow); ctorflow.freeFieldinit(); Scope* enc = enclosing; if (!nofree) { enclosing = freelist; freelist = &this; flags |= SCOPE.free; } return enc; } /************************* * Similar to pop(), but the results in `this` are not folded * into `enclosing`. */ extern (D) void detach() { ctorflow.freeFieldinit(); enclosing = null; pop(); } extern (C++) Scope* startCTFE() { Scope* sc = this.push(); sc.flags = this.flags | SCOPE.ctfe; version (none) { /* TODO: Currently this is not possible, because we need to * unspeculative some types and symbols if they are necessary for the * final executable. Consider: * * struct S(T) { * string toString() const { return "instantiated"; } * } * enum x = S!int(); * void main() { * // To call x.toString in runtime, compiler should unspeculative S!int. * assert(x.toString() == "instantiated"); * } */ // If a template is instantiated from CT evaluated expression, // compiler can elide its code generation. sc.tinst = null; sc.minst = null; } return sc; } extern (C++) Scope* endCTFE() { assert(flags & SCOPE.ctfe); return pop(); } /******************************* * Merge results of `ctorflow` into `this`. * Params: * loc = for error messages * ctorflow = flow results to merge in */ extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow) { if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper)) error(loc, "one path skips constructor"); const fies = ctorflow.fieldinit; if (this.ctorflow.fieldinit.length && fies.length) { FuncDeclaration f = func; if (fes) f = fes.func; auto ad = f.isMember2(); assert(ad); foreach (i, v; ad.fields) { bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); auto fieldInit = &this.ctorflow.fieldinit[i]; const fiesCurrent = fies[i]; if (fieldInit.loc == Loc.init) fieldInit.loc = fiesCurrent.loc; if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit) { error(loc, "one path skips field `%s`", v.toChars()); } } } } extern (C++) Module instantiatingModule() { // TODO: in speculative context, returning 'module' is correct? return minst ? minst : _module; } /************************************ * Perform unqualified name lookup by following the chain of scopes up * until found. * * Params: * loc = location to use for error messages * ident = name to look up * pscopesym = if supplied and name is found, set to scope that ident was found in * flags = modify search based on flags * * Returns: * symbol if found, null if not */ extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) { version (LOGSEARCH) { printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags); // Print scope chain for (Scope* sc = &this; sc; sc = sc.enclosing) { if (!sc.scopesym) continue; printf("\tscope %s\n", sc.scopesym.toChars()); } static void printMsg(string txt, Dsymbol s) { printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr, s.parent ? s.parent.toChars() : "", s.toChars(), s.kind()); } } // This function is called only for unqualified lookup assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); /* If ident is "start at module scope", only look at module scope */ if (ident == Id.empty) { // Look for module scope for (Scope* sc = &this; sc; sc = sc.enclosing) { assert(sc != sc.enclosing); if (!sc.scopesym) continue; if (Dsymbol s = sc.scopesym.isModule()) { //printMsg("\tfound", s); if (pscopesym) *pscopesym = sc.scopesym; return s; } } return null; } Dsymbol searchScopes(int flags) { for (Scope* sc = &this; sc; sc = sc.enclosing) { assert(sc != sc.enclosing); if (!sc.scopesym) continue; //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); if (sc.scopesym.isModule()) flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) { if (!(flags & (SearchImportsOnly | IgnoreErrors)) && ident == Id.length && sc.scopesym.isArrayScopeSymbol() && sc.enclosing && sc.enclosing.search(loc, ident, null, flags)) { warning(s.loc, "array `length` hides other `length` name in outer scope"); } //printMsg("\tfound local", s); if (pscopesym) *pscopesym = sc.scopesym; return s; } // Stop when we hit a module, but keep going if that is not just under the global scope if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing)) break; } return null; } if (this.flags & SCOPE.ignoresymbolvisibility) flags |= IgnoreSymbolVisibility; Dsymbol sold = void; if (global.params.bug10378 || global.params.check10378) { sold = searchScopes(flags | IgnoreSymbolVisibility); if (!global.params.check10378) return sold; if (ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=15825 return sold; // Search both ways } // First look in local scopes Dsymbol s = searchScopes(flags | SearchLocalsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); if (!s) { // Second look in imported modules s = searchScopes(flags | SearchImportsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); /** Still find private symbols, so that symbols that weren't access * checked by the compiler remain usable. Once the deprecation is over, * this should be moved to search_correct instead. */ if (!s && !(flags & IgnoreSymbolVisibility)) { s = searchScopes(flags | SearchLocalsOnly | IgnoreSymbolVisibility); if (!s) s = searchScopes(flags | SearchImportsOnly | IgnoreSymbolVisibility); if (s && !(flags & IgnoreErrors)) .deprecation(loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), _module.toChars()); version (LOGSEARCH) if (s) printMsg("-Scope.search() found imported private symbol", s); } } if (global.params.check10378) { alias snew = s; if (sold !is snew) deprecation10378(loc, sold, snew); if (global.params.bug10378) s = sold; } return s; } /* A helper function to show deprecation message for new name lookup rule. */ extern (D) static void deprecation10378(Loc loc, Dsymbol sold, Dsymbol snew) { // https://issues.dlang.org/show_bug.cgi?id=15857 // // The overloadset found via the new lookup rules is either // equal or a subset of the overloadset found via the old // lookup rules, so it suffices to compare the dimension to // check for equality. OverloadSet osold, osnew; if (sold && (osold = sold.isOverloadSet()) !is null && snew && (osnew = snew.isOverloadSet()) !is null && osold.a.dim == osnew.a.dim) return; OutBuffer buf; buf.writestring("local import search method found "); if (osold) buf.printf("%s `%s` (%d overloads)", sold.kind(), sold.toPrettyChars(), cast(int) osold.a.dim); else if (sold) buf.printf("%s `%s`", sold.kind(), sold.toPrettyChars()); else buf.writestring("nothing"); buf.writestring(" instead of "); if (osnew) buf.printf("%s `%s` (%d overloads)", snew.kind(), snew.toPrettyChars(), cast(int) osnew.a.dim); else if (snew) buf.printf("%s `%s`", snew.kind(), snew.toPrettyChars()); else buf.writestring("nothing"); deprecation(loc, buf.peekString()); } extern (C++) Dsymbol search_correct(Identifier ident) { if (global.gag) return null; // don't do it for speculative compiles; too time consuming /************************************************ * Given the failed search attempt, try to find * one with a close spelling. */ extern (D) void* scope_search_fp(const(char)* seed, ref int cost) { //printf("scope_search_fp('%s')\n", seed); /* If not in the lexer's string table, it certainly isn't in the symbol table. * Doing this first is a lot faster. */ size_t len = strlen(seed); if (!len) return null; Identifier id = Identifier.lookup(seed, len); if (!id) return null; Scope* sc = &this; Module.clearCache(); Dsymbol scopesym = null; Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); if (s) { for (cost = 0; sc; sc = sc.enclosing, ++cost) if (sc.scopesym == scopesym) break; if (scopesym != s.parent) { ++cost; // got to the symbol through an import if (s.prot().kind == Prot.Kind.private_) return null; } } return cast(void*)s; } return cast(Dsymbol)speller(ident.toChars(), &scope_search_fp, idchars); } /************************************ * Maybe `ident` was a C or C++ name. Check for that, * and suggest the D equivalent. * Params: * ident = unknown identifier * Returns: * D identifier string if found, null if not */ extern (D) static const(char)* search_correct_C(Identifier ident) { TOK tok; if (ident == Id.NULL) tok = TOK.null_; else if (ident == Id.TRUE) tok = TOK.true_; else if (ident == Id.FALSE) tok = TOK.false_; else if (ident == Id.unsigned) tok = TOK.uns32; else if (ident == Id.wchar_t) tok = global.params.isWindows ? TOK.wchar_ : TOK.dchar_; else return null; return Token.toChars(tok); } extern (C++) Dsymbol insert(Dsymbol s) { if (VarDeclaration vd = s.isVarDeclaration()) { if (lastVar) vd.lastVar = lastVar; lastVar = vd; } else if (WithScopeSymbol ss = s.isWithScopeSymbol()) { if (VarDeclaration vd = ss.withstate.wthis) { if (lastVar) vd.lastVar = lastVar; lastVar = vd; } return null; } for (Scope* sc = &this; sc; sc = sc.enclosing) { //printf("\tsc = %p\n", sc); if (sc.scopesym) { //printf("\t\tsc.scopesym = %p\n", sc.scopesym); if (!sc.scopesym.symtab) sc.scopesym.symtab = new DsymbolTable(); return sc.scopesym.symtabInsert(s); } } assert(0); } /******************************************** * Search enclosing scopes for ClassDeclaration. */ extern (C++) ClassDeclaration getClassScope() { for (Scope* sc = &this; sc; sc = sc.enclosing) { if (!sc.scopesym) continue; ClassDeclaration cd = sc.scopesym.isClassDeclaration(); if (cd) return cd; } return null; } /******************************************** * Search enclosing scopes for ClassDeclaration. */ extern (C++) AggregateDeclaration getStructClassScope() { for (Scope* sc = &this; sc; sc = sc.enclosing) { if (!sc.scopesym) continue; AggregateDeclaration ad = sc.scopesym.isClassDeclaration(); if (ad) return ad; ad = sc.scopesym.isStructDeclaration(); if (ad) return ad; } return null; } /******************************************* * For TemplateDeclarations, we need to remember the Scope * where it was declared. So mark the Scope as not * to be free'd. */ extern (C++) void setNoFree() { //int i = 0; //printf("Scope::setNoFree(this = %p)\n", this); for (Scope* sc = &this; sc; sc = sc.enclosing) { //printf("\tsc = %p\n", sc); sc.nofree = true; assert(!(flags & SCOPE.free)); //assert(sc != sc.enclosing); //assert(!sc.enclosing || sc != sc.enclosing.enclosing); //if (++i == 10) // assert(0); } } extern (D) this(ref Scope sc) { this._module = sc._module; this.scopesym = sc.scopesym; this.enclosing = sc.enclosing; this.parent = sc.parent; this.sw = sc.sw; this.tf = sc.tf; this.os = sc.os; this.tinst = sc.tinst; this.minst = sc.minst; this.sbreak = sc.sbreak; this.scontinue = sc.scontinue; this.fes = sc.fes; this.callsc = sc.callsc; this.aligndecl = sc.aligndecl; this.func = sc.func; this.slabel = sc.slabel; this.linkage = sc.linkage; this.cppmangle = sc.cppmangle; this.inlining = sc.inlining; this.protection = sc.protection; this.explicitProtection = sc.explicitProtection; this.stc = sc.stc; this.depdecl = sc.depdecl; this.inunion = sc.inunion; this.nofree = sc.nofree; this.inLoop = sc.inLoop; this.intypeof = sc.intypeof; this.lastVar = sc.lastVar; this.ctorflow = sc.ctorflow; this.flags = sc.flags; this.lastdc = sc.lastdc; this.anchorCounts = sc.anchorCounts; this.prevAnchor = sc.prevAnchor; this.userAttribDecl = sc.userAttribDecl; } structalign_t alignment() { if (aligndecl) return aligndecl.getAlignment(&this); else return STRUCTALIGN_DEFAULT; } /********************************** * Checks whether the current scope (or any of its parents) is deprecated. * * Returns: `true` if this or any parent scope is deprecated, `false` otherwise` */ extern(C++) bool isDeprecated() { for (Dsymbol sp = this.parent; sp; sp = sp.parent) { if (sp.isDeprecated()) return true; } for (Scope* sc2 = &this; sc2; sc2 = sc2.enclosing) { if (sc2.scopesym && sc2.scopesym.isDeprecated()) return true; // If inside a StorageClassDeclaration that is deprecated if (sc2.stc & STC.deprecated_) return true; } return false; } } ================================================ FILE: gcc/d/dmd/dstruct.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dstruct.d, _dstruct.d) * Documentation: https://dlang.org/phobos/dmd_dstruct.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dstruct.d */ module dmd.dstruct; import dmd.aggregate; import dmd.arraytypes; import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.opover; import dmd.semantic3; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.typinf; import dmd.visitor; /*************************************** * Search sd for a member function of the form: * `extern (D) string toString();` * Params: * sd = struct declaration to search * Returns: * FuncDeclaration of `toString()` if found, `null` if not */ extern (C++) FuncDeclaration search_toString(StructDeclaration sd) { Dsymbol s = search_function(sd, Id.tostring); FuncDeclaration fd = s ? s.isFuncDeclaration() : null; if (fd) { __gshared TypeFunction tftostring; if (!tftostring) { tftostring = new TypeFunction(null, Type.tstring, 0, LINK.d); tftostring = tftostring.merge().toTypeFunction(); } fd = fd.overloadExactMatch(tftostring); } return fd; } /*************************************** * Request additional semantic analysis for TypeInfo generation. * Params: * sc = context * t = type that TypeInfo is being generated for */ extern (C++) void semanticTypeInfo(Scope* sc, Type t) { extern (C++) final class FullTypeInfoVisitor : Visitor { alias visit = Visitor.visit; public: Scope* sc; override void visit(Type t) { Type tb = t.toBasetype(); if (tb != t) tb.accept(this); } override void visit(TypeNext t) { if (t.next) t.next.accept(this); } override void visit(TypeBasic t) { } override void visit(TypeVector t) { t.basetype.accept(this); } override void visit(TypeAArray t) { t.index.accept(this); visit(cast(TypeNext)t); } override void visit(TypeFunction t) { visit(cast(TypeNext)t); // Currently TypeInfo_Function doesn't store parameter types. } override void visit(TypeStruct t) { //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars()); StructDeclaration sd = t.sym; /* Step 1: create TypeInfoDeclaration */ if (!sc) // inline may request TypeInfo. { Scope scx; scx._module = sd.getModule(); getTypeInfoType(sd.loc, t, &scx); sd.requestTypeInfo = true; } else if (!sc.minst) { // don't yet have to generate TypeInfo instance if // the typeid(T) expression exists in speculative scope. } else { getTypeInfoType(sd.loc, t, sc); sd.requestTypeInfo = true; // https://issues.dlang.org/show_bug.cgi?id=15149 // if the typeid operand type comes from a // result of auto function, it may be yet speculative. unSpeculative(sc, sd); } /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later. * This should be done even if typeid(T) exists in speculative scope. * Because it may appear later in non-speculative scope. */ if (!sd.members) return; // opaque struct if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd)) return; // none of TypeInfo-specific members // If the struct is in a non-root module, run semantic3 to get // correct symbols for the member function. if (sd.semanticRun >= PASS.semantic3) { // semantic3 is already done } else if (TemplateInstance ti = sd.isInstantiated()) { if (ti.minst && !ti.minst.isRoot()) Module.addDeferredSemantic3(sd); } else { if (sd.inNonRoot()) { //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot()); Module.addDeferredSemantic3(sd); } } } override void visit(TypeClass t) { } override void visit(TypeTuple t) { if (t.arguments) { for (size_t i = 0; i < t.arguments.dim; i++) { Type tprm = (*t.arguments)[i].type; if (tprm) tprm.accept(this); } } } } if (sc) { if (!sc.func) return; if (sc.intypeof) return; if (sc.flags & (SCOPE.ctfe | SCOPE.compile)) return; } scope FullTypeInfoVisitor v = new FullTypeInfoVisitor(); v.sc = sc; t.accept(v); } enum StructFlags : int { none = 0x0, hasPointers = 0x1, // NB: should use noPointers as in ClassFlags } enum StructPOD : int { no, // struct is not POD yes, // struct is POD fwd, // POD not yet computed } /*********************************************************** * All `struct` declarations are an instance of this. */ extern (C++) class StructDeclaration : AggregateDeclaration { bool zeroInit; // !=0 if initialize with 0 fill bool hasIdentityAssign; // true if has identity opAssign bool hasIdentityEquals; // true if has identity opEquals bool hasNoFields; // has no fields FuncDeclarations postblits; // Array of postblit functions FuncDeclaration postblit; // aggregate postblit FuncDeclaration xeq; // TypeInfo_Struct.xopEquals FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp FuncDeclaration xhash; // TypeInfo_Struct.xtoHash extern (C++) __gshared FuncDeclaration xerreq; // object.xopEquals extern (C++) __gshared FuncDeclaration xerrcmp; // object.xopCmp structalign_t alignment; // alignment applied outside of the struct StructPOD ispod; // if struct is POD // For 64 bit Efl function call/return ABI Type arg1type; Type arg2type; // Even if struct is defined as non-root symbol, some built-in operations // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo. // For those, today TypeInfo_Struct is generated in COMDAT. bool requestTypeInfo; extern (D) this(const ref Loc loc, Identifier id, bool inObject) { super(loc, id); zeroInit = false; // assume false until we do semantic processing ispod = StructPOD.fwd; // For forward references type = new TypeStruct(this); if (inObject) { if (id == Id.ModuleInfo && !Module.moduleinfo) Module.moduleinfo = this; } } static StructDeclaration create(Loc loc, Identifier id, bool inObject) { return new StructDeclaration(loc, id, inObject); } override Dsymbol syntaxCopy(Dsymbol s) { StructDeclaration sd = s ? cast(StructDeclaration)s : new StructDeclaration(loc, ident, false); return ScopeDsymbol.syntaxCopy(sd); } final void semanticTypeInfoMembers() { if (xeq && xeq._scope && xeq.semanticRun < PASS.semantic3done) { uint errors = global.startGagging(); xeq.semantic3(xeq._scope); if (global.endGagging(errors)) xeq = xerreq; } if (xcmp && xcmp._scope && xcmp.semanticRun < PASS.semantic3done) { uint errors = global.startGagging(); xcmp.semantic3(xcmp._scope); if (global.endGagging(errors)) xcmp = xerrcmp; } FuncDeclaration ftostr = search_toString(this); if (ftostr && ftostr._scope && ftostr.semanticRun < PASS.semantic3done) { ftostr.semantic3(ftostr._scope); } if (xhash && xhash._scope && xhash.semanticRun < PASS.semantic3done) { xhash.semantic3(xhash._scope); } if (postblit && postblit._scope && postblit.semanticRun < PASS.semantic3done) { postblit.semantic3(postblit._scope); } if (dtor && dtor._scope && dtor.semanticRun < PASS.semantic3done) { dtor.semantic3(dtor._scope); } } override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); if (_scope && !symtab) dsymbolSemantic(this, _scope); if (!members || !symtab) // opaque or semantic() is not yet called { error("is forward referenced when looking for `%s`", ident.toChars()); return null; } return ScopeDsymbol.search(loc, ident, flags); } override const(char)* kind() const { return "struct"; } override final void finalizeSize() { //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok); assert(sizeok != Sizeok.done); //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok); fields.setDim(0); // workaround // Set the offsets of the fields and determine the size of the struct uint offset = 0; bool isunion = isUnionDeclaration() !is null; for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.setFieldOffset(this, &offset, isunion); } if (type.ty == Terror) return; // 0 sized struct's are set to 1 byte if (structsize == 0) { hasNoFields = true; structsize = 1; alignsize = 1; } // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. if (alignment == STRUCTALIGN_DEFAULT) structsize = (structsize + alignsize - 1) & ~(alignsize - 1); else structsize = (structsize + alignment - 1) & ~(alignment - 1); sizeok = Sizeok.done; //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize); if (errors) return; // Calculate fields[i].overlapped if (checkOverlappedFields()) { errors = true; return; } // Determine if struct is all zeros or not zeroInit = true; foreach (vd; fields) { if (vd._init) { if (vd._init.isVoidInitializer()) /* Treat as 0 for the purposes of putting the initializer * in the BSS segment, or doing a mass set to 0 */ continue; // Zero size fields are zero initialized if (vd.type.size(vd.loc) == 0) continue; // Examine init to see if it is all 0s. auto exp = vd.getConstInitializer(); if (!exp || !_isZeroInit(exp)) { zeroInit = false; break; } } else if (!vd.type.isZeroInit(loc)) { zeroInit = false; break; } } auto tt = Target.toArgTypes(type); size_t dim = tt.arguments.dim; if (dim >= 1) { assert(dim <= 2); arg1type = (*tt.arguments)[0].type; if (dim == 2) arg2type = (*tt.arguments)[1].type; } } /*************************************** * Fit elements[] to the corresponding types of the struct's fields. * * Params: * loc = location to use for error messages * sc = context * elements = explicit arguments used to construct object * stype = the constructed object type. * Returns: * false if any errors occur, * otherwise true and elements[] are rewritten for the output. */ final bool fit(const ref Loc loc, Scope* sc, Expressions* elements, Type stype) { if (!elements) return true; size_t nfields = fields.dim - isNested(); size_t offset = 0; for (size_t i = 0; i < elements.dim; i++) { Expression e = (*elements)[i]; if (!e) continue; e = resolveProperties(sc, e); if (i >= nfields) { if (i == fields.dim - 1 && isNested() && e.op == TOK.null_) { // CTFE sometimes creates null as hidden pointer; we'll allow this. continue; } .error(loc, "more initializers than fields (%d) of `%s`", nfields, toChars()); return false; } VarDeclaration v = fields[i]; if (v.offset < offset) { .error(loc, "overlapping initialization for `%s`", v.toChars()); return false; } offset = cast(uint)(v.offset + v.type.size()); Type t = v.type; if (stype) t = t.addMod(stype.mod); Type origType = t; Type tb = t.toBasetype(); const hasPointers = tb.hasPointers(); if (hasPointers) { if ((stype.alignment() < Target.ptrsize || (v.offset & (Target.ptrsize - 1))) && (sc.func && sc.func.setUnsafe())) { .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", toChars(), v.toChars()); return false; } } /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (e.op == TOK.string_ && tb.ty == Tsarray) { StringExp se = cast(StringExp)e; Type typeb = se.type.toBasetype(); TY tynto = tb.nextOf().ty; if (!se.committed && (typeb.ty == Tarray || typeb.ty == Tsarray) && (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) { e = se.castTo(sc, t); goto L1; } } while (!e.implicitConvTo(t) && tb.ty == Tsarray) { /* Static array initialization, as in: * T[3][5] = e; */ t = tb.nextOf(); tb = t.toBasetype(); } if (!e.implicitConvTo(t)) t = origType; // restore type for better diagnostic e = e.implicitCastTo(sc, t); L1: if (e.op == TOK.error) return false; (*elements)[i] = doCopyOrMove(sc, e); } return true; } /*************************************** * Determine if struct is POD (Plain Old Data). * * POD is defined as: * $(OL * $(LI not nested) * $(LI no postblits, destructors, or assignment operators) * $(LI no `ref` fields or fields that are themselves non-POD) * ) * The idea being these are compatible with C structs. * * Returns: * true if struct is POD */ final bool isPOD() { // If we've already determined whether this struct is POD. if (ispod != StructPOD.fwd) return (ispod == StructPOD.yes); ispod = StructPOD.yes; if (enclosing || postblit || dtor) ispod = StructPOD.no; // Recursively check all fields are POD. for (size_t i = 0; i < fields.dim; i++) { VarDeclaration v = fields[i]; if (v.storage_class & STC.ref_) { ispod = StructPOD.no; break; } Type tv = v.type.baseElemOf(); if (tv.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tv; StructDeclaration sd = ts.sym; if (!sd.isPOD()) { ispod = StructPOD.no; break; } } } return (ispod == StructPOD.yes); } override final inout(StructDeclaration) isStructDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /********************************** * Determine if exp is all binary zeros. * Params: * exp = expression to check * Returns: * true if it's all binary 0 */ private bool _isZeroInit(Expression exp) { switch (exp.op) { case TOK.int64: return exp.toInteger() == 0; case TOK.null_: case TOK.false_: return true; case TOK.structLiteral: { auto sle = cast(StructLiteralExp) exp; foreach (i; 0 .. sle.sd.fields.dim) { auto field = sle.sd.fields[i]; if (field.type.size(field.loc)) { auto e = (*sle.elements)[i]; if (e ? !_isZeroInit(e) : !field.type.isZeroInit(field.loc)) return false; } } return true; } case TOK.arrayLiteral: { auto ale = cast(ArrayLiteralExp)exp; const dim = ale.elements ? ale.elements.dim : 0; if (ale.type.toBasetype().ty == Tarray) // if initializing a dynamic array return dim == 0; foreach (i; 0 .. dim) { if (!_isZeroInit(ale.getElement(i))) return false; } /* Note that true is returned for all T[0] */ return true; } case TOK.string_: { StringExp se = cast(StringExp)exp; if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array return se.len == 0; foreach (i; 0 .. se.len) { if (se.getCodeUnit(i)) return false; } return true; } case TOK.vector: { auto ve = cast(VectorExp) exp; return _isZeroInit(ve.e1); } case TOK.float64: case TOK.complex80: { import dmd.root.ctfloat : CTFloat; return (exp.toReal() is CTFloat.zero) && (exp.toImaginary() is CTFloat.zero); } default: return false; } } /*********************************************************** * Unions are a variation on structs. */ extern (C++) final class UnionDeclaration : StructDeclaration { extern (D) this(const ref Loc loc, Identifier id) { super(loc, id, false); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto ud = new UnionDeclaration(loc, ident); return StructDeclaration.syntaxCopy(ud); } override const(char)* kind() const { return "union"; } override inout(UnionDeclaration) isUnionDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/dsymbol.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dsymbol.d, _dsymbol.d) * Documentation: https://dlang.org/phobos/dmd_dsymbol.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d */ module dmd.dsymbol; import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.string; import core.stdc.stdlib; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.attrib; import dmd.gluelayer; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.lexer; import dmd.mtype; import dmd.nspace; import dmd.opover; import dmd.root.aav; import dmd.root.rmem; import dmd.root.rootobject; import dmd.root.speller; import dmd.statement; import dmd.tokens; import dmd.visitor; struct Ungag { uint oldgag; extern (D) this(uint old) { this.oldgag = old; } extern (C++) ~this() { global.gag = oldgag; } } struct Prot { /// enum Kind : int { undefined, none, // no access private_, package_, protected_, public_, export_, } Kind kind; Package pkg; extern (D) this(Prot.Kind kind) { this.kind = kind; } extern (C++): /** * Checks if `this` is superset of `other` restrictions. * For example, "protected" is more restrictive than "public". */ bool isMoreRestrictiveThan(const Prot other) const { return this.kind < other.kind; } /** * Checks if `this` is absolutely identical protection attribute to `other` */ bool opEquals(ref const Prot other) const { if (this.kind == other.kind) { if (this.kind == Prot.Kind.package_) return this.pkg == other.pkg; return true; } return false; } /** * Checks if parent defines different access restrictions than this one. * * Params: * parent = protection attribute for scope that hosts this one * * Returns: * 'true' if parent is already more restrictive than this one and thus * no differentiation is needed. */ bool isSubsetOf(ref const Prot parent) const { if (this.kind != parent.kind) return false; if (this.kind == Prot.Kind.package_) { if (!this.pkg) return true; if (!parent.pkg) return false; if (parent.pkg.isAncestorPackageOf(this.pkg)) return true; } return true; } } enum PASS : int { init, // initial state semantic, // semantic() started semanticdone, // semantic() done semantic2, // semantic2() started semantic2done, // semantic2() done semantic3, // semantic3() started semantic3done, // semantic3() done inline, // inline started inlinedone, // inline done obj, // toObjFile() run } // Search options enum : int { IgnoreNone = 0x00, // default IgnorePrivateImports = 0x01, // don't search private imports IgnoreErrors = 0x02, // don't give error messages IgnoreAmbiguous = 0x04, // return NULL if ambiguous SearchLocalsOnly = 0x08, // only look at locals (don't search imports) SearchImportsOnly = 0x10, // only look in imports SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, // meaning don't search imports in that scope, // because qualified module searches search // their imports IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols } extern (C++) alias Dsymbol_apply_ft_t = int function(Dsymbol, void*); /*********************************************************** */ extern (C++) class Dsymbol : RootObject { Identifier ident; Dsymbol parent; Symbol* csym; // symbol for code generator Symbol* isym; // import version of csym const(char)* comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope* _scope; // !=null means context to use for semantic() const(char)* prettystring; // cached value of toPrettyChars() bool errors; // this symbol failed to pass semantic() PASS semanticRun; DeprecatedDeclaration depdecl; // customized deprecation message UserAttributeDeclaration userAttribDecl; // user defined attributes // !=null means there's a ddoc unittest associated with this symbol // (only use this with ddoc) UnitTestDeclaration ddocUnittest; final extern (D) this() { //printf("Dsymbol::Dsymbol(%p)\n", this); this.semanticRun = PASS.init; } final extern (D) this(Identifier ident) { //printf("Dsymbol::Dsymbol(%p, ident)\n", this); this.ident = ident; this.semanticRun = PASS.init; } static Dsymbol create(Identifier ident) { return new Dsymbol(ident); } override const(char)* toChars() { return ident ? ident.toChars() : "__anonymous"; } // helper to print fully qualified (template) arguments const(char)* toPrettyCharsHelper() { return toChars(); } final ref const(Loc) getLoc() { if (!loc.isValid()) // avoid bug 5861. { auto m = getModule(); if (m && m.srcfile) loc.filename = m.srcfile.toChars(); } return loc; } final const(char)* locToChars() { return getLoc().toChars(); } override bool equals(RootObject o) { if (this == o) return true; if (o.dyncast() != DYNCAST.dsymbol) return false; Dsymbol s = cast(Dsymbol)o; // Overload sets don't have an ident if (s && ident && s.ident && ident.equals(s.ident)) return true; return false; } bool isAnonymous() { return ident is null; } final void error(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); const cstr = toPrettyChars(); const pretty = '`' ~ cstr[0 .. strlen(cstr)] ~ "`\0"; .verror(loc, format, ap, kind(), pretty.ptr); va_end(ap); } final void error(const(char)* format, ...) { va_list ap; va_start(ap, format); const cstr = toPrettyChars(); const pretty = '`' ~ cstr[0 .. strlen(cstr)] ~ "`\0"; .verror(getLoc(), format, ap, kind(), pretty.ptr); va_end(ap); } final void deprecation(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); const cstr = toPrettyChars(); const pretty = '`' ~ cstr[0 .. strlen(cstr)] ~ "`\0"; .vdeprecation(loc, format, ap, kind(), pretty.ptr); va_end(ap); } final void deprecation(const(char)* format, ...) { va_list ap; va_start(ap, format); const cstr = toPrettyChars(); const pretty = '`' ~ cstr[0 .. strlen(cstr)] ~ "`\0"; .vdeprecation(getLoc(), format, ap, kind(), pretty.ptr); va_end(ap); } final bool checkDeprecated(const ref Loc loc, Scope* sc) { if (global.params.useDeprecated != Diagnostic.off && isDeprecated()) { // Don't complain if we're inside a deprecated symbol's scope if (sc.isDeprecated()) return false; const(char)* message = null; for (Dsymbol p = this; p; p = p.parent) { message = p.depdecl ? p.depdecl.getMessage() : null; if (message) break; } if (message) deprecation(loc, "is deprecated - %s", message); else deprecation(loc, "is deprecated"); return true; } return false; } /********************************** * Determine which Module a Dsymbol is in. */ final Module getModule() { //printf("Dsymbol::getModule()\n"); if (TemplateInstance ti = isInstantiated()) return ti.tempdecl.getModule(); Dsymbol s = this; while (s) { //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars()); Module m = s.isModule(); if (m) return m; s = s.parent; } return null; } /********************************** * Determine which Module a Dsymbol is in, as far as access rights go. */ final Module getAccessModule() { //printf("Dsymbol::getAccessModule()\n"); if (TemplateInstance ti = isInstantiated()) return ti.tempdecl.getAccessModule(); Dsymbol s = this; while (s) { //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars()); Module m = s.isModule(); if (m) return m; TemplateInstance ti = s.isTemplateInstance(); if (ti && ti.enclosing) { /* Because of local template instantiation, the parent isn't where the access * rights come from - it's the template declaration */ s = ti.tempdecl; } else s = s.parent; } return null; } final inout(Dsymbol) pastMixin() inout { //printf("Dsymbol::pastMixin() %s\n", toChars()); if (!isTemplateMixin() && !isForwardingAttribDeclaration()) return this; if (!parent) return null; return parent.pastMixin(); } /********************************** * `parent` field returns a lexically enclosing scope symbol this is a member of. * * `toParent()` returns a logically enclosing scope symbol this is a member of. * It skips over TemplateMixin's. * * `toParent2()` returns an enclosing scope symbol this is living at runtime. * It skips over both TemplateInstance's and TemplateMixin's. * It's used when looking for the 'this' pointer of the enclosing function/class. * * Examples: * module mod; * template Foo(alias a) { mixin Bar!(); } * mixin template Bar() { * public { // ProtDeclaration * void baz() { a = 2; } * } * } * void test() { * int v = 1; * alias foo = Foo!(v); * foo.baz(); * assert(v == 2); * } * * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()') * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()') * // s.toParent() == TemplateInstance('mod.test.Foo!()') * // s.toParent2() == FuncDeclaration('mod.test') */ final inout(Dsymbol) toParent() inout { return parent ? parent.pastMixin() : null; } /// ditto final inout(Dsymbol) toParent2() inout { if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration()) return parent; return parent.toParent2; } final inout(TemplateInstance) isInstantiated() inout { if (!parent) return null; auto ti = parent.isTemplateInstance(); if (ti && !ti.isTemplateMixin()) return ti; return parent.isInstantiated(); } // Check if this function is a member of a template which has only been // instantiated speculatively, eg from inside is(typeof()). // Return the speculative template instance it is part of, // or NULL if not speculative. final inout(TemplateInstance) isSpeculative() inout { if (!parent) return null; auto ti = parent.isTemplateInstance(); if (ti && ti.gagged) return ti; if (!parent.toParent()) return null; return parent.isSpeculative(); } final Ungag ungagSpeculative() const { uint oldgag = global.gag; if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration()) global.gag = 0; return Ungag(oldgag); } // kludge for template.isSymbol() override final DYNCAST dyncast() const { return DYNCAST.dsymbol; } /************************************* * Do syntax copy of an array of Dsymbol's. */ extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a) { Dsymbols* b = null; if (a) { b = a.copy(); for (size_t i = 0; i < b.dim; i++) { (*b)[i] = (*b)[i].syntaxCopy(null); } } return b; } Identifier getIdent() { return ident; } const(char)* toPrettyChars(bool QualifyTypes = false) { if (prettystring && !QualifyTypes) return prettystring; //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); if (!parent) { auto s = toChars(); if (!QualifyTypes) prettystring = s; return s; } // Computer number of components size_t complength = 0; for (Dsymbol p = this; p; p = p.parent) ++complength; // Allocate temporary array comp[] alias T = const(char)[]; auto compptr = cast(T*)malloc(complength * T.sizeof); if (!compptr) Mem.error(); auto comp = compptr[0 .. complength]; // Fill in comp[] and compute length of final result size_t length = 0; int i; for (Dsymbol p = this; p; p = p.parent) { const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars(); const len = strlen(s); comp[i] = s[0 .. len]; ++i; length += len + 1; } auto s = cast(char*)mem.xmalloc(length); auto q = s + length - 1; *q = 0; foreach (j; 0 .. complength) { const t = comp[j].ptr; const len = comp[j].length; q -= len; memcpy(q, t, len); if (q == s) break; *--q = '.'; } free(comp.ptr); if (!QualifyTypes) prettystring = s; return s; } const(char)* kind() const pure nothrow @nogc @safe { return "symbol"; } /********************************* * If this symbol is really an alias for another, * return that other. * If needed, semantic() is invoked due to resolve forward reference. */ Dsymbol toAlias() { return this; } /********************************* * Resolve recursive tuple expansion in eponymous template. */ Dsymbol toAlias2() { return toAlias(); } /********************************* * Iterate this dsymbol or members of this scoped dsymbol, then * call `fp` with the found symbol and `param`. * Params: * fp = function pointer to process the iterated symbol. * If it returns nonzero, the iteration will be aborted. * param = a parameter passed to fp. * Returns: * nonzero if the iteration is aborted by the return value of fp, * or 0 if it's completed. */ int apply(Dsymbol_apply_ft_t fp, void* param) { return (*fp)(this, param); } void addMember(Scope* sc, ScopeDsymbol sds) { //printf("Dsymbol::addMember('%s')\n", toChars()); //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); parent = sds; if (!isAnonymous()) // no name, so can't add it to symbol table { if (!sds.symtabInsert(this)) // if name is already defined { Dsymbol s2 = sds.symtabLookup(this,ident); if (!s2.overloadInsert(this)) { sds.multiplyDefined(Loc.initial, this, s2); errors = true; } } if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) { if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof) { error("`.%s` property cannot be redefined", ident.toChars()); errors = true; } } } } /************************************* * Set scope for future semantic analysis so we can * deal better with forward references. */ void setScope(Scope* sc) { //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc); if (!sc.nofree) sc.setNoFree(); // may need it even after semantic() finishes _scope = sc; if (sc.depdecl) depdecl = sc.depdecl; if (!userAttribDecl) userAttribDecl = sc.userAttribDecl; } void importAll(Scope* sc) { } /********************************************* * Search for ident as member of s. * Params: * loc = location to print for error messages * ident = identifier to search for * flags = IgnoreXXXX * Returns: * null if not found */ Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) { //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); return null; } final Dsymbol search_correct(Identifier ident) { /*************************************************** * Search for symbol with correct spelling. */ extern (D) void* symbol_search_fp(const(char)* seed, ref int cost) { /* If not in the lexer's string table, it certainly isn't in the symbol table. * Doing this first is a lot faster. */ size_t len = strlen(seed); if (!len) return null; Identifier id = Identifier.lookup(seed, len); if (!id) return null; cost = 0; Dsymbol s = this; Module.clearCache(); return cast(void*)s.search(Loc.initial, id, IgnoreErrors); } if (global.gag) return null; // don't do it for speculative compiles; too time consuming return cast(Dsymbol)speller(ident.toChars(), &symbol_search_fp, idchars); } /*************************************** * Search for identifier id as a member of `this`. * `id` may be a template instance. * * Params: * loc = location to print the error messages * sc = the scope where the symbol is located * id = the id of the symbol * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` * * Returns: * symbol found, NULL if not */ final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); Dsymbol s = toAlias(); Dsymbol sm; if (Declaration d = s.isDeclaration()) { if (d.inuse) { .error(loc, "circular reference to `%s`", d.toPrettyChars()); return null; } } switch (id.dyncast()) { case DYNCAST.identifier: sm = s.search(loc, cast(Identifier)id, flags); break; case DYNCAST.dsymbol: { // It's a template instance //printf("\ttemplate instance id\n"); Dsymbol st = cast(Dsymbol)id; TemplateInstance ti = st.isTemplateInstance(); sm = s.search(loc, ti.name); if (!sm) { sm = s.search_correct(ti.name); if (sm) .error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars()); else .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars()); return null; } sm = sm.toAlias(); TemplateDeclaration td = sm.isTemplateDeclaration(); if (!td) { .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind()); return null; } ti.tempdecl = td; if (!ti.semanticRun) ti.dsymbolSemantic(sc); sm = ti.toAlias(); break; } case DYNCAST.type: case DYNCAST.expression: default: assert(0); } return sm; } bool overloadInsert(Dsymbol s) { //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); return false; } /********************************* * Returns: * SIZE_INVALID when the size cannot be determined */ d_uns64 size(const ref Loc loc) { error("Dsymbol `%s` has no size", toChars()); return SIZE_INVALID; } bool isforwardRef() { return false; } // is a 'this' required to access the member inout(AggregateDeclaration) isThis() inout { return null; } // is Dsymbol exported? bool isExport() const { return false; } // is Dsymbol imported? bool isImportedSymbol() const { return false; } // is Dsymbol deprecated? bool isDeprecated() { return false; } bool isOverloadable() { return false; } // is this a LabelDsymbol()? LabelDsymbol isLabel() { return null; } /// Returns an AggregateDeclaration when toParent() is that. final inout(AggregateDeclaration) isMember() inout { //printf("Dsymbol::isMember() %s\n", toChars()); auto p = toParent(); //printf("parent is %s %s\n", p.kind(), p.toChars()); return p ? p.isAggregateDeclaration() : null; } /// Returns an AggregateDeclaration when toParent2() is that. final inout(AggregateDeclaration) isMember2() inout { //printf("Dsymbol::isMember2() '%s'\n", toChars()); auto p = toParent2(); //printf("parent is %s %s\n", p.kind(), p.toChars()); return p ? p.isAggregateDeclaration() : null; } // is this a member of a ClassDeclaration? final ClassDeclaration isClassMember() { auto ad = isMember(); return ad ? ad.isClassDeclaration() : null; } // is this a type? Type getType() { return null; } // need a 'this' pointer? bool needThis() { return false; } /************************************* */ Prot prot() { return Prot(Prot.Kind.public_); } /************************************** * Copy the syntax. * Used for template instantiations. * If s is NULL, allocate the new object, otherwise fill it in. */ Dsymbol syntaxCopy(Dsymbol s) { printf("%s %s\n", kind(), toChars()); assert(0); } /************************************** * Determine if this symbol is only one. * Returns: * false, *ps = NULL: There are 2 or more symbols * true, *ps = NULL: There are zero symbols * true, *ps = symbol: The one and only one symbol */ bool oneMember(Dsymbol* ps, Identifier ident) { //printf("Dsymbol::oneMember()\n"); *ps = this; return true; } /***************************************** * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0); Dsymbol s = null; if (members) { for (size_t i = 0; i < members.dim; i++) { Dsymbol sx = (*members)[i]; bool x = sx.oneMember(ps, ident); //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps); if (!x) { //printf("\tfalse 1\n"); assert(*ps is null); return false; } if (*ps) { assert(ident); if (!(*ps).ident || !(*ps).ident.equals(ident)) continue; if (!s) s = *ps; else if (s.isOverloadable() && (*ps).isOverloadable()) { // keep head of overload set FuncDeclaration f1 = s.isFuncDeclaration(); FuncDeclaration f2 = (*ps).isFuncDeclaration(); if (f1 && f2) { assert(!f1.isFuncAliasDeclaration()); assert(!f2.isFuncAliasDeclaration()); for (; f1 != f2; f1 = f1.overnext0) { if (f1.overnext0 is null) { f1.overnext0 = f2; break; } } } } else // more than one symbol { *ps = null; //printf("\tfalse 2\n"); return false; } } } } *ps = s; // s is the one symbol, null if none //printf("\ttrue\n"); return true; } void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { } /***************************************** * Is Dsymbol a variable that contains pointers? */ bool hasPointers() { //printf("Dsymbol::hasPointers() %s\n", toChars()); return false; } bool hasStaticCtorOrDtor() { //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); return false; } void addLocalClass(ClassDeclarations*) { } void checkCtorConstInit() { } /**************************************** * Add documentation comment to Dsymbol. * Ignore NULL comments. */ void addComment(const(char)* comment) { //if (comment) // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); if (!this.comment) this.comment = comment; else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0) { // Concatenate the two this.comment = Lexer.combineComments(this.comment, comment, true); } } /**************************************** * Returns true if this symbol is defined in a non-root module without instantiation. */ final bool inNonRoot() { Dsymbol s = parent; for (; s; s = s.toParent()) { if (auto ti = s.isTemplateInstance()) { return false; } if (auto m = s.isModule()) { if (!m.isRoot()) return true; break; } } return false; } // Eliminate need for dynamic_cast inout(Package) isPackage() inout { return null; } inout(Module) isModule() inout { return null; } inout(EnumMember) isEnumMember() inout { return null; } inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; } inout(TemplateInstance) isTemplateInstance() inout { return null; } inout(TemplateMixin) isTemplateMixin() inout { return null; } inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; } inout(Nspace) isNspace() inout { return null; } inout(Declaration) isDeclaration() inout { return null; } inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; } inout(ThisDeclaration) isThisDeclaration() inout { return null; } inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; } inout(TupleDeclaration) isTupleDeclaration() inout { return null; } inout(AliasDeclaration) isAliasDeclaration() inout { return null; } inout(AggregateDeclaration) isAggregateDeclaration() inout pure nothrow @safe @nogc { return null; } inout(FuncDeclaration) isFuncDeclaration() inout { return null; } inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; } inout(OverDeclaration) isOverDeclaration() inout { return null; } inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; } inout(CtorDeclaration) isCtorDeclaration() inout { return null; } inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; } inout(DtorDeclaration) isDtorDeclaration() inout { return null; } inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; } inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; } inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; } inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; } inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; } inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; } inout(NewDeclaration) isNewDeclaration() inout { return null; } inout(VarDeclaration) isVarDeclaration() inout { return null; } inout(ClassDeclaration) isClassDeclaration() inout { return null; } inout(StructDeclaration) isStructDeclaration() inout { return null; } inout(UnionDeclaration) isUnionDeclaration() inout { return null; } inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; } inout(ScopeDsymbol) isScopeDsymbol() inout { return null; } inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; } inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; } inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; } inout(Import) isImport() inout { return null; } inout(EnumDeclaration) isEnumDeclaration() inout { return null; } inout(DeleteDeclaration) isDeleteDeclaration() inout { return null; } inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; } inout(AttribDeclaration) isAttribDeclaration() inout { return null; } inout(AnonDeclaration) isAnonDeclaration() inout { return null; } inout(ProtDeclaration) isProtDeclaration() inout { return null; } inout(OverloadSet) isOverloadSet() inout { return null; } /************ */ void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Dsymbol that generates a scope */ extern (C++) class ScopeDsymbol : Dsymbol { Dsymbols* members; // all Dsymbol's in this scope DsymbolTable symtab; // members[] sorted into table uint endlinnum; // the linnumber of the statement after the scope (0 if unknown) private: /// symbols whose members have been imported, i.e. imported modules and template mixins Dsymbols* importedScopes; Prot.Kind* prots; // array of Prot.Kind, one for each import import dmd.root.array : BitArray; BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages public: final extern (D) this() { } final extern (D) this(Identifier id) { super(id); } override Dsymbol syntaxCopy(Dsymbol s) { //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident); sds.members = arraySyntaxCopy(members); sds.endlinnum = endlinnum; return sds; } /***************************************** * This function is #1 on the list of functions that eat cpu time. * Be very, very careful about slowing it down. */ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module if (symtab && !(flags & SearchImportsOnly)) { //printf(" look in locals\n"); auto s1 = symtab.lookup(ident); if (s1) { //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); return s1; } } //printf(" not found in locals\n"); // Look in imported scopes if (importedScopes) { //printf(" look in imports\n"); Dsymbol s = null; OverloadSet a = null; // Look in imported modules for (size_t i = 0; i < importedScopes.dim; i++) { // If private import, don't search it if ((flags & IgnorePrivateImports) && prots[i] == Prot.Kind.private_) continue; int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches Dsymbol ss = (*importedScopes)[i]; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss.toChars(), prots[i], ss.isModule(), ss.isImport()); if (ss.isModule()) { if (flags & SearchLocalsOnly) continue; } else // mixin template { if (flags & SearchImportsOnly) continue; // compatibility with -transition=import // https://issues.dlang.org/show_bug.cgi?id=15925 // SearchLocalsOnly should always get set for new lookup rules sflags |= (flags & SearchLocalsOnly); } /* Don't find private members if ss is a module */ Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); import dmd.access : symbolIsVisible; if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)) continue; if (!s) { s = s2; if (s && s.isOverloadSet()) a = mergeOverloadSet(ident, a, s); } else if (s2 && s != s2) { if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) { /* After following aliases, we found the same * symbol, so it's not an ambiguity. But if one * alias is deprecated or less accessible, prefer * the other. */ if (s.isDeprecated() || s.prot().isMoreRestrictiveThan(s2.prot()) && s2.prot().kind != Prot.Kind.none) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import i1 = s.isImport(); Import i2 = s2.isImport(); if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) { /* https://issues.dlang.org/show_bug.cgi?id=8668 * Public selective import adds AliasDeclaration in module. * To make an overload set, resolve aliases in here and * get actual overload roots which accessible via s and s2. */ s = s.toAlias(); s2 = s2.toAlias(); /* If both s2 and s are overloadable (though we only * need to check s once) */ if ((s2.isOverloadSet() || s2.isOverloadable()) && (a || s.isOverloadable())) { if (symbolIsVisible(this, s2)) { a = mergeOverloadSet(ident, a, s2); } if (!symbolIsVisible(this, s)) s = s2; continue; } if (flags & IgnoreAmbiguous) // if return NULL on ambiguity return null; if (!(flags & IgnoreErrors)) ScopeDsymbol.multiplyDefined(loc, s, s2); break; } } } } if (s) { /* Build special symbol if we had multiple finds */ if (a) { if (!s.isOverloadSet()) a = mergeOverloadSet(ident, a, s); s = a; } // TODO: remove once private symbol visibility has been deprecated if (!(flags & IgnoreErrors) && s.prot().kind == Prot.Kind.private_ && !s.isOverloadable() && !s.parent.isTemplateMixin() && !s.parent.isNspace()) { AliasDeclaration ad = void; // accessing private selective and renamed imports is // deprecated by restricting the symbol visibility if (s.isImport() || (ad = s.isAliasDeclaration()) !is null && ad._import !is null) {} else error(loc, "%s `%s` is `private`", s.kind(), s.toPrettyChars()); } //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); return s; } //printf(" not found in imports\n"); } return null; } final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) { if (!os) { os = new OverloadSet(ident); os.parent = this; } if (OverloadSet os2 = s.isOverloadSet()) { // Merge the cross-module overload set 'os2' into 'os' if (os.a.dim == 0) { os.a.setDim(os2.a.dim); memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim); } else { for (size_t i = 0; i < os2.a.dim; i++) { os = mergeOverloadSet(ident, os, os2.a[i]); } } } else { assert(s.isOverloadable()); /* Don't add to os[] if s is alias of previous sym */ for (size_t j = 0; j < os.a.dim; j++) { Dsymbol s2 = os.a[j]; if (s.toAlias() == s2.toAlias()) { if (s2.isDeprecated() || (s2.prot().isMoreRestrictiveThan(s.prot()) && s.prot().kind != Prot.Kind.none)) { os.a[j] = s; } goto Lcontinue; } } os.push(s); Lcontinue: } return os; } void importScope(Dsymbol s, Prot protection) { //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), protection); // No circular or redundant import's if (s != this) { if (!importedScopes) importedScopes = new Dsymbols(); else { for (size_t i = 0; i < importedScopes.dim; i++) { Dsymbol ss = (*importedScopes)[i]; if (ss == s) // if already imported { if (protection.kind > prots[i]) prots[i] = protection.kind; // upgrade access return; } } } importedScopes.push(s); prots = cast(Prot.Kind*)mem.xrealloc(prots, importedScopes.dim * (prots[0]).sizeof); prots[importedScopes.dim - 1] = protection.kind; } } final void addAccessiblePackage(Package p, Prot protection) { // https://issues.dlang.org/show_bug.cgi?id=17991 // An import of truly empty file/package can happen if (p is null) return; auto pary = protection.kind == Prot.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages; if (pary.length <= p.tag) pary.length = p.tag + 1; (*pary)[p.tag] = true; } bool isPackageAccessible(Package p, Prot protection, int flags = 0) { if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] || protection.kind == Prot.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag]) return true; foreach (i, ss; importedScopes ? (*importedScopes)[] : null) { // only search visible scopes && imported modules should ignore private imports if (protection.kind <= prots[i] && ss.isScopeDsymbol.isPackageAccessible(p, protection, IgnorePrivateImports)) return true; } return false; } override final bool isforwardRef() { return (members is null); } static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2) { version (none) { printf("ScopeDsymbol::multiplyDefined()\n"); printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : ""); printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : ""); } if (loc.isValid()) { .error(loc, "`%s` at %s conflicts with `%s` at %s", s1.toPrettyChars(), s1.locToChars(), s2.toPrettyChars(), s2.locToChars()); } else { s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars()); } } override const(char)* kind() const { return "ScopeDsymbol"; } /******************************************* * Look for member of the form: * const(MemberInfo)[] getMembers(string); * Returns NULL if not found */ final FuncDeclaration findGetMembers() { Dsymbol s = search_function(this, Id.getmembers); FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; version (none) { // Finish __gshared TypeFunction tfgetmembers; if (!tfgetmembers) { Scope sc; auto parameters = new Parameters(); Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); parameters.push(p); Type tret = null; tfgetmembers = new TypeFunction(parameters, tret, 0, LINK.d); tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc); } if (fdx) fdx = fdx.overloadExactMatch(tfgetmembers); } if (fdx && fdx.isVirtual()) fdx = null; return fdx; } Dsymbol symtabInsert(Dsymbol s) { return symtab.insert(s); } /**************************************** * Look up identifier in symbol table. */ Dsymbol symtabLookup(Dsymbol s, Identifier id) { return symtab.lookup(id); } /**************************************** * Return true if any of the members are static ctors or static dtors, or if * any members have members that are. */ override bool hasStaticCtorOrDtor() { if (members) { for (size_t i = 0; i < members.dim; i++) { Dsymbol member = (*members)[i]; if (member.hasStaticCtorOrDtor()) return true; } } return false; } extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s); /*************************************** * Expands attribute declarations in members in depth first * order. Calls dg(size_t symidx, Dsymbol *sym) for each * member. * If dg returns !=0, stops and returns that value else returns 0. * Use this function to avoid the O(N + N^2/2) complexity of * calculating dim and calling N times getNth. * Returns: * last value returned by dg() */ extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) { assert(dg); if (!members) return 0; size_t n = pn ? *pn : 0; // take over index int result = 0; foreach (size_t i; 0 .. members.dim) { Dsymbol s = (*members)[i]; if (AttribDeclaration a = s.isAttribDeclaration()) result = _foreach(sc, a.include(sc), dg, &n); else if (TemplateMixin tm = s.isTemplateMixin()) result = _foreach(sc, tm.members, dg, &n); else if (s.isTemplateInstance()) { } else if (s.isUnitTestDeclaration()) { } else result = dg(n++, s); if (result) break; } if (pn) *pn = n; // update index return result; } override final inout(ScopeDsymbol) isScopeDsymbol() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * With statement scope */ extern (C++) final class WithScopeSymbol : ScopeDsymbol { WithStatement withstate; extern (D) this(WithStatement withstate) { this.withstate = withstate; } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); if (flags & SearchImportsOnly) return null; // Acts as proxy to the with class declaration Dsymbol s = null; Expression eold = null; for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e)) { if (e.op == TOK.scope_) { s = (cast(ScopeExp)e).sds; } else if (e.op == TOK.type) { s = e.type.toDsymbol(null); } else { Type t = e.type.toBasetype(); s = t.toDsymbol(null); } if (s) { s = s.search(loc, ident, flags); if (s) return s; } eold = e; } return null; } override inout(WithScopeSymbol) isWithScopeSymbol() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Array Index/Slice scope */ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol { Expression exp; // IndexExp or SliceExp TypeTuple type; // for tuple[length] TupleDeclaration td; // for tuples of objects Scope* sc; extern (D) this(Scope* sc, Expression e) { assert(e.op == TOK.index || e.op == TOK.slice || e.op == TOK.array); exp = e; this.sc = sc; } extern (D) this(Scope* sc, TypeTuple t) { type = t; this.sc = sc; } extern (D) this(Scope* sc, TupleDeclaration s) { td = s; this.sc = sc; } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) { //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); if (ident == Id.dollar) { VarDeclaration* pvar; Expression ce; L1: if (td) { /* $ gives the number of elements in the tuple */ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t); v._init = new ExpInitializer(Loc.initial, e); v.storage_class |= STC.temp | STC.static_ | STC.const_; v.dsymbolSemantic(sc); return v; } if (type) { /* $ gives the number of type entries in the type tuple */ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); Expression e = new IntegerExp(Loc.initial, type.arguments.dim, Type.tsize_t); v._init = new ExpInitializer(Loc.initial, e); v.storage_class |= STC.temp | STC.static_ | STC.const_; v.dsymbolSemantic(sc); return v; } if (exp.op == TOK.index) { /* array[index] where index is some function of $ */ IndexExp ie = cast(IndexExp)exp; pvar = &ie.lengthVar; ce = ie.e1; } else if (exp.op == TOK.slice) { /* array[lwr .. upr] where lwr or upr is some function of $ */ SliceExp se = cast(SliceExp)exp; pvar = &se.lengthVar; ce = se.e1; } else if (exp.op == TOK.array) { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) */ ArrayExp ae = cast(ArrayExp)exp; pvar = &ae.lengthVar; ce = ae.e1; } else { /* Didn't find $, look in enclosing scope(s). */ return null; } while (ce.op == TOK.comma) ce = (cast(CommaExp)ce).e2; /* If we are indexing into an array that is really a type * tuple, rewrite this as an index into a type tuple and * try again. */ if (ce.op == TOK.type) { Type t = (cast(TypeExp)ce).type; if (t.ty == Ttuple) { type = cast(TypeTuple)t; goto L1; } } /* *pvar is lazily initialized, so if we refer to $ * multiple times, it gets set only once. */ if (!*pvar) // if not already initialized { /* Create variable v and set it to the value of $ */ VarDeclaration v; Type t; if (ce.op == TOK.tuple) { /* It is for an expression tuple, so the * length will be a const. */ Expression e = new IntegerExp(Loc.initial, (cast(TupleExp)ce).exps.dim, Type.tsize_t); v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); v.storage_class |= STC.temp | STC.static_ | STC.const_; } else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) { // Look for opDollar assert(exp.op == TOK.array || exp.op == TOK.slice); AggregateDeclaration ad = isAggregate(t); assert(ad); Dsymbol s = ad.search(loc, Id.opDollar); if (!s) // no dollar exists -- search in higher scope return null; s = s.toAlias(); Expression e = null; // Check for multi-dimensional opDollar(dim) template. if (TemplateDeclaration td = s.isTemplateDeclaration()) { dinteger_t dim = 0; if (exp.op == TOK.array) { dim = (cast(ArrayExp)exp).currentDimension; } else if (exp.op == TOK.slice) { dim = 0; // slices are currently always one-dimensional } else { assert(0); } auto tiargs = new Objects(); Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); edim = edim.expressionSemantic(sc); tiargs.push(edim); e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); } else { /* opDollar exists, but it's not a template. * This is acceptable ONLY for single-dimension indexing. * Note that it's impossible to have both template & function opDollar, * because both take no arguments. */ if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1) { exp.error("`%s` only defines opDollar for one dimension", ad.toChars()); return null; } Declaration d = s.isDeclaration(); assert(d); e = new DotVarExp(loc, ce, d); } e = e.expressionSemantic(sc); if (!e.type) exp.error("`%s` has no value", e.toChars()); t = e.type.toBasetype(); if (t && t.ty == Tfunction) e = new CallExp(e.loc, e); v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; } else { /* For arrays, $ will either be a compile-time constant * (in which case its value in set during constant-folding), * or a variable (in which case an expression is created in * toir.c). */ auto e = new VoidInitializer(Loc.initial); e.type = Type.tsize_t; v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable } *pvar = v; } (*pvar).dsymbolSemantic(sc); return (*pvar); } return null; } override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Overload Sets */ extern (C++) final class OverloadSet : Dsymbol { Dsymbols a; // array of Dsymbols extern (D) this(Identifier ident, OverloadSet os = null) { super(ident); if (os) { for (size_t i = 0; i < os.a.dim; i++) a.push(os.a[i]); } } void push(Dsymbol s) { a.push(s); } override inout(OverloadSet) isOverloadSet() inout { return this; } override const(char)* kind() const { return "overloadset"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and * ForwardingScopeDeclaration to forward symbol insertions to another * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more * details. */ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol { /************************* * Symbol to forward insertions to. * Can be `null` before being lazily initialized. */ ScopeDsymbol forward; extern (D) this(ScopeDsymbol forward) { super(null); this.forward = forward; } override Dsymbol symtabInsert(Dsymbol s) { assert(forward); if (auto d = s.isDeclaration()) { if (d.storage_class & STC.local) { // Symbols with storage class STC.local are not // forwarded, but stored in the local symbol // table. (Those are the `static foreach` variables.) if (!symtab) { symtab = new DsymbolTable(); } return super.symtabInsert(s); // insert locally } } if (!forward.symtab) { forward.symtab = new DsymbolTable(); } // Non-STC.local symbols are forwarded to `forward`. return forward.symtabInsert(s); } /************************ * This override handles the following two cases: * static foreach (i, i; [0]) { ... } * and * static foreach (i; [0]) { enum i = 2; } */ override Dsymbol symtabLookup(Dsymbol s, Identifier id) { assert(forward); // correctly diagnose clashing foreach loop variables. if (auto d = s.isDeclaration()) { if (d.storage_class & STC.local) { if (!symtab) { symtab = new DsymbolTable(); } return super.symtabLookup(s,id); } } // Declarations within `static foreach` do not clash with // `static foreach` loop variables. if (!forward.symtab) { forward.symtab = new DsymbolTable(); } return forward.symtabLookup(s,id); } override void importScope(Dsymbol s, Prot protection) { forward.importScope(s, protection); } override const(char)* kind()const{ return "local scope"; } override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return this; } } /*********************************************************** * Table of Dsymbol's */ extern (C++) final class DsymbolTable : RootObject { AssocArray!(Identifier, Dsymbol) tab; // Look up Identifier. Return Dsymbol if found, NULL if not. Dsymbol lookup(const Identifier ident) { //printf("DsymbolTable::lookup(%s)\n", ident.toChars()); return tab[ident]; } // Insert Dsymbol in table. Return NULL if already there. Dsymbol insert(Dsymbol s) { //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s.ident.toChars()); const ident = s.ident; Dsymbol* ps = tab.getLvalue(ident); if (*ps) return null; // already in table *ps = s; return s; } // Look for Dsymbol in table. If there, return it. If not, insert s and return that. Dsymbol update(Dsymbol s) { const ident = s.ident; Dsymbol* ps = tab.getLvalue(ident); *ps = s; return s; } // when ident and s are not the same Dsymbol insert(const Identifier ident, Dsymbol s) { //printf("DsymbolTable::insert()\n"); Dsymbol* ps = tab.getLvalue(ident); if (*ps) return null; // already in table *ps = s; return s; } /***** * Returns: * number of symbols in symbol table */ uint len() const pure { return cast(uint)tab.length; } } ================================================ FILE: gcc/d/dmd/dsymbol.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.h */ #pragma once #include "root/port.h" #include "globals.h" #include "arraytypes.h" #include "visitor.h" class Identifier; struct Scope; class DsymbolTable; class Declaration; class ThisDeclaration; class TypeInfoDeclaration; class TupleDeclaration; class AliasDeclaration; class AggregateDeclaration; class EnumDeclaration; class ClassDeclaration; class InterfaceDeclaration; class StructDeclaration; class UnionDeclaration; class FuncDeclaration; class FuncAliasDeclaration; class OverDeclaration; class FuncLiteralDeclaration; class CtorDeclaration; class PostBlitDeclaration; class DtorDeclaration; class StaticCtorDeclaration; class StaticDtorDeclaration; class SharedStaticCtorDeclaration; class SharedStaticDtorDeclaration; class InvariantDeclaration; class UnitTestDeclaration; class NewDeclaration; class VarDeclaration; class AttribDeclaration; class ProtDeclaration; class Package; class Module; class Import; class Type; class TypeTuple; class WithStatement; class LabelDsymbol; class ScopeDsymbol; class ForwardingScopeDsymbol; class TemplateDeclaration; class TemplateInstance; class TemplateMixin; class ForwardingAttribDeclaration; class Nspace; class EnumMember; class WithScopeSymbol; class ArrayScopeSymbol; class SymbolDeclaration; class Expression; class DeleteDeclaration; class OverloadSet; struct AA; #ifdef IN_GCC typedef union tree_node Symbol; #else struct Symbol; #endif struct Ungag { unsigned oldgag; Ungag(unsigned old) : oldgag(old) {} ~Ungag() { global.gag = oldgag; } }; void dsymbolSemantic(Dsymbol *dsym, Scope *sc); void semantic2(Dsymbol *dsym, Scope *sc); void semantic3(Dsymbol *dsym, Scope* sc); struct Prot { enum Kind { undefined, none, // no access private_, package_, protected_, public_, export_ }; Kind kind; Package *pkg; bool isMoreRestrictiveThan(const Prot other) const; bool isSubsetOf(const Prot& other) const; }; /* State of symbol in winding its way through the passes of the compiler */ enum PASS { PASSinit, // initial state PASSsemantic, // semantic() started PASSsemanticdone, // semantic() done PASSsemantic2, // semantic2() started PASSsemantic2done, // semantic2() done PASSsemantic3, // semantic3() started PASSsemantic3done, // semantic3() done PASSinline, // inline started PASSinlinedone, // inline done PASSobj // toObjFile() run }; /* Flags for symbol search */ enum { IgnoreNone = 0x00, // default IgnorePrivateImports = 0x01, // don't search private imports IgnoreErrors = 0x02, // don't give error messages IgnoreAmbiguous = 0x04, // return NULL if ambiguous SearchLocalsOnly = 0x08, // only look at locals (don't search imports) SearchImportsOnly = 0x10, // only look in imports SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, // meaning don't search imports in that scope, // because qualified module searches search // their imports IgnoreSymbolVisibility = 0x80 // also find private and package protected symbols }; typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); class Dsymbol : public RootObject { public: Identifier *ident; Dsymbol *parent; Symbol *csym; // symbol for code generator Symbol *isym; // import version of csym const utf8_t *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *_scope; // !=NULL means context to use for semantic() const utf8_t *prettystring; bool errors; // this symbol failed to pass semantic() PASS semanticRun; DeprecatedDeclaration *depdecl; // customized deprecation message UserAttributeDeclaration *userAttribDecl; // user defined attributes UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc) static Dsymbol *create(Identifier *); const char *toChars(); virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments Loc& getLoc(); const char *locToChars(); bool equals(RootObject *o); virtual bool isAnonymous(); void error(Loc loc, const char *format, ...); void error(const char *format, ...); void deprecation(const Loc &loc, const char *format, ...); void deprecation(const char *format, ...); bool checkDeprecated(const Loc &loc, Scope *sc); Module *getModule(); Module *getAccessModule(); Dsymbol *pastMixin(); Dsymbol *toParent(); Dsymbol *toParent2(); TemplateInstance *isInstantiated(); TemplateInstance *isSpeculative(); Ungag ungagSpeculative(); // kludge for template.isSymbol() int dyncast() const { return DYNCAST_DSYMBOL; } virtual Identifier *getIdent(); virtual const char *toPrettyChars(bool QualifyTypes = false); virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); virtual int apply(Dsymbol_apply_ft_t fp, void *param); virtual void addMember(Scope *sc, ScopeDsymbol *sds); virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); Dsymbol *search_correct(Identifier *id); Dsymbol *searchX(const Loc &loc, Scope *sc, RootObject *id); virtual bool overloadInsert(Dsymbol *s); virtual d_uns64 size(const Loc &loc); virtual bool isforwardRef(); virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member virtual bool isExport() const; // is Dsymbol exported? virtual bool isImportedSymbol() const; // is Dsymbol imported? virtual bool isDeprecated(); // is Dsymbol deprecated? virtual bool isOverloadable(); virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? AggregateDeclaration *isMember(); // is this a member of an AggregateDeclaration? AggregateDeclaration *isMember2(); // is this a member of an AggregateDeclaration? ClassDeclaration *isClassMember(); // is this a member of a ClassDeclaration? virtual Type *getType(); // is this a type? virtual bool needThis(); // need a 'this' pointer? virtual Prot prot(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees virtual bool oneMember(Dsymbol **ps, Identifier *ident); virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addLocalClass(ClassDeclarations *) { } virtual void checkCtorConstInit() { } virtual void addComment(const utf8_t *comment); bool inNonRoot(); // Eliminate need for dynamic_cast virtual Package *isPackage() { return NULL; } virtual Module *isModule() { return NULL; } virtual EnumMember *isEnumMember() { return NULL; } virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } virtual TemplateInstance *isTemplateInstance() { return NULL; } virtual TemplateMixin *isTemplateMixin() { return NULL; } virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return NULL; } virtual Nspace *isNspace() { return NULL; } virtual Declaration *isDeclaration() { return NULL; } virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; } virtual ThisDeclaration *isThisDeclaration() { return NULL; } virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; } virtual TupleDeclaration *isTupleDeclaration() { return NULL; } virtual AliasDeclaration *isAliasDeclaration() { return NULL; } virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } virtual FuncDeclaration *isFuncDeclaration() { return NULL; } virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } virtual OverDeclaration *isOverDeclaration() { return NULL; } virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } virtual CtorDeclaration *isCtorDeclaration() { return NULL; } virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } virtual DtorDeclaration *isDtorDeclaration() { return NULL; } virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } virtual NewDeclaration *isNewDeclaration() { return NULL; } virtual VarDeclaration *isVarDeclaration() { return NULL; } virtual ClassDeclaration *isClassDeclaration() { return NULL; } virtual StructDeclaration *isStructDeclaration() { return NULL; } virtual UnionDeclaration *isUnionDeclaration() { return NULL; } virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return NULL; } virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } virtual Import *isImport() { return NULL; } virtual EnumDeclaration *isEnumDeclaration() { return NULL; } virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } virtual AttribDeclaration *isAttribDeclaration() { return NULL; } virtual AnonDeclaration *isAnonDeclaration() { return NULL; } virtual ProtDeclaration *isProtDeclaration() { return NULL; } virtual OverloadSet *isOverloadSet() { return NULL; } virtual void accept(Visitor *v) { v->visit(this); } }; // Dsymbol that generates a scope class ScopeDsymbol : public Dsymbol { public: Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table unsigned endlinnum; // the linnumber of the statement after the scope (0 if unknown) private: Dsymbols *importedScopes; // imported Dsymbol's Prot::Kind *prots; // array of PROTKIND, one for each import BitArray accessiblePackages, privateAccessiblePackages; public: Dsymbol *syntaxCopy(Dsymbol *s); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); OverloadSet *mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s); virtual void importScope(Dsymbol *s, Prot protection); void addAccessiblePackage(Package *p, Prot protection); virtual bool isPackageAccessible(Package *p, Prot protection, int flags = 0); bool isforwardRef(); static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); const char *kind() const; FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); bool hasStaticCtorOrDtor(); ScopeDsymbol *isScopeDsymbol() { return this; } void accept(Visitor *v) { v->visit(this); } }; // With statement scope class WithScopeSymbol : public ScopeDsymbol { public: WithStatement *withstate; Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); WithScopeSymbol *isWithScopeSymbol() { return this; } void accept(Visitor *v) { v->visit(this); } }; // Array Index/Slice scope class ArrayScopeSymbol : public ScopeDsymbol { public: Expression *exp; // IndexExp or SliceExp TypeTuple *type; // for tuple[length] TupleDeclaration *td; // for tuples of objects Scope *sc; Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); ArrayScopeSymbol *isArrayScopeSymbol() { return this; } void accept(Visitor *v) { v->visit(this); } }; // Overload Sets class OverloadSet : public Dsymbol { public: Dsymbols a; // array of Dsymbols void push(Dsymbol *s); OverloadSet *isOverloadSet() { return this; } const char *kind() const; void accept(Visitor *v) { v->visit(this); } }; // Forwarding ScopeDsymbol class ForwardingScopeDsymbol : public ScopeDsymbol { ScopeDsymbol *forward; Dsymbol *symtabInsert(Dsymbol *s); Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); void importScope(Dsymbol *s, Prot protection); const char *kind() const; ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; } }; // Table of Dsymbol's class DsymbolTable : public RootObject { public: AA *tab; // Look up Identifier. Return Dsymbol if found, NULL if not. Dsymbol *lookup(Identifier const * const ident); // Insert Dsymbol in table. Return NULL if already there. Dsymbol *insert(Dsymbol *s); // Look for Dsymbol in table. If there, return it. If not, insert s and return that. Dsymbol *update(Dsymbol *s); Dsymbol *insert(Identifier const * const ident, Dsymbol *s); // when ident and s are not the same }; ================================================ FILE: gcc/d/dmd/dsymbolsem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dsymbolsem.d, _dsymbolsem.d) * Documentation: https://dlang.org/phobos/dmd_dsymbolsem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbolsem.d */ module dmd.dsymbolsem; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.astcodegen; import dmd.attrib; import dmd.blockexit; import dmd.clone; import dmd.compiler; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.dversion; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.hdrgen; import dmd.mtype; import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.parse; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.semantic2; import dmd.semantic3; import dmd.sideeffect; import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utf; import dmd.utils; import dmd.statement; import dmd.target; import dmd.templateparamsem; import dmd.typesem; import dmd.visitor; enum LOG = false; /***************************************** * Create inclusive postblit for struct by aggregating * all the postblits in postblits[] with the postblits for * all the members. * Note the close similarity with AggregateDeclaration::buildDtor(), * and the ordering changes (runs forward instead of backwards). */ private FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) { //printf("StructDeclaration::buildPostBlit() %s\n", sd.toChars()); if (sd.isUnionDeclaration()) return null; // by default, the storage class of the created postblit StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc; Loc loc; // internal code should have no loc to prevent coverage // if any of the postblits are disabled, then the generated postblit // will be disabled for (size_t i = 0; i < sd.postblits.dim; i++) { stc |= sd.postblits[i].storage_class & STC.disable; } VarDeclaration[] fieldsToDestroy; auto postblitCalls = new Statements(); // iterate through all the struct fields that are not disabled for (size_t i = 0; i < sd.fields.dim && !(stc & STC.disable); i++) { auto structField = sd.fields[i]; if (structField.storage_class & STC.ref_) continue; if (structField.overlapped) continue; // if it's a struct declaration or an array of structs Type tv = structField.type.baseElemOf(); if (tv.ty != Tstruct) continue; auto sdv = (cast(TypeStruct)tv).sym; // which has a postblit declaration if (!sdv.postblit) continue; assert(!sdv.isUnionDeclaration()); // if this field's postblit is not `nothrow`, add a `scope(failure)` // block to destroy any prior successfully postblitted fields should // this field's postblit fail if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow) { // create a list of destructors that need to be called Expression[] dtorCalls; foreach(sf; fieldsToDestroy) { Expression ex; tv = sf.type.toBasetype(); if (tv.ty == Tstruct) { // this.v.__xdtor() ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, sf); // This is a hack so we can call destructors on const/immutable objects. ex = new AddrExp(loc, ex); ex = new CastExp(loc, ex, sf.type.mutableOf().pointerTo()); ex = new PtrExp(loc, ex); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; auto sfv = (cast(TypeStruct)sf.type.baseElemOf()).sym; ex = new DotVarExp(loc, ex, sfv.dtor, false); ex = new CallExp(loc, ex); dtorCalls ~= ex; } else { // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) uinteger_t length = 1; while (tv.ty == Tsarray) { length *= (cast(TypeSArray)tv).dim.toUInteger(); tv = tv.nextOf().toBasetype(); } //if (n == 0) // continue; ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, sf); // This is a hack so we can call destructors on const/immutable objects. ex = new DotIdExp(loc, ex, Id.ptr); ex = new CastExp(loc, ex, sdv.type.pointerTo()); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, length, Type.tsize_t)); // Prevent redundant bounds check (cast(SliceExp)ex).upperIsInBounds = true; (cast(SliceExp)ex).lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex); dtorCalls ~= ex; } } fieldsToDestroy = []; // aggregate the destructor calls auto dtors = new Statements(); foreach_reverse(dc; dtorCalls) { dtors.push(new ExpStatement(loc, dc)); } // put destructor calls in a `scope(failure)` block postblitCalls.push(new OnScopeStatement(loc, TOK.onScopeFailure, new CompoundStatement(loc, dtors))); } // perform semantic on the member postblit in order to // be able to aggregate it later on with the rest of the // postblits sdv.postblit.functionSemantic(); stc = mergeFuncAttrs(stc, sdv.postblit); stc = mergeFuncAttrs(stc, sdv.dtor); // if any of the struct member fields has disabled // its postblit, then `sd` is not copyable, so no // postblit is generated if (stc & STC.disable) { postblitCalls.setDim(0); break; } Expression ex; tv = structField.type.toBasetype(); if (tv.ty == Tstruct) { // this.v.__xpostblit() ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, structField); // This is a hack so we can call postblits on const/immutable objects. ex = new AddrExp(loc, ex); ex = new CastExp(loc, ex, structField.type.mutableOf().pointerTo()); ex = new PtrExp(loc, ex); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new DotVarExp(loc, ex, sdv.postblit, false); ex = new CallExp(loc, ex); } else { // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) uinteger_t length = 1; while (tv.ty == Tsarray) { length *= (cast(TypeSArray)tv).dim.toUInteger(); tv = tv.nextOf().toBasetype(); } if (length == 0) continue; ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, structField); // This is a hack so we can call postblits on const/immutable objects. ex = new DotIdExp(loc, ex, Id.ptr); ex = new CastExp(loc, ex, sdv.type.pointerTo()); if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, length, Type.tsize_t)); // Prevent redundant bounds check (cast(SliceExp)ex).upperIsInBounds = true; (cast(SliceExp)ex).lowerIsLessThanUpper = true; ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayPostblit), ex); } postblitCalls.push(new ExpStatement(loc, ex)); // combine in forward order /* https://issues.dlang.org/show_bug.cgi?id=10972 * When subsequent field postblit calls fail, * this field should be destructed for Exception Safety. */ if (sdv.dtor) { sdv.dtor.functionSemantic(); // keep a list of fields that need to be destroyed in case // of a future postblit failure fieldsToDestroy ~= structField; } } void checkShared() { if (sd.type.isShared()) stc |= STC.shared_; } // Build our own "postblit" which executes a, but only if needed. if (postblitCalls.dim || (stc & STC.disable)) { //printf("Building __fieldPostBlit()\n"); checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit); dd.generated = true; dd.storage_class |= STC.inference; dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls); sd.postblits.shift(dd); sd.members.push(dd); dd.dsymbolSemantic(sc); } // create __xpostblit, which is the generated postblit FuncDeclaration xpostblit = null; switch (sd.postblits.dim) { case 0: break; case 1: xpostblit = sd.postblits[0]; break; default: Expression e = null; stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; for (size_t i = 0; i < sd.postblits.dim; i++) { auto fd = sd.postblits[i]; stc = mergeFuncAttrs(stc, fd); if (stc & STC.disable) { e = null; break; } Expression ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, fd, false); ex = new CallExp(loc, ex); e = Expression.combine(e, ex); } checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit); dd.generated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); sd.members.push(dd); dd.dsymbolSemantic(sc); xpostblit = dd; break; } // Add an __xpostblit alias to make the inclusive postblit accessible if (xpostblit) { auto _alias = new AliasDeclaration(Loc.initial, Id.__xpostblit, xpostblit); _alias.dsymbolSemantic(sc); sd.members.push(_alias); _alias.addMember(sc, sd); // add to symbol table } return xpostblit; } private uint setMangleOverride(Dsymbol s, const(char)[] sym) { AttribDeclaration ad = s.isAttribDeclaration(); if (ad) { Dsymbols* decls = ad.include(null); uint nestedCount = 0; if (decls && decls.dim) for (size_t i = 0; i < decls.dim; ++i) nestedCount += setMangleOverride((*decls)[i], sym); return nestedCount; } else if (s.isFuncDeclaration() || s.isVarDeclaration()) { s.isDeclaration().mangleOverride = sym; return 1; } else return 0; } /************************************* * Does semantic analysis on the public face of declarations. */ extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc) { scope v = new DsymbolSemanticVisitor(sc); dsym.accept(v); } structalign_t getAlignment(AlignDeclaration ad, Scope* sc) { if (ad.salign != ad.UNKNOWN) return ad.salign; if (!ad.ealign) return ad.salign = STRUCTALIGN_DEFAULT; sc = sc.startCTFE(); ad.ealign = ad.ealign.expressionSemantic(sc); ad.ealign = resolveProperties(sc, ad.ealign); sc = sc.endCTFE(); ad.ealign = ad.ealign.ctfeInterpret(); if (ad.ealign.op == TOK.error) return ad.salign = STRUCTALIGN_DEFAULT; Type tb = ad.ealign.type.toBasetype(); auto n = ad.ealign.toInteger(); if (n < 1 || n & (n - 1) || structalign_t.max < n || !tb.isintegral()) { error(ad.loc, "alignment must be an integer positive power of 2, not %s", ad.ealign.toChars()); return ad.salign = STRUCTALIGN_DEFAULT; } return ad.salign = cast(structalign_t)n; } const(char)* getMessage(DeprecatedDeclaration dd) { if (auto sc = dd._scope) { dd._scope = null; sc = sc.startCTFE(); dd.msg = dd.msg.expressionSemantic(sc); dd.msg = resolveProperties(sc, dd.msg); sc = sc.endCTFE(); dd.msg = dd.msg.ctfeInterpret(); if (auto se = dd.msg.toStringExp()) dd.msgstr = se.toStringz().ptr; else dd.msg.error("compile time constant expected, not `%s`", dd.msg.toChars()); } return dd.msgstr; } // Returns true if a contract can appear without a function body. package bool allowsContractWithoutBody(FuncDeclaration funcdecl) { assert(!funcdecl.fbody); /* Contracts can only appear without a body when they are virtual * interface functions or abstract. */ Dsymbol parent = funcdecl.toParent(); InterfaceDeclaration id = parent.isInterfaceDeclaration(); if (!funcdecl.isAbstract() && (funcdecl.fensures || funcdecl.frequires) && !(id && funcdecl.isVirtual())) { auto cd = parent.isClassDeclaration(); if (!(cd && cd.isAbstract())) return false; } return true; } private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; Scope* sc; this(Scope* sc) { this.sc = sc; } override void visit(Dsymbol dsym) { dsym.error("%p has no semantic routine", dsym); } override void visit(ScopeDsymbol) { } override void visit(Declaration) { } override void visit(AliasThis dsym) { if (dsym.semanticRun != PASS.init) return; if (dsym._scope) { sc = dsym._scope; dsym._scope = null; } if (!sc) return; dsym.semanticRun = PASS.semantic; Dsymbol p = sc.parent.pastMixin(); AggregateDeclaration ad = p.isAggregateDeclaration(); if (!ad) { error(dsym.loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); return; } assert(ad.members); Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) { s = sc.search(dsym.loc, dsym.ident, null); if (s) error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); else error(dsym.loc, "undefined identifier `%s`", dsym.ident.toChars()); return; } if (ad.aliasthis && s != ad.aliasthis) { error(dsym.loc, "there can be only one alias this"); return; } /* disable the alias this conversion so the implicit conversion check * doesn't use it. */ ad.aliasthis = null; Dsymbol sx = s; if (sx.isAliasDeclaration()) sx = sx.toAlias(); Declaration d = sx.isDeclaration(); if (d && !d.isTupleDeclaration()) { /* https://issues.dlang.org/show_bug.cgi?id=18429 * * If the identifier in the AliasThis declaration * is defined later and is a voldemort type, we must * perform semantic on the declaration to deduce the type. */ if (!d.type) d.dsymbolSemantic(sc); Type t = d.type; assert(t); if (ad.type.implicitConvTo(t) > MATCH.nomatch) { error(dsym.loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars()); } } ad.aliasthis = s; dsym.semanticRun = PASS.semanticdone; } override void visit(AliasDeclaration dsym) { if (dsym.semanticRun >= PASS.semanticdone) return; assert(dsym.semanticRun <= PASS.semantic); dsym.storage_class |= sc.stc & STC.deprecated_; dsym.protection = sc.protection; dsym.userAttribDecl = sc.userAttribDecl; if (!sc.func && dsym.inNonRoot()) return; aliasSemantic(dsym, sc); } override void visit(VarDeclaration dsym) { version (none) { printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n", toChars(), sc.parent ? sc.parent.toChars() : null, sem); printf(" type = %s\n", type ? type.toChars() : "null"); printf(" stc = x%x\n", sc.stc); printf(" storage_class = x%llx\n", storage_class); printf("linkage = %d\n", sc.linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } //if (semanticRun > PASS.init) // return; //semanticRun = PSSsemantic; if (dsym.semanticRun >= PASS.semanticdone) return; Scope* scx = null; if (dsym._scope) { sc = dsym._scope; scx = sc; dsym._scope = null; } if (!sc) return; dsym.semanticRun = PASS.semantic; /* Pick up storage classes from context, but except synchronized, * override, abstract, and final. */ dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)); if (dsym.storage_class & STC.extern_ && dsym._init) dsym.error("extern symbols cannot have initializers"); dsym.userAttribDecl = sc.userAttribDecl; AggregateDeclaration ad = dsym.isThis(); if (ad) dsym.storage_class |= ad.storage_class & STC.TYPECTOR; /* If auto type inference, do the inference */ int inferred = 0; if (!dsym.type) { dsym.inuse++; // Infering the type requires running semantic, // so mark the scope as ctfe if required bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0; if (needctfe) sc = sc.startCTFE(); //printf("inferring type for %s with init %s\n", toChars(), _init.toChars()); dsym._init = dsym._init.inferType(sc); dsym.type = dsym._init.initializerToExpression().type; if (needctfe) sc = sc.endCTFE(); dsym.inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII * declarations. */ dsym.storage_class &= ~STC.auto_; dsym.originalType = dsym.type.syntaxCopy(); } else { if (!dsym.originalType) dsym.originalType = dsym.type.syntaxCopy(); /* Prefix function attributes of variable declaration can affect * its type: * pure nothrow void function() fp; * static assert(is(typeof(fp) == void function() pure nothrow)); */ Scope* sc2 = sc.push(); sc2.stc |= (dsym.storage_class & STC.FUNCATTR); dsym.inuse++; dsym.type = dsym.type.typeSemantic(dsym.loc, sc2); dsym.inuse--; sc2.pop(); } //printf(" semantic type = %s\n", type ? type.toChars() : "null"); if (dsym.type.ty == Terror) dsym.errors = true; dsym.type.checkDeprecated(dsym.loc, sc); dsym.linkage = sc.linkage; dsym.parent = sc.parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent.toChars()); dsym.protection = sc.protection; /* If scope's alignment is the default, use the type's alignment, * otherwise the scope overrrides. */ dsym.alignment = sc.alignment(); if (dsym.alignment == STRUCTALIGN_DEFAULT) dsym.alignment = dsym.type.alignment(); // use type's alignment //printf("sc.stc = %x\n", sc.stc); //printf("storage_class = x%x\n", storage_class); if (global.params.vcomplex) dsym.type.checkComplexTransition(dsym.loc, sc); // Calculate type size + safety checks if (sc.func && !sc.intypeof) { if (dsym.storage_class & STC.gshared && !dsym.isMember()) { if (sc.func.setUnsafe()) dsym.error("__gshared not allowed in safe functions; use shared"); } } Dsymbol parent = dsym.toParent(); Type tb = dsym.type.toBasetype(); Type tbn = tb.baseElemOf(); if (tb.ty == Tvoid && !(dsym.storage_class & STC.lazy_)) { if (inferred) { dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars()); } else dsym.error("variables cannot be of type `void`"); dsym.type = Type.terror; tb = dsym.type; } if (tb.ty == Tfunction) { dsym.error("cannot be declared to be a function"); dsym.type = Type.terror; tb = dsym.type; } if (tb.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tb; if (!ts.sym.members) { dsym.error("no definition of struct `%s`", ts.toChars()); } } if ((dsym.storage_class & STC.auto_) && !inferred) dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); if (tb.ty == Ttuple) { /* Instead, declare variables for each of the tuple elements * and add those. */ TypeTuple tt = cast(TypeTuple)tb; size_t nelems = Parameter.dim(tt.arguments); Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null; if (ie) ie = ie.expressionSemantic(sc); if (nelems > 0 && ie) { auto iexps = new Expressions(); iexps.push(ie); auto exps = new Expressions(); for (size_t pos = 0; pos < iexps.dim; pos++) { Lexpand1: Expression e = (*iexps)[pos]; Parameter arg = Parameter.getNth(tt.arguments, pos); arg.type = arg.type.typeSemantic(dsym.loc, sc); //printf("[%d] iexps.dim = %d, ", pos, iexps.dim); //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars()); //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); if (e != ie) { if (iexps.dim > nelems) goto Lnomatch; if (e.type.implicitConvTo(arg.type)) continue; } if (e.op == TOK.tuple) { TupleExp te = cast(TupleExp)e; if (iexps.dim - 1 + te.exps.dim > nelems) goto Lnomatch; iexps.remove(pos); iexps.insert(pos, te.exps); (*iexps)[pos] = Expression.combine(te.e0, (*iexps)[pos]); goto Lexpand1; } else if (isAliasThisTuple(e)) { auto v = copyToTemp(0, "__tup", e); v.dsymbolSemantic(sc); auto ve = new VarExp(dsym.loc, v); ve.type = e.type; exps.setDim(1); (*exps)[0] = ve; expandAliasThisTuples(exps, 0); for (size_t u = 0; u < exps.dim; u++) { Lexpand2: Expression ee = (*exps)[u]; arg = Parameter.getNth(tt.arguments, pos + u); arg.type = arg.type.typeSemantic(dsym.loc, sc); //printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim); //printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars()); //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); size_t iexps_dim = iexps.dim - 1 + exps.dim; if (iexps_dim > nelems) goto Lnomatch; if (ee.type.implicitConvTo(arg.type)) continue; if (expandAliasThisTuples(exps, u) != -1) goto Lexpand2; } if ((*exps)[0] != ve) { Expression e0 = (*exps)[0]; (*exps)[0] = new CommaExp(dsym.loc, new DeclarationExp(dsym.loc, v), e0); (*exps)[0].type = e0.type; iexps.remove(pos); iexps.insert(pos, exps); goto Lexpand1; } } } if (iexps.dim < nelems) goto Lnomatch; ie = new TupleExp(dsym._init.loc, iexps); } Lnomatch: if (ie && ie.op == TOK.tuple) { TupleExp te = cast(TupleExp)ie; size_t tedim = te.exps.dim; if (tedim != nelems) { error(dsym.loc, "tuple of %d elements cannot be assigned to tuple of %d elements", cast(int)tedim, cast(int)nelems); for (size_t u = tedim; u < nelems; u++) // fill dummy expression te.exps.push(new ErrorExp()); } } auto exps = new Objects(nelems); for (size_t i = 0; i < nelems; i++) { Parameter arg = Parameter.getNth(tt.arguments, i); OutBuffer buf; buf.printf("__%s_field_%llu", dsym.ident.toChars(), cast(ulong)i); auto id = Identifier.idPool(buf.peekSlice()); Initializer ti; if (ie) { Expression einit = ie; if (ie.op == TOK.tuple) { TupleExp te = cast(TupleExp)ie; einit = (*te.exps)[i]; if (i == 0) einit = Expression.combine(te.e0, einit); } ti = new ExpInitializer(einit.loc, einit); } else ti = dsym._init ? dsym._init.syntaxCopy() : null; StorageClass storage_class = STC.temp | dsym.storage_class; if (arg.storageClass & STC.parameter) storage_class |= arg.storageClass; auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class); //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars()); v.dsymbolSemantic(sc); if (sc.scopesym) { //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars()); if (sc.scopesym.members) // Note this prevents using foreach() over members, because the limits can change sc.scopesym.members.push(v); } Expression e = new DsymbolExp(dsym.loc, v); (*exps)[i] = e; } auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps); v2.parent = dsym.parent; v2.isexp = true; dsym.aliassym = v2; dsym.semanticRun = PASS.semanticdone; return; } /* Storage class can modify the type */ dsym.type = dsym.type.addStorageClass(dsym.storage_class); /* Adjust storage class to reflect type */ if (dsym.type.isConst()) { dsym.storage_class |= STC.const_; if (dsym.type.isShared()) dsym.storage_class |= STC.shared_; } else if (dsym.type.isImmutable()) dsym.storage_class |= STC.immutable_; else if (dsym.type.isShared()) dsym.storage_class |= STC.shared_; else if (dsym.type.isWild()) dsym.storage_class |= STC.wild; if (StorageClass stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_)) { if (stc == STC.final_) dsym.error("cannot be `final`, perhaps you meant `const`?"); else { OutBuffer buf; stcToBuffer(&buf, stc); dsym.error("cannot be `%s`", buf.peekString()); } dsym.storage_class &= ~stc; // strip off } if (dsym.storage_class & STC.scope_) { StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.tls | STC.gshared); if (stc) { OutBuffer buf; stcToBuffer(&buf, stc); dsym.error("cannot be `scope` and `%s`", buf.peekString()); } else if (dsym.isMember()) { dsym.error("field cannot be `scope`"); } else if (!dsym.type.hasPointers()) { dsym.storage_class &= ~STC.scope_; // silently ignore; may occur in generic code } } if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe)) { } else { AggregateDeclaration aad = parent.isAggregateDeclaration(); if (aad) { if (global.params.vfield && dsym.storage_class & (STC.const_ | STC.immutable_) && dsym._init && !dsym._init.isVoidInitializer()) { const(char)* s = (dsym.storage_class & STC.immutable_) ? "immutable" : "const"; message(dsym.loc, "`%s.%s` is `%s` field", ad.toPrettyChars(), dsym.toChars(), s); } dsym.storage_class |= STC.field; if (tbn.ty == Tstruct && (cast(TypeStruct)tbn).sym.noDefaultCtor) { if (!dsym.isThisDeclaration() && !dsym._init) aad.noDefaultCtor = true; } } InterfaceDeclaration id = parent.isInterfaceDeclaration(); if (id) { dsym.error("field not allowed in interface"); } else if (aad && aad.sizeok == Sizeok.done) { dsym.error("cannot be further field because it will change the determined %s size", aad.toChars()); } /* Templates cannot add fields to aggregates */ TemplateInstance ti = parent.isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template AggregateDeclaration ad2 = ti.tempdecl.isMember(); if (ad2 && dsym.storage_class != STC.undefined_) { dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars()); } } } if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This) { dsym.error("only parameters or `foreach` declarations can be `ref`"); } if (dsym.type.hasWild()) { if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) { dsym.error("only parameters or stack based variables can be `inout`"); } FuncDeclaration func = sc.func; if (func) { if (func.fes) func = func.fes.func; bool isWild = false; for (FuncDeclaration fd = func; fd; fd = fd.toParent2().isFuncDeclaration()) { if ((cast(TypeFunction)fd.type).iswild) { isWild = true; break; } } if (!isWild) { dsym.error("`inout` variables can only be declared inside `inout` functions"); } } } if (!(dsym.storage_class & (STC.ctfe | STC.ref_ | STC.result)) && tbn.ty == Tstruct && (cast(TypeStruct)tbn).sym.noDefaultCtor) { if (!dsym._init) { if (dsym.isField()) { /* For fields, we'll check the constructor later to make sure it is initialized */ dsym.storage_class |= STC.nodefaultctor; } else if (dsym.storage_class & STC.parameter) { } else dsym.error("default construction is disabled for type `%s`", dsym.type.toChars()); } } FuncDeclaration fd = parent.isFuncDeclaration(); if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor)) { if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.tls | STC.gshared) || !fd) { dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`"); } if (!(dsym.storage_class & STC.scope_)) { if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym) dsym.error("reference to `scope class` must be `scope`"); } } // Calculate type size + safety checks if (sc.func && !sc.intypeof) { if (dsym._init && dsym._init.isVoidInitializer() && dsym.type.hasPointers()) // get type size { if (sc.func.setUnsafe()) dsym.error("`void` initializers for pointers not allowed in safe functions"); } else if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field | STC.parameter)) && dsym.type.hasVoidInitPointers()) { if (sc.func.setUnsafe()) dsym.error("`void` initializers for pointers not allowed in safe functions"); } } if ((!dsym._init || dsym._init.isVoidInitializer) && !fd) { // If not mutable, initializable by constructor only dsym.storage_class |= STC.ctorinit; } if (dsym._init) dsym.storage_class |= STC.init; // remember we had an explicit initializer else if (dsym.storage_class & STC.manifest) dsym.error("manifest constants must have initializers"); bool isBlit = false; d_uns64 sz; if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.gshared | STC.extern_)) && fd && (!(dsym.storage_class & (STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) || (dsym.storage_class & STC.out_)) && (sz = dsym.type.size()) != 0) { // Provide a default initializer //printf("Providing default initializer for '%s'\n", toChars()); if (sz == SIZE_INVALID && dsym.type.ty != Terror) dsym.error("size of type `%s` is invalid", dsym.type.toChars()); Type tv = dsym.type; while (tv.ty == Tsarray) // Don't skip Tenum tv = tv.nextOf(); if (tv.needsNested()) { /* Nested struct requires valid enclosing frame pointer. * In StructLiteralExp::toElem(), it's calculated. */ assert(tbn.ty == Tstruct); checkFrameAccess(dsym.loc, sc, (cast(TypeStruct)tbn).sym); Expression e = tv.defaultInitLiteral(dsym.loc); e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); e = e.expressionSemantic(sc); dsym._init = new ExpInitializer(dsym.loc, e); goto Ldtor; } if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.zeroInit) { /* If a struct is all zeros, as a special case * set it's initializer to the integer 0. * In AssignExp::toElem(), we check for this and issue * a memset() to initialize the struct. * Must do same check in interpreter. */ Expression e = new IntegerExp(dsym.loc, 0, Type.tint32); e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e); e.type = dsym.type; // don't type check this, it would fail dsym._init = new ExpInitializer(dsym.loc, e); goto Ldtor; } if (dsym.type.baseElemOf().ty == Tvoid) { dsym.error("`%s` does not have a default initializer", dsym.type.toChars()); } else if (auto e = dsym.type.defaultInit(dsym.loc)) { dsym._init = new ExpInitializer(dsym.loc, e); } // Default initializer is always a blit isBlit = true; } if (dsym._init) { sc = sc.push(); sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable); ExpInitializer ei = dsym._init.isExpInitializer(); if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424 // Preset the required type to fail in FuncLiteralDeclaration::semantic3 ei.exp = inferType(ei.exp, dsym.type); // If inside function, there is no semantic3() call if (sc.func || sc.intypeof == 1) { // If local variable, use AssignExp to handle all the various // possibilities. if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.tls | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer()) { //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars()); if (!ei) { ArrayInitializer ai = dsym._init.isArrayInitializer(); Expression e; if (ai && tb.ty == Taarray) e = ai.toAssocArrayLiteral(); else e = dsym._init.initializerToExpression(); if (!e) { // Run semantic, but don't need to interpret dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret); e = dsym._init.initializerToExpression(); if (!e) { dsym.error("is not a static and cannot have static initializer"); e = new ErrorExp(); } } ei = new ExpInitializer(dsym._init.loc, e); dsym._init = ei; } Expression exp = ei.exp; Expression e1 = new VarExp(dsym.loc, dsym); if (isBlit) exp = new BlitExp(dsym.loc, e1, exp); else exp = new ConstructExp(dsym.loc, e1, exp); dsym.canassign++; exp = exp.expressionSemantic(sc); dsym.canassign--; exp = exp.optimize(WANTvalue); if (exp.op == TOK.error) { dsym._init = new ErrorInitializer(); ei = null; } else ei.exp = exp; if (ei && dsym.isScope()) { Expression ex = ei.exp; while (ex.op == TOK.comma) ex = (cast(CommaExp)ex).e2; if (ex.op == TOK.blit || ex.op == TOK.construct) ex = (cast(AssignExp)ex).e2; if (ex.op == TOK.new_) { // See if initializer is a NewExp that can be allocated on the stack NewExp ne = cast(NewExp)ex; if (dsym.type.toBasetype().ty == Tclass) { if (ne.newargs && ne.newargs.dim > 1) { dsym.mynew = true; } else { ne.onstack = 1; dsym.onstack = true; } } } else if (ex.op == TOK.function_) { // or a delegate that doesn't escape a reference to the function FuncDeclaration f = (cast(FuncExp)ex).fd; f.tookAddressOf--; } } } else { // https://issues.dlang.org/show_bug.cgi?id=14166 // Don't run CTFE for the temporary variables inside typeof dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); const init_err = dsym._init.isExpInitializer(); if (init_err && init_err.exp.op == TOK.showCtfeContext) { errorSupplemental(dsym.loc, "compile time context created here"); } } } else if (parent.isAggregateDeclaration()) { dsym._scope = scx ? scx : sc.copy(); dsym._scope.setNoFree(); } else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) || dsym.type.isConst() || dsym.type.isImmutable()) { /* Because we may need the results of a const declaration in a * subsequent type, such as an array dimension, before semantic2() * gets ordinarily run, try to run semantic2() now. * Ignore failure. */ if (!inferred) { uint errors = global.errors; dsym.inuse++; if (ei) { Expression exp = ei.exp.syntaxCopy(); bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest); if (needctfe) sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); exp = resolveProperties(sc, exp); if (needctfe) sc = sc.endCTFE(); Type tb2 = dsym.type.toBasetype(); Type ti = exp.type.toBasetype(); /* The problem is the following code: * struct CopyTest { * double x; * this(double a) { x = a * 10.0;} * this(this) { x += 2.0; } * } * const CopyTest z = CopyTest(5.3); // ok * const CopyTest w = z; // not ok, postblit not run * static assert(w.x == 55.0); * because the postblit doesn't get run on the initialization of w. */ if (ti.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)ti).sym; /* Look to see if initializer involves a copy constructor * (which implies a postblit) */ // there is a copy constructor // and exp is the same struct if (sd.postblit && tb2.toDsymbol(null) == sd) { // The only allowable initializer is a (non-copy) constructor if (exp.isLvalue()) dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars()); } } ei.exp = exp; } dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret); dsym.inuse--; if (global.errors > errors) { dsym._init = new ErrorInitializer(); dsym.type = Type.terror; } } else { dsym._scope = scx ? scx : sc.copy(); dsym._scope.setNoFree(); } } sc = sc.pop(); } Ldtor: /* Build code to execute destruction, if necessary */ dsym.edtor = dsym.callScopeDtor(sc); if (dsym.edtor) { /* If dsym is a local variable, who's type is a struct with a scope destructor, * then make dsym scope, too. */ if (global.params.vsafe && !(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) && !dsym.isDataseg() && !dsym.doNotInferScope && dsym.type.hasPointers()) { auto tv = dsym.type.baseElemOf(); if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.dtor.storage_class & STC.scope_) { dsym.storage_class |= STC.scope_; } } if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared)) dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope); else dsym.edtor = dsym.edtor.expressionSemantic(sc); version (none) { // currently disabled because of std.stdio.stdin, stdout and stderr if (dsym.isDataseg() && !(dsym.storage_class & STC.extern_)) dsym.error("static storage variables cannot have destructors"); } } dsym.semanticRun = PASS.semanticdone; if (dsym.type.toBasetype().ty == Terror) dsym.errors = true; if(sc.scopesym && !sc.scopesym.isAggregateDeclaration()) { for (ScopeDsymbol sym = sc.scopesym; sym && dsym.endlinnum == 0; sym = sym.parent ? sym.parent.isScopeDsymbol() : null) dsym.endlinnum = sym.endlinnum; } } override void visit(TypeInfoDeclaration dsym) { assert(dsym.linkage == LINK.c); } override void visit(Import imp) { //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); if (imp.semanticRun > PASS.init) return; if (imp._scope) { sc = imp._scope; imp._scope = null; } if (!sc) return; imp.semanticRun = PASS.semantic; // Load if not already done so bool loadErrored = false; if (!imp.mod) { loadErrored = imp.load(sc); if (imp.mod) imp.mod.importAll(null); } if (imp.mod) { // Modules need a list of each imported module //printf("%s imports %s\n", sc._module.toChars(), imp.mod.toChars()); sc._module.aimports.push(imp.mod); if (sc.explicitProtection) imp.protection = sc.protection; if (!imp.aliasId && !imp.names.dim) // neither a selective nor a renamed import { ScopeDsymbol scopesym; for (Scope* scd = sc; scd; scd = scd.enclosing) { if (!scd.scopesym) continue; scopesym = scd.scopesym; break; } if (!imp.isstatic) { scopesym.importScope(imp.mod, imp.protection); } // Mark the imported packages as accessible from the current // scope. This access check is necessary when using FQN b/c // we're using a single global package tree. // https://issues.dlang.org/show_bug.cgi?id=313 if (imp.packages) { // import a.b.c.d; auto p = imp.pkg; // a scopesym.addAccessiblePackage(p, imp.protection); foreach (id; (*imp.packages)[1 .. imp.packages.dim]) // [b, c] { p = cast(Package) p.symtab.lookup(id); scopesym.addAccessiblePackage(p, imp.protection); } } scopesym.addAccessiblePackage(imp.mod, imp.protection); // d } if (!loadErrored) { imp.mod.dsymbolSemantic(null); } if (imp.mod.needmoduleinfo) { //printf("module4 %s because of %s\n", sc.module.toChars(), mod.toChars()); sc._module.needmoduleinfo = 1; } sc = sc.push(imp.mod); sc.protection = imp.protection; for (size_t i = 0; i < imp.aliasdecls.dim; i++) { AliasDeclaration ad = imp.aliasdecls[i]; //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); Dsymbol sym = imp.mod.search(imp.loc, imp.names[i] /*, IgnorePrivateImports */); if (sym) { // Deprecated in 2018-01. // Change to error in 2019-01 by deleteting the following 5 lines and uncommenting // the IgnorePrivateImports parameter from above. // @@@DEPRECATED_2019-01@@@. Dsymbol s = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); if (!s) .deprecation(imp.loc, "Symbol `%s` is not visible from module `%s` because it is privately imported in module `%s`", sym.toPrettyChars, sc._module.toChars(), imp.mod.toChars()); // Deprecated in 2018-01. // Change to error in 2019-01. // @@@DEPRECATED_2019-01@@@. import dmd.access : symbolIsVisible; if (!symbolIsVisible(sc, sym)) imp.mod.deprecation(imp.loc, "member `%s` is not visible from module `%s`", imp.names[i].toChars(), sc._module.toChars()); ad.dsymbolSemantic(sc); // If the import declaration is in non-root module, // analysis of the aliased symbol is deferred. // Therefore, don't see the ad.aliassym or ad.type here. } else { Dsymbol s = imp.mod.search_correct(imp.names[i]); if (s) imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars()); else imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars()); ad.type = Type.terror; } } sc = sc.pop(); } imp.semanticRun = PASS.semanticdone; // object self-imports itself, so skip that // https://issues.dlang.org/show_bug.cgi?id=7547 // don't list pseudo modules __entrypoint.d, __main.d // https://issues.dlang.org/show_bug.cgi?id=11117 // https://issues.dlang.org/show_bug.cgi?id=11164 if (global.params.moduleDeps !is null && !(imp.id == Id.object && sc._module.ident == Id.object) && sc._module.ident != Id.entrypoint && strcmp(sc._module.ident.toChars(), "__main") != 0) { /* The grammar of the file is: * ImportDeclaration * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " * ModuleAliasIdentifier ] "\n" * * BasicImportDeclaration * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" * * FilePath * - any string with '(', ')' and '\' escaped with the '\' character */ OutBuffer* ob = global.params.moduleDeps; Module imod = sc.instantiatingModule(); if (!global.params.moduleDepsFile) ob.writestring("depsImport "); ob.writestring(imod.toPrettyChars()); ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); // use protection instead of sc.protection because it couldn't be // resolved yet, see the comment above protectionToBuffer(ob, imp.protection); ob.writeByte(' '); if (imp.isstatic) { stcToBuffer(ob, STC.static_); ob.writeByte(' '); } ob.writestring(": "); if (imp.packages) { for (size_t i = 0; i < imp.packages.dim; i++) { Identifier pid = (*imp.packages)[i]; ob.printf("%s.", pid.toChars()); } } ob.writestring(imp.id.toChars()); ob.writestring(" ("); if (imp.mod) escapePath(ob, imp.mod.srcfile.toChars()); else ob.writestring("???"); ob.writeByte(')'); foreach (i, name; imp.names) { if (i == 0) ob.writeByte(':'); else ob.writeByte(','); Identifier _alias = imp.aliases[i]; if (!_alias) { ob.printf("%s", name.toChars()); _alias = name; } else ob.printf("%s=%s", _alias.toChars(), name.toChars()); } if (imp.aliasId) ob.printf(" -> %s", imp.aliasId.toChars()); ob.writenl(); } //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); } void attribSemantic(AttribDeclaration ad) { if (ad.semanticRun != PASS.init) return; ad.semanticRun = PASS.semantic; Dsymbols* d = ad.include(sc); //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) { Scope* sc2 = ad.newScope(sc); bool errors; for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.dsymbolSemantic(sc2); errors |= s.errors; } ad.errors |= errors; if (sc2 != sc) sc2.pop(); } ad.semanticRun = PASS.semanticdone; } override void visit(AttribDeclaration atd) { attribSemantic(atd); } override void visit(AnonDeclaration scd) { //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); assert(sc.parent); auto p = sc.parent.pastMixin(); auto ad = p.isAggregateDeclaration(); if (!ad) { error(scd.loc, "%s can only be a part of an aggregate, not %s `%s`", scd.kind(), p.kind(), p.toChars()); scd.errors = true; return; } if (scd.decl) { sc = sc.push(); sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.gshared); sc.inunion = scd.isunion; sc.flags = 0; for (size_t i = 0; i < scd.decl.dim; i++) { Dsymbol s = (*scd.decl)[i]; s.dsymbolSemantic(sc); } sc = sc.pop(); } } override void visit(PragmaDeclaration pd) { // Should be merged with PragmaStatement //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars()); if (global.params.mscoff) { if (pd.ident == Id.linkerDirective) { if (!pd.args || pd.args.dim != 1) pd.error("one string argument expected for pragma(linkerDirective)"); else { auto se = semanticString(sc, (*pd.args)[0], "linker directive"); if (!se) goto Lnodecl; (*pd.args)[0] = se; if (global.params.verbose) message("linkopt %.*s", cast(int)se.len, se.string); } goto Lnodecl; } } if (pd.ident == Id.msg) { if (pd.args) { for (size_t i = 0; i < pd.args.dim; i++) { Expression e = (*pd.args)[i]; sc = sc.startCTFE(); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); // pragma(msg) is allowed to contain types as well as expressions if (e.type && e.type.ty == Tvoid) { error(pd.loc, "Cannot pass argument `%s` to `pragma msg` because it is `void`", e.toChars()); return; } e = ctfeInterpretForPragmaMsg(e); if (e.op == TOK.error) { errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); return; } StringExp se = e.toStringExp(); if (se) { se = se.toUTF8(sc); fprintf(stderr, "%.*s", cast(int)se.len, se.string); } else fprintf(stderr, "%s", e.toChars()); } fprintf(stderr, "\n"); } goto Lnodecl; } else if (pd.ident == Id.lib) { if (!pd.args || pd.args.dim != 1) pd.error("string expected for library name"); else { auto se = semanticString(sc, (*pd.args)[0], "library name"); if (!se) goto Lnodecl; (*pd.args)[0] = se; auto name = cast(char*)mem.xmalloc(se.len + 1); memcpy(name, se.string, se.len); name[se.len] = 0; if (global.params.verbose) message("library %s", name); if (global.params.moduleDeps && !global.params.moduleDepsFile) { OutBuffer* ob = global.params.moduleDeps; Module imod = sc.instantiatingModule(); ob.writestring("depsLib "); ob.writestring(imod.toPrettyChars()); ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); ob.writestring(name); ob.writenl(); } mem.xfree(name); } goto Lnodecl; } else if (pd.ident == Id.startaddress) { if (!pd.args || pd.args.dim != 1) pd.error("function name expected for start address"); else { /* https://issues.dlang.org/show_bug.cgi?id=11980 * resolveProperties and ctfeInterpret call are not necessary. */ Expression e = (*pd.args)[0]; sc = sc.startCTFE(); e = e.expressionSemantic(sc); sc = sc.endCTFE(); (*pd.args)[0] = e; Dsymbol sa = getDsymbol(e); if (!sa || !sa.isFuncDeclaration()) pd.error("function name expected for start address, not `%s`", e.toChars()); } goto Lnodecl; } else if (pd.ident == Id.Pinline) { goto Ldecl; } else if (pd.ident == Id.mangle) { if (!pd.args) pd.args = new Expressions(); if (pd.args.dim != 1) { pd.error("string expected for mangled name"); pd.args.setDim(1); (*pd.args)[0] = new ErrorExp(); // error recovery goto Ldecl; } auto se = semanticString(sc, (*pd.args)[0], "mangled name"); if (!se) goto Ldecl; (*pd.args)[0] = se; // Will be used later if (!se.len) { pd.error("zero-length string not allowed for mangled name"); goto Ldecl; } if (se.sz != 1) { pd.error("mangled name characters can only be of type `char`"); goto Ldecl; } version (all) { /* Note: D language specification should not have any assumption about backend * implementation. Ideally pragma(mangle) can accept a string of any content. * * Therefore, this validation is compiler implementation specific. */ for (size_t i = 0; i < se.len;) { char* p = se.string; dchar c = p[i]; if (c < 0x80) { if (c.isValidMangling) { ++i; continue; } else { pd.error("char 0x%02x not allowed in mangled name", c); break; } } if (const msg = utf_decodeChar(se.string, se.len, i, c)) { pd.error("%s", msg); break; } if (!isUniAlpha(c)) { pd.error("char `0x%04x` not allowed in mangled name", c); break; } } } } else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) { if (pd.args && pd.args.dim != 0) pd.error("takes no argument"); goto Ldecl; } else if (global.params.ignoreUnsupportedPragmas) { if (global.params.verbose) { /* Print unrecognized pragmas */ OutBuffer buf; buf.writestring(pd.ident.toChars()); if (pd.args) { for (size_t i = 0; i < pd.args.dim; i++) { Expression e = (*pd.args)[i]; sc = sc.startCTFE(); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); e = e.ctfeInterpret(); if (i == 0) buf.writestring(" ("); else buf.writeByte(','); buf.writestring(e.toChars()); } if (pd.args.dim) buf.writeByte(')'); } message("pragma %s", buf.peekString()); } goto Lnodecl; } else error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); Ldecl: if (pd.decl) { Scope* sc2 = pd.newScope(sc); for (size_t i = 0; i < pd.decl.dim; i++) { Dsymbol s = (*pd.decl)[i]; s.dsymbolSemantic(sc2); if (pd.ident == Id.mangle) { assert(pd.args && pd.args.dim == 1); if (auto se = (*pd.args)[0].toStringExp()) { char* name = cast(char*)mem.xmalloc(se.len + 1); memcpy(name, se.string, se.len); name[se.len] = 0; uint cnt = setMangleOverride(s, name[0 .. se.len]); if (cnt > 1) pd.error("can only apply to a single declaration"); } } } if (sc2 != sc) sc2.pop(); } return; Lnodecl: if (pd.decl) { pd.error("is missing a terminating `;`"); goto Ldecl; // do them anyway, to avoid segfaults. } } override void visit(StaticIfDeclaration sid) { attribSemantic(sid); } override void visit(StaticForeachDeclaration sfd) { attribSemantic(sfd); } private Dsymbols* compileIt(CompileDeclaration cd) { //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars()); OutBuffer buf; if (cd.exps) { foreach (ex; *cd.exps) { sc = sc.startCTFE(); auto e = ex.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); // allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); if (e.op == TOK.error) { //errorSupplemental(exp.loc, "while evaluating `mixin(%s)`", ex.toChars()); return null; } StringExp se = e.toStringExp(); if (se) { se = se.toUTF8(sc); buf.printf("%.*s", cast(int)se.len, se.string); } else buf.printf("%s", e.toChars()); } } const errors = global.errors; const len = buf.offset; const str = buf.extractString()[0 .. len]; scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); p.nextToken(); auto d = p.parseDeclDefs(0); if (p.errors) { assert(global.errors != errors); // should have caught all these cases return null; } if (p.token.value != TOK.endOfFile) { cd.error("incomplete mixin declaration `%s`", str.ptr); return null; } return d; } /*********************************************************** * https://dlang.org/spec/module.html#mixin-declaration */ override void visit(CompileDeclaration cd) { //printf("CompileDeclaration::semantic()\n"); if (!cd.compiled) { cd.decl = compileIt(cd); cd.AttribDeclaration.addMember(sc, cd.scopesym); cd.compiled = true; if (cd._scope && cd.decl) { for (size_t i = 0; i < cd.decl.dim; i++) { Dsymbol s = (*cd.decl)[i]; s.setScope(cd._scope); } } } attribSemantic(cd); } override void visit(UserAttributeDeclaration uad) { //printf("UserAttributeDeclaration::semantic() %p\n", this); if (uad.decl && !uad._scope) uad.Dsymbol.setScope(sc); // for function local symbols return attribSemantic(uad); } override void visit(StaticAssert sa) { if (sa.semanticRun < PASS.semanticdone) sa.semanticRun = PASS.semanticdone; } override void visit(DebugSymbol ds) { //printf("DebugSymbol::semantic() %s\n", toChars()); if (ds.semanticRun < PASS.semanticdone) ds.semanticRun = PASS.semanticdone; } override void visit(VersionSymbol vs) { if (vs.semanticRun < PASS.semanticdone) vs.semanticRun = PASS.semanticdone; } override void visit(Package pkg) { if (pkg.semanticRun < PASS.semanticdone) pkg.semanticRun = PASS.semanticdone; } override void visit(Module m) { if (m.semanticRun != PASS.init) return; //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); m.semanticRun = PASS.semantic; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope* sc = m._scope; // see if already got one from importAll() if (!sc) { Scope.createGlobal(m); // create root scope } //printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage); // Pass 1 semantic routines: do public side of the definition for (size_t i = 0; i < m.members.dim; i++) { Dsymbol s = (*m.members)[i]; //printf("\tModule('%s'): '%s'.dsymbolSemantic()\n", toChars(), s.toChars()); s.dsymbolSemantic(sc); m.runDeferredSemantic(); } if (m.userAttribDecl) { m.userAttribDecl.dsymbolSemantic(sc); } if (!m._scope) { sc = sc.pop(); sc.pop(); // 2 pops because Scope::createGlobal() created 2 } m.semanticRun = PASS.semanticdone; //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); } override void visit(EnumDeclaration ed) { //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), toChars()); //printf("EnumDeclaration::semantic() %p %s\n", this, toChars()); if (ed.semanticRun >= PASS.semanticdone) return; // semantic() already completed if (ed.semanticRun == PASS.semantic) { assert(ed.memtype); error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); ed.errors = true; ed.semanticRun = PASS.semanticdone; return; } uint dprogress_save = Module.dprogress; Scope* scx = null; if (ed._scope) { sc = ed._scope; scx = ed._scope; // save so we don't make redundant copies ed._scope = null; } if (!sc) return; ed.parent = sc.parent; ed.type = ed.type.typeSemantic(ed.loc, sc); ed.protection = sc.protection; if (sc.stc & STC.deprecated_) ed.isdeprecated = true; ed.userAttribDecl = sc.userAttribDecl; ed.semanticRun = PASS.semantic; if (!ed.members && !ed.memtype) // enum ident; { ed.semanticRun = PASS.semanticdone; return; } if (!ed.symtab) ed.symtab = new DsymbolTable(); /* The separate, and distinct, cases are: * 1. enum { ... } * 2. enum : memtype { ... } * 3. enum ident { ... } * 4. enum ident : memtype { ... } * 5. enum ident : memtype; * 6. enum ident; */ if (ed.memtype) { ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); /* Check to see if memtype is forward referenced */ if (ed.memtype.ty == Tenum) { EnumDeclaration sym = cast(EnumDeclaration)ed.memtype.toDsymbol(sc); if (!sym.memtype || !sym.members || !sym.symtab || sym._scope) { // memtype is forward referenced, so try again later ed._scope = scx ? scx : sc.copy(); ed._scope.setNoFree(); ed._scope._module.addDeferredSemantic(ed); Module.dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); ed.semanticRun = PASS.init; return; } } if (ed.memtype.ty == Tvoid) { ed.error("base type must not be `void`"); ed.memtype = Type.terror; } if (ed.memtype.ty == Terror) { ed.errors = true; if (ed.members) { for (size_t i = 0; i < ed.members.dim; i++) { Dsymbol s = (*ed.members)[i]; s.errors = true; // poison all the members } } ed.semanticRun = PASS.semanticdone; return; } } ed.semanticRun = PASS.semanticdone; if (!ed.members) // enum ident : memtype; return; if (ed.members.dim == 0) { ed.error("enum `%s` must have at least one member", ed.toChars()); ed.errors = true; return; } Module.dprogress++; Scope* sce; if (ed.isAnonymous()) sce = sc; else { sce = sc.push(ed); sce.parent = ed; } sce = sce.startCTFE(); sce.setNoFree(); // needed for getMaxMinValue() /* Each enum member gets the sce scope */ for (size_t i = 0; i < ed.members.dim; i++) { EnumMember em = (*ed.members)[i].isEnumMember(); if (em) em._scope = sce; } if (!ed.added) { /* addMember() is not called when the EnumDeclaration appears as a function statement, * so we have to do what addMember() does and install the enum members in the right symbol * table */ ScopeDsymbol scopesym = null; if (ed.isAnonymous()) { /* Anonymous enum members get added to enclosing scope. */ for (Scope* sct = sce; 1; sct = sct.enclosing) { assert(sct); if (sct.scopesym) { scopesym = sct.scopesym; if (!sct.scopesym.symtab) sct.scopesym.symtab = new DsymbolTable(); break; } } } else { // Otherwise enum members are in the EnumDeclaration's symbol table scopesym = ed; } for (size_t i = 0; i < ed.members.dim; i++) { EnumMember em = (*ed.members)[i].isEnumMember(); if (em) { em.ed = ed; em.addMember(sc, scopesym); } } } for (size_t i = 0; i < ed.members.dim; i++) { EnumMember em = (*ed.members)[i].isEnumMember(); if (em) em.dsymbolSemantic(em._scope); } //printf("defaultval = %lld\n", defaultval); //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); //printf("members = %s\n", members.toChars()); } override void visit(EnumMember em) { //printf("EnumMember::semantic() %s\n", toChars()); void errorReturn() { em.errors = true; em.semanticRun = PASS.semanticdone; } if (em.errors || em.semanticRun >= PASS.semanticdone) return; if (em.semanticRun == PASS.semantic) { em.error("circular reference to `enum` member"); return errorReturn(); } assert(em.ed); em.ed.dsymbolSemantic(sc); if (em.ed.errors) return errorReturn(); if (em.errors || em.semanticRun >= PASS.semanticdone) return; if (em._scope) sc = em._scope; if (!sc) return; em.semanticRun = PASS.semantic; em.protection = em.ed.isAnonymous() ? em.ed.protection : Prot(Prot.Kind.public_); em.linkage = LINK.d; em.storage_class |= STC.manifest; // https://issues.dlang.org/show_bug.cgi?id=9701 if (em.ed.isAnonymous()) { if (em.userAttribDecl) em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; else em.userAttribDecl = em.ed.userAttribDecl; } // The first enum member is special bool first = (em == (*em.ed.members)[0]); if (em.origType) { em.origType = em.origType.typeSemantic(em.loc, sc); em.type = em.origType; assert(em.value); // "type id;" is not a valid enum member declaration } if (em.value) { Expression e = em.value; assert(e.dyncast() == DYNCAST.expression); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); e = e.ctfeInterpret(); if (e.op == TOK.error) return errorReturn(); if (first && !em.ed.memtype && !em.ed.isAnonymous()) { em.ed.memtype = e.type; if (em.ed.memtype.ty == Terror) { em.ed.errors = true; return errorReturn(); } if (em.ed.memtype.ty != Terror) { /* https://issues.dlang.org/show_bug.cgi?id=11746 * All of named enum members should have same type * with the first member. If the following members were referenced * during the first member semantic, their types should be unified. */ for (size_t i = 0; i < em.ed.members.dim; i++) { EnumMember enm = (*em.ed.members)[i].isEnumMember(); if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) continue; //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); Expression ev = enm.value; ev = ev.implicitCastTo(sc, em.ed.memtype); ev = ev.ctfeInterpret(); ev = ev.castTo(sc, em.ed.type); if (ev.op == TOK.error) em.ed.errors = true; enm.value = ev; } if (em.ed.errors) { em.ed.memtype = Type.terror; return errorReturn(); } } } if (em.ed.memtype && !em.origType) { e = e.implicitCastTo(sc, em.ed.memtype); e = e.ctfeInterpret(); // save origValue for better json output em.origValue = e; if (!em.ed.isAnonymous()) { e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 e = e.ctfeInterpret(); } } else if (em.origType) { e = e.implicitCastTo(sc, em.origType); e = e.ctfeInterpret(); assert(em.ed.isAnonymous()); // save origValue for better json output em.origValue = e; } em.value = e; } else if (first) { Type t; if (em.ed.memtype) t = em.ed.memtype; else { t = Type.tint32; if (!em.ed.isAnonymous()) em.ed.memtype = t; } Expression e = new IntegerExp(em.loc, 0, t); e = e.ctfeInterpret(); // save origValue for better json output em.origValue = e; if (!em.ed.isAnonymous()) { e = e.castTo(sc, em.ed.type); e = e.ctfeInterpret(); } em.value = e; } else { /* Find the previous enum member, * and set this to be the previous value + 1 */ EnumMember emprev = null; for (size_t i = 0; i < em.ed.members.dim; i++) { EnumMember enm = (*em.ed.members)[i].isEnumMember(); if (enm) { if (enm == em) break; emprev = enm; } } assert(emprev); if (emprev.semanticRun < PASS.semanticdone) // if forward reference emprev.dsymbolSemantic(emprev._scope); // resolve it if (emprev.errors) return errorReturn(); Expression eprev = emprev.value; // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) ? em.ed.memtype : eprev.type; Expression emax = tprev.getProperty(em.ed.loc, Id.max, 0); emax = emax.expressionSemantic(sc); emax = emax.ctfeInterpret(); // Set value to (eprev + 1). // But first check that (eprev != emax) assert(eprev); Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax); e = e.expressionSemantic(sc); e = e.ctfeInterpret(); if (e.toInteger()) { em.error("initialization with `%s.%s+1` causes overflow for type `%s`", emprev.ed.toChars(), emprev.toChars(), em.ed.memtype.toChars()); return errorReturn(); } // Now set e to (eprev + 1) e = new AddExp(em.loc, eprev, new IntegerExp(em.loc, 1, Type.tint32)); e = e.expressionSemantic(sc); e = e.castTo(sc, eprev.type); e = e.ctfeInterpret(); // save origValue (without cast) for better json output if (e.op != TOK.error) // avoid duplicate diagnostics { assert(emprev.origValue); em.origValue = new AddExp(em.loc, emprev.origValue, new IntegerExp(em.loc, 1, Type.tint32)); em.origValue = em.origValue.expressionSemantic(sc); em.origValue = em.origValue.ctfeInterpret(); } if (e.op == TOK.error) return errorReturn(); if (e.type.isfloating()) { // Check that e != eprev (not always true for floats) Expression etest = new EqualExp(TOK.equal, em.loc, e, eprev); etest = etest.expressionSemantic(sc); etest = etest.ctfeInterpret(); if (etest.toInteger()) { em.error("has inexact value due to loss of precision"); return errorReturn(); } } em.value = e; } if (!em.origType) em.type = em.value.type; assert(em.origValue); em.semanticRun = PASS.semanticdone; } override void visit(TemplateDeclaration tempdecl) { static if (LOG) { printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); printf("sc.stc = %llx\n", sc.stc); printf("sc.module = %s\n", sc._module.toChars()); } if (tempdecl.semanticRun != PASS.init) return; // semantic() already run if (tempdecl._scope) { sc = tempdecl._scope; tempdecl._scope = null; } if (!sc) return; // Remember templates defined in module object that we need to know about if (sc._module && sc._module.ident == Id.object) { if (tempdecl.ident == Id.RTInfo) Type.rtinfo = tempdecl; } /* Remember Scope for later instantiations, but make * a copy since attributes can change. */ if (!tempdecl._scope) { tempdecl._scope = sc.copy(); tempdecl._scope.setNoFree(); } tempdecl.semanticRun = PASS.semantic; tempdecl.parent = sc.parent; tempdecl.protection = sc.protection; tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); if (!tempdecl.isstatic) { if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) ad.makeNested(); } // Set up scope for parameters auto paramsym = new ScopeDsymbol(); paramsym.parent = tempdecl.parent; Scope* paramscope = sc.push(paramsym); paramscope.stc = 0; if (global.params.doDocComments) { tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.dim); for (size_t i = 0; i < tempdecl.parameters.dim; i++) { TemplateParameter tp = (*tempdecl.parameters)[i]; (*tempdecl.origParameters)[i] = tp.syntaxCopy(); } } for (size_t i = 0; i < tempdecl.parameters.dim; i++) { TemplateParameter tp = (*tempdecl.parameters)[i]; if (!tp.declareParameter(paramscope)) { error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); tempdecl.errors = true; } if (!tp.tpsemantic(paramscope, tempdecl.parameters)) { tempdecl.errors = true; } if (i + 1 != tempdecl.parameters.dim && tp.isTemplateTupleParameter()) { tempdecl.error("template tuple parameter must be last one"); tempdecl.errors = true; } } /* Calculate TemplateParameter.dependent */ TemplateParameters tparams = TemplateParameters(1); for (size_t i = 0; i < tempdecl.parameters.dim; i++) { TemplateParameter tp = (*tempdecl.parameters)[i]; tparams[0] = tp; for (size_t j = 0; j < tempdecl.parameters.dim; j++) { // Skip cases like: X(T : T) if (i == j) continue; if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) { if (reliesOnTident(ttp.specType, &tparams)) tp.dependent = true; } else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) { if (reliesOnTident(tap.specType, &tparams) || reliesOnTident(isType(tap.specAlias), &tparams)) { tp.dependent = true; } } } } paramscope.pop(); // Compute again tempdecl.onemember = null; if (tempdecl.members) { Dsymbol s; if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s) { tempdecl.onemember = s; s.parent = tempdecl; } } /* BUG: should check: * o no virtual functions or non-static data members of classes */ tempdecl.semanticRun = PASS.semanticdone; } override void visit(TemplateInstance ti) { templateInstanceSemantic(ti, sc, null); } override void visit(TemplateMixin tm) { static if (LOG) { printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n",tm.toChars(), tm); fflush(stdout); } if (tm.semanticRun != PASS.init) { // When a class/struct contains mixin members, and is done over // because of forward references, never reach here so semanticRun // has been reset to PASS.init. static if (LOG) { printf("\tsemantic done\n"); } return; } tm.semanticRun = PASS.semantic; static if (LOG) { printf("\tdo semantic\n"); } Scope* scx = null; if (tm._scope) { sc = tm._scope; scx = tm._scope; // save so we don't make redundant copies tm._scope = null; } /* Run semantic on each argument, place results in tiargs[], * then find best match template with tiargs */ if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null)) { if (tm.semanticRun == PASS.init) // forward reference had occurred { //printf("forward reference - deferring\n"); tm._scope = scx ? scx : sc.copy(); tm._scope.setNoFree(); tm._scope._module.addDeferredSemantic(tm); return; } tm.inst = tm; tm.errors = true; return; // error recovery } auto tempdecl = tm.tempdecl.isTemplateDeclaration(); assert(tempdecl); if (!tm.ident) { /* Assign scope local unique identifier, as same as lambdas. */ const(char)* s = "__mixin"; if (FuncDeclaration func = sc.parent.isFuncDeclaration()) { tm.symtab = func.localsymtab; if (tm.symtab) { // Inside template constraint, symtab is not set yet. goto L1; } } else { tm.symtab = sc.parent.isScopeDsymbol().symtab; L1: assert(tm.symtab); tm.ident = Identifier.generateId(s, tm.symtab.len + 1); tm.symtab.insert(tm); } } tm.inst = tm; tm.parent = sc.parent; /* Detect recursive mixin instantiations. */ for (Dsymbol s = tm.parent; s; s = s.parent) { //printf("\ts = '%s'\n", s.toChars()); TemplateMixin tmix = s.isTemplateMixin(); if (!tmix || tempdecl != tmix.tempdecl) continue; /* Different argument list lengths happen with variadic args */ if (tm.tiargs.dim != tmix.tiargs.dim) continue; for (size_t i = 0; i < tm.tiargs.dim; i++) { RootObject o = (*tm.tiargs)[i]; Type ta = isType(o); Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); RootObject tmo = (*tmix.tiargs)[i]; if (ta) { Type tmta = isType(tmo); if (!tmta) goto Lcontinue; if (!ta.equals(tmta)) goto Lcontinue; } else if (ea) { Expression tme = isExpression(tmo); if (!tme || !ea.equals(tme)) goto Lcontinue; } else if (sa) { Dsymbol tmsa = isDsymbol(tmo); if (sa != tmsa) goto Lcontinue; } else assert(0); } tm.error("recursive mixin instantiation"); return; Lcontinue: continue; } // Copy the syntax trees from the TemplateDeclaration tm.members = Dsymbol.arraySyntaxCopy(tempdecl.members); if (!tm.members) return; tm.symtab = new DsymbolTable(); for (Scope* sce = sc; 1; sce = sce.enclosing) { ScopeDsymbol sds = sce.scopesym; if (sds) { sds.importScope(tm, Prot(Prot.Kind.public_)); break; } } static if (LOG) { printf("\tcreate scope for template parameters '%s'\n", tm.toChars()); } Scope* scy = sc.push(tm); scy.parent = tm; tm.argsym = new ScopeDsymbol(); tm.argsym.parent = scy.parent; Scope* argscope = scy.push(tm.argsym); uint errorsave = global.errors; // Declare each template parameter as an alias for the argument type tm.declareParameters(argscope); // Add members to enclosing scope, as well as this scope for (size_t i = 0; i < tm.members.dim; i++) { Dsymbol s = (*tm.members)[i]; s.addMember(argscope, tm); //printf("sc.parent = %p, sc.scopesym = %p\n", sc.parent, sc.scopesym); //printf("s.parent = %s\n", s.parent.toChars()); } // Do semantic() analysis on template instance members static if (LOG) { printf("\tdo semantic() on template instance members '%s'\n", tm.toChars()); } Scope* sc2 = argscope.push(tm); //size_t deferred_dim = Module.deferred.dim; __gshared int nest; //printf("%d\n", nest); if (++nest > 500) { global.gag = 0; // ensure error message gets printed tm.error("recursive expansion"); fatal(); } for (size_t i = 0; i < tm.members.dim; i++) { Dsymbol s = (*tm.members)[i]; s.setScope(sc2); } for (size_t i = 0; i < tm.members.dim; i++) { Dsymbol s = (*tm.members)[i]; s.importAll(sc2); } for (size_t i = 0; i < tm.members.dim; i++) { Dsymbol s = (*tm.members)[i]; s.dsymbolSemantic(sc2); } nest--; /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. * Because the members would already call Module.addDeferredSemantic() for themselves. * See Struct, Class, Interface, and EnumDeclaration.dsymbolSemantic(). */ //if (!sc.func && Module.deferred.dim > deferred_dim) {} AggregateDeclaration ad = tm.toParent().isAggregateDeclaration(); if (sc.func && !ad) { tm.semantic2(sc2); tm.semantic3(sc2); } // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { tm.error("error instantiating"); tm.errors = true; } sc2.pop(); argscope.pop(); scy.pop(); static if (LOG) { printf("-TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); } } override void visit(Nspace ns) { if (ns.semanticRun != PASS.init) return; static if (LOG) { printf("+Nspace::semantic('%s')\n", ns.toChars()); } if (ns._scope) { sc = ns._scope; ns._scope = null; } if (!sc) return; ns.semanticRun = PASS.semantic; ns.parent = sc.parent; if (ns.members) { assert(sc); sc = sc.push(ns); sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage sc.parent = ns; foreach (s; *ns.members) { s.importAll(sc); } foreach (s; *ns.members) { static if (LOG) { printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); } s.dsymbolSemantic(sc); } sc.pop(); } ns.semanticRun = PASS.semanticdone; static if (LOG) { printf("-Nspace::semantic('%s')\n", ns.toChars()); } } void funcDeclarationSemantic(FuncDeclaration funcdecl) { TypeFunction f; AggregateDeclaration ad; InterfaceDeclaration id; version (none) { printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); if (funcdecl.isFuncLiteralDeclaration()) printf("\tFuncLiteralDeclaration()\n"); printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); } if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration()) { /* Member functions that have return types that are * forward references can have semantic() run more than * once on them. * See test\interface2.d, test20 */ return; } if (funcdecl.semanticRun >= PASS.semanticdone) return; assert(funcdecl.semanticRun <= PASS.semantic); funcdecl.semanticRun = PASS.semantic; if (funcdecl._scope) { sc = funcdecl._scope; funcdecl._scope = null; } if (!sc || funcdecl.errors) return; funcdecl.parent = sc.parent; Dsymbol parent = funcdecl.toParent(); funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function funcdecl.storage_class |= sc.stc & ~STC.ref_; ad = funcdecl.isThis(); // Don't nest structs b/c of generated methods which should not access the outer scopes. // https://issues.dlang.org/show_bug.cgi?id=16627 if (ad && !funcdecl.generated) { funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); ad.makeNested(); } if (sc.func) funcdecl.storage_class |= sc.func.storage_class & STC.disable; // Remove prefix storage classes silently. if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) funcdecl.storage_class &= ~STC.TYPECTOR; //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration::isFinal()); if (sc.flags & SCOPE.compile) funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function FuncLiteralDeclaration fld = funcdecl.isFuncLiteralDeclaration(); if (fld && fld.treq) { Type treq = fld.treq; assert(treq.nextOf().ty == Tfunction); if (treq.ty == Tdelegate) fld.tok = TOK.delegate_; else if (treq.ty == Tpointer && treq.nextOf().ty == Tfunction) fld.tok = TOK.function_; else assert(0); funcdecl.linkage = treq.nextOf().toTypeFunction().linkage; } else funcdecl.linkage = sc.linkage; funcdecl.inlining = sc.inlining; funcdecl.protection = sc.protection; funcdecl.userAttribDecl = sc.userAttribDecl; if (!funcdecl.originalType) funcdecl.originalType = funcdecl.type.syntaxCopy(); if (funcdecl.type.ty != Tfunction) { if (funcdecl.type.ty != Terror) { funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars()); funcdecl.type = Type.terror; } funcdecl.errors = true; return; } if (!funcdecl.type.deco) { sc = sc.push(); sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type TypeFunction tf = funcdecl.type.toTypeFunction(); if (sc.func) { /* If the nesting parent is pure without inference, * then this function defaults to pure too. * * auto foo() pure { * auto bar() {} // become a weak purity function * class C { // nested class * auto baz() {} // become a weak purity function * } * * static auto boo() {} // typed as impure * // Even though, boo cannot call any impure functions. * // See also Expression::checkPurity(). * } */ if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) { FuncDeclaration fd = null; for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) { if (AggregateDeclaration adx = p.isAggregateDeclaration()) { if (adx.isNested()) continue; break; } if ((fd = p.isFuncDeclaration()) !is null) break; } /* If the parent's purity is inferred, then this function's purity needs * to be inferred first. */ if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) { tf.purity = PURE.fwdref; // default to pure } } } if (tf.isref) sc.stc |= STC.ref_; if (tf.isscope) sc.stc |= STC.scope_; if (tf.isnothrow) sc.stc |= STC.nothrow_; if (tf.isnogc) sc.stc |= STC.nogc; if (tf.isproperty) sc.stc |= STC.property; if (tf.purity == PURE.fwdref) sc.stc |= STC.pure_; if (tf.trust != TRUST.default_) sc.stc &= ~(STC.safe | STC.system | STC.trusted); if (tf.trust == TRUST.safe) sc.stc |= STC.safe; if (tf.trust == TRUST.system) sc.stc |= STC.system; if (tf.trust == TRUST.trusted) sc.stc |= STC.trusted; if (funcdecl.isCtorDeclaration()) { sc.flags |= SCOPE.ctor; Type tret = ad.handleType(); assert(tret); tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); tret = tret.addMod(funcdecl.type.mod); tf.next = tret; if (ad.isStructDeclaration()) sc.stc |= STC.ref_; } // 'return' on a non-static class member function implies 'scope' as well if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) sc.stc |= STC.scope_; // If 'this' has no pointers, remove 'scope' as it has no meaning if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) { sc.stc &= ~STC.scope_; tf.isscope = false; } sc.linkage = funcdecl.linkage; if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { OutBuffer buf; MODtoBuffer(&buf, tf.mod); funcdecl.error("without `this` cannot be `%s`", buf.peekString()); tf.mod = 0; // remove qualifiers } /* Apply const, immutable, wild and shared storage class * to the function type. Do this before type semantic. */ auto stc = funcdecl.storage_class; if (funcdecl.type.isImmutable()) stc |= STC.immutable_; if (funcdecl.type.isConst()) stc |= STC.const_; if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) stc |= STC.shared_; if (funcdecl.type.isWild()) stc |= STC.wild; funcdecl.type = funcdecl.type.addSTC(stc); funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); sc = sc.pop(); } if (funcdecl.type.ty != Tfunction) { if (funcdecl.type.ty != Terror) { funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars()); funcdecl.type = Type.terror; } funcdecl.errors = true; return; } else { // Merge back function attributes into 'originalType'. // It's used for mangling, ddoc, and json output. TypeFunction tfo = funcdecl.originalType.toTypeFunction(); TypeFunction tfx = funcdecl.type.toTypeFunction(); tfo.mod = tfx.mod; tfo.isscope = tfx.isscope; tfo.isscopeinferred = tfx.isscopeinferred; tfo.isref = tfx.isref; tfo.isnothrow = tfx.isnothrow; tfo.isnogc = tfx.isnogc; tfo.isproperty = tfx.isproperty; tfo.purity = tfx.purity; tfo.trust = tfx.trust; funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); } f = cast(TypeFunction)funcdecl.type; if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) funcdecl.error("storage class `auto` has no effect if return type is not inferred"); /* Functions can only be 'scope' if they have a 'this' */ if (f.isscope && !funcdecl.isNested() && !ad) { funcdecl.error("functions cannot be `scope`"); } if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) { /* Non-static nested functions have a hidden 'this' pointer to which * the 'return' applies */ funcdecl.error("`static` member has no `this` to which `return` can apply"); } if (funcdecl.isAbstract() && !funcdecl.isVirtual()) { const(char)* sfunc; if (funcdecl.isStatic()) sfunc = "static"; else if (funcdecl.protection.kind == Prot.Kind.private_ || funcdecl.protection.kind == Prot.Kind.package_) sfunc = protectionToChars(funcdecl.protection.kind); else sfunc = "final"; funcdecl.error("`%s` functions cannot be `abstract`", sfunc); } if (funcdecl.isOverride() && !funcdecl.isVirtual()) { Prot.Kind kind = funcdecl.prot().kind; if ((kind == Prot.Kind.private_ || kind == Prot.Kind.package_) && funcdecl.isMember()) funcdecl.error("`%s` method is not virtual and cannot override", protectionToChars(kind)); else funcdecl.error("cannot override a non-virtual function"); } if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) funcdecl.error("cannot be both `final` and `abstract`"); version (none) { if (funcdecl.isAbstract() && funcdecl.fbody) funcdecl.error("`abstract` functions cannot have bodies"); } version (none) { if (funcdecl.isStaticConstructor() || funcdecl.isStaticDestructor()) { if (!funcdecl.isStatic() || funcdecl.type.nextOf().ty != Tvoid) funcdecl.error("static constructors / destructors must be `static void`"); if (f.arguments && f.arguments.dim) funcdecl.error("static constructors / destructors must have empty parameter list"); // BUG: check for invalid storage classes } } id = parent.isInterfaceDeclaration(); if (id) { funcdecl.storage_class |= STC.abstract_; if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) funcdecl.error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", id.toChars()); if (funcdecl.fbody && funcdecl.isVirtual()) funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars()); } if (UnionDeclaration ud = parent.isUnionDeclaration()) { if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) funcdecl.error("destructors, postblits and invariants are not allowed in union `%s`", ud.toChars()); } if (StructDeclaration sd = parent.isStructDeclaration()) { if (funcdecl.isCtorDeclaration()) { goto Ldone; } } if (ClassDeclaration cd = parent.isClassDeclaration()) { if (funcdecl.isCtorDeclaration()) { goto Ldone; } if (funcdecl.storage_class & STC.abstract_) cd.isabstract = Abstract.yes; // if static function, do not put in vtbl[] if (!funcdecl.isVirtual()) { //printf("\tnot virtual\n"); goto Ldone; } // Suppress further errors if the return type is an error if (funcdecl.type.nextOf() == Type.terror) goto Ldone; bool may_override = false; for (size_t i = 0; i < cd.baseclasses.dim; i++) { BaseClass* b = (*cd.baseclasses)[i]; ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); if (!cbd) continue; for (size_t j = 0; j < cbd.vtbl.dim; j++) { FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); if (!f2 || f2.ident != funcdecl.ident) continue; if (cbd.parent && cbd.parent.isTemplateInstance()) { if (!f2.functionSemantic()) goto Ldone; } may_override = true; } } if (may_override && funcdecl.type.nextOf() is null) { /* If same name function exists in base class but 'this' is auto return, * cannot find index of base class's vtbl[] to override. */ funcdecl.error("return type inference is not supported if may override base class function"); } /* Find index of existing function in base class's vtbl[] to override * (the index will be the same as in cd's current vtbl[]) */ int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.dim) : -1; bool doesoverride = false; switch (vi) { case -1: Lintro: /* Didn't find one, so * This is an 'introducing' function which gets a new * slot in the vtbl[]. */ // Verify this doesn't override previous final function if (cd.baseClass) { Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); if (s) { FuncDeclaration f2 = s.isFuncDeclaration(); if (f2) { f2 = f2.overloadExactMatch(funcdecl.type); if (f2 && f2.isFinalFunc() && f2.prot().kind != Prot.Kind.private_) funcdecl.error("cannot override `final` function `%s`", f2.toPrettyChars()); } } } /* These quirky conditions mimic what VC++ appears to do */ if (global.params.mscoff && cd.classKind == ClassKind.cpp && cd.baseClass && cd.baseClass.vtbl.dim) { /* if overriding an interface function, then this is not * introducing and don't put it in the class vtbl[] */ funcdecl.interfaceVirtual = funcdecl.overrideInterface(); if (funcdecl.interfaceVirtual) { //printf("\tinterface function %s\n", toChars()); cd.vtblFinal.push(funcdecl); goto Linterfaces; } } if (funcdecl.isFinalFunc()) { // Don't check here, as it may override an interface function //if (isOverride()) // error("is marked as override, but does not override any function"); cd.vtblFinal.push(funcdecl); } else { //printf("\tintroducing function %s\n", toChars()); funcdecl.introducing = 1; if (cd.classKind == ClassKind.cpp && Target.reverseCppOverloads) { // with dmc, overloaded functions are grouped and in reverse order funcdecl.vtblIndex = cast(int)cd.vtbl.dim; for (size_t i = 0; i < cd.vtbl.dim; i++) { if (cd.vtbl[i].ident == funcdecl.ident && cd.vtbl[i].parent == parent) { funcdecl.vtblIndex = cast(int)i; break; } } // shift all existing functions back for (size_t i = cd.vtbl.dim; i > funcdecl.vtblIndex; i--) { FuncDeclaration fd = cd.vtbl[i - 1].isFuncDeclaration(); assert(fd); fd.vtblIndex++; } cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); } else { // Append to end of vtbl[] vi = cast(int)cd.vtbl.dim; cd.vtbl.push(funcdecl); funcdecl.vtblIndex = vi; } } break; case -2: // can't determine because of forward references funcdecl.errors = true; return; default: { FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); // This function is covariant with fdv if (fdc == funcdecl) { doesoverride = true; break; } if (fdc.toParent() == parent) { //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); // fdc overrides fdv exactly, then this introduces new function. if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) goto Lintro; } if (fdv.isDeprecated) deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", funcdecl.toPrettyChars, fdv.toPrettyChars); // This function overrides fdv if (fdv.isFinalFunc()) funcdecl.error("cannot override `final` function `%s`", fdv.toPrettyChars()); if (!funcdecl.isOverride()) { if (fdv.isFuture()) { deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] goto Lintro; } else { int vi2 = funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.dim, false); if (vi2 < 0) // https://issues.dlang.org/show_bug.cgi?id=17349 deprecation(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", fdv.toPrettyChars(), funcdecl.toPrettyChars()); else error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", fdv.toPrettyChars(), funcdecl.toPrettyChars()); } } doesoverride = true; if (fdc.toParent() == parent) { // If both are mixins, or both are not, then error. // If either is not, the one that is not overrides the other. bool thismixin = funcdecl.parent.isClassDeclaration() !is null; bool fdcmixin = fdc.parent.isClassDeclaration() !is null; if (thismixin == fdcmixin) { funcdecl.error("multiple overrides of same function"); } else if (!thismixin) // fdc overrides fdv { // this doesn't override any function break; } } cd.vtbl[vi] = funcdecl; funcdecl.vtblIndex = vi; /* Remember which functions this overrides */ funcdecl.foverrides.push(fdv); /* This works by whenever this function is called, * it actually returns tintro, which gets dynamically * cast to type. But we know that tintro is a base * of type, so we could optimize it by not doing a * dynamic cast, but just subtracting the isBaseOf() * offset if the value is != null. */ if (fdv.tintro) funcdecl.tintro = fdv.tintro; else if (!funcdecl.type.equals(fdv.type)) { /* Only need to have a tintro if the vptr * offsets differ */ int offset; if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) { funcdecl.tintro = fdv.type; } } break; } } /* Go through all the interface bases. * If this function is covariant with any members of those interface * functions, set the tintro. */ Linterfaces: foreach (b; cd.interfaces) { vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); switch (vi) { case -1: break; case -2: // can't determine because of forward references funcdecl.errors = true; return; default: { auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; Type ti = null; /* Remember which functions this overrides */ funcdecl.foverrides.push(fdv); /* Should we really require 'override' when implementing * an interface function? */ //if (!isOverride()) // warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars()); if (fdv.tintro) ti = fdv.tintro; else if (!funcdecl.type.equals(fdv.type)) { /* Only need to have a tintro if the vptr * offsets differ */ int offset; if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) { ti = fdv.type; } } if (ti) { if (funcdecl.tintro) { if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) { funcdecl.error("incompatible covariant types `%s` and `%s`", funcdecl.tintro.toChars(), ti.toChars()); } } funcdecl.tintro = ti; } goto L2; } } } if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) { BaseClass* bc = null; Dsymbol s = null; for (size_t i = 0; i < cd.baseclasses.dim; i++) { bc = (*cd.baseclasses)[i]; s = bc.sym.search_correct(funcdecl.ident); if (s) break; } if (s) { HdrGenState hgs; OutBuffer buf; auto fd = s.isFuncDeclaration(); functionToBufferFull(cast(TypeFunction)(funcdecl.type), &buf, new Identifier(funcdecl.toPrettyChars()), &hgs, null); const(char)* funcdeclToChars = buf.peekString(); if (fd) { OutBuffer buf1; functionToBufferFull(cast(TypeFunction)(fd.type), &buf1, new Identifier(fd.toPrettyChars()), &hgs, null); error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", funcdeclToChars, buf1.peekString()); } else { error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", funcdeclToChars, s.kind, s.toPrettyChars()); errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overriden"); } } else funcdecl.error("does not override any function"); } L2: /* Go through all the interface bases. * Disallow overriding any final functions in the interface(s). */ foreach (b; cd.interfaces) { if (b.sym) { Dsymbol s = search_function(b.sym, funcdecl.ident); if (s) { FuncDeclaration f2 = s.isFuncDeclaration(); if (f2) { f2 = f2.overloadExactMatch(funcdecl.type); if (f2 && f2.isFinalFunc() && f2.prot().kind != Prot.Kind.private_) funcdecl.error("cannot override `final` function `%s.%s`", b.sym.toChars(), f2.toPrettyChars()); } } } } if (funcdecl.isOverride) { if (funcdecl.storage_class & STC.disable) deprecation(funcdecl.loc, "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", funcdecl.toPrettyChars); if (funcdecl.isDeprecated) deprecation(funcdecl.loc, "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", funcdecl.toPrettyChars); } } else if (funcdecl.isOverride() && !parent.isTemplateInstance()) funcdecl.error("`override` only applies to class member functions"); // Reflect this.type to f because it could be changed by findVtblIndex f = funcdecl.type.toTypeFunction(); Ldone: if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) funcdecl.error("`in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract"); /* Do not allow template instances to add virtual functions * to a class. */ if (funcdecl.isVirtual()) { TemplateInstance ti = parent.isTemplateInstance(); if (ti) { // Take care of nested templates while (1) { TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); if (!ti2) break; ti = ti2; } // If it's a member template ClassDeclaration cd = ti.tempdecl.isClassMember(); if (cd) { funcdecl.error("cannot use template to add virtual function to class `%s`", cd.toChars()); } } } if (funcdecl.isMain()) funcdecl.checkDmain(); // Check main() parameters and return type /* Purity and safety can be inferred for some functions by examining * the function body. */ if (funcdecl.canInferAttributes(sc)) funcdecl.initInferAttributes(); Module.dprogress++; funcdecl.semanticRun = PASS.semanticdone; /* Save scope for possible later use (if we need the * function internals) */ funcdecl._scope = sc.copy(); funcdecl._scope.setNoFree(); __gshared bool printedMain = false; // semantic might run more than once if (global.params.verbose && !printedMain) { const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; Module mod = sc._module; if (type && mod) { printedMain = true; const(char)* name = FileName.searchPath(global.path, mod.srcfile.toChars(), true); message("entry %-10s\t%s", type, name); } } if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) Compiler.genCmain(sc); assert(funcdecl.type.ty != Terror || funcdecl.errors); // semantic for parameters' UDAs foreach (i; 0 .. Parameter.dim(f.parameters)) { Parameter param = Parameter.getNth(f.parameters, i); if (param && param.userAttribDecl) param.userAttribDecl.dsymbolSemantic(sc); } } /// Do the semantic analysis on the external interface to the function. override void visit(FuncDeclaration funcdecl) { funcDeclarationSemantic(funcdecl); } override void visit(CtorDeclaration ctd) { //printf("CtorDeclaration::semantic() %s\n", toChars()); if (ctd.semanticRun >= PASS.semanticdone) return; if (ctd._scope) { sc = ctd._scope; ctd._scope = null; } ctd.parent = sc.parent; Dsymbol p = ctd.toParent2(); AggregateDeclaration ad = p.isAggregateDeclaration(); if (!ad) { error(ctd.loc, "constructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); ctd.type = Type.terror; ctd.errors = true; return; } sc = sc.push(); if (sc.stc & STC.static_) { // Deprecated in 2018-04. // Change to error in 2019-04. // @@@DEPRECATED_2019-04@@@. if (sc.stc & STC.shared_) deprecation(ctd.loc, "`shared static` has no effect on a constructor inside a `shared static` block. Use `shared static this()`"); else deprecation(ctd.loc, "`static` has no effect on a constructor inside a `static` block. Use `static this()`"); } sc.stc &= ~STC.static_; // not a static constructor sc.flags |= SCOPE.ctor; funcDeclarationSemantic(ctd); sc.pop(); if (ctd.errors) return; TypeFunction tf = ctd.type.toTypeFunction(); /* See if it's the default constructor * But, template constructor should not become a default constructor. */ if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin())) { immutable dim = Parameter.dim(tf.parameters); if (auto sd = ad.isStructDeclaration()) { if (dim == 0 && tf.varargs == 0) // empty default ctor w/o any varargs { if (ctd.fbody || !(ctd.storage_class & STC.disable)) { ctd.error("default constructor for structs only allowed " ~ "with `@disable`, no body, and no parameters"); ctd.storage_class |= STC.disable; ctd.fbody = null; } sd.noDefaultCtor = true; } else if (dim == 0 && tf.varargs) // allow varargs only ctor { } else if (dim && Parameter.getNth(tf.parameters, 0).defaultArg) { // if the first parameter has a default argument, then the rest does as well if (ctd.storage_class & STC.disable) { ctd.deprecation("is marked `@disable`, so it cannot have default "~ "arguments for all parameters."); deprecationSupplemental(ctd.loc, "Use `@disable this();` if you want to disable default initialization."); } else ctd.deprecation("all parameters have default arguments, "~ "but structs cannot have default constructors."); } } else if (dim == 0 && tf.varargs == 0) { ad.defaultCtor = ctd; } } } override void visit(PostBlitDeclaration pbd) { //printf("PostBlitDeclaration::semantic() %s\n", toChars()); //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor); //printf("stc = x%llx\n", sc.stc); if (pbd.semanticRun >= PASS.semanticdone) return; if (pbd._scope) { sc = pbd._scope; pbd._scope = null; } pbd.parent = sc.parent; Dsymbol p = pbd.toParent2(); StructDeclaration ad = p.isStructDeclaration(); if (!ad) { error(pbd.loc, "postblit can only be a member of struct, not %s `%s`", p.kind(), p.toChars()); pbd.type = Type.terror; pbd.errors = true; return; } if (pbd.ident == Id.postblit && pbd.semanticRun < PASS.semantic) ad.postblits.push(pbd); if (!pbd.type) pbd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, pbd.storage_class); sc = sc.push(); sc.stc &= ~STC.static_; // not static sc.linkage = LINK.d; funcDeclarationSemantic(pbd); sc.pop(); } override void visit(DtorDeclaration dd) { //printf("DtorDeclaration::semantic() %s\n", toChars()); //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor); if (dd.semanticRun >= PASS.semanticdone) return; if (dd._scope) { sc = dd._scope; dd._scope = null; } dd.parent = sc.parent; Dsymbol p = dd.toParent2(); AggregateDeclaration ad = p.isAggregateDeclaration(); if (!ad) { error(dd.loc, "destructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); dd.type = Type.terror; dd.errors = true; return; } if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic) ad.dtors.push(dd); if (!dd.type) { dd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, dd.storage_class); if (ad.classKind == ClassKind.cpp && dd.ident == Id.dtor) { if (auto cldec = ad.isClassDeclaration()) { assert (cldec.cppDtorVtblIndex == -1); // double-call check already by dd.type if (cldec.baseClass && cldec.baseClass.cppDtorVtblIndex != -1) { // override the base virtual cldec.cppDtorVtblIndex = cldec.baseClass.cppDtorVtblIndex; } else if (!dd.isFinal()) { // reserve the dtor slot for the destructor (which we'll create later) cldec.cppDtorVtblIndex = cast(int)cldec.vtbl.dim; cldec.vtbl.push(dd); if (Target.twoDtorInVtable) cldec.vtbl.push(dd); // deleting destructor uses a second slot } } } } sc = sc.push(); sc.stc &= ~STC.static_; // not a static destructor if (sc.linkage != LINK.cpp) sc.linkage = LINK.d; funcDeclarationSemantic(dd); sc.pop(); } override void visit(StaticCtorDeclaration scd) { //printf("StaticCtorDeclaration::semantic()\n"); if (scd.semanticRun >= PASS.semanticdone) return; if (scd._scope) { sc = scd._scope; scd._scope = null; } scd.parent = sc.parent; Dsymbol p = scd.parent.pastMixin(); if (!p.isScopeDsymbol()) { const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : ""); error(scd.loc, "`%sstatic` constructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars()); scd.type = Type.terror; scd.errors = true; return; } if (!scd.type) scd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, scd.storage_class); /* If the static ctor appears within a template instantiation, * it could get called multiple times by the module constructors * for different modules. Thus, protect it with a gate. */ if (scd.isInstantiated() && scd.semanticRun < PASS.semantic) { /* Add this prefix to the function: * static int gate; * if (++gate != 1) return; * Note that this is not thread safe; should not have threads * during static construction. */ auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); v.storage_class = STC.temp | (scd.isSharedStaticCtorDeclaration() ? STC.static_ : STC.tls); auto sa = new Statements(); Statement s = new ExpStatement(Loc.initial, v); sa.push(s); Expression e = new IdentifierExp(Loc.initial, v.ident); e = new AddAssignExp(Loc.initial, e, new IntegerExp(1)); e = new EqualExp(TOK.notEqual, Loc.initial, e, new IntegerExp(1)); s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); sa.push(s); if (scd.fbody) sa.push(scd.fbody); scd.fbody = new CompoundStatement(Loc.initial, sa); } funcDeclarationSemantic(scd); // We're going to need ModuleInfo Module m = scd.getModule(); if (!m) m = sc._module; if (m) { m.needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m.toChars()); } } override void visit(StaticDtorDeclaration sdd) { if (sdd.semanticRun >= PASS.semanticdone) return; if (sdd._scope) { sc = sdd._scope; sdd._scope = null; } sdd.parent = sc.parent; Dsymbol p = sdd.parent.pastMixin(); if (!p.isScopeDsymbol()) { const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : ""); error(sdd.loc, "`%sstatic` destructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars()); sdd.type = Type.terror; sdd.errors = true; return; } if (!sdd.type) sdd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, sdd.storage_class); /* If the static ctor appears within a template instantiation, * it could get called multiple times by the module constructors * for different modules. Thus, protect it with a gate. */ if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic) { /* Add this prefix to the function: * static int gate; * if (--gate != 0) return; * Increment gate during constructor execution. * Note that this is not thread safe; should not have threads * during static destruction. */ auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null); v.storage_class = STC.temp | (sdd.isSharedStaticDtorDeclaration() ? STC.static_ : STC.tls); auto sa = new Statements(); Statement s = new ExpStatement(Loc.initial, v); sa.push(s); Expression e = new IdentifierExp(Loc.initial, v.ident); e = new AddAssignExp(Loc.initial, e, new IntegerExp(-1)); e = new EqualExp(TOK.notEqual, Loc.initial, e, new IntegerExp(0)); s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial); sa.push(s); if (sdd.fbody) sa.push(sdd.fbody); sdd.fbody = new CompoundStatement(Loc.initial, sa); sdd.vgate = v; } funcDeclarationSemantic(sdd); // We're going to need ModuleInfo Module m = sdd.getModule(); if (!m) m = sc._module; if (m) { m.needmoduleinfo = 1; //printf("module2 %s needs moduleinfo\n", m.toChars()); } } override void visit(InvariantDeclaration invd) { if (invd.semanticRun >= PASS.semanticdone) return; if (invd._scope) { sc = invd._scope; invd._scope = null; } invd.parent = sc.parent; Dsymbol p = invd.parent.pastMixin(); AggregateDeclaration ad = p.isAggregateDeclaration(); if (!ad) { error(invd.loc, "`invariant` can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); invd.type = Type.terror; invd.errors = true; return; } if (invd.ident != Id.classInvariant && invd.semanticRun < PASS.semantic && !ad.isUnionDeclaration() // users are on their own with union fields ) ad.invs.push(invd); if (!invd.type) invd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, invd.storage_class); sc = sc.push(); sc.stc &= ~STC.static_; // not a static invariant sc.stc |= STC.const_; // invariant() is always const sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_; sc.linkage = LINK.d; funcDeclarationSemantic(invd); sc.pop(); } override void visit(UnitTestDeclaration utd) { if (utd.semanticRun >= PASS.semanticdone) return; if (utd._scope) { sc = utd._scope; utd._scope = null; } utd.protection = sc.protection; utd.parent = sc.parent; Dsymbol p = utd.parent.pastMixin(); if (!p.isScopeDsymbol()) { error(utd.loc, "`unittest` can only be a member of module/aggregate/template, not %s `%s`", p.kind(), p.toChars()); utd.type = Type.terror; utd.errors = true; return; } if (global.params.useUnitTests) { if (!utd.type) utd.type = new TypeFunction(null, Type.tvoid, false, LINK.d, utd.storage_class); Scope* sc2 = sc.push(); sc2.linkage = LINK.d; funcDeclarationSemantic(utd); sc2.pop(); } version (none) { // We're going to need ModuleInfo even if the unit tests are not // compiled in, because other modules may import this module and refer // to this ModuleInfo. // (This doesn't make sense to me?) Module m = utd.getModule(); if (!m) m = sc._module; if (m) { //printf("module3 %s needs moduleinfo\n", m.toChars()); m.needmoduleinfo = 1; } } } override void visit(NewDeclaration nd) { //printf("NewDeclaration::semantic()\n"); // `@disable new();` should not be deprecated if (!nd.isDisabled() && !nd.isDeprecated()) { // @@@DEPRECATED_2.084@@@ // Should be changed to an error in 2.084 deprecation(nd.loc, "class allocators have been deprecated, consider moving the allocation strategy outside of the class"); } if (nd.semanticRun >= PASS.semanticdone) return; if (nd._scope) { sc = nd._scope; nd._scope = null; } nd.parent = sc.parent; Dsymbol p = nd.parent.pastMixin(); if (!p.isAggregateDeclaration()) { error(nd.loc, "allocator can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); nd.type = Type.terror; nd.errors = true; return; } Type tret = Type.tvoid.pointerTo(); if (!nd.type) nd.type = new TypeFunction(nd.parameters, tret, nd.varargs, LINK.d, nd.storage_class); nd.type = nd.type.typeSemantic(nd.loc, sc); // allow for `@disable new();` to force users of a type to use an external allocation strategy if (!nd.isDisabled()) { // Check that there is at least one argument of type size_t TypeFunction tf = nd.type.toTypeFunction(); if (Parameter.dim(tf.parameters) < 1) { nd.error("at least one argument of type `size_t` expected"); } else { Parameter fparam = Parameter.getNth(tf.parameters, 0); if (!fparam.type.equals(Type.tsize_t)) nd.error("first argument must be type `size_t`, not `%s`", fparam.type.toChars()); } } funcDeclarationSemantic(nd); } override void visit(DeleteDeclaration deld) { //printf("DeleteDeclaration::semantic()\n"); // @@@DEPRECATED_2.084@@@ // Should be changed to an error in 2.084 if (!deld.isDeprecated()) deprecation(deld.loc, "class deallocators have been deprecated, consider moving the deallocation strategy outside of the class"); if (deld.semanticRun >= PASS.semanticdone) return; if (deld._scope) { sc = deld._scope; deld._scope = null; } deld.parent = sc.parent; Dsymbol p = deld.parent.pastMixin(); if (!p.isAggregateDeclaration()) { error(deld.loc, "deallocator can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); deld.type = Type.terror; deld.errors = true; return; } if (!deld.type) deld.type = new TypeFunction(deld.parameters, Type.tvoid, 0, LINK.d, deld.storage_class); deld.type = deld.type.typeSemantic(deld.loc, sc); // Check that there is only one argument of type void* TypeFunction tf = deld.type.toTypeFunction(); if (Parameter.dim(tf.parameters) != 1) { deld.error("one argument of type `void*` expected"); } else { Parameter fparam = Parameter.getNth(tf.parameters, 0); if (!fparam.type.equals(Type.tvoid.pointerTo())) deld.error("one argument of type `void*` expected, not `%s`", fparam.type.toChars()); } funcDeclarationSemantic(deld); } override void visit(StructDeclaration sd) { //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); //static int count; if (++count == 20) assert(0); if (sd.semanticRun >= PASS.semanticdone) return; int errors = global.errors; //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toPrettyChars(), sizeok); Scope* scx = null; if (sd._scope) { sc = sd._scope; scx = sd._scope; // save so we don't make redundant copies sd._scope = null; } if (!sd.parent) { assert(sc.parent && sc.func); sd.parent = sc.parent; } assert(sd.parent && !sd.isAnonymous()); if (sd.errors) sd.type = Type.terror; if (sd.semanticRun == PASS.init) sd.type = sd.type.addSTC(sc.stc | sd.storage_class); sd.type = sd.type.typeSemantic(sd.loc, sc); if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd) { auto ti = (cast(TypeStruct)sd.type).sym.isInstantiated(); if (ti && isError(ti)) (cast(TypeStruct)sd.type).sym = sd; } // Ungag errors when not speculative Ungag ungag = sd.ungagSpeculative(); if (sd.semanticRun == PASS.init) { sd.protection = sc.protection; sd.alignment = sc.alignment(); sd.storage_class |= sc.stc; if (sd.storage_class & STC.deprecated_) sd.isdeprecated = true; if (sd.storage_class & STC.abstract_) sd.error("structs, unions cannot be `abstract`"); sd.userAttribDecl = sc.userAttribDecl; if (sc.linkage == LINK.cpp) sd.classKind = ClassKind.cpp; } else if (sd.symtab && !scx) return; sd.semanticRun = PASS.semantic; if (!sd.members) // if opaque declaration { sd.semanticRun = PASS.semanticdone; return; } if (!sd.symtab) { sd.symtab = new DsymbolTable(); for (size_t i = 0; i < sd.members.dim; i++) { auto s = (*sd.members)[i]; //printf("adding member '%s' to '%s'\n", s.toChars(), this.toChars()); s.addMember(sc, sd); } } auto sc2 = sd.newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < sd.members.dim; i++) { auto s = (*sd.members)[i]; //printf("struct: setScope %s %s\n", s.kind(), s.toChars()); s.setScope(sc2); } for (size_t i = 0; i < sd.members.dim; i++) { auto s = (*sd.members)[i]; s.importAll(sc2); } for (size_t i = 0; i < sd.members.dim; i++) { auto s = (*sd.members)[i]; s.dsymbolSemantic(sc2); sd.errors |= s.errors; } if (sd.errors) sd.type = Type.terror; if (!sd.determineFields()) { if (sd.type.ty != Terror) { sd.error(sd.loc, "circular or forward reference"); sd.errors = true; sd.type = Type.terror; } sc2.pop(); sd.semanticRun = PASS.semanticdone; return; } /* Following special member functions creation needs semantic analysis * completion of sub-structs in each field types. For example, buildDtor * needs to check existence of elaborate dtor in type of each fields. * See the case in compilable/test14838.d */ foreach (v; sd.fields) { Type tb = v.type.baseElemOf(); if (tb.ty != Tstruct) continue; auto sdec = (cast(TypeStruct)tb).sym; if (sdec.semanticRun >= PASS.semanticdone) continue; sc2.pop(); sd._scope = scx ? scx : sc.copy(); sd._scope.setNoFree(); sd._scope._module.addDeferredSemantic(sd); //printf("\tdeferring %s\n", toChars()); return; } /* Look for special member functions. */ sd.aggNew = cast(NewDeclaration)sd.search(Loc.initial, Id.classNew); sd.aggDelete = cast(DeleteDeclaration)sd.search(Loc.initial, Id.classDelete); // Look for the constructor sd.ctor = sd.searchCtor(); sd.dtor = buildDtor(sd, sc2); sd.tidtor = buildExternDDtor(sd, sc2); sd.postblit = buildPostBlit(sd, sc2); buildOpAssign(sd, sc2); buildOpEquals(sd, sc2); if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo { sd.xeq = buildXopEquals(sd, sc2); sd.xcmp = buildXopCmp(sd, sc2); sd.xhash = buildXtoHash(sd, sc2); } sd.inv = buildInv(sd, sc2); Module.dprogress++; sd.semanticRun = PASS.semanticdone; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars()); sc2.pop(); if (sd.ctor) { Dsymbol scall = sd.search(Loc.initial, Id.call); if (scall) { uint xerrors = global.startGagging(); sc = sc.push(); sc.tinst = null; sc.minst = null; auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, null, 1); sc = sc.pop(); global.endGagging(xerrors); if (fcall && fcall.isStatic()) { sd.error(fcall.loc, "`static opCall` is hidden by constructors and can never be called"); errorSupplemental(fcall.loc, "Please use a factory method instead, or replace all constructors with `static opCall`."); } } } if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd) { // https://issues.dlang.org/show_bug.cgi?id=19024 StructDeclaration sym = (cast(TypeStruct)sd.type).sym; version (none) { printf("this = %p %s\n", sd, sd.toChars()); printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars()); } sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars()); } if (global.errors != errors) { // The type is no good. sd.type = Type.terror; sd.errors = true; if (sd.deferred) sd.deferred.errors = true; } if (sd.deferred && !global.gag) { sd.deferred.semantic2(sc); sd.deferred.semantic3(sc); } } void interfaceSemantic(ClassDeclaration cd) { cd.vtblInterfaces = new BaseClasses(); cd.vtblInterfaces.reserve(cd.interfaces.length); foreach (b; cd.interfaces) { cd.vtblInterfaces.push(b); b.copyBaseInterfaces(cd.vtblInterfaces); } } override void visit(ClassDeclaration cldec) { //printf("ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : ""); //printf("sc.stc = %x\n", sc.stc); //{ static int n; if (++n == 20) *(char*)0=0; } if (cldec.semanticRun >= PASS.semanticdone) return; int errors = global.errors; //printf("+ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); Scope* scx = null; if (cldec._scope) { sc = cldec._scope; scx = cldec._scope; // save so we don't make redundant copies cldec._scope = null; } if (!cldec.parent) { assert(sc.parent); cldec.parent = sc.parent; } if (cldec.errors) cldec.type = Type.terror; cldec.type = cldec.type.typeSemantic(cldec.loc, sc); if (cldec.type.ty == Tclass && (cast(TypeClass)cldec.type).sym != cldec) { auto ti = (cast(TypeClass)cldec.type).sym.isInstantiated(); if (ti && isError(ti)) (cast(TypeClass)cldec.type).sym = cldec; } // Ungag errors when not speculative Ungag ungag = cldec.ungagSpeculative(); if (cldec.semanticRun == PASS.init) { cldec.protection = sc.protection; cldec.storage_class |= sc.stc; if (cldec.storage_class & STC.deprecated_) cldec.isdeprecated = true; if (cldec.storage_class & STC.auto_) cldec.error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?"); if (cldec.storage_class & STC.scope_) cldec.stack = true; if (cldec.storage_class & STC.abstract_) cldec.isabstract = Abstract.yes; cldec.userAttribDecl = sc.userAttribDecl; if (sc.linkage == LINK.cpp) cldec.classKind = ClassKind.cpp; if (sc.linkage == LINK.objc) objc.setObjc(cldec); } else if (cldec.symtab && !scx) { cldec.semanticRun = PASS.semanticdone; return; } cldec.semanticRun = PASS.semantic; if (cldec.baseok < Baseok.done) { /* https://issues.dlang.org/show_bug.cgi?id=12078 * https://issues.dlang.org/show_bug.cgi?id=12143 * https://issues.dlang.org/show_bug.cgi?id=15733 * While resolving base classes and interfaces, a base may refer * the member of this derived class. In that time, if all bases of * this class can be determined, we can go forward the semantc process * beyond the Lancestorsdone. To do the recursive semantic analysis, * temporarily set and unset `_scope` around exp(). */ T resolveBase(T)(lazy T exp) { if (!scx) { scx = sc.copy(); scx.setNoFree(); } static if (!is(T == void)) { cldec._scope = scx; auto r = exp(); cldec._scope = null; return r; } else { cldec._scope = scx; exp(); cldec._scope = null; } } cldec.baseok = Baseok.start; // Expand any tuples in baseclasses[] for (size_t i = 0; i < cldec.baseclasses.dim;) { auto b = (*cldec.baseclasses)[i]; b.type = resolveBase(b.type.typeSemantic(cldec.loc, sc)); Type tb = b.type.toBasetype(); if (tb.ty == Ttuple) { TypeTuple tup = cast(TypeTuple)tb; cldec.baseclasses.remove(i); size_t dim = Parameter.dim(tup.arguments); for (size_t j = 0; j < dim; j++) { Parameter arg = Parameter.getNth(tup.arguments, j); b = new BaseClass(arg.type); cldec.baseclasses.insert(i + j, b); } } else i++; } if (cldec.baseok >= Baseok.done) { //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun); if (cldec.semanticRun >= PASS.semanticdone) return; goto Lancestorsdone; } // See if there's a base class as first in baseclasses[] if (cldec.baseclasses.dim) { BaseClass* b = (*cldec.baseclasses)[0]; Type tb = b.type.toBasetype(); TypeClass tc = (tb.ty == Tclass) ? cast(TypeClass)tb : null; if (!tc) { if (b.type != Type.terror) cldec.error("base type must be `class` or `interface`, not `%s`", b.type.toChars()); cldec.baseclasses.remove(0); goto L7; } if (tc.sym.isDeprecated()) { if (!cldec.isDeprecated()) { // Deriving from deprecated class makes this one deprecated too cldec.isdeprecated = true; tc.checkDeprecated(cldec.loc, sc); } } if (tc.sym.isInterfaceDeclaration()) goto L7; for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass) { if (cdb == cldec) { cldec.error("circular inheritance"); cldec.baseclasses.remove(0); goto L7; } } /* https://issues.dlang.org/show_bug.cgi?id=11034 * Class inheritance hierarchy * and instance size of each classes are orthogonal information. * Therefore, even if tc.sym.sizeof == Sizeok.none, * we need to set baseClass field for class covariance check. */ cldec.baseClass = tc.sym; b.sym = cldec.baseClass; if (tc.sym.baseok < Baseok.done) resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference if (tc.sym.baseok < Baseok.done) { //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars()); if (tc.sym._scope) tc.sym._scope._module.addDeferredSemantic(tc.sym); cldec.baseok = Baseok.none; } L7: } // Treat the remaining entries in baseclasses as interfaces // Check for errors, handle forward references bool multiClassError = false; for (size_t i = (cldec.baseClass ? 1 : 0); i < cldec.baseclasses.dim;) { BaseClass* b = (*cldec.baseclasses)[i]; Type tb = b.type.toBasetype(); TypeClass tc = (tb.ty == Tclass) ? cast(TypeClass)tb : null; if (!tc || !tc.sym.isInterfaceDeclaration()) { // It's a class if (tc) { if (!multiClassError) { error(cldec.loc,"`%s`: multiple class inheritance is not supported." ~ " Use multiple interface inheritance and/or composition.", cldec.toPrettyChars()); multiClassError = true; } if (tc.sym.fields.dim) errorSupplemental(cldec.loc,"`%s` has fields, consider making it a member of `%s`", b.type.toChars(), cldec.type.toChars()); else errorSupplemental(cldec.loc,"`%s` has no fields, consider making it an `interface`", b.type.toChars()); } // It's something else: e.g. `int` in `class Foo : Bar, int { ... }` else if (b.type != Type.terror) { error(cldec.loc,"`%s`: base type must be `interface`, not `%s`", cldec.toPrettyChars(), b.type.toChars()); } cldec.baseclasses.remove(i); continue; } // Check for duplicate interfaces for (size_t j = (cldec.baseClass ? 1 : 0); j < i; j++) { BaseClass* b2 = (*cldec.baseclasses)[j]; if (b2.sym == tc.sym) { cldec.error("inherits from duplicate interface `%s`", b2.sym.toChars()); cldec.baseclasses.remove(i); continue; } } if (tc.sym.isDeprecated()) { if (!cldec.isDeprecated()) { // Deriving from deprecated class makes this one deprecated too cldec.isdeprecated = true; tc.checkDeprecated(cldec.loc, sc); } } b.sym = tc.sym; if (tc.sym.baseok < Baseok.done) resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference if (tc.sym.baseok < Baseok.done) { //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars()); if (tc.sym._scope) tc.sym._scope._module.addDeferredSemantic(tc.sym); cldec.baseok = Baseok.none; } i++; } if (cldec.baseok == Baseok.none) { // Forward referencee of one or more bases, try again later cldec._scope = scx ? scx : sc.copy(); cldec._scope.setNoFree(); cldec._scope._module.addDeferredSemantic(cldec); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); return; } cldec.baseok = Baseok.done; // If no base class, and this is not an Object, use Object as base class if (!cldec.baseClass && cldec.ident != Id.Object && cldec.object && cldec.classKind == ClassKind.d) { void badObjectDotD() { cldec.error("missing or corrupt object.d"); fatal(); } if (!cldec.object || cldec.object.errors) badObjectDotD(); Type t = cldec.object.type; t = t.typeSemantic(cldec.loc, sc).toBasetype(); if (t.ty == Terror) badObjectDotD(); assert(t.ty == Tclass); TypeClass tc = cast(TypeClass)t; auto b = new BaseClass(tc); cldec.baseclasses.shift(b); cldec.baseClass = tc.sym; assert(!cldec.baseClass.isInterfaceDeclaration()); b.sym = cldec.baseClass; } if (cldec.baseClass) { if (cldec.baseClass.storage_class & STC.final_) cldec.error("cannot inherit from class `%s` because it is `final`", cldec.baseClass.toChars()); // Inherit properties from base class if (cldec.baseClass.isCOMclass()) cldec.com = true; if (cldec.baseClass.isCPPclass()) cldec.classKind = ClassKind.cpp; if (cldec.baseClass.stack) cldec.stack = true; cldec.enclosing = cldec.baseClass.enclosing; cldec.storage_class |= cldec.baseClass.storage_class & STC.TYPECTOR; } cldec.interfaces = cldec.baseclasses.tdata()[(cldec.baseClass ? 1 : 0) .. cldec.baseclasses.dim]; foreach (b; cldec.interfaces) { // If this is an interface, and it derives from a COM interface, // then this is a COM interface too. if (b.sym.isCOMinterface()) cldec.com = true; if (cldec.classKind == ClassKind.cpp && !b.sym.isCPPinterface()) { error(cldec.loc, "C++ class `%s` cannot implement D interface `%s`", cldec.toPrettyChars(), b.sym.toPrettyChars()); } } interfaceSemantic(cldec); } Lancestorsdone: //printf("\tClassDeclaration.dsymbolSemantic(%s) baseok = %d\n", toChars(), baseok); if (!cldec.members) // if opaque declaration { cldec.semanticRun = PASS.semanticdone; return; } if (!cldec.symtab) { cldec.symtab = new DsymbolTable(); /* https://issues.dlang.org/show_bug.cgi?id=12152 * The semantic analysis of base classes should be finished * before the members semantic analysis of this class, in order to determine * vtbl in this class. However if a base class refers the member of this class, * it can be resolved as a normal forward reference. * Call addMember() and setScope() to make this class members visible from the base classes. */ for (size_t i = 0; i < cldec.members.dim; i++) { auto s = (*cldec.members)[i]; s.addMember(sc, cldec); } auto sc2 = cldec.newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < cldec.members.dim; i++) { auto s = (*cldec.members)[i]; //printf("[%d] setScope %s %s, sc2 = %p\n", i, s.kind(), s.toChars(), sc2); s.setScope(sc2); } sc2.pop(); } for (size_t i = 0; i < cldec.baseclasses.dim; i++) { BaseClass* b = (*cldec.baseclasses)[i]; Type tb = b.type.toBasetype(); assert(tb.ty == Tclass); TypeClass tc = cast(TypeClass)tb; if (tc.sym.semanticRun < PASS.semanticdone) { // Forward referencee of one or more bases, try again later cldec._scope = scx ? scx : sc.copy(); cldec._scope.setNoFree(); if (tc.sym._scope) tc.sym._scope._module.addDeferredSemantic(tc.sym); cldec._scope._module.addDeferredSemantic(cldec); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); return; } } if (cldec.baseok == Baseok.done) { cldec.baseok = Baseok.semanticdone; // initialize vtbl if (cldec.baseClass) { if (cldec.classKind == ClassKind.cpp && cldec.baseClass.vtbl.dim == 0) { cldec.error("C++ base class `%s` needs at least one virtual function", cldec.baseClass.toChars()); } // Copy vtbl[] from base class cldec.vtbl.setDim(cldec.baseClass.vtbl.dim); memcpy(cldec.vtbl.tdata(), cldec.baseClass.vtbl.tdata(), (void*).sizeof * cldec.vtbl.dim); cldec.vthis = cldec.baseClass.vthis; } else { // No base class, so this is the root of the class hierarchy cldec.vtbl.setDim(0); if (cldec.vtblOffset()) cldec.vtbl.push(cldec); // leave room for classinfo as first member } /* If this is a nested class, add the hidden 'this' * member which is a pointer to the enclosing scope. */ if (cldec.vthis) // if inheriting from nested class { // Use the base class's 'this' member if (cldec.storage_class & STC.static_) cldec.error("static class cannot inherit from nested class `%s`", cldec.baseClass.toChars()); if (cldec.toParent2() != cldec.baseClass.toParent2() && (!cldec.toParent2() || !cldec.baseClass.toParent2().getType() || !cldec.baseClass.toParent2().getType().isBaseOf(cldec.toParent2().getType(), null))) { if (cldec.toParent2()) { cldec.error("is nested within `%s`, but super class `%s` is nested within `%s`", cldec.toParent2().toChars(), cldec.baseClass.toChars(), cldec.baseClass.toParent2().toChars()); } else { cldec.error("is not nested, but super class `%s` is nested within `%s`", cldec.baseClass.toChars(), cldec.baseClass.toParent2().toChars()); } cldec.enclosing = null; } } else cldec.makeNested(); } auto sc2 = cldec.newScope(sc); for (size_t i = 0; i < cldec.members.dim; ++i) { auto s = (*cldec.members)[i]; s.importAll(sc2); } // Note that members.dim can grow due to tuple expansion during semantic() for (size_t i = 0; i < cldec.members.dim; ++i) { auto s = (*cldec.members)[i]; s.dsymbolSemantic(sc2); } if (!cldec.determineFields()) { assert(cldec.type == Type.terror); sc2.pop(); return; } /* Following special member functions creation needs semantic analysis * completion of sub-structs in each field types. */ foreach (v; cldec.fields) { Type tb = v.type.baseElemOf(); if (tb.ty != Tstruct) continue; auto sd = (cast(TypeStruct)tb).sym; if (sd.semanticRun >= PASS.semanticdone) continue; sc2.pop(); cldec._scope = scx ? scx : sc.copy(); cldec._scope.setNoFree(); cldec._scope._module.addDeferredSemantic(cldec); //printf("\tdeferring %s\n", toChars()); return; } /* Look for special member functions. * They must be in this class, not in a base class. */ // Can be in base class cldec.aggNew = cast(NewDeclaration)cldec.search(Loc.initial, Id.classNew); cldec.aggDelete = cast(DeleteDeclaration)cldec.search(Loc.initial, Id.classDelete); // Look for the constructor cldec.ctor = cldec.searchCtor(); if (!cldec.ctor && cldec.noDefaultCtor) { // A class object is always created by constructor, so this check is legitimate. foreach (v; cldec.fields) { if (v.storage_class & STC.nodefaultctor) error(v.loc, "field `%s` must be initialized in constructor", v.toChars()); } } // If this class has no constructor, but base class has a default // ctor, create a constructor: // this() { } if (!cldec.ctor && cldec.baseClass && cldec.baseClass.ctor) { auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, null, 1); if (!fd) // try shared base ctor instead fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, null, 1); if (fd && !fd.errors) { //printf("Creating default this(){} for class %s\n", toChars()); auto btf = fd.type.toTypeFunction(); auto tf = new TypeFunction(null, null, 0, LINK.d, fd.storage_class); tf.mod = btf.mod; tf.purity = btf.purity; tf.isnothrow = btf.isnothrow; tf.isnogc = btf.isnogc; tf.trust = btf.trust; auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); cldec.members.push(ctor); ctor.addMember(sc, cldec); ctor.dsymbolSemantic(sc2); cldec.ctor = ctor; cldec.defaultCtor = ctor; } else { cldec.error("cannot implicitly generate a default constructor when base class `%s` is missing a default constructor", cldec.baseClass.toPrettyChars()); } } cldec.dtor = buildDtor(cldec, sc2); cldec.tidtor = buildExternDDtor(cldec, sc2); if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1) { // now we've built the aggregate destructor, we'll make it virtual and assign it to the reserved vtable slot cldec.dtor.vtblIndex = cldec.cppDtorVtblIndex; cldec.vtbl[cldec.cppDtorVtblIndex] = cldec.dtor; if (Target.twoDtorInVtable) { // TODO: create a C++ compatible deleting destructor (call out to `operator delete`) // for the moment, we'll call the non-deleting destructor and leak cldec.vtbl[cldec.cppDtorVtblIndex + 1] = cldec.dtor; } } if (auto f = hasIdentityOpAssign(cldec, sc2)) { if (!(f.storage_class & STC.disable)) cldec.error(f.loc, "identity assignment operator overload is illegal"); } cldec.inv = buildInv(cldec, sc2); Module.dprogress++; cldec.semanticRun = PASS.semanticdone; //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); sc2.pop(); /* isAbstract() is undecidable in some cases because of circular dependencies. * Now that semantic is finished, get a definitive result, and error if it is not the same. */ if (cldec.isabstract != Abstract.fwdref) // if evaluated it before completion { const isabstractsave = cldec.isabstract; cldec.isabstract = Abstract.fwdref; cldec.isAbstract(); // recalculate if (cldec.isabstract != isabstractsave) { cldec.error("cannot infer `abstract` attribute due to circular dependencies"); } } if (cldec.type.ty == Tclass && (cast(TypeClass)cldec.type).sym != cldec) { // https://issues.dlang.org/show_bug.cgi?id=17492 ClassDeclaration cd = (cast(TypeClass)cldec.type).sym; version (none) { printf("this = %p %s\n", cldec, cldec.toPrettyChars()); printf("type = %d sym = %p, %s\n", cldec.type.ty, cd, cd.toPrettyChars()); } cldec.error("already exists at %s. Perhaps in another function with the same name?", cd.loc.toChars()); } if (global.errors != errors) { // The type is no good. cldec.type = Type.terror; cldec.errors = true; if (cldec.deferred) cldec.deferred.errors = true; } // Verify fields of a synchronized class are not public if (cldec.storage_class & STC.synchronized_) { foreach (vd; cldec.fields) { if (!vd.isThisDeclaration() && !vd.prot().isMoreRestrictiveThan(Prot(Prot.Kind.public_))) { vd.error("Field members of a `synchronized` class cannot be `%s`", protectionToChars(vd.prot().kind)); } } } if (cldec.deferred && !global.gag) { cldec.deferred.semantic2(sc); cldec.deferred.semantic3(sc); } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); } override void visit(InterfaceDeclaration idec) { //printf("InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); if (idec.semanticRun >= PASS.semanticdone) return; int errors = global.errors; //printf("+InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); Scope* scx = null; if (idec._scope) { sc = idec._scope; scx = idec._scope; // save so we don't make redundant copies idec._scope = null; } if (!idec.parent) { assert(sc.parent && sc.func); idec.parent = sc.parent; } assert(idec.parent && !idec.isAnonymous()); if (idec.errors) idec.type = Type.terror; idec.type = idec.type.typeSemantic(idec.loc, sc); if (idec.type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec) { auto ti = (cast(TypeClass)idec.type).sym.isInstantiated(); if (ti && isError(ti)) (cast(TypeClass)idec.type).sym = idec; } // Ungag errors when not speculative Ungag ungag = idec.ungagSpeculative(); if (idec.semanticRun == PASS.init) { idec.protection = sc.protection; idec.storage_class |= sc.stc; if (idec.storage_class & STC.deprecated_) idec.isdeprecated = true; idec.userAttribDecl = sc.userAttribDecl; } else if (idec.symtab) { if (idec.sizeok == Sizeok.done || !scx) { idec.semanticRun = PASS.semanticdone; return; } } idec.semanticRun = PASS.semantic; if (idec.baseok < Baseok.done) { T resolveBase(T)(lazy T exp) { if (!scx) { scx = sc.copy(); scx.setNoFree(); } static if (!is(T == void)) { idec._scope = scx; auto r = exp(); idec._scope = null; return r; } else { idec._scope = scx; exp(); idec._scope = null; } } idec.baseok = Baseok.start; // Expand any tuples in baseclasses[] for (size_t i = 0; i < idec.baseclasses.dim;) { auto b = (*idec.baseclasses)[i]; b.type = resolveBase(b.type.typeSemantic(idec.loc, sc)); Type tb = b.type.toBasetype(); if (tb.ty == Ttuple) { TypeTuple tup = cast(TypeTuple)tb; idec.baseclasses.remove(i); size_t dim = Parameter.dim(tup.arguments); for (size_t j = 0; j < dim; j++) { Parameter arg = Parameter.getNth(tup.arguments, j); b = new BaseClass(arg.type); idec.baseclasses.insert(i + j, b); } } else i++; } if (idec.baseok >= Baseok.done) { //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun); if (idec.semanticRun >= PASS.semanticdone) return; goto Lancestorsdone; } if (!idec.baseclasses.dim && sc.linkage == LINK.cpp) idec.classKind = ClassKind.cpp; if (sc.linkage == LINK.objc) objc.setObjc(idec); // Check for errors, handle forward references for (size_t i = 0; i < idec.baseclasses.dim;) { BaseClass* b = (*idec.baseclasses)[i]; Type tb = b.type.toBasetype(); TypeClass tc = (tb.ty == Tclass) ? cast(TypeClass)tb : null; if (!tc || !tc.sym.isInterfaceDeclaration()) { if (b.type != Type.terror) idec.error("base type must be `interface`, not `%s`", b.type.toChars()); idec.baseclasses.remove(i); continue; } // Check for duplicate interfaces for (size_t j = 0; j < i; j++) { BaseClass* b2 = (*idec.baseclasses)[j]; if (b2.sym == tc.sym) { idec.error("inherits from duplicate interface `%s`", b2.sym.toChars()); idec.baseclasses.remove(i); continue; } } if (tc.sym == idec || idec.isBaseOf2(tc.sym)) { idec.error("circular inheritance of interface"); idec.baseclasses.remove(i); continue; } if (tc.sym.isDeprecated()) { if (!idec.isDeprecated()) { // Deriving from deprecated class makes this one deprecated too idec.isdeprecated = true; tc.checkDeprecated(idec.loc, sc); } } b.sym = tc.sym; if (tc.sym.baseok < Baseok.done) resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference if (tc.sym.baseok < Baseok.done) { //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars()); if (tc.sym._scope) tc.sym._scope._module.addDeferredSemantic(tc.sym); idec.baseok = Baseok.none; } i++; } if (idec.baseok == Baseok.none) { // Forward referencee of one or more bases, try again later idec._scope = scx ? scx : sc.copy(); idec._scope.setNoFree(); idec._scope._module.addDeferredSemantic(idec); return; } idec.baseok = Baseok.done; idec.interfaces = idec.baseclasses.tdata()[0 .. idec.baseclasses.dim]; foreach (b; idec.interfaces) { // If this is an interface, and it derives from a COM interface, // then this is a COM interface too. if (b.sym.isCOMinterface()) idec.com = true; if (b.sym.isCPPinterface()) idec.classKind = ClassKind.cpp; } interfaceSemantic(idec); } Lancestorsdone: if (!idec.members) // if opaque declaration { idec.semanticRun = PASS.semanticdone; return; } if (!idec.symtab) idec.symtab = new DsymbolTable(); for (size_t i = 0; i < idec.baseclasses.dim; i++) { BaseClass* b = (*idec.baseclasses)[i]; Type tb = b.type.toBasetype(); assert(tb.ty == Tclass); TypeClass tc = cast(TypeClass)tb; if (tc.sym.semanticRun < PASS.semanticdone) { // Forward referencee of one or more bases, try again later idec._scope = scx ? scx : sc.copy(); idec._scope.setNoFree(); if (tc.sym._scope) tc.sym._scope._module.addDeferredSemantic(tc.sym); idec._scope._module.addDeferredSemantic(idec); return; } } if (idec.baseok == Baseok.done) { idec.baseok = Baseok.semanticdone; objc.setMetaclass(idec); // initialize vtbl if (idec.vtblOffset()) idec.vtbl.push(idec); // leave room at vtbl[0] for classinfo // Cat together the vtbl[]'s from base interfaces foreach (i, b; idec.interfaces) { // Skip if b has already appeared for (size_t k = 0; k < i; k++) { if (b == idec.interfaces[k]) goto Lcontinue; } // Copy vtbl[] from base class if (b.sym.vtblOffset()) { size_t d = b.sym.vtbl.dim; if (d > 1) { idec.vtbl.reserve(d - 1); for (size_t j = 1; j < d; j++) idec.vtbl.push(b.sym.vtbl[j]); } } else { idec.vtbl.append(&b.sym.vtbl); } Lcontinue: } } for (size_t i = 0; i < idec.members.dim; i++) { Dsymbol s = (*idec.members)[i]; s.addMember(sc, idec); } auto sc2 = idec.newScope(sc); /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ for (size_t i = 0; i < idec.members.dim; i++) { Dsymbol s = (*idec.members)[i]; //printf("setScope %s %s\n", s.kind(), s.toChars()); s.setScope(sc2); } for (size_t i = 0; i < idec.members.dim; i++) { Dsymbol s = (*idec.members)[i]; s.importAll(sc2); } for (size_t i = 0; i < idec.members.dim; i++) { Dsymbol s = (*idec.members)[i]; s.dsymbolSemantic(sc2); } Module.dprogress++; idec.semanticRun = PASS.semanticdone; //printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); sc2.pop(); if (global.errors != errors) { // The type is no good. idec.type = Type.terror; } version (none) { if (type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec) { printf("this = %p %s\n", idec, idec.toChars()); printf("type = %d sym = %p\n", idec.type.ty, (cast(TypeClass)idec.type).sym); } } assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec); } } void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* fargs) { //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc); version (none) { for (Dsymbol s = tempinst; s; s = s.parent) { printf("\t%s\n", s.toChars()); } printf("Scope\n"); for (Scope* scx = sc; scx; scx = scx.enclosing) { printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null"); } } static if (LOG) { printf("\n+TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst); } if (tempinst.inst) // if semantic() was already run { static if (LOG) { printf("-TemplateInstance.dsymbolSemantic('%s', this=%p) already run\n", inst.toChars(), tempinst.inst); } return; } if (tempinst.semanticRun != PASS.init) { static if (LOG) { printf("Recursive template expansion\n"); } auto ungag = Ungag(global.gag); if (!tempinst.gagged) global.gag = 0; tempinst.error(tempinst.loc, "recursive template expansion"); if (tempinst.gagged) tempinst.semanticRun = PASS.init; else tempinst.inst = tempinst; tempinst.errors = true; return; } // Get the enclosing template instance from the scope tinst tempinst.tinst = sc.tinst; // Get the instantiating module from the scope minst tempinst.minst = sc.minst; // https://issues.dlang.org/show_bug.cgi?id=10920 // If the enclosing function is non-root symbol, // this instance should be speculative. if (!tempinst.tinst && sc.func && sc.func.inNonRoot()) { tempinst.minst = null; } tempinst.gagged = (global.gag > 0); tempinst.semanticRun = PASS.semantic; static if (LOG) { printf("\tdo semantic\n"); } /* Find template declaration first, * then run semantic on each argument (place results in tiargs[]), * last find most specialized template from overload list/set. */ if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, fargs)) { Lerror: if (tempinst.gagged) { // https://issues.dlang.org/show_bug.cgi?id=13220 // Roll back status for later semantic re-running tempinst.semanticRun = PASS.init; } else tempinst.inst = tempinst; tempinst.errors = true; return; } TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); // If tempdecl is a mixin, disallow it if (tempdecl.ismixin) { tempinst.error("mixin templates are not regular templates"); goto Lerror; } tempinst.hasNestedArgs(tempinst.tiargs, tempdecl.isstatic); if (tempinst.errors) goto Lerror; /* See if there is an existing TemplateInstantiation that already * implements the typeargs. If so, just refer to that one instead. */ tempinst.inst = tempdecl.findExistingInstance(tempinst, fargs); TemplateInstance errinst = null; if (!tempinst.inst) { // So, we need to implement 'this' instance. } else if (tempinst.inst.gagged && !tempinst.gagged && tempinst.inst.errors) { // If the first instantiation had failed, re-run semantic, // so that error messages are shown. errinst = tempinst.inst; } else { // It's a match tempinst.parent = tempinst.inst.parent; tempinst.errors = tempinst.inst.errors; // If both this and the previous instantiation were gagged, // use the number of errors that happened last time. global.errors += tempinst.errors; global.gaggedErrors += tempinst.errors; // If the first instantiation was gagged, but this is not: if (tempinst.inst.gagged) { // It had succeeded, mark it is a non-gagged instantiation, // and reuse it. tempinst.inst.gagged = tempinst.gagged; } tempinst.tnext = tempinst.inst.tnext; tempinst.inst.tnext = tempinst; /* A module can have explicit template instance and its alias * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`). * If the first instantiation 'inst' had happened in non-root module, * compiler can assume that its instantiated code would be included * in the separately compiled obj/lib file (e.g. phobos.lib). * * However, if 'this' second instantiation happened in root module, * compiler might need to invoke its codegen * (https://issues.dlang.org/show_bug.cgi?id=2500 & https://issues.dlang.org/show_bug.cgi?id=2644). * But whole import graph is not determined until all semantic pass finished, * so 'inst' should conservatively finish the semantic3 pass for the codegen. */ if (tempinst.minst && tempinst.minst.isRoot() && !(tempinst.inst.minst && tempinst.inst.minst.isRoot())) { /* Swap the position of 'inst' and 'this' in the instantiation graph. * Then, the primary instance `inst` will be changed to a root instance. * * Before: * non-root -> A!() -> B!()[inst] -> C!() * | * root -> D!() -> B!()[this] * * After: * non-root -> A!() -> B!()[this] * | * root -> D!() -> B!()[inst] -> C!() */ Module mi = tempinst.minst; TemplateInstance ti = tempinst.tinst; tempinst.minst = tempinst.inst.minst; tempinst.tinst = tempinst.inst.tinst; tempinst.inst.minst = mi; tempinst.inst.tinst = ti; if (tempinst.minst) // if inst was not speculative { /* Add 'inst' once again to the root module members[], then the * instance members will get codegen chances. */ tempinst.inst.appendToModuleMember(); } } static if (LOG) { printf("\tit's a match with instance %p, %d\n", tempinst.inst, tempinst.inst.semanticRun); } return; } static if (LOG) { printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), tempinst.toChars()); printf("\ttempdecl %s\n", tempdecl.toChars()); } uint errorsave = global.errors; tempinst.inst = tempinst; tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; //printf("parent = '%s'\n", parent.kind()); TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); //getIdent(); // Store the place we added it to in target_symbol_list(_idx) so we can // remove it later if we encounter an error. Dsymbols* target_symbol_list = tempinst.appendToModuleMember(); size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list.dim - 1 : 0; // Copy the syntax trees from the TemplateDeclaration tempinst.members = Dsymbol.arraySyntaxCopy(tempdecl.members); // resolve TemplateThisParameter for (size_t i = 0; i < tempdecl.parameters.dim; i++) { if ((*tempdecl.parameters)[i].isTemplateThisParameter() is null) continue; Type t = isType((*tempinst.tiargs)[i]); assert(t); if (StorageClass stc = ModToStc(t.mod)) { //printf("t = %s, stc = x%llx\n", t.toChars(), stc); auto s = new Dsymbols(); s.push(new StorageClassDeclaration(stc, tempinst.members)); tempinst.members = s; } break; } // Create our own scope for the template parameters Scope* _scope = tempdecl._scope; if (tempdecl.semanticRun == PASS.init) { tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars()); return; } static if (LOG) { printf("\tcreate scope for template parameters '%s'\n", tempinst.toChars()); } tempinst.argsym = new ScopeDsymbol(); tempinst.argsym.parent = _scope.parent; _scope = _scope.push(tempinst.argsym); _scope.tinst = tempinst; _scope.minst = tempinst.minst; //scope.stc = 0; // Declare each template parameter as an alias for the argument type Scope* paramscope = _scope.push(); paramscope.stc = 0; paramscope.protection = Prot(Prot.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=14169 // template parameters should be public tempinst.declareParameters(paramscope); paramscope.pop(); // Add members of template instance to template instance symbol table //parent = scope.scopesym; tempinst.symtab = new DsymbolTable(); for (size_t i = 0; i < tempinst.members.dim; i++) { Dsymbol s = (*tempinst.members)[i]; static if (LOG) { printf("\t[%d] adding member '%s' %p kind %s to '%s'\n", i, s.toChars(), s, s.kind(), tempinst.toChars()); } s.addMember(_scope, tempinst); } static if (LOG) { printf("adding members done\n"); } /* See if there is only one member of template instance, and that * member has the same name as the template instance. * If so, this template instance becomes an alias for that member. */ //printf("members.dim = %d\n", members.dim); if (tempinst.members.dim) { Dsymbol s; if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) { //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); tempinst.aliasdecl = s; } } /* If function template declaration */ if (fargs && tempinst.aliasdecl) { FuncDeclaration fd = tempinst.aliasdecl.isFuncDeclaration(); if (fd) { /* Transmit fargs to type so that TypeFunction.dsymbolSemantic() can * resolve any "auto ref" storage classes. */ TypeFunction tf = cast(TypeFunction)fd.type; if (tf && tf.ty == Tfunction) tf.fargs = fargs; } } // Do semantic() analysis on template instance members static if (LOG) { printf("\tdo semantic() on template instance members '%s'\n", tempinst.toChars()); } Scope* sc2; sc2 = _scope.push(tempinst); //printf("enclosing = %d, sc.parent = %s\n", tempinst.enclosing, sc.parent.toChars()); sc2.parent = tempinst; sc2.tinst = tempinst; sc2.minst = tempinst.minst; tempinst.tryExpandMembers(sc2); tempinst.semanticRun = PASS.semanticdone; /* ConditionalDeclaration may introduce eponymous declaration, * so we should find it once again after semantic. */ if (tempinst.members.dim) { Dsymbol s; if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) { if (!tempinst.aliasdecl || tempinst.aliasdecl != s) { //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl 2\n"); tempinst.aliasdecl = s; } } } if (global.errors != errorsave) goto Laftersemantic; /* If any of the instantiation members didn't get semantic() run * on them due to forward references, we cannot run semantic2() * or semantic3() yet. */ { bool found_deferred_ad = false; for (size_t i = 0; i < Module.deferred.dim; i++) { Dsymbol sd = Module.deferred[i]; AggregateDeclaration ad = sd.isAggregateDeclaration(); if (ad && ad.parent && ad.parent.isTemplateInstance()) { //printf("deferred template aggregate: %s %s\n", // sd.parent.toChars(), sd.toChars()); found_deferred_ad = true; if (ad.parent == tempinst) { ad.deferred = tempinst; break; } } } if (found_deferred_ad || Module.deferred.dim) goto Laftersemantic; } /* The problem is when to parse the initializer for a variable. * Perhaps VarDeclaration.dsymbolSemantic() should do it like it does * for initializers inside a function. */ //if (sc.parent.isFuncDeclaration()) { /* https://issues.dlang.org/show_bug.cgi?id=782 * this has problems if the classes this depends on * are forward referenced. Find a way to defer semantic() * on this template. */ tempinst.semantic2(sc2); } if (global.errors != errorsave) goto Laftersemantic; if ((sc.func || (sc.flags & SCOPE.fullinst)) && !tempinst.tinst) { /* If a template is instantiated inside function, the whole instantiation * should be done at that position. But, immediate running semantic3 of * dependent templates may cause unresolved forward reference. * https://issues.dlang.org/show_bug.cgi?id=9050 * To avoid the issue, don't run semantic3 until semantic and semantic2 done. */ TemplateInstances deferred; tempinst.deferred = &deferred; //printf("Run semantic3 on %s\n", toChars()); tempinst.trySemantic3(sc2); for (size_t i = 0; i < deferred.dim; i++) { //printf("+ run deferred semantic3 on %s\n", deferred[i].toChars()); deferred[i].semantic3(null); } tempinst.deferred = null; } else if (tempinst.tinst) { bool doSemantic3 = false; FuncDeclaration fd; if (tempinst.aliasdecl) fd = tempinst.aliasdecl.toAlias2().isFuncDeclaration(); if (fd) { /* Template function instantiation should run semantic3 immediately * for attribute inference. */ scope fld = fd.isFuncLiteralDeclaration(); if (fld && fld.tok == TOK.reserved) doSemantic3 = true; else if (sc.func) doSemantic3 = true; } else if (sc.func) { /* A lambda function in template arguments might capture the * instantiated scope context. For the correct context inference, * all instantiated functions should run the semantic3 immediately. * See also compilable/test14973.d */ foreach (oarg; tempinst.tdtypes) { auto s = getDsymbol(oarg); if (!s) continue; if (auto td = s.isTemplateDeclaration()) { if (!td.literal) continue; assert(td.members && td.members.dim == 1); s = (*td.members)[0]; } if (auto fld = s.isFuncLiteralDeclaration()) { if (fld.tok == TOK.reserved) { doSemantic3 = true; break; } } } //printf("[%s] %s doSemantic3 = %d\n", loc.toChars(), toChars(), doSemantic3); } if (doSemantic3) tempinst.trySemantic3(sc2); TemplateInstance ti = tempinst.tinst; int nest = 0; while (ti && !ti.deferred && ti.tinst) { ti = ti.tinst; if (++nest > 500) { global.gag = 0; // ensure error message gets printed tempinst.error("recursive expansion"); fatal(); } } if (ti && ti.deferred) { //printf("deferred semantic3 of %p %s, ti = %s, ti.deferred = %p\n", this, toChars(), ti.toChars()); for (size_t i = 0;; i++) { if (i == ti.deferred.dim) { ti.deferred.push(tempinst); break; } if ((*ti.deferred)[i] == tempinst) break; } } } if (tempinst.aliasdecl) { /* https://issues.dlang.org/show_bug.cgi?id=13816 * AliasDeclaration tries to resolve forward reference * twice (See inuse check in AliasDeclaration.toAlias()). It's * necessary to resolve mutual references of instantiated symbols, but * it will left a true recursive alias in tuple declaration - an * AliasDeclaration A refers TupleDeclaration B, and B contains A * in its elements. To correctly make it an error, we strictly need to * resolve the alias of eponymous member. */ tempinst.aliasdecl = tempinst.aliasdecl.toAlias2(); } Laftersemantic: sc2.pop(); _scope.pop(); // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { if (!tempinst.errors) { if (!tempdecl.literal) tempinst.error(tempinst.loc, "error instantiating"); if (tempinst.tinst) tempinst.tinst.printInstantiationTrace(); } tempinst.errors = true; if (tempinst.gagged) { // Errors are gagged, so remove the template instance from the // instance/symbol lists we added it to and reset our state to // finish clean and so we can try to instantiate it again later // (see https://issues.dlang.org/show_bug.cgi?id=4302 and https://issues.dlang.org/show_bug.cgi?id=6602). tempdecl.removeInstance(tempdecl_instance_idx); if (target_symbol_list) { // Because we added 'this' in the last position above, we // should be able to remove it without messing other indices up. assert((*target_symbol_list)[target_symbol_list_idx] == tempinst); target_symbol_list.remove(target_symbol_list_idx); tempinst.memberOf = null; // no longer a member } tempinst.semanticRun = PASS.init; tempinst.inst = null; tempinst.symtab = null; } } else if (errinst) { /* https://issues.dlang.org/show_bug.cgi?id=14541 * If the previous gagged instance had failed by * circular references, currrent "error reproduction instantiation" * might succeed, because of the difference of instantiated context. * On such case, the cached error instance needs to be overridden by the * succeeded instance. */ //printf("replaceInstance()\n"); assert(errinst.errors); auto ti1 = TemplateInstanceBox(errinst); tempdecl.instances.remove(ti1); auto ti2 = TemplateInstanceBox(tempinst); tempdecl.instances[ti2] = tempinst; } static if (LOG) { printf("-TemplateInstance.dsymbolSemantic('%s', this=%p)\n", toChars(), this); } } // function used to perform semantic on AliasDeclaration void aliasSemantic(AliasDeclaration ds, Scope* sc) { //printf("AliasDeclaration::semantic() %s\n", ds.toChars()); if (ds.aliassym) { auto fd = ds.aliassym.isFuncLiteralDeclaration(); auto td = ds.aliassym.isTemplateDeclaration(); if (fd || td && td.literal) { if (fd && fd.semanticRun >= PASS.semanticdone) return; Expression e = new FuncExp(ds.loc, ds.aliassym); e = e.expressionSemantic(sc); if (e.op == TOK.function_) { FuncExp fe = cast(FuncExp)e; ds.aliassym = fe.td ? cast(Dsymbol)fe.td : fe.fd; } else { ds.aliassym = null; ds.type = Type.terror; } return; } if (ds.aliassym.isTemplateInstance()) ds.aliassym.dsymbolSemantic(sc); return; } ds.inuse = 1; // Given: // alias foo.bar.abc def; // it is not knowable from the syntax whether this is an alias // for a type or an alias for a symbol. It is up to the semantic() // pass to distinguish. // If it is a type, then type is set and getType() will return that // type. If it is a symbol, then aliassym is set and type is NULL - // toAlias() will return aliasssym. uint errors = global.errors; Type oldtype = ds.type; // Ungag errors when not instantiated DeclDefs scope alias auto ungag = Ungag(global.gag); //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated()); if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration()) { //printf("%s type = %s\n", toPrettyChars(), type.toChars()); global.gag = 0; } // https://issues.dlang.org/show_bug.cgi?id=18480 // Detect `alias sym = sym;` to prevent creating loops in overload overnext lists. // Selective imports are allowed to alias to the same name `import mod : sym=sym`. if (ds.type.ty == Tident && !ds._import) { auto tident = cast(TypeIdentifier)ds.type; if (tident.ident is ds.ident && !tident.idents.dim) { error(ds.loc, "`alias %s = %s;` cannot alias itself, use a qualified name to create an overload set", ds.ident.toChars(), tident.ident.toChars()); ds.type = Type.terror; } } /* This section is needed because Type.resolve() will: * const x = 3; * alias y = x; * try to convert identifier x to 3. */ auto s = ds.type.toDsymbol(sc); if (errors != global.errors) { s = null; ds.type = Type.terror; } if (s && s == ds) { ds.error("cannot resolve"); s = null; ds.type = Type.terror; } if (!s || !s.isEnumMember()) { Type t; Expression e; Scope* sc2 = sc; if (ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.disable)) { // For 'ref' to be attached to function types, and picked // up by Type.resolve(), it has to go into sc. sc2 = sc.push(); sc2.stc |= ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable); } ds.type = ds.type.addSTC(ds.storage_class); ds.type.resolve(ds.loc, sc2, &e, &t, &s); if (sc2 != sc) sc2.pop(); if (e) // Try to convert Expression to Dsymbol { s = getDsymbol(e); if (!s) { if (e.op != TOK.error) ds.error("cannot alias an expression `%s`", e.toChars()); t = Type.terror; } } ds.type = t; } if (s == ds) { assert(global.errors); ds.type = Type.terror; s = null; } if (!s) // it's a type alias { //printf("alias %s resolved to type %s\n", toChars(), type.toChars()); ds.type = ds.type.typeSemantic(ds.loc, sc); ds.aliassym = null; } else // it's a symbolic alias { //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars()); ds.type = null; ds.aliassym = s; } if (global.gag && errors != global.errors) { ds.type = oldtype; ds.aliassym = null; } ds.inuse = 0; ds.semanticRun = PASS.semanticdone; if (auto sx = ds.overnext) { ds.overnext = null; if (!ds.overloadInsert(sx)) ScopeDsymbol.multiplyDefined(Loc.initial, sx, ds); } } ================================================ FILE: gcc/d/dmd/dtemplate.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Template implementation. * * Copyright: Copyright (C) 1999-2018 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/dtemplate.d, _dtemplate.d) * Documentation: https://dlang.org/phobos/dmd_dtemplate.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d */ module dmd.dtemplate; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.impcnvtab; import dmd.init; import dmd.initsem; import dmd.mtype; import dmd.opover; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.semantic2; import dmd.semantic3; import dmd.tokens; import dmd.typesem; import dmd.visitor; import dmd.templateparamsem; //debug = FindExistingInstance; // print debug stats of findExistingInstance private enum LOG = false; enum IDX_NOTFOUND = 0x12345678; /******************************************** * These functions substitute for dynamic_cast. dynamic_cast does not work * on earlier versions of gcc. */ extern (C++) inout(Expression) isExpression(inout RootObject o) { //return dynamic_cast(o); if (!o || o.dyncast() != DYNCAST.expression) return null; return cast(inout(Expression))o; } extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o) { //return dynamic_cast(o); if (!o || o.dyncast() != DYNCAST.dsymbol) return null; return cast(inout(Dsymbol))o; } extern (C++) inout(Type) isType(inout RootObject o) { //return dynamic_cast(o); if (!o || o.dyncast() != DYNCAST.type) return null; return cast(inout(Type))o; } extern (C++) inout(Tuple) isTuple(inout RootObject o) { //return dynamic_cast(o); if (!o || o.dyncast() != DYNCAST.tuple) return null; return cast(inout(Tuple))o; } extern (C++) inout(Parameter) isParameter(inout RootObject o) { //return dynamic_cast(o); if (!o || o.dyncast() != DYNCAST.parameter) return null; return cast(inout(Parameter))o; } extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o) { if (!o || o.dyncast() != DYNCAST.templateparameter) return null; return cast(inout(TemplateParameter))o; } /************************************** * Is this Object an error? */ extern (C++) bool isError(const RootObject o) { if (const t = isType(o)) return (t.ty == Terror); if (const e = isExpression(o)) return (e.op == TOK.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) return arrayObjectIsError(&v.objects); const s = isDsymbol(o); assert(s); if (s.errors) return true; return s.parent ? isError(s.parent) : false; } /************************************** * Are any of the Objects an error? */ extern (C++) bool arrayObjectIsError(const Objects* args) { foreach (const o; *args) { if (isError(o)) return true; } return false; } /*********************** * Try to get arg as a type. */ extern (C++) inout(Type) getType(inout RootObject o) { inout t = isType(o); if (!t) { if (inout e = isExpression(o)) return e.type; } return t; } extern (C++) Dsymbol getDsymbol(RootObject oarg) { //printf("getDsymbol()\n"); //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg)); Dsymbol sa; if (Expression ea = isExpression(oarg)) { // Try to convert Expression to symbol if (ea.op == TOK.variable) sa = (cast(VarExp)ea).var; else if (ea.op == TOK.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; else sa = (cast(FuncExp)ea).fd; } else if (ea.op == TOK.template_) sa = (cast(TemplateExp)ea).td; else sa = null; } else { // Try to convert Type to symbol if (Type ta = isType(oarg)) sa = ta.toDsymbol(null); else sa = isDsymbol(oarg); // if already a symbol } return sa; } private Expression getValue(ref Dsymbol s) { if (s) { if (VarDeclaration v = s.isVarDeclaration()) { if (v.storage_class & STC.manifest) return v.getConstInitializer(); } } return null; } /*********************** * Try to get value from manifest constant */ private Expression getValue(Expression e) { if (e && e.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && v.storage_class & STC.manifest) { e = v.getConstInitializer(); } } return e; } private Expression getExpression(RootObject o) { auto s = isDsymbol(o); return s ? .getValue(s) : .getValue(isExpression(o)); } /****************************** * If o1 matches o2, return true. * Else, return false. */ private bool match(RootObject o1, RootObject o2) { enum log = false; static if (log) { printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n", o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast()); } /* A proper implementation of the various equals() overrides * should make it possible to just do o1.equals(o2), but * we'll do that another day. */ /* Manifest constants should be compared by their values, * at least in template arguments. */ if (auto t1 = isType(o1)) { auto t2 = isType(o2); if (!t2) goto Lnomatch; static if (log) { printf("\tt1 = %s\n", t1.toChars()); printf("\tt2 = %s\n", t2.toChars()); } if (!t1.equals(t2)) goto Lnomatch; goto Lmatch; } if (auto e1 = getExpression(o1)) { auto e2 = getExpression(o2); if (!e2) goto Lnomatch; static if (log) { printf("\te1 = %s '%s' %s\n", e1.type.toChars(), Token.toChars(e1.op), e1.toChars()); printf("\te2 = %s '%s' %s\n", e2.type.toChars(), Token.toChars(e2.op), e2.toChars()); } // two expressions can be equal although they do not have the same // type; that happens when they have the same value. So check type // as well as expression equality to ensure templates are properly // matched. if (!e1.type.equals(e2.type) || !e1.equals(e2)) goto Lnomatch; goto Lmatch; } if (auto s1 = isDsymbol(o1)) { auto s2 = isDsymbol(o2); if (!s2) goto Lnomatch; static if (log) { printf("\ts1 = %s \n", s1.kind(), s1.toChars()); printf("\ts2 = %s \n", s2.kind(), s2.toChars()); } if (!s1.equals(s2)) goto Lnomatch; if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration()) goto Lnomatch; goto Lmatch; } if (auto u1 = isTuple(o1)) { auto u2 = isTuple(o2); if (!u2) goto Lnomatch; static if (log) { printf("\tu1 = %s\n", u1.toChars()); printf("\tu2 = %s\n", u2.toChars()); } if (!arrayObjectMatch(&u1.objects, &u2.objects)) goto Lnomatch; goto Lmatch; } Lmatch: static if (log) printf("\t. match\n"); return true; Lnomatch: static if (log) printf("\t. nomatch\n"); return false; } /************************************ * Match an array of them. */ private bool arrayObjectMatch(Objects* oa1, Objects* oa2) { if (oa1 == oa2) return true; if (oa1.dim != oa2.dim) return false; immutable oa1dim = oa1.dim; auto oa1d = (*oa1).data; auto oa2d = (*oa2).data; foreach (j; 0 .. oa1dim) { RootObject o1 = oa1d[j]; RootObject o2 = oa2d[j]; if (!match(o1, o2)) { return false; } } return true; } /************************************ * Return hash of Objects. */ private hash_t arrayObjectHash(Objects* oa1) { import dmd.root.hash : mixHash; hash_t hash = 0; foreach (o1; *oa1) { /* Must follow the logic of match() */ if (auto t1 = isType(o1)) hash = mixHash(hash, cast(size_t)t1.deco); else if (auto e1 = getExpression(o1)) hash = mixHash(hash, expressionHash(e1)); else if (auto s1 = isDsymbol(o1)) { auto fa1 = s1.isFuncAliasDeclaration(); if (fa1) s1 = fa1.toAliasFunc(); hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent)); } else if (auto u1 = isTuple(o1)) hash = mixHash(hash, arrayObjectHash(&u1.objects)); } return hash; } /************************************ * Computes hash of expression. * Handles all Expression classes and MUST match their equals method, * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2). */ private hash_t expressionHash(Expression e) { import dmd.root.ctfloat : CTFloat; import dmd.root.hash : calcHash, mixHash; switch (e.op) { case TOK.int64: return cast(size_t) (cast(IntegerExp)e).getInteger(); case TOK.float64: return CTFloat.hash((cast(RealExp)e).value); case TOK.complex80: auto ce = cast(ComplexExp)e; return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary)); case TOK.identifier: return cast(size_t)cast(void*) (cast(IdentifierExp)e).ident; case TOK.null_: return cast(size_t)cast(void*) (cast(NullExp)e).type; case TOK.string_: auto se = cast(StringExp)e; return calcHash(se.string, se.len * se.sz); case TOK.tuple: { auto te = cast(TupleExp)e; size_t hash = 0; hash += te.e0 ? expressionHash(te.e0) : 0; foreach (elem; *te.exps) hash = mixHash(hash, expressionHash(elem)); return hash; } case TOK.arrayLiteral: { auto ae = cast(ArrayLiteralExp)e; size_t hash; foreach (i; 0 .. ae.elements.dim) hash = mixHash(hash, expressionHash(ae.getElement(i))); return hash; } case TOK.assocArrayLiteral: { auto ae = cast(AssocArrayLiteralExp)e; size_t hash; foreach (i; 0 .. ae.keys.dim) // reduction needs associative op as keys are unsorted (use XOR) hash ^= mixHash(expressionHash((*ae.keys)[i]), expressionHash((*ae.values)[i])); return hash; } case TOK.structLiteral: { auto se = cast(StructLiteralExp)e; size_t hash; foreach (elem; *se.elements) hash = mixHash(hash, elem ? expressionHash(elem) : 0); return hash; } case TOK.variable: return cast(size_t)cast(void*) (cast(VarExp)e).var; case TOK.function_: return cast(size_t)cast(void*) (cast(FuncExp)e).fd; default: // no custom equals for this expression assert((&e.equals).funcptr is &RootObject.equals); // equals based on identity return cast(size_t)cast(void*) e; } } RootObject objectSyntaxCopy(RootObject o) { if (!o) return null; if (Type t = isType(o)) return t.syntaxCopy(); if (Expression e = isExpression(o)) return e.syntaxCopy(); return o; } extern (C++) final class Tuple : RootObject { Objects objects; extern (D) this() {} /** Params: numObjects = The initial number of objects. */ extern (D) this(size_t numObjects) { objects.setDim(numObjects); } // kludge for template.isType() override DYNCAST dyncast() const { return DYNCAST.tuple; } override const(char)* toChars() { return objects.toChars(); } } struct TemplatePrevious { TemplatePrevious* prev; Scope* sc; Objects* dedargs; } /*********************************************************** */ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TemplateParameters* parameters; // array of TemplateParameter's TemplateParameters* origParameters; // originals for Ddoc Expression constraint; // Hash table to look up TemplateInstance's of this TemplateDeclaration TemplateInstance[TemplateInstanceBox] instances; TemplateDeclaration overnext; // next overloaded TemplateDeclaration TemplateDeclaration overroot; // first in overnext list FuncDeclaration funcroot; // first function in unified overload list Dsymbol onemember; // if !=null then one member of this template bool literal; // this template declaration is a literal bool ismixin; // template declaration is only to be used as a mixin bool isstatic; // this is static template declaration Prot protection; int inuse; /// for recursive expansion detection // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; extern (D) this(const ref Loc loc, Identifier id, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { super(id); static if (LOG) { printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id.toChars()); } version (none) { if (parameters) for (int i = 0; i < parameters.dim; i++) { TemplateParameter tp = (*parameters)[i]; //printf("\tparameter[%d] = %p\n", i, tp); TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); if (ttp) { printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); } } } this.loc = loc; this.parameters = parameters; this.origParameters = parameters; this.constraint = constraint; this.members = decldefs; this.literal = literal; this.ismixin = ismixin; this.isstatic = true; this.protection = Prot(Prot.Kind.undefined); // Compute in advance for Ddoc's use // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails. if (members && ident) { Dsymbol s; if (Dsymbol.oneMembers(members, &s, ident) && s) { onemember = s; s.parent = this; } } } override Dsymbol syntaxCopy(Dsymbol) { //printf("TemplateDeclaration.syntaxCopy()\n"); TemplateParameters* p = null; if (parameters) { p = new TemplateParameters(parameters.dim); for (size_t i = 0; i < p.dim; i++) (*p)[i] = (*parameters)[i].syntaxCopy(); } return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal); } /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. * Return true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { static if (LOG) { printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars()); } FuncDeclaration fd = s.isFuncDeclaration(); if (fd) { if (funcroot) return funcroot.overloadInsert(fd); funcroot = fd; return funcroot.overloadInsert(this); } TemplateDeclaration td = s.isTemplateDeclaration(); if (!td) return false; TemplateDeclaration pthis = this; TemplateDeclaration* ptd; for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext) { } td.overroot = this; *ptd = td; static if (LOG) { printf("\ttrue: no conflict\n"); } return true; } override bool hasStaticCtorOrDtor() { return false; // don't scan uninstantiated templates } override const(char)* kind() const { return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template"; } override const(char)* toChars() { if (literal) return Dsymbol.toChars(); OutBuffer buf; HdrGenState hgs; buf.writestring(ident.toChars()); buf.writeByte('('); for (size_t i = 0; i < parameters.dim; i++) { TemplateParameter tp = (*parameters)[i]; if (i) buf.writestring(", "); .toCBuffer(tp, &buf, &hgs); } buf.writeByte(')'); if (onemember) { FuncDeclaration fd = onemember.isFuncDeclaration(); if (fd && fd.type) { TypeFunction tf = cast(TypeFunction)fd.type; buf.writestring(parametersTypeToChars(tf.parameters, tf.varargs)); } } if (constraint) { buf.writestring(" if ("); .toCBuffer(constraint, &buf, &hgs); buf.writeByte(')'); } return buf.extractString(); } override Prot prot() { return protection; } /**************************** * Check to see if constraint is satisfied. */ extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) { /* Detect recursive attempts to instantiate this template declaration, * https://issues.dlang.org/show_bug.cgi?id=4072 * void foo(T)(T x) if (is(typeof(foo(x)))) { } * static assert(!is(typeof(foo(7)))); * Recursive attempts are regarded as a constraint failure. */ /* There's a chicken-and-egg problem here. We don't know yet if this template * instantiation will be a local one (enclosing is set), and we won't know until * after selecting the correct template. Thus, function we're nesting inside * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). * Workaround the problem by setting a flag to relax the checking on frame errors. */ for (TemplatePrevious* p = previous; p; p = p.prev) { if (arrayObjectMatch(p.dedargs, dedargs)) { //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive * instantiations. */ for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx == p.sc) return false; } } /* BUG: should also check for ref param differences */ } TemplatePrevious pr; pr.prev = previous; pr.sc = paramscope; pr.dedargs = dedargs; previous = ≺ // add this to threaded list Scope* scx = paramscope.push(ti); scx.parent = ti; scx.tinst = null; scx.minst = null; assert(!ti.symtab); if (fd) { /* Declare all the function parameters as variables and add them to the scope * Making parameters is similar to FuncDeclaration.semantic3 */ TypeFunction tf = cast(TypeFunction)fd.type; assert(tf.ty == Tfunction); scx.parent = fd; Parameters* fparameters = tf.parameters; int fvarargs = tf.varargs; size_t nfparams = Parameter.dim(fparameters); for (size_t i = 0; i < nfparams; i++) { Parameter fparam = Parameter.getNth(fparameters, i); fparam.storageClass &= (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); fparam.storageClass |= STC.parameter; if (fvarargs == 2 && i + 1 == nfparams) { fparam.storageClass |= STC.variadic; /* Don't need to set STC.scope_ because this will only * be evaluated at compile time */ } } for (size_t i = 0; i < fparameters.dim; i++) { Parameter fparam = (*fparameters)[i]; if (!fparam.ident) continue; // don't add it, if it has no name auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null); v.storage_class = fparam.storageClass; v.dsymbolSemantic(scx); if (!ti.symtab) ti.symtab = new DsymbolTable(); if (!scx.insert(v)) error("parameter `%s.%s` is already defined", toChars(), v.toChars()); else v.parent = fd; } if (isstatic) fd.storage_class |= STC.static_; fd.vthis = fd.declareThis(scx, fd.isThis()); } Expression e = constraint.syntaxCopy(); import dmd.staticcond; assert(ti.inst is null); ti.inst = ti; // temporary instantiation to enable genIdent() scx.flags |= SCOPE.constraint; bool errors; bool result = evalStaticCondition(scx, constraint, e, errors); ti.inst = null; ti.symtab = null; scx = scx.pop(); previous = pr.prev; // unlink from threaded list if (errors) return false; return result; } /*************************************** * Given that ti is an instance of this TemplateDeclaration, * deduce the types of the parameters to this, and store * those deduced types in dedtypes[]. * Input: * flag 1: don't do semantic() because of dummy types * 2: don't change types in matchArg() * Output: * dedtypes deduced arguments * Return match level. */ extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag) { enum LOGM = 0; static if (LOGM) { printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); } version (none) { printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes.dim, parameters.dim); if (ti.tiargs.dim) printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, (*ti.tiargs)[0]); } MATCH m; size_t dedtypes_dim = dedtypes.dim; dedtypes.zero(); if (errors) return MATCH.nomatch; size_t parameters_dim = parameters.dim; int variadic = isVariadic() !is null; // If more arguments than parameters, no match if (ti.tiargs.dim > parameters_dim && !variadic) { static if (LOGM) { printf(" no match: more arguments than parameters\n"); } return MATCH.nomatch; } assert(dedtypes_dim == parameters_dim); assert(dedtypes_dim >= ti.tiargs.dim || variadic); assert(_scope); // Set up scope for template parameters auto paramsym = new ScopeDsymbol(); paramsym.parent = _scope.parent; Scope* paramscope = _scope.push(paramsym); paramscope.tinst = ti; paramscope.minst = sc.minst; paramscope.callsc = sc; paramscope.stc = 0; // Attempt type deduction m = MATCH.exact; for (size_t i = 0; i < dedtypes_dim; i++) { MATCH m2; TemplateParameter tp = (*parameters)[i]; Declaration sparam; //printf("\targument [%d]\n", i); static if (LOGM) { //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); if (ttp) printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); } inuse++; m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); inuse--; //printf("\tm2 = %d\n", m2); if (m2 == MATCH.nomatch) { version (none) { printf("\tmatchArg() for parameter %i failed\n", i); } goto Lnomatch; } if (m2 < m) m = m2; if (!flag) sparam.dsymbolSemantic(paramscope); if (!paramscope.insert(sparam)) // TODO: This check can make more early { // in TemplateDeclaration.semantic, and // then we don't need to make sparam if flags == 0 goto Lnomatch; } } if (!flag) { /* Any parameter left without a type gets the type of * its corresponding arg */ for (size_t i = 0; i < dedtypes_dim; i++) { if (!(*dedtypes)[i]) { assert(i < ti.tiargs.dim); (*dedtypes)[i] = cast(Type)(*ti.tiargs)[i]; } } } if (m > MATCH.nomatch && constraint && !flag) { if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error ti.parent = ti.enclosing; else ti.parent = this.parent; // Similar to doHeaderInstantiation FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null; if (fd) { assert(fd.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)fd.type.syntaxCopy(); fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); fd.parent = ti; fd.inferRetType = true; // Shouldn't run semantic on default arguments and return type. for (size_t i = 0; i < tf.parameters.dim; i++) (*tf.parameters)[i].defaultArg = null; tf.next = null; // Resolve parameter types and 'auto ref's. tf.fargs = fargs; uint olderrors = global.startGagging(); fd.type = tf.typeSemantic(loc, paramscope); if (global.endGagging(olderrors)) { assert(fd.type.ty != Tfunction); goto Lnomatch; } assert(fd.type.ty == Tfunction); fd.originalType = fd.type; // for mangling } // TODO: dedtypes => ti.tiargs ? if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) goto Lnomatch; } static if (LOGM) { // Print out the results printf("--------------------------\n"); printf("template %s\n", toChars()); printf("instance %s\n", ti.toChars()); if (m > MATCH.nomatch) { for (size_t i = 0; i < dedtypes_dim; i++) { TemplateParameter tp = (*parameters)[i]; RootObject oarg; printf(" [%d]", i); if (i < ti.tiargs.dim) oarg = (*ti.tiargs)[i]; else oarg = null; tp.print(oarg, (*dedtypes)[i]); } } else goto Lnomatch; } static if (LOGM) { printf(" match = %d\n", m); } goto Lret; Lnomatch: static if (LOGM) { printf(" no match\n"); } m = MATCH.nomatch; Lret: paramscope.pop(); static if (LOGM) { printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); } return m; } /******************************************** * Determine partial specialization order of 'this' vs td2. * Returns: * match this is at least as specialized as td2 * 0 td2 is more specialized than this */ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); } /* This works by taking the template parameters to this template * declaration and feeding them to td2 as if it were a template * instance. * If it works, then this template is at least as specialized * as td2. */ // Set type arguments to dummy template instance to be types // generated from the parameters to this template declaration auto tiargs = new Objects(); tiargs.reserve(parameters.dim); for (size_t i = 0; i < parameters.dim; i++) { TemplateParameter tp = (*parameters)[i]; if (tp.dependent) break; RootObject p = cast(RootObject)tp.dummyArg(); if (!p) break; tiargs.push(p); } scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance // Temporary Array to hold deduced types Objects dedtypes = Objects(td2.parameters.dim); // Attempt a type deduction MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1); if (m > MATCH.nomatch) { /* A non-variadic template is more specialized than a * variadic one. */ TemplateTupleParameter tp = isVariadic(); if (tp && !tp.dependent && !td2.isVariadic()) goto L1; static if (LOG_LEASTAS) { printf(" matches %d, so is least as specialized\n", m); } return m; } L1: static if (LOG_LEASTAS) { printf(" doesn't match, so is not as specialized\n"); } return MATCH.nomatch; } /************************************************* * Match function arguments against a specific template function. * Input: * ti * sc instantiation scope * fd * tthis 'this' argument if !NULL * fargs arguments to function * Output: * fd Partially instantiated function declaration * ti.tdtypes Expression/Type deduced template arguments * Returns: * match level * bit 0-3 Match template parameters by inferred template arguments * bit 4-7 Match template parameters by initial template arguments */ extern (D) MATCH deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs) { size_t nfparams; size_t nfargs; size_t ntargs; // array size of tiargs size_t fptupindex = IDX_NOTFOUND; MATCH match = MATCH.exact; MATCH matchTiargs = MATCH.exact; Parameters* fparameters; // function parameter list int fvarargs; // function varargs uint wildmatch = 0; size_t inferStart = 0; Loc instLoc = ti.loc; Objects* tiargs = ti.tiargs; auto dedargs = new Objects(); Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T version (none) { printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++) { Expression e = (*fargs)[i]; printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); } printf("fd = %s\n", fd.toChars()); printf("fd.type = %s\n", fd.type.toChars()); if (tthis) printf("tthis = %s\n", tthis.toChars()); } assert(_scope); dedargs.setDim(parameters.dim); dedargs.zero(); dedtypes.setDim(parameters.dim); dedtypes.zero(); if (errors || fd.errors) return MATCH.nomatch; // Set up scope for parameters auto paramsym = new ScopeDsymbol(); paramsym.parent = _scope.parent; // should use hasnestedArgs and enclosing? Scope* paramscope = _scope.push(paramsym); paramscope.tinst = ti; paramscope.minst = sc.minst; paramscope.callsc = sc; paramscope.stc = 0; TemplateTupleParameter tp = isVariadic(); Tuple declaredTuple = null; version (none) { for (size_t i = 0; i < dedargs.dim; i++) { printf("\tdedarg[%d] = ", i); RootObject oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg.toChars()); printf("\n"); } } ntargs = 0; if (tiargs) { // Set initial template arguments ntargs = tiargs.dim; size_t n = parameters.dim; if (tp) n--; if (ntargs > n) { if (!tp) goto Lnomatch; /* The extra initial template arguments * now form the tuple argument. */ auto t = new Tuple(ntargs - n); assert(parameters.dim); (*dedargs)[parameters.dim - 1] = t; for (size_t i = 0; i < t.objects.dim; i++) { t.objects[i] = (*tiargs)[n + i]; } declareParameter(paramscope, tp, t); declaredTuple = t; } else n = ntargs; memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); for (size_t i = 0; i < n; i++) { assert(i < parameters.dim); Declaration sparam = null; MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m <= MATCH.nomatch) goto Lnomatch; if (m < matchTiargs) matchTiargs = m; sparam.dsymbolSemantic(paramscope); if (!paramscope.insert(sparam)) goto Lnomatch; } if (n < parameters.dim && !declaredTuple) { inferStart = n; } else inferStart = parameters.dim; //printf("tiargs matchTiargs = %d\n", matchTiargs); } version (none) { for (size_t i = 0; i < dedargs.dim; i++) { printf("\tdedarg[%d] = ", i); RootObject oarg = (*dedargs)[i]; if (oarg) printf("%s", oarg.toChars()); printf("\n"); } } fparameters = fd.getParameters(&fvarargs); nfparams = Parameter.dim(fparameters); // number of function parameters nfargs = fargs ? fargs.dim : 0; // number of function arguments /* Check for match of function arguments with variadic template * parameter, such as: * * void foo(T, A...)(T t, A a); * void main() { foo(1,2,3); } */ if (tp) // if variadic { // TemplateTupleParameter always makes most lesser matching. matchTiargs = MATCH.convert; if (nfparams == 0 && nfargs != 0) // if no function parameters { if (!declaredTuple) { auto t = new Tuple(); //printf("t = %p\n", t); (*dedargs)[parameters.dim - 1] = t; declareParameter(paramscope, tp, t); declaredTuple = t; } } else { /* Figure out which of the function parameters matches * the tuple template parameter. Do this by matching * type identifiers. * Set the index of this function parameter to fptupindex. */ for (fptupindex = 0; fptupindex < nfparams; fptupindex++) { Parameter fparam = (*fparameters)[fptupindex]; if (fparam.type.ty != Tident) continue; TypeIdentifier tid = cast(TypeIdentifier)fparam.type; if (!tp.ident.equals(tid.ident) || tid.idents.dim) continue; if (fvarargs) // variadic function doesn't goto Lnomatch; // go with variadic template goto L1; } fptupindex = IDX_NOTFOUND; L1: } } if (toParent().isModule() || (_scope.stc & STC.static_)) tthis = null; if (tthis) { bool hasttp = false; // Match 'tthis' to any TemplateThisParameter's for (size_t i = 0; i < parameters.dim; i++) { TemplateThisParameter ttp = (*parameters)[i].isTemplateThisParameter(); if (ttp) { hasttp = true; Type t = new TypeIdentifier(Loc.initial, ttp.ident); MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); if (m <= MATCH.nomatch) goto Lnomatch; if (m < match) match = m; // pick worst match } } // Match attributes of tthis against attributes of fd if (fd.type && !fd.isCtorDeclaration()) { StorageClass stc = _scope.stc | fd.storage_class2; // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 Dsymbol p = parent; while (p.isTemplateDeclaration() || p.isTemplateInstance()) p = p.parent; AggregateDeclaration ad = p.isAggregateDeclaration(); if (ad) stc |= ad.storage_class; ubyte mod = fd.type.mod; if (stc & STC.immutable_) mod = MODFlags.immutable_; else { if (stc & (STC.shared_ | STC.synchronized_)) mod |= MODFlags.shared_; if (stc & STC.const_) mod |= MODFlags.const_; if (stc & STC.wild) mod |= MODFlags.wild; } ubyte thismod = tthis.mod; if (hasttp) mod = MODmerge(thismod, mod); MATCH m = MODmethodConv(thismod, mod); if (m <= MATCH.nomatch) goto Lnomatch; if (m < match) match = m; } } // Loop through the function parameters { //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.dim : 0); //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); size_t argi = 0; size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs for (size_t parami = 0; parami < nfparams; parami++) { Parameter fparam = Parameter.getNth(fparameters, parami); // Apply function parameter storage classes to parameter types Type prmtype = fparam.type.addStorageClass(fparam.storageClass); Expression farg; /* See function parameters which wound up * as part of a template tuple parameter. */ if (fptupindex != IDX_NOTFOUND && parami == fptupindex) { assert(prmtype.ty == Tident); TypeIdentifier tid = cast(TypeIdentifier)prmtype; if (!declaredTuple) { /* The types of the function arguments * now form the tuple argument. */ declaredTuple = new Tuple(); (*dedargs)[parameters.dim - 1] = declaredTuple; /* Count function parameters with no defaults following a tuple parameter. * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) */ size_t rem = 0; for (size_t j = parami + 1; j < nfparams; j++) { Parameter p = Parameter.getNth(fparameters, j); if (p.defaultArg) { break; } if (!reliesOnTident(p.type, parameters, inferStart)) { Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.dim : 1; } else { ++rem; } } if (nfargs2 - argi < rem) goto Lnomatch; declaredTuple.objects.setDim(nfargs2 - argi - rem); for (size_t i = 0; i < declaredTuple.objects.dim; i++) { farg = (*fargs)[argi + i]; // Check invalid arguments to detect errors early. if (farg.op == TOK.error || farg.type.ty == Terror) goto Lnomatch; if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid) goto Lnomatch; Type tt; MATCH m; if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) { wildmatch |= wm; m = MATCH.constant; } else { m = deduceTypeHelper(farg.type, &tt, tid); } if (m <= MATCH.nomatch) goto Lnomatch; if (m < match) match = m; /* Remove top const for dynamic array types and pointer types */ if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) { tt = tt.mutableOf(); } declaredTuple.objects[i] = tt; } declareParameter(paramscope, tp, declaredTuple); } else { // https://issues.dlang.org/show_bug.cgi?id=6810 // If declared tuple is not a type tuple, // it cannot be function parameter types. for (size_t i = 0; i < declaredTuple.objects.dim; i++) { if (!isType(declaredTuple.objects[i])) goto Lnomatch; } } assert(declaredTuple); argi += declaredTuple.objects.dim; continue; } // If parameter type doesn't depend on inferred template parameters, // semantic it to get actual type. if (!reliesOnTident(prmtype, parameters, inferStart)) { // should copy prmtype to avoid affecting semantic result prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); if (prmtype.ty == Ttuple) { TypeTuple tt = cast(TypeTuple)prmtype; size_t tt_dim = tt.arguments.dim; for (size_t j = 0; j < tt_dim; j++, ++argi) { Parameter p = (*tt.arguments)[j]; if (j == tt_dim - 1 && fvarargs == 2 && parami + 1 == nfparams && argi < nfargs) { prmtype = p.type; goto Lvarargs; } if (argi >= nfargs) { if (p.defaultArg) continue; goto Lnomatch; } farg = (*fargs)[argi]; if (!farg.implicitConvTo(p.type)) goto Lnomatch; } continue; } } if (argi >= nfargs) // if not enough arguments { if (!fparam.defaultArg) goto Lvarargs; /* https://issues.dlang.org/show_bug.cgi?id=2803 * Before the starting of type deduction from the function * default arguments, set the already deduced parameters into paramscope. * It's necessary to avoid breaking existing acceptable code. Cases: * * 1. Already deduced template parameters can appear in fparam.defaultArg: * auto foo(A, B)(A a, B b = A.stringof); * foo(1); * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' * * 2. If prmtype depends on default-specified template parameter, the * default type should be preferred. * auto foo(N = size_t, R)(R r, N start = 0) * foo([1,2,3]); * // at fparam `N start = 0`, N should be 'size_t' before * // the deduction result from fparam.defaultArg. */ if (argi == nfargs) { for (size_t i = 0; i < dedtypes.dim; i++) { Type at = isType((*dedtypes)[i]); if (at && at.ty == Tnone) { TypeDeduced xt = cast(TypeDeduced)at; (*dedtypes)[i] = xt.tded; // 'unbox' } } for (size_t i = ntargs; i < dedargs.dim; i++) { TemplateParameter tparam = (*parameters)[i]; RootObject oarg = (*dedargs)[i]; RootObject oded = (*dedtypes)[i]; if (!oarg) { if (oded) { if (tparam.specialization() || !tparam.isTemplateTypeParameter()) { /* The specialization can work as long as afterwards * the oded == oarg */ (*dedargs)[i] = oded; MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); //printf("m2 = %d\n", m2); if (m2 <= MATCH.nomatch) goto Lnomatch; if (m2 < matchTiargs) matchTiargs = m2; // pick worst match if (!(*dedtypes)[i].equals(oded)) error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars()); } else { if (MATCH.convert < matchTiargs) matchTiargs = MATCH.convert; } (*dedargs)[i] = declareParameter(paramscope, tparam, oded); } else { inuse++; oded = tparam.defaultArg(instLoc, paramscope); inuse--; if (oded) (*dedargs)[i] = declareParameter(paramscope, tparam, oded); } } } } nfargs2 = argi + 1; /* If prmtype does not depend on any template parameters: * * auto foo(T)(T v, double x = 0); * foo("str"); * // at fparam == 'double x = 0' * * or, if all template parameters in the prmtype are already deduced: * * auto foo(R)(R range, ElementType!R sum = 0); * foo([1,2,3]); * // at fparam == 'ElementType!R sum = 0' * * Deducing prmtype from fparam.defaultArg is not necessary. */ if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope)) { ++argi; continue; } // Deduce prmtype from the defaultArg. farg = fparam.defaultArg.syntaxCopy(); farg = farg.expressionSemantic(paramscope); farg = resolveProperties(paramscope, farg); } else { farg = (*fargs)[argi]; } { // Check invalid arguments to detect errors early. if (farg.op == TOK.error || farg.type.ty == Terror) goto Lnomatch; Type att = null; Lretry: version (none) { printf("\tfarg.type = %s\n", farg.type.toChars()); printf("\tfparam.type = %s\n", prmtype.toChars()); } Type argtype = farg.type; if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != TOK.function_) goto Lnomatch; // https://issues.dlang.org/show_bug.cgi?id=12876 // Optimize argument to allow CT-known length matching farg = farg.optimize(WANTvalue, (fparam.storageClass & (STC.ref_ | STC.out_)) != 0); //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); RootObject oarg = farg; if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) { /* Allow expressions that have CT-known boundaries and type [] to match with [dim] */ Type taai; if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) { if (farg.op == TOK.string_) { StringExp se = cast(StringExp)farg; argtype = se.type.nextOf().sarrayOf(se.len); } else if (farg.op == TOK.arrayLiteral) { ArrayLiteralExp ae = cast(ArrayLiteralExp)farg; argtype = ae.type.nextOf().sarrayOf(ae.elements.dim); } else if (farg.op == TOK.slice) { SliceExp se = cast(SliceExp)farg; if (Type tsa = toStaticArrayType(se)) argtype = tsa; } } oarg = argtype; } else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.dim == 0) { /* The farg passing to the prmtype always make a copy. Therefore, * we can shrink the set of the deduced type arguments for prmtype * by adjusting top-qualifier of the argtype. * * prmtype argtype ta * T <- const(E)[] const(E)[] * T <- const(E[]) const(E)[] * qualifier(T) <- const(E)[] const(E[]) * qualifier(T) <- const(E[]) const(E[]) */ Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); if (ta != argtype) { Expression ea = farg.copy(); ea.type = ta; oarg = ea; } } if (fvarargs == 2 && parami + 1 == nfparams && argi + 1 < nfargs) goto Lvarargs; uint wm = 0; MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart); //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch); wildmatch |= wm; /* If no match, see if the argument can be matched by using * implicit conversions. */ if (m == MATCH.nomatch && prmtype.deco) m = farg.implicitConvTo(prmtype); if (m == MATCH.nomatch) { AggregateDeclaration ad = isAggregate(farg.type); if (ad && ad.aliasthis && argtype != att) { if (!att && argtype.checkAliasThisRec()) // https://issues.dlang.org/show_bug.cgi?id=12537 att = argtype; /* If a semantic error occurs while doing alias this, * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), * just regard it as not a match. */ if (auto e = resolveAliasThis(sc, farg, true)) { farg = e; goto Lretry; } } } if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) { if (!farg.isLvalue()) { if ((farg.op == TOK.string_ || farg.op == TOK.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] } else goto Lnomatch; } } if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) { if (!farg.isLvalue()) goto Lnomatch; if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 goto Lnomatch; } if (m == MATCH.nomatch && (fparam.storageClass & STC.lazy_) && prmtype.ty == Tvoid && farg.type.ty != Tvoid) m = MATCH.convert; if (m != MATCH.nomatch) { if (m < match) match = m; // pick worst match argi++; continue; } } Lvarargs: /* The following code for variadic arguments closely * matches TypeFunction.callMatch() */ if (!(fvarargs == 2 && parami + 1 == nfparams)) goto Lnomatch; /* Check for match with function parameter T... */ Type tb = prmtype.toBasetype(); switch (tb.ty) { // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). case Tsarray: case Taarray: { // Perhaps we can do better with this, see TypeFunction.callMatch() if (tb.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tb; dinteger_t sz = tsa.dim.toInteger(); if (sz != nfargs - argi) goto Lnomatch; } else if (tb.ty == Taarray) { TypeAArray taa = cast(TypeAArray)tb; Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); size_t i = templateParameterLookup(taa.index, parameters); if (i == IDX_NOTFOUND) { Expression e; Type t; Dsymbol s; Scope *sco; uint errors = global.startGagging(); /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 * The parameter isn't part of the template * ones, let's try to find it in the * instantiation scope 'sc' and the one * belonging to the template itself. */ sco = sc; taa.index.resolve(instLoc, sco, &e, &t, &s); if (!e) { sco = paramscope; taa.index.resolve(instLoc, sco, &e, &t, &s); } global.endGagging(errors); if (!e) { goto Lnomatch; } e = e.ctfeInterpret(); e = e.implicitCastTo(sco, Type.tsize_t); e = e.optimize(WANTvalue); if (!dim.equals(e)) goto Lnomatch; } else { // This code matches code in TypeInstance.deduceType() TemplateParameter tprm = (*parameters)[i]; TemplateValueParameter tvp = tprm.isTemplateValueParameter(); if (!tvp) goto Lnomatch; Expression e = cast(Expression)(*dedtypes)[i]; if (e) { if (!dim.equals(e)) goto Lnomatch; } else { Type vt = tvp.valType.typeSemantic(Loc.initial, sc); MATCH m = dim.implicitConvTo(vt); if (m <= MATCH.nomatch) goto Lnomatch; (*dedtypes)[i] = dim; } } } goto case Tarray; } case Tarray: { TypeArray ta = cast(TypeArray)tb; Type tret = fparam.isLazyArray(); for (; argi < nfargs; argi++) { Expression arg = (*fargs)[argi]; assert(arg); MATCH m; /* If lazy array of delegates, * convert arg(s) to delegate(s) */ if (tret) { if (ta.next.equals(arg.type)) { m = MATCH.exact; } else { m = arg.implicitConvTo(tret); if (m == MATCH.nomatch) { if (tret.toBasetype().ty == Tvoid) m = MATCH.convert; } } } else { uint wm = 0; m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); wildmatch |= wm; } if (m == MATCH.nomatch) goto Lnomatch; if (m < match) match = m; } goto Lmatch; } case Tclass: case Tident: goto Lmatch; default: goto Lnomatch; } assert(0); } //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); if (argi != nfargs2 && !fvarargs) goto Lnomatch; } Lmatch: for (size_t i = 0; i < dedtypes.dim; i++) { Type at = isType((*dedtypes)[i]); if (at) { if (at.ty == Tnone) { TypeDeduced xt = cast(TypeDeduced)at; at = xt.tded; // 'unbox' } (*dedtypes)[i] = at.merge2(); } } for (size_t i = ntargs; i < dedargs.dim; i++) { TemplateParameter tparam = (*parameters)[i]; //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); /* For T:T*, the dedargs is the T*, dedtypes is the T * But for function templates, we really need them to match */ RootObject oarg = (*dedargs)[i]; RootObject oded = (*dedtypes)[i]; //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); //if (oarg) printf("oarg: %s\n", oarg.toChars()); //if (oded) printf("oded: %s\n", oded.toChars()); if (!oarg) { if (oded) { if (tparam.specialization() || !tparam.isTemplateTypeParameter()) { /* The specialization can work as long as afterwards * the oded == oarg */ (*dedargs)[i] = oded; MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); //printf("m2 = %d\n", m2); if (m2 <= MATCH.nomatch) goto Lnomatch; if (m2 < matchTiargs) matchTiargs = m2; // pick worst match if (!(*dedtypes)[i].equals(oded)) error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars()); } else { // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 if (MATCH.convert < matchTiargs) matchTiargs = MATCH.convert; } } else { inuse++; oded = tparam.defaultArg(instLoc, paramscope); inuse--; if (!oded) { // if tuple parameter and // tuple parameter was not in function parameter list and // we're one or more arguments short (i.e. no tuple argument) if (tparam == tp && fptupindex == IDX_NOTFOUND && ntargs <= dedargs.dim - 1) { // make tuple argument an empty tuple oded = cast(RootObject)new Tuple(); } else goto Lnomatch; } if (isError(oded)) goto Lerror; ntargs++; /* At the template parameter T, the picked default template argument * X!int should be matched to T in order to deduce dependent * template parameter A. * auto foo(T : X!A = X!int, A...)() { ... } * foo(); // T <-- X!int, A <-- (int) */ if (tparam.specialization()) { (*dedargs)[i] = oded; MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); //printf("m2 = %d\n", m2); if (m2 <= MATCH.nomatch) goto Lnomatch; if (m2 < matchTiargs) matchTiargs = m2; // pick worst match if (!(*dedtypes)[i].equals(oded)) error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars()); } } oded = declareParameter(paramscope, tparam, oded); (*dedargs)[i] = oded; } } /* https://issues.dlang.org/show_bug.cgi?id=7469 * As same as the code for 7469 in findBestMatch, * expand a Tuple in dedargs to normalize template arguments. */ if (auto d = dedargs.dim) { if (auto va = isTuple((*dedargs)[d - 1])) { dedargs.setDim(d - 1); dedargs.insert(d - 1, &va.objects); } } ti.tiargs = dedargs; // update to the normalized template arguments. // Partially instantiate function for constraint and fd.leastAsSpecialized() { assert(paramsym); Scope* sc2 = _scope; sc2 = sc2.push(paramsym); sc2 = sc2.push(ti); sc2.parent = ti; sc2.tinst = ti; sc2.minst = sc.minst; fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); sc2 = sc2.pop(); sc2 = sc2.pop(); if (!fd) goto Lnomatch; } if (constraint) { if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) goto Lnomatch; } version (none) { for (size_t i = 0; i < dedargs.dim; i++) { RootObject o = (*dedargs)[i]; printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); } } paramscope.pop(); //printf("\tmatch %d\n", match); return cast(MATCH)(match | (matchTiargs << 4)); Lnomatch: paramscope.pop(); //printf("\tnomatch\n"); return MATCH.nomatch; Lerror: // todo: for the future improvement paramscope.pop(); //printf("\terror\n"); return MATCH.nomatch; } /************************************************** * Declare template parameter tp with value o, and install it in the scope sc. */ RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o) { //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); Type ta = isType(o); Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); Tuple va = isTuple(o); Declaration d; VarDeclaration v = null; if (ea && ea.op == TOK.type) ta = ea.type; else if (ea && ea.op == TOK.scope_) sa = (cast(ScopeExp)ea).sds; else if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_)) sa = (cast(ThisExp)ea).var; else if (ea && ea.op == TOK.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; else sa = (cast(FuncExp)ea).fd; } if (ta) { //printf("type %s\n", ta.toChars()); d = new AliasDeclaration(Loc.initial, tp.ident, ta); } else if (sa) { //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); d = new AliasDeclaration(Loc.initial, tp.ident, sa); } else if (ea) { // tdtypes.data[i] always matches ea here Initializer _init = new ExpInitializer(loc, ea); TemplateValueParameter tvp = tp.isTemplateValueParameter(); Type t = tvp ? tvp.valType : null; v = new VarDeclaration(loc, t, tp.ident, _init); v.storage_class = STC.manifest | STC.templateparameter; d = v; } else if (va) { //printf("\ttuple\n"); d = new TupleDeclaration(loc, tp.ident, &va.objects); } else { assert(0); } d.storage_class |= STC.templateparameter; if (ta) { Type t = ta; // consistent with Type.checkDeprecated() while (t.ty != Tenum) { if (!t.nextOf()) break; t = (cast(TypeNext)t).next; } if (Dsymbol s = t.toDsymbol(sc)) { if (s.isDeprecated()) d.storage_class |= STC.deprecated_; } } else if (sa) { if (sa.isDeprecated()) d.storage_class |= STC.deprecated_; } if (!sc.insert(d)) error("declaration `%s` is already defined", tp.ident.toChars()); d.dsymbolSemantic(sc); /* So the caller's o gets updated with the result of semantic() being run on o */ if (v) o = v._init.initializerToExpression(); return o; } /************************************************* * Limited function template instantiation for using fd.leastAsSpecialized() */ extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) { assert(fd); version (none) { printf("doHeaderInstantiation this = %s\n", toChars()); } // function body and contracts are not need if (fd.isCtorDeclaration()) fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); else fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); fd.parent = ti; assert(fd.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)fd.type; tf.fargs = fargs; if (tthis) { // Match 'tthis' to any TemplateThisParameter's bool hasttp = false; for (size_t i = 0; i < parameters.dim; i++) { TemplateParameter tp = (*parameters)[i]; TemplateThisParameter ttp = tp.isTemplateThisParameter(); if (ttp) hasttp = true; } if (hasttp) { tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); assert(!tf.deco); } } Scope* scx = sc2.push(); // Shouldn't run semantic on default arguments and return type. for (size_t i = 0; i < tf.parameters.dim; i++) (*tf.parameters)[i].defaultArg = null; if (fd.isCtorDeclaration()) { // For constructors, emitting return type is necessary for // isReturnIsolated() in functionResolve. scx.flags |= SCOPE.ctor; Dsymbol parent = toParent2(); Type tret; AggregateDeclaration ad = parent.isAggregateDeclaration(); if (!ad || parent.isUnionDeclaration()) { tret = Type.tvoid; } else { tret = ad.handleType(); assert(tret); tret = tret.addStorageClass(fd.storage_class | scx.stc); tret = tret.addMod(tf.mod); } tf.next = tret; if (ad && ad.isStructDeclaration()) tf.isref = 1; //printf("tf = %s\n", tf.toChars()); } else tf.next = null; fd.type = tf; fd.type = fd.type.addSTC(scx.stc); fd.type = fd.type.typeSemantic(fd.loc, scx); scx = scx.pop(); if (fd.type.ty != Tfunction) return null; fd.originalType = fd.type; // for mangling //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); //printf("fd.needThis() = %d\n", fd.needThis()); return fd; } debug (FindExistingInstance) { __gshared uint nFound, nNotFound, nAdded, nRemoved; shared static ~this() { printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n", nFound, nNotFound, nAdded, nRemoved); } } /**************************************************** * Given a new instance tithis of this TemplateDeclaration, * see if there already exists an instance. * If so, return that existing instance. */ extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs) { //printf("findExistingInstance(%p)\n", tithis); tithis.fargs = fargs; auto tibox = TemplateInstanceBox(tithis); auto p = tibox in instances; debug (FindExistingInstance) ++(p ? nFound : nNotFound); //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n"); return p ? *p : null; } /******************************************** * Add instance ti to TemplateDeclaration's table of instances. * Return a handle we can use to later remove it if it fails instantiation. */ extern (D) TemplateInstance addInstance(TemplateInstance ti) { //printf("addInstance() %p %p\n", instances, ti); auto tibox = TemplateInstanceBox(ti); instances[tibox] = ti; debug (FindExistingInstance) ++nAdded; return ti; } /******************************************* * Remove TemplateInstance from table of instances. * Input: * handle returned by addInstance() */ extern (D) void removeInstance(TemplateInstance ti) { //printf("removeInstance()\n"); auto tibox = TemplateInstanceBox(ti); debug (FindExistingInstance) ++nRemoved; instances.remove(tibox); } override inout(TemplateDeclaration) isTemplateDeclaration() inout { return this; } /** * Check if the last template parameter is a tuple one, * and returns it if so, else returns `null`. * * Returns: * The last template parameter if it's a `TemplateTupleParameter` */ TemplateTupleParameter isVariadic() { size_t dim = parameters.dim; if (dim == 0) return null; return (*parameters)[dim - 1].isTemplateTupleParameter(); } /*********************************** * We can overload templates. */ override bool isOverloadable() { return true; } override void accept(Visitor v) { v.visit(this); } } extern (C++) final class TypeDeduced : Type { Type tded; Expressions argexps; // corresponding expressions Types tparams; // tparams[i].mod extern (D) this(Type tt, Expression e, Type tparam) { super(Tnone); tded = tt; argexps.push(e); tparams.push(tparam); } void update(Expression e, Type tparam) { argexps.push(e); tparams.push(tparam); } void update(Type tt, Expression e, Type tparam) { tded = tt; argexps.push(e); tparams.push(tparam); } MATCH matchAll(Type tt) { MATCH match = MATCH.exact; for (size_t j = 0; j < argexps.dim; j++) { Expression e = argexps[j]; assert(e); if (e == emptyArrayElement) continue; Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_); MATCH m = e.implicitConvTo(t); if (match > m) match = m; if (match <= MATCH.nomatch) break; } return match; } } /************************************************* * Given function arguments, figure out which template function * to expand, and return matching result. * Params: * m = matching result * dstart = the root of overloaded function templates * loc = instantiation location * sc = instantiation scope * tiargs = initial list of template arguments * tthis = if !NULL, the 'this' pointer argument * fargs = arguments to function * pMessage = address to store error message, or null */ void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, Type tthis, Expressions* fargs, const(char)** pMessage = null) { version (none) { printf("functionResolve() dstart = %s\n", dstart.toChars()); printf(" tiargs:\n"); if (tiargs) { for (size_t i = 0; i < tiargs.dim; i++) { RootObject arg = (*tiargs)[i]; printf("\t%s\n", arg.toChars()); } } printf(" fargs:\n"); for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++) { Expression arg = (*fargs)[i]; printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); //printf("\tty = %d\n", arg.type.ty); } //printf("stc = %llx\n", dstart.scope.stc); //printf("match:t/f = %d/%d\n", ta_last, m.last); } // results int property = 0; // 0: uninitialized // 1: seen @property // 2: not @property size_t ov_index = 0; TemplateDeclaration td_best; TemplateInstance ti_best; MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch; Type tthis_best; int applyFunction(FuncDeclaration fd) { // skip duplicates if (fd == m.lastf) return 0; // explicitly specified tiargs never match to non template function if (tiargs && tiargs.dim > 0) return 0; if (fd.semanticRun < PASS.semanticdone) { Ungag ungag = fd.ungagSpeculative(); fd.dsymbolSemantic(null); } if (fd.semanticRun == PASS.init) { .error(loc, "forward reference to template `%s`", fd.toChars()); return 1; } //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); m.anyf = fd; auto tf = cast(TypeFunction)fd.type; int prop = tf.isproperty ? 1 : 2; if (property == 0) property = prop; else if (property != prop) error(fd.loc, "cannot overload both property and non-property functions"); /* For constructors, qualifier check will be opposite direction. * Qualified constructor always makes qualified object, then will be checked * that it is implicitly convertible to tthis. */ Type tthis_fd = fd.needThis() ? tthis : null; bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); if (isCtorCall) { //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), // tf.mod, tthis_fd.mod, fd.isReturnIsolated()); if (MODimplicitConv(tf.mod, tthis_fd.mod) || tf.isWild() && tf.isShared() == tthis_fd.isShared() || fd.isReturnIsolated()) { /* && tf.isShared() == tthis_fd.isShared()*/ // Uniquely constructed object can ignore shared qualifier. // TODO: Is this appropriate? tthis_fd = null; } else return 0; // MATCH.nomatch } /* Fix Issue 17970: If a struct is declared as shared the dtor is automatically considered to be shared, but when the struct is instantiated the instance is no longer considered to be shared when the function call matching is done. The fix makes it so that if a struct declaration is shared, when the destructor is called, the instantiated struct is also considered shared. */ if (auto dt = fd.isDtorDeclaration()) { auto dtmod = dt.type.toTypeFunction(); auto shared_dtor = dtmod.mod & MODFlags.shared_; auto shared_this = tthis_fd !is null ? tthis_fd.mod & MODFlags.shared_ : 0; if (shared_dtor && !shared_this) tthis_fd = dtmod; else if (shared_this && !shared_dtor && tthis_fd !is null) tf.mod = tthis_fd.mod; } MATCH mfa = tf.callMatch(tthis_fd, fargs, 0, pMessage); //printf("test1: mfa = %d\n", mfa); if (mfa > MATCH.nomatch) { if (mfa > m.last) goto LfIsBetter; if (mfa < m.last) goto LlastIsBetter; /* See if one of the matches overrides the other. */ assert(m.lastf); if (m.lastf.overrides(fd)) goto LlastIsBetter; if (fd.overrides(m.lastf)) goto LfIsBetter; /* Try to disambiguate using template-style partial ordering rules. * In essence, if f() and g() are ambiguous, if f() can call g(), * but g() cannot call f(), then pick f(). * This is because f() is "more specialized." */ { MATCH c1 = fd.leastAsSpecialized(m.lastf); MATCH c2 = m.lastf.leastAsSpecialized(fd); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto LfIsBetter; if (c1 < c2) goto LlastIsBetter; } /* The 'overrides' check above does covariant checking only * for virtual member functions. It should do it for all functions, * but in order to not risk breaking code we put it after * the 'leastAsSpecialized' check. * In the future try moving it before. * I.e. a not-the-same-but-covariant match is preferred, * as it is more restrictive. */ if (!m.lastf.type.equals(fd.type)) { //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type)); if (m.lastf.type.covariant(fd.type) == 1) goto LlastIsBetter; if (fd.type.covariant(m.lastf.type) == 1) goto LfIsBetter; } /* If the two functions are the same function, like: * int foo(int); * int foo(int x) { ... } * then pick the one with the body. */ if (tf.equals(m.lastf.type) && fd.storage_class == m.lastf.storage_class && fd.parent == m.lastf.parent && fd.protection == m.lastf.protection && fd.linkage == m.lastf.linkage) { if (fd.fbody && !m.lastf.fbody) goto LfIsBetter; if (!fd.fbody && m.lastf.fbody) goto LlastIsBetter; } // https://issues.dlang.org/show_bug.cgi?id=14450 // Prefer exact qualified constructor for the creating object type if (isCtorCall && tf.mod != m.lastf.type.mod) { if (tthis.mod == tf.mod) goto LfIsBetter; if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter; } m.nextf = fd; m.count++; return 0; LlastIsBetter: return 0; LfIsBetter: td_best = null; ti_best = null; ta_last = MATCH.exact; m.last = mfa; m.lastf = fd; tthis_best = tthis_fd; ov_index = 0; m.count = 1; return 0; } return 0; } int applyTemplate(TemplateDeclaration td) { //printf("applyTemplate()\n"); if (td.inuse) { td.error(loc, "recursive template expansion"); return 1; } if (td == td_best) // skip duplicates return 0; if (!sc) sc = td._scope; // workaround for Type.aliasthisOf if (td.semanticRun == PASS.init && td._scope) { // Try to fix forward reference. Ungag errors while doing so. Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } if (td.semanticRun == PASS.init) { .error(loc, "forward reference to template `%s`", td.toChars()); Lerror: m.lastf = null; m.count = 0; m.last = MATCH.nomatch; return 1; } //printf("td = %s\n", td.toChars()); auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; if (!f) { if (!tiargs) tiargs = new Objects(); auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.dim); assert(td.semanticRun != PASS.init); MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0); //printf("matchWithInstance = %d\n", mta); if (mta <= MATCH.nomatch || mta < ta_last) // no match or less match return 0; ti.templateInstanceSemantic(sc, fargs); if (!ti.inst) // if template failed to expand return 0; Dsymbol s = ti.inst.toAlias(); FuncDeclaration fd; if (auto tdx = s.isTemplateDeclaration()) { Objects dedtypesX; // empty tiargs // https://issues.dlang.org/show_bug.cgi?id=11553 // Check for recursive instantiation of tdx. for (TemplatePrevious* p = tdx.previous; p; p = p.prev) { if (arrayObjectMatch(p.dedargs, &dedtypesX)) { //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); /* It must be a subscope of p.sc, other scope chains are not recursive * instantiations. */ for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx == p.sc) { error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars()); goto Lerror; } } } /* BUG: should also check for ref param differences */ } TemplatePrevious pr; pr.prev = tdx.previous; pr.sc = sc; pr.dedargs = &dedtypesX; tdx.previous = ≺ // add this to threaded list fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, 1); tdx.previous = pr.prev; // unlink from threaded list } else if (s.isFuncDeclaration()) { fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, 1); } else goto Lerror; if (!fd) return 0; if (fd.type.ty != Tfunction) { m.lastf = fd; // to propagate "error match" m.count = 1; m.last = MATCH.nomatch; return 1; } Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; auto tf = cast(TypeFunction)fd.type; MATCH mfa = tf.callMatch(tthis_fd, fargs); if (mfa < m.last) return 0; if (mta < ta_last) goto Ltd_best2; if (mta > ta_last) goto Ltd2; if (mfa < m.last) goto Ltd_best2; if (mfa > m.last) goto Ltd2; Lambig2: // td_best and td are ambiguous //printf("Lambig2\n"); m.nextf = fd; m.count++; return 0; Ltd_best2: return 0; Ltd2: // td is the new best match assert(td._scope); td_best = td; ti_best = null; property = 0; // (backward compatibility) ta_last = mta; m.last = mfa; m.lastf = fd; tthis_best = tthis_fd; ov_index = 0; m.nextf = null; m.count = 1; return 0; } //printf("td = %s\n", td.toChars()); for (size_t ovi = 0; f; f = f.overnext0, ovi++) { if (f.type.ty != Tfunction || f.errors) goto Lerror; /* This is a 'dummy' instance to evaluate constraint properly. */ auto ti = new TemplateInstance(loc, td, tiargs); ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. auto fd = f; int x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs); MATCH mta = cast(MATCH)(x >> 4); MATCH mfa = cast(MATCH)(x & 0xF); //printf("match:t/f = %d/%d\n", mta, mfa); if (!fd || mfa == MATCH.nomatch) continue; Type tthis_fd = fd.needThis() ? tthis : null; bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); if (isCtorCall) { // Constructor call requires additional check. auto tf = cast(TypeFunction)fd.type; assert(tf.next); if (MODimplicitConv(tf.mod, tthis_fd.mod) || tf.isWild() && tf.isShared() == tthis_fd.isShared() || fd.isReturnIsolated()) { tthis_fd = null; } else continue; // MATCH.nomatch } if (mta < ta_last) goto Ltd_best; if (mta > ta_last) goto Ltd; if (mfa < m.last) goto Ltd_best; if (mfa > m.last) goto Ltd; if (td_best) { // Disambiguate by picking the most specialized TemplateDeclaration MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); //printf("1: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } assert(fd && m.lastf); { // Disambiguate by tf.callMatch auto tf1 = cast(TypeFunction)fd.type; assert(tf1.ty == Tfunction); auto tf2 = cast(TypeFunction)m.lastf.type; assert(tf2.ty == Tfunction); MATCH c1 = tf1.callMatch(tthis_fd, fargs); MATCH c2 = tf2.callMatch(tthis_best, fargs); //printf("2: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } { // Disambiguate by picking the most specialized FunctionDeclaration MATCH c1 = fd.leastAsSpecialized(m.lastf); MATCH c2 = m.lastf.leastAsSpecialized(fd); //printf("3: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } // https://issues.dlang.org/show_bug.cgi?id=14450 // Prefer exact qualified constructor for the creating object type if (isCtorCall && fd.type.mod != m.lastf.type.mod) { if (tthis.mod == fd.type.mod) goto Ltd; if (tthis.mod == m.lastf.type.mod) goto Ltd_best; } m.nextf = fd; m.count++; continue; Ltd_best: // td_best is the best match so far //printf("Ltd_best\n"); continue; Ltd: // td is the new best match //printf("Ltd\n"); assert(td._scope); td_best = td; ti_best = ti; property = 0; // (backward compatibility) ta_last = mta; m.last = mfa; m.lastf = fd; tthis_best = tthis_fd; ov_index = ovi; m.nextf = null; m.count = 1; continue; } return 0; } auto td = dstart.isTemplateDeclaration(); if (td && td.funcroot) dstart = td.funcroot; overloadApply(dstart, (Dsymbol s) { if (s.errors) return 0; if (auto fd = s.isFuncDeclaration()) return applyFunction(fd); if (auto td = s.isTemplateDeclaration()) return applyTemplate(td); return 0; }, sc); //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); if (td_best && ti_best && m.count == 1) { // Matches to template function assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); /* The best match is td_best with arguments tdargs. * Now instantiate the template. */ assert(td_best._scope); if (!sc) sc = td_best._scope; // workaround for Type.aliasthisOf auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); ti.templateInstanceSemantic(sc, fargs); m.lastf = ti.toAlias().isFuncDeclaration(); if (!m.lastf) goto Lnomatch; if (ti.errors) { Lerror: m.count = 1; assert(m.lastf); m.last = MATCH.nomatch; return; } // look forward instantiated overload function // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. // it has filled overnext0d while (ov_index--) { m.lastf = m.lastf.overnext0; assert(m.lastf); } tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; auto tf = cast(TypeFunction)m.lastf.type; if (tf.ty == Terror) goto Lerror; assert(tf.ty == Tfunction); if (!tf.callMatch(tthis_best, fargs)) goto Lnomatch; /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, * a template instance can be matched while instantiating * that same template. Thus, the function type can be incomplete. Complete it. * * https://issues.dlang.org/show_bug.cgi?id=9208 * For auto function, completion should be deferred to the end of * its semantic3. Should not complete it in here. */ if (tf.next && !m.lastf.inferRetType) { m.lastf.type = tf.typeSemantic(loc, sc); } } else if (m.lastf) { // Matches to non template function, // or found matches were ambiguous. assert(m.count >= 1); } else { Lnomatch: m.count = 0; m.lastf = null; m.last = MATCH.nomatch; } } /* ======================== Type ============================================ */ /**** * Given an identifier, figure out which TemplateParameter it is. * Return IDX_NOTFOUND if not found. */ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters) { for (size_t i = 0; i < parameters.dim; i++) { TemplateParameter tp = (*parameters)[i]; if (tp.ident.equals(id)) return i; } return IDX_NOTFOUND; } private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { if (tparam.ty == Tident) { TypeIdentifier tident = cast(TypeIdentifier)tparam; //printf("\ttident = '%s'\n", tident.toChars()); return templateIdentifierLookup(tident.ident, parameters); } return IDX_NOTFOUND; } private ubyte deduceWildHelper(Type t, Type* at, Type tparam) { if ((tparam.mod & MODFlags.wild) == 0) return 0; *at = null; auto X(T, U)(T U, U T) { return (U << 4) | T; } switch (X(tparam.mod, t.mod)) { case X(MODFlags.wild, 0): case X(MODFlags.wild, MODFlags.const_): case X(MODFlags.wild, MODFlags.shared_): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.wild, MODFlags.immutable_): case X(MODFlags.wildconst, 0): case X(MODFlags.wildconst, MODFlags.const_): case X(MODFlags.wildconst, MODFlags.shared_): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.wildconst, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_): { ubyte wm = (t.mod & ~MODFlags.shared_); if (wm == 0) wm = MODFlags.mutable; ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_); *at = t.unqualify(m); return wm; } case X(MODFlags.wild, MODFlags.wild): case X(MODFlags.wild, MODFlags.wildconst): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.wildconst, MODFlags.wild): case X(MODFlags.wildconst, MODFlags.wildconst): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst): { *at = t.unqualify(tparam.mod & t.mod); return MODFlags.wild; } default: return 0; } } /** * Returns the common type of the 2 types. */ private Type rawTypeMerge(Type t1, Type t2) { if (t1.equals(t2)) return t1; if (t1.equivalent(t2)) return t1.castMod(MODmerge(t1.mod, t2.mod)); auto t1b = t1.toBasetype(); auto t2b = t2.toBasetype(); if (t1b.equals(t2b)) return t1b; if (t1b.equivalent(t2b)) return t1b.castMod(MODmerge(t1b.mod, t2b.mod)); auto ty = cast(TY)impcnvResult[t1b.ty][t2b.ty]; if (ty != Terror) return Type.basic[ty]; return null; } private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) { // 9*9 == 81 cases auto X(T, U)(T U, U T) { return (U << 4) | T; } switch (X(tparam.mod, t.mod)) { case X(0, 0): case X(0, MODFlags.const_): case X(0, MODFlags.wild): case X(0, MODFlags.wildconst): case X(0, MODFlags.shared_): case X(0, MODFlags.shared_ | MODFlags.const_): case X(0, MODFlags.shared_ | MODFlags.wild): case X(0, MODFlags.shared_ | MODFlags.wildconst): case X(0, MODFlags.immutable_): // foo(U) T => T // foo(U) const(T) => const(T) // foo(U) inout(T) => inout(T) // foo(U) inout(const(T)) => inout(const(T)) // foo(U) shared(T) => shared(T) // foo(U) shared(const(T)) => shared(const(T)) // foo(U) shared(inout(T)) => shared(inout(T)) // foo(U) shared(inout(const(T))) => shared(inout(const(T))) // foo(U) immutable(T) => immutable(T) { *at = t; return MATCH.exact; } case X(MODFlags.const_, MODFlags.const_): case X(MODFlags.wild, MODFlags.wild): case X(MODFlags.wildconst, MODFlags.wildconst): case X(MODFlags.shared_, MODFlags.shared_): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.immutable_, MODFlags.immutable_): // foo(const(U)) const(T) => T // foo(inout(U)) inout(T) => T // foo(inout(const(U))) inout(const(T)) => T // foo(shared(U)) shared(T) => T // foo(shared(const(U))) shared(const(T)) => T // foo(shared(inout(U))) shared(inout(T)) => T // foo(shared(inout(const(U)))) shared(inout(const(T))) => T // foo(immutable(U)) immutable(T) => T { *at = t.mutableOf().unSharedOf(); return MATCH.exact; } case X(MODFlags.const_, 0): case X(MODFlags.const_, MODFlags.wild): case X(MODFlags.const_, MODFlags.wildconst): case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.const_, MODFlags.immutable_): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_): // foo(const(U)) T => T // foo(const(U)) inout(T) => T // foo(const(U)) inout(const(T)) => T // foo(const(U)) shared(const(T)) => shared(T) // foo(const(U)) shared(inout(T)) => shared(T) // foo(const(U)) shared(inout(const(T))) => shared(T) // foo(const(U)) immutable(T) => T // foo(inout(U)) shared(inout(T)) => shared(T) // foo(inout(const(U))) shared(inout(const(T))) => shared(T) // foo(shared(const(U))) immutable(T) => T { *at = t.mutableOf(); return MATCH.constant; } case X(MODFlags.const_, MODFlags.shared_): // foo(const(U)) shared(T) => shared(T) { *at = t; return MATCH.constant; } case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_): // foo(shared(U)) shared(const(T)) => const(T) // foo(shared(U)) shared(inout(T)) => inout(T) // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) // foo(shared(const(U))) shared(T) => T { *at = t.unSharedOf(); return MATCH.constant; } case X(MODFlags.wildconst, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): // foo(inout(const(U))) immutable(T) => T // foo(shared(const(U))) shared(inout(const(T))) => T // foo(shared(inout(const(U)))) immutable(T) => T // foo(shared(inout(const(U)))) shared(inout(T)) => T { *at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): // foo(shared(const(U))) shared(inout(T)) => T { *at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.wild, 0): case X(MODFlags.wild, MODFlags.const_): case X(MODFlags.wild, MODFlags.wildconst): case X(MODFlags.wild, MODFlags.immutable_): case X(MODFlags.wild, MODFlags.shared_): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.wildconst, 0): case X(MODFlags.wildconst, MODFlags.const_): case X(MODFlags.wildconst, MODFlags.wild): case X(MODFlags.wildconst, MODFlags.shared_): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_, 0): case X(MODFlags.shared_, MODFlags.const_): case X(MODFlags.shared_, MODFlags.wild): case X(MODFlags.shared_, MODFlags.wildconst): case X(MODFlags.shared_, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.const_, 0): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wild, 0): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wildconst, 0): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.immutable_, 0): case X(MODFlags.immutable_, MODFlags.const_): case X(MODFlags.immutable_, MODFlags.wild): case X(MODFlags.immutable_, MODFlags.wildconst): case X(MODFlags.immutable_, MODFlags.shared_): case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_): case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst): // foo(inout(U)) T => nomatch // foo(inout(U)) const(T) => nomatch // foo(inout(U)) inout(const(T)) => nomatch // foo(inout(U)) immutable(T) => nomatch // foo(inout(U)) shared(T) => nomatch // foo(inout(U)) shared(const(T)) => nomatch // foo(inout(U)) shared(inout(const(T))) => nomatch // foo(inout(const(U))) T => nomatch // foo(inout(const(U))) const(T) => nomatch // foo(inout(const(U))) inout(T) => nomatch // foo(inout(const(U))) shared(T) => nomatch // foo(inout(const(U))) shared(const(T)) => nomatch // foo(inout(const(U))) shared(inout(T)) => nomatch // foo(shared(U)) T => nomatch // foo(shared(U)) const(T) => nomatch // foo(shared(U)) inout(T) => nomatch // foo(shared(U)) inout(const(T)) => nomatch // foo(shared(U)) immutable(T) => nomatch // foo(shared(const(U))) T => nomatch // foo(shared(const(U))) const(T) => nomatch // foo(shared(const(U))) inout(T) => nomatch // foo(shared(const(U))) inout(const(T)) => nomatch // foo(shared(inout(U))) T => nomatch // foo(shared(inout(U))) const(T) => nomatch // foo(shared(inout(U))) inout(T) => nomatch // foo(shared(inout(U))) inout(const(T)) => nomatch // foo(shared(inout(U))) immutable(T) => nomatch // foo(shared(inout(U))) shared(T) => nomatch // foo(shared(inout(U))) shared(const(T)) => nomatch // foo(shared(inout(U))) shared(inout(const(T))) => nomatch // foo(shared(inout(const(U)))) T => nomatch // foo(shared(inout(const(U)))) const(T) => nomatch // foo(shared(inout(const(U)))) inout(T) => nomatch // foo(shared(inout(const(U)))) inout(const(T)) => nomatch // foo(shared(inout(const(U)))) shared(T) => nomatch // foo(shared(inout(const(U)))) shared(const(T)) => nomatch // foo(immutable(U)) T => nomatch // foo(immutable(U)) const(T) => nomatch // foo(immutable(U)) inout(T) => nomatch // foo(immutable(U)) inout(const(T)) => nomatch // foo(immutable(U)) shared(T) => nomatch // foo(immutable(U)) shared(const(T)) => nomatch // foo(immutable(U)) shared(inout(T)) => nomatch // foo(immutable(U)) shared(inout(const(T))) => nomatch return MATCH.nomatch; default: assert(0); } } __gshared Expression emptyArrayElement = null; /* These form the heart of template argument deduction. * Given 'this' being the type argument to the template instance, * it is matched against the template declaration parameter specialization * 'tparam' to determine the type to be used for the parameter. * Example: * template Foo(T:T*) // template declaration * Foo!(int*) // template instantiation * Input: * this = int* * tparam = T* * parameters = [ T:T* ] // Array of TemplateParameter's * Output: * dedtypes = [ int ] // Array of Expression/Type's */ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0) { extern (C++) final class DeduceType : Visitor { alias visit = Visitor.visit; public: Scope* sc; Type tparam; TemplateParameters* parameters; Objects* dedtypes; uint* wm; size_t inferStart; MATCH result; extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart) { this.sc = sc; this.tparam = tparam; this.parameters = parameters; this.dedtypes = dedtypes; this.wm = wm; this.inferStart = inferStart; result = MATCH.nomatch; } override void visit(Type t) { if (!tparam) goto Lnomatch; if (t == tparam) goto Lexact; if (tparam.ty == Tident) { // Determine which parameter tparam is size_t i = templateParameterLookup(tparam, parameters); if (i == IDX_NOTFOUND) { if (!sc) goto Lnomatch; /* Need a loc to go with the semantic routine. */ Loc loc; if (parameters.dim) { TemplateParameter tp = (*parameters)[0]; loc = tp.loc; } /* BUG: what if tparam is a template instance, that * has as an argument another Tident? */ tparam = tparam.typeSemantic(loc, sc); assert(tparam.ty != Tident); result = deduceType(t, sc, tparam, parameters, dedtypes, wm); return; } TemplateParameter tp = (*parameters)[i]; TypeIdentifier tident = cast(TypeIdentifier)tparam; if (tident.idents.dim > 0) { //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); Dsymbol s = t.toDsymbol(sc); for (size_t j = tident.idents.dim; j-- > 0;) { RootObject id = tident.idents[j]; if (id.dyncast() == DYNCAST.identifier) { if (!s || !s.parent) goto Lnomatch; Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id); if (!s2) goto Lnomatch; s2 = s2.toAlias(); //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars()); if (s != s2) { if (Type tx = s2.getType()) { if (s != tx.toDsymbol(sc)) goto Lnomatch; } else goto Lnomatch; } s = s.parent; } else goto Lnomatch; } //printf("[e] s = %s\n", s?s.toChars():"(null)"); if (tp.isTemplateTypeParameter()) { Type tt = s.getType(); if (!tt) goto Lnomatch; Type at = cast(Type)(*dedtypes)[i]; if (at && at.ty == Tnone) at = (cast(TypeDeduced)at).tded; if (!at || tt.equals(at)) { (*dedtypes)[i] = tt; goto Lexact; } } if (tp.isTemplateAliasParameter()) { Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; if (!s2 || s == s2) { (*dedtypes)[i] = s; goto Lexact; } } goto Lnomatch; } // Found the corresponding parameter tp if (!tp.isTemplateTypeParameter()) goto Lnomatch; Type at = cast(Type)(*dedtypes)[i]; Type tt; if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) { // type vs (none) if (!at) { (*dedtypes)[i] = tt; *wm |= wx; result = MATCH.constant; return; } // type vs expressions if (at.ty == Tnone) { TypeDeduced xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { (*dedtypes)[i] = tt; if (result > MATCH.constant) result = MATCH.constant; // limit level for inout matches } return; } // type vs type if (tt.equals(at)) { (*dedtypes)[i] = tt; // Prefer current type match goto Lconst; } if (tt.implicitConvTo(at.constOf())) { (*dedtypes)[i] = at.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } if (at.implicitConvTo(tt.constOf())) { (*dedtypes)[i] = tt.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } goto Lnomatch; } else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) { // type vs (none) if (!at) { (*dedtypes)[i] = tt; result = m; return; } // type vs expressions if (at.ty == Tnone) { TypeDeduced xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { (*dedtypes)[i] = tt; } return; } // type vs type if (tt.equals(at)) { goto Lexact; } if (tt.ty == Tclass && at.ty == Tclass) { result = tt.implicitConvTo(at); return; } if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant) { goto Lexact; } } goto Lnomatch; } if (tparam.ty == Ttypeof) { /* Need a loc to go with the semantic routine. */ Loc loc; if (parameters.dim) { TemplateParameter tp = (*parameters)[0]; loc = tp.loc; } tparam = tparam.typeSemantic(loc, sc); } if (t.ty != tparam.ty) { if (Dsymbol sym = t.toDsymbol(sc)) { if (sym.isforwardRef() && !tparam.deco) goto Lnomatch; } MATCH m = t.implicitConvTo(tparam); if (m == MATCH.nomatch) { if (t.ty == Tclass) { TypeClass tc = cast(TypeClass)t; if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) { tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT); m = deduceType(ato, sc, tparam, parameters, dedtypes, wm); tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT); } } } else if (t.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)t; if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) { ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT); m = deduceType(ato, sc, tparam, parameters, dedtypes, wm); ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT); } } } } result = m; return; } if (t.nextOf()) { if (tparam.deco && !tparam.hasWild()) { result = t.implicitConvTo(tparam); return; } Type tpn = tparam.nextOf(); if (wm && t.ty == Taarray && tparam.isWild()) { // https://issues.dlang.org/show_bug.cgi?id=12403 // In IFTI, stop inout matching on transitive part of AA types. tpn = tpn.substWildTo(MODFlags.mutable); } result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm); return; } Lexact: result = MATCH.exact; return; Lnomatch: result = MATCH.nomatch; return; Lconst: result = MATCH.constant; } override void visit(TypeVector t) { if (tparam.ty == Tvector) { TypeVector tp = cast(TypeVector)tparam; result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); return; } visit(cast(Type)t); } override void visit(TypeDArray t) { visit(cast(Type)t); } override void visit(TypeSArray t) { // Extra check that array dimensions must match if (tparam) { if (tparam.ty == Tarray) { MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch; return; } TemplateParameter tp = null; Expression edim = null; size_t i; if (tparam.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tparam; if (tsa.dim.op == TOK.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter) { Identifier id = (cast(VarExp)tsa.dim).var.ident; i = templateIdentifierLookup(id, parameters); assert(i != IDX_NOTFOUND); tp = (*parameters)[i]; } else edim = tsa.dim; } else if (tparam.ty == Taarray) { TypeAArray taa = cast(TypeAArray)tparam; i = templateParameterLookup(taa.index, parameters); if (i != IDX_NOTFOUND) tp = (*parameters)[i]; else { Expression e; Type tx; Dsymbol s; taa.index.resolve(Loc.initial, sc, &e, &tx, &s); edim = s ? getValue(s) : getValue(e); } } if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; } } visit(cast(Type)t); } override void visit(TypeAArray t) { // Extra check that index type must match if (tparam && tparam.ty == Taarray) { TypeAArray tp = cast(TypeAArray)tparam; if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) { result = MATCH.nomatch; return; } } visit(cast(Type)t); } override void visit(TypeFunction t) { // Extra check that function characteristics must match if (tparam && tparam.ty == Tfunction) { TypeFunction tp = cast(TypeFunction)tparam; if (t.varargs != tp.varargs || t.linkage != tp.linkage) { result = MATCH.nomatch; return; } foreach (fparam; *tp.parameters) { // https://issues.dlang.org/show_bug.cgi?id=2579 // Apply function parameter storage classes to parameter types fparam.type = fparam.type.addStorageClass(fparam.storageClass); fparam.storageClass &= ~(STC.TYPECTOR | STC.in_); // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters if (!reliesOnTident(fparam.type, parameters, inferStart)) { auto tx = fparam.type.typeSemantic(Loc.initial, sc); if (tx.ty == Terror) { result = MATCH.nomatch; return; } fparam.type = tx; } } size_t nfargs = Parameter.dim(t.parameters); size_t nfparams = Parameter.dim(tp.parameters); /* See if tuple match */ if (nfparams > 0 && nfargs >= nfparams - 1) { /* See if 'A' of the template parameter matches 'A' * of the type of the last function parameter. */ Parameter fparam = Parameter.getNth(tp.parameters, nfparams - 1); assert(fparam); assert(fparam.type); if (fparam.type.ty != Tident) goto L1; TypeIdentifier tid = cast(TypeIdentifier)fparam.type; if (tid.idents.dim) goto L1; /* Look through parameters to find tuple matching tid.ident */ size_t tupi = 0; for (; 1; tupi++) { if (tupi == parameters.dim) goto L1; TemplateParameter tx = (*parameters)[tupi]; TemplateTupleParameter tup = tx.isTemplateTupleParameter(); if (tup && tup.ident.equals(tid.ident)) break; } /* The types of the function arguments [nfparams - 1 .. nfargs] * now form the tuple argument. */ size_t tuple_dim = nfargs - (nfparams - 1); /* See if existing tuple, and whether it matches or not */ RootObject o = (*dedtypes)[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match Tuple tup = isTuple(o); if (!tup || tup.objects.dim != tuple_dim) { result = MATCH.nomatch; return; } for (size_t i = 0; i < tuple_dim; i++) { Parameter arg = Parameter.getNth(t.parameters, nfparams - 1 + i); if (!arg.type.equals(tup.objects[i])) { result = MATCH.nomatch; return; } } } else { // Create new tuple auto tup = new Tuple(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) { Parameter arg = Parameter.getNth(t.parameters, nfparams - 1 + i); tup.objects[i] = arg.type; } (*dedtypes)[tupi] = tup; } nfparams--; // don't consider the last parameter for type deduction goto L2; } L1: if (nfargs != nfparams) { result = MATCH.nomatch; return; } L2: for (size_t i = 0; i < nfparams; i++) { Parameter a = Parameter.getNth(t.parameters, i); Parameter ap = Parameter.getNth(tp.parameters, i); if (!a.isCovariant(t.isref, ap) || !deduceType(a.type, sc, ap.type, parameters, dedtypes)) { result = MATCH.nomatch; return; } } } visit(cast(Type)t); } override void visit(TypeIdentifier t) { // Extra check if (tparam && tparam.ty == Tident) { TypeIdentifier tp = cast(TypeIdentifier)tparam; for (size_t i = 0; i < t.idents.dim; i++) { RootObject id1 = t.idents[i]; RootObject id2 = tp.idents[i]; if (!id1.equals(id2)) { result = MATCH.nomatch; return; } } } visit(cast(Type)t); } override void visit(TypeInstance t) { // Extra check if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl) { TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); TypeInstance tp = cast(TypeInstance)tparam; //printf("tempinst.tempdecl = %p\n", tempdecl); //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); if (!tp.tempinst.tempdecl) { //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars()); /* Handle case of: * template Foo(T : sa!(T), alias sa) */ size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking * it up and seeing if is an alias. * https://issues.dlang.org/show_bug.cgi?id=1454 */ auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name); Type tx; Expression e; Dsymbol s; tid.resolve(tp.loc, sc, &e, &tx, &s); if (tx) { s = tx.toDsymbol(sc); if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null) { // https://issues.dlang.org/show_bug.cgi?id=14290 // Try to match with ti.tempecl, // only when ti is an enclosing instance. Dsymbol p = sc.parent; while (p && p != ti) p = p.parent; if (p) s = ti.tempdecl; } } if (s) { s = s.toAlias(); TemplateDeclaration td = s.isTemplateDeclaration(); if (td) { if (td.overroot) td = td.overroot; for (; td; td = td.overnext) { if (td == tempdecl) goto L2; } } } goto Lnomatch; } TemplateParameter tpx = (*parameters)[i]; if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) goto Lnomatch; } else if (tempdecl != tp.tempinst.tempdecl) goto Lnomatch; L2: for (size_t i = 0; 1; i++) { //printf("\ttest: tempinst.tiargs[%d]\n", i); RootObject o1 = null; if (i < t.tempinst.tiargs.dim) o1 = (*t.tempinst.tiargs)[i]; else if (i < t.tempinst.tdtypes.dim && i < tp.tempinst.tiargs.dim) { // Pick up default arg o1 = t.tempinst.tdtypes[i]; } else if (i >= tp.tempinst.tiargs.dim) break; if (i >= tp.tempinst.tiargs.dim) { size_t dim = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) { i++; } if (i >= dim) break; // match if all remained parameters are dependent goto Lnomatch; } RootObject o2 = (*tp.tempinst.tiargs)[i]; Type t2 = isType(o2); size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.dim - 1) ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; if (j != IDX_NOTFOUND && j == parameters.dim - 1 && (*parameters)[j].isTemplateTupleParameter()) { /* Given: * struct A(B...) {} * alias A!(int, float) X; * static if (is(X Y == A!(Z), Z...)) {} * deduce that Z is a tuple(int, float) */ /* Create tuple from remaining args */ size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.dim : t.tempinst.tdtypes.dim) - i; auto vt = new Tuple(vtdim); for (size_t k = 0; k < vtdim; k++) { RootObject o; if (k < t.tempinst.tiargs.dim) o = (*t.tempinst.tiargs)[i + k]; else // Pick up default arg o = t.tempinst.tdtypes[i + k]; vt.objects[k] = o; } Tuple v = cast(Tuple)(*dedtypes)[j]; if (v) { if (!match(v, vt)) goto Lnomatch; } else (*dedtypes)[j] = vt; break; } else if (!o1) break; Type t1 = isType(o1); Dsymbol s1 = isDsymbol(o1); Dsymbol s2 = isDsymbol(o2); Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); Expression e2 = isExpression(o2); version (none) { Tuple v1 = isTuple(o1); Tuple v2 = isTuple(o2); if (t1) printf("t1 = %s\n", t1.toChars()); if (t2) printf("t2 = %s\n", t2.toChars()); if (e1) printf("e1 = %s\n", e1.toChars()); if (e2) printf("e2 = %s\n", e2.toChars()); if (s1) printf("s1 = %s\n", s1.toChars()); if (s2) printf("s2 = %s\n", s2.toChars()); if (v1) printf("v1 = %s\n", v1.toChars()); if (v2) printf("v2 = %s\n", v2.toChars()); } if (t1 && t2) { if (!deduceType(t1, sc, t2, parameters, dedtypes)) goto Lnomatch; } else if (e1 && e2) { Le: e1 = e1.ctfeInterpret(); /* If it is one of the template parameters for this template, * we should not attempt to interpret it. It already has a value. */ if (e2.op == TOK.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter)) { /* * (T:Number!(e2), int e2) */ j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters); if (j != IDX_NOTFOUND) goto L1; // The template parameter was not from this template // (it may be from a parent template, for example) } e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 e2 = e2.ctfeInterpret(); //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); if (!e1.equals(e2)) { if (!e2.implicitConvTo(e1.type)) goto Lnomatch; e2 = e2.implicitCastTo(sc, e1.type); e2 = e2.ctfeInterpret(); if (!e1.equals(e2)) goto Lnomatch; } } else if (e1 && t2 && t2.ty == Tident) { j = templateParameterLookup(t2, parameters); L1: if (j == IDX_NOTFOUND) { t2.resolve((cast(TypeIdentifier)t2).loc, sc, &e2, &t2, &s2); if (e2) goto Le; goto Lnomatch; } if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) goto Lnomatch; } else if (s1 && s2) { Ls: if (!s1.equals(s2)) goto Lnomatch; } else if (s1 && t2 && t2.ty == Tident) { j = templateParameterLookup(t2, parameters); if (j == IDX_NOTFOUND) { t2.resolve((cast(TypeIdentifier)t2).loc, sc, &e2, &t2, &s2); if (s2) goto Ls; goto Lnomatch; } if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) goto Lnomatch; } else goto Lnomatch; } } visit(cast(Type)t); return; Lnomatch: //printf("no match\n"); result = MATCH.nomatch; } override void visit(TypeStruct t) { /* If this struct is a template struct, and we're matching * it against a template instance, convert the struct type * to a template instance, too, and try again. */ TemplateInstance ti = t.sym.parent.isTemplateInstance(); if (tparam && tparam.ty == Tinstance) { if (ti && ti.toAlias() == t.sym) { auto tx = new TypeInstance(Loc.initial, ti); result = deduceType(tx, sc, tparam, parameters, dedtypes, wm); return; } /* Match things like: * S!(T).foo */ TypeInstance tpi = cast(TypeInstance)tparam; if (tpi.idents.dim) { RootObject id = tpi.idents[tpi.idents.dim - 1]; if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id)) { Type tparent = t.sym.parent.getType(); if (tparent) { /* Slice off the .foo in S!(T).foo */ tpi.idents.dim--; result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); tpi.idents.dim++; return; } } } } // Extra check if (tparam && tparam.ty == Tstruct) { TypeStruct tp = cast(TypeStruct)tparam; //printf("\t%d\n", (MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) { result = MATCH.constant; return; } result = t.implicitConvTo(tp); return; } visit(cast(Type)t); } override void visit(TypeEnum t) { // Extra check if (tparam && tparam.ty == Tenum) { TypeEnum tp = cast(TypeEnum)tparam; if (t.sym == tp.sym) visit(cast(Type)t); else result = MATCH.nomatch; return; } Type tb = t.toBasetype(); if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray) { result = deduceType(tb, sc, tparam, parameters, dedtypes, wm); return; } visit(cast(Type)t); } /* Helper for TypeClass.deduceType(). * Classes can match with implicit conversion to a base class or interface. * This is complicated, because there may be more than one base class which * matches. In such cases, one or more parameters remain ambiguous. * For example, * * interface I(X, Y) {} * class C : I(uint, double), I(char, double) {} * C x; * foo(T, U)( I!(T, U) x) * * deduces that U is double, but T remains ambiguous (could be char or uint). * * Given a baseclass b, and initial deduced types 'dedtypes', this function * tries to match tparam with b, and also tries all base interfaces of b. * If a match occurs, numBaseClassMatches is incremented, and the new deduced * types are ANDed with the current 'best' estimate for dedtypes. */ static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) { TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; if (parti) { // Make a temporary copy of dedtypes so we don't destroy it auto tmpdedtypes = new Objects(dedtypes.dim); memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.dim * (void*).sizeof); auto t = new TypeInstance(Loc.initial, parti); MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); if (m > MATCH.nomatch) { // If this is the first ever match, it becomes our best estimate if (numBaseClassMatches == 0) memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.dim * (void*).sizeof); else for (size_t k = 0; k < tmpdedtypes.dim; ++k) { // If we've found more than one possible type for a parameter, // mark it as unknown. if ((*tmpdedtypes)[k] != (*best)[k]) (*best)[k] = (*dedtypes)[k]; } ++numBaseClassMatches; } } // Now recursively test the inherited interfaces foreach (ref bi; b.baseInterfaces) { deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); } } override void visit(TypeClass t) { //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); /* If this class is a template class, and we're matching * it against a template instance, convert the class type * to a template instance, too, and try again. */ TemplateInstance ti = t.sym.parent.isTemplateInstance(); if (tparam && tparam.ty == Tinstance) { if (ti && ti.toAlias() == t.sym) { auto tx = new TypeInstance(Loc.initial, ti); MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm); // Even if the match fails, there is still a chance it could match // a base class. if (m != MATCH.nomatch) { result = m; return; } } /* Match things like: * S!(T).foo */ TypeInstance tpi = cast(TypeInstance)tparam; if (tpi.idents.dim) { RootObject id = tpi.idents[tpi.idents.dim - 1]; if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id)) { Type tparent = t.sym.parent.getType(); if (tparent) { /* Slice off the .foo in S!(T).foo */ tpi.idents.dim--; result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); tpi.idents.dim++; return; } } } // If it matches exactly or via implicit conversion, we're done visit(cast(Type)t); if (result != MATCH.nomatch) return; /* There is still a chance to match via implicit conversion to * a base class or interface. Because there could be more than one such * match, we need to check them all. */ int numBaseClassMatches = 0; // Have we found an interface match? // Our best guess at dedtypes auto best = new Objects(dedtypes.dim); ClassDeclaration s = t.sym; while (s && s.baseclasses.dim > 0) { // Test the base class deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); // Test the interfaces inherited by the base class foreach (b; s.interfaces) { deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); } s = (*s.baseclasses)[0].sym; } if (numBaseClassMatches == 0) { result = MATCH.nomatch; return; } // If we got at least one match, copy the known types into dedtypes memcpy(dedtypes.tdata(), best.tdata(), best.dim * (void*).sizeof); result = MATCH.convert; return; } // Extra check if (tparam && tparam.ty == Tclass) { TypeClass tp = cast(TypeClass)tparam; //printf("\t%d\n", (MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) { result = MATCH.constant; return; } result = t.implicitConvTo(tp); return; } visit(cast(Type)t); } override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); size_t i = templateParameterLookup(tparam, parameters); if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.dim > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) { Type tn = (cast(TypeNext)tparam).next; result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); return; } e.type.accept(this); return; } TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); if (!tp) return; // nomatch if (e == emptyArrayElement) { if ((*dedtypes)[i]) { result = MATCH.exact; return; } if (tp.defaultType) { tp.defaultType.accept(this); return; } } /* Returns `true` if `t` is a reference type, or an array of reference types */ bool isTopRef(Type t) { auto tb = t.baseElemOf(); return tb.ty == Tclass || tb.ty == Taarray || tb.ty == Tstruct && tb.hasPointers(); } Type at = cast(Type)(*dedtypes)[i]; Type tt; if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) { *wm |= wx; result = MATCH.constant; } else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) { result = m; } else if (!isTopRef(e.type)) { /* https://issues.dlang.org/show_bug.cgi?id=15653 * In IFTI, recognize top-qualifier conversions * through the value copy, e.g. * int --> immutable(int) * immutable(string[]) --> immutable(string)[] */ tt = e.type.mutableOf(); result = MATCH.convert; } else return; // nomatch // expression vs (none) if (!at) { (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); return; } TypeDeduced xt = null; if (at.ty == Tnone) { xt = cast(TypeDeduced)at; at = xt.tded; } // From previous matched expressions to current deduced type MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch; // From current expressions to previous deduced type Type pt = at.addMod(tparam.mod); if (*wm) pt = pt.substWildTo(*wm); MATCH match2 = e.implicitConvTo(pt); if (match1 > MATCH.nomatch && match2 > MATCH.nomatch) { if (at.implicitConvTo(tt) <= MATCH.nomatch) match1 = MATCH.nomatch; // Prefer at else if (tt.implicitConvTo(at) <= MATCH.nomatch) match2 = MATCH.nomatch; // Prefer tt else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod) { if (!tt.isMutable() && !at.isMutable()) tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod)); else if (tt.isMutable()) { if (at.mod == 0) // Prefer unshared match1 = MATCH.nomatch; else match2 = MATCH.nomatch; } else if (at.isMutable()) { if (tt.mod == 0) // Prefer unshared match2 = MATCH.nomatch; else match1 = MATCH.nomatch; } //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars()); } else { match1 = MATCH.nomatch; match2 = MATCH.nomatch; } } if (match1 > MATCH.nomatch) { // Prefer current match: tt if (xt) xt.update(tt, e, tparam); else (*dedtypes)[i] = tt; result = match1; return; } if (match2 > MATCH.nomatch) { // Prefer previous match: (*dedtypes)[i] if (xt) xt.update(e, tparam); result = match2; return; } /* Deduce common type */ if (Type t = rawTypeMerge(at, tt)) { if (xt) xt.update(t, e, tparam); else (*dedtypes)[i] = t; pt = tt.addMod(tparam.mod); if (*wm) pt = pt.substWildTo(*wm); result = e.implicitConvTo(pt); return; } result = MATCH.nomatch; } MATCH deduceEmptyArrayElement() { if (!emptyArrayElement) { emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy emptyArrayElement.type = Type.tvoid; } assert(tparam.ty == Tarray); Type tn = (cast(TypeNext)tparam).next; return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); } override void visit(NullExp e) { if (tparam.ty == Tarray && e.type.ty == Tnull) { // tparam:T[] <- e:null (void[]) result = deduceEmptyArrayElement(); return; } visit(cast(Expression)e); } override void visit(StringExp e) { Type taai; if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) { // Consider compile-time known boundaries e.type.nextOf().sarrayOf(e.len).accept(this); return; } visit(cast(Expression)e); } override void visit(ArrayLiteralExp e) { if ((!e.elements || !e.elements.dim) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray) { // tparam:T[] <- e:[] (void[]) result = deduceEmptyArrayElement(); return; } if (tparam.ty == Tarray && e.elements && e.elements.dim) { Type tn = (cast(TypeDArray)tparam).next; result = MATCH.exact; if (e.basis) { MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm); if (m < result) result = m; } for (size_t i = 0; i < e.elements.dim; i++) { if (result <= MATCH.nomatch) break; auto el = (*e.elements)[i]; if (!el) continue; MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm); if (m < result) result = m; } return; } Type taai; if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) { // Consider compile-time known boundaries e.type.nextOf().sarrayOf(e.elements.dim).accept(this); return; } visit(cast(Expression)e); } override void visit(AssocArrayLiteralExp e) { if (tparam.ty == Taarray && e.keys && e.keys.dim) { TypeAArray taa = cast(TypeAArray)tparam; result = MATCH.exact; for (size_t i = 0; i < e.keys.dim; i++) { MATCH m1 = deduceType((*e.keys)[i], sc, taa.index, parameters, dedtypes, wm); if (m1 < result) result = m1; if (result <= MATCH.nomatch) break; MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm); if (m2 < result) result = m2; if (result <= MATCH.nomatch) break; } return; } visit(cast(Expression)e); } override void visit(FuncExp e) { //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars()); if (e.td) { Type to = tparam; if (!to.nextOf() || to.nextOf().ty != Tfunction) return; TypeFunction tof = cast(TypeFunction)to.nextOf(); // Parameter types inference from 'tof' assert(e.td._scope); TypeFunction tf = cast(TypeFunction)e.fd.type; //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); size_t dim = Parameter.dim(tf.parameters); if (Parameter.dim(tof.parameters) != dim || tof.varargs != tf.varargs) return; auto tiargs = new Objects(); tiargs.reserve(e.td.parameters.dim); for (size_t i = 0; i < e.td.parameters.dim; i++) { TemplateParameter tp = (*e.td.parameters)[i]; size_t u = 0; for (; u < dim; u++) { Parameter p = Parameter.getNth(tf.parameters, u); if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) { break; } } assert(u < dim); Parameter pto = Parameter.getNth(tof.parameters, u); if (!pto) break; Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 if (reliesOnTident(t, parameters, inferStart)) return; t = t.typeSemantic(e.loc, sc); if (t.ty == Terror) return; tiargs.push(t); } // Set target of return type inference if (!tf.next && tof.next) e.fd.treq = tparam; auto ti = new TemplateInstance(e.loc, e.td, tiargs); Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope); // Reset inference target for the later re-semantic e.fd.treq = null; if (ex.op == TOK.error) return; if (ex.op != TOK.function_) return; visit(ex.type); return; } Type t = e.type; if (t.ty == Tdelegate && tparam.ty == Tpointer) return; // Allow conversion from implicit function pointer to delegate if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate) { TypeFunction tf = cast(TypeFunction)t.nextOf(); t = (new TypeDelegate(tf)).merge(); } //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); visit(t); } override void visit(SliceExp e) { Type taai; if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) { // Consider compile-time known boundaries if (Type tsa = toStaticArrayType(e)) { tsa.accept(this); return; } } visit(cast(Expression)e); } override void visit(CommaExp e) { e.e2.accept(this); } } scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart); if (Type t = isType(o)) t.accept(v); else { assert(isExpression(o) && wm); (cast(Expression)o).accept(v); } return v.result; } /*********************************************************** * Check whether the type t representation relies on one or more the template parameters. * Params: * t = Tested type, if null, returns false. * tparams = Template parameters. * iStart = Start index of tparams to limit the tested parameters. If it's * nonzero, tparams[0..iStart] will be excluded from the test target. */ bool reliesOnTident(Type t, TemplateParameters* tparams = null, size_t iStart = 0) { extern (C++) final class ReliesOnTident : Visitor { alias visit = Visitor.visit; public: TemplateParameters* tparams; size_t iStart; bool result; extern (D) this(TemplateParameters* tparams, size_t iStart) { this.tparams = tparams; this.iStart = iStart; } override void visit(Type t) { } override void visit(TypeNext t) { t.next.accept(this); } override void visit(TypeVector t) { t.basetype.accept(this); } override void visit(TypeAArray t) { visit(cast(TypeNext)t); if (!result) t.index.accept(this); } override void visit(TypeFunction t) { size_t dim = Parameter.dim(t.parameters); for (size_t i = 0; i < dim; i++) { Parameter fparam = Parameter.getNth(t.parameters, i); fparam.type.accept(this); if (result) return; } if (t.next) t.next.accept(this); } override void visit(TypeIdentifier t) { for (size_t i = iStart; i < tparams.dim; i++) { TemplateParameter tp = (*tparams)[i]; if (tp.ident.equals(t.ident)) { result = true; return; } } } override void visit(TypeInstance t) { for (size_t i = iStart; i < tparams.dim; i++) { TemplateParameter tp = (*tparams)[i]; if (t.tempinst.name == tp.ident) { result = true; return; } } if (!t.tempinst.tiargs) return; for (size_t i = 0; i < t.tempinst.tiargs.dim; i++) { Type ta = isType((*t.tempinst.tiargs)[i]); if (ta) { ta.accept(this); if (result) return; } } } override void visit(TypeTypeof t) { //printf("TypeTypeof.reliesOnTident('%s')\n", t.toChars()); t.exp.accept(this); } override void visit(TypeTuple t) { if (t.arguments) { for (size_t i = 0; i < t.arguments.dim; i++) { Parameter arg = (*t.arguments)[i]; arg.type.accept(this); if (result) return; } } } override void visit(Expression e) { //printf("Expression.reliesOnTident('%s')\n", e.toChars()); } override void visit(IdentifierExp e) { //printf("IdentifierExp.reliesOnTident('%s')\n", e.toChars()); for (size_t i = iStart; i < tparams.dim; i++) { auto tp = (*tparams)[i]; if (e.ident == tp.ident) { result = true; return; } } } override void visit(TupleExp e) { //printf("TupleExp.reliesOnTident('%s')\n", e.toChars()); if (e.exps) { foreach (ea; *e.exps) { ea.accept(this); if (result) return; } } } override void visit(ArrayLiteralExp e) { //printf("ArrayLiteralExp.reliesOnTident('%s')\n", e.toChars()); if (e.elements) { foreach (el; *e.elements) { el.accept(this); if (result) return; } } } override void visit(AssocArrayLiteralExp e) { //printf("AssocArrayLiteralExp.reliesOnTident('%s')\n", e.toChars()); foreach (ek; *e.keys) { ek.accept(this); if (result) return; } foreach (ev; *e.values) { ev.accept(this); if (result) return; } } override void visit(StructLiteralExp e) { //printf("StructLiteralExp.reliesOnTident('%s')\n", e.toChars()); if (e.elements) { foreach (ea; *e.elements) { ea.accept(this); if (result) return; } } } override void visit(TypeExp e) { //printf("TypeExp.reliesOnTident('%s')\n", e.toChars()); e.type.accept(this); } override void visit(NewExp e) { //printf("NewExp.reliesOnTident('%s')\n", e.toChars()); if (e.thisexp) e.thisexp.accept(this); if (!result && e.newargs) { foreach (ea; *e.newargs) { ea.accept(this); if (result) return; } } e.newtype.accept(this); if (!result && e.arguments) { foreach (ea; *e.arguments) { ea.accept(this); if (result) return; } } } override void visit(NewAnonClassExp e) { //printf("NewAnonClassExp.reliesOnTident('%s')\n", e.toChars()); result = true; } override void visit(FuncExp e) { //printf("FuncExp.reliesOnTident('%s')\n", e.toChars()); result = true; } override void visit(TypeidExp e) { //printf("TypeidExp.reliesOnTident('%s')\n", e.toChars()); if (auto ea = isExpression(e.obj)) ea.accept(this); else if (auto ta = isType(e.obj)) ta.accept(this); } override void visit(TraitsExp e) { //printf("TraitsExp.reliesOnTident('%s')\n", e.toChars()); if (e.args) { foreach (oa; *e.args) { if (auto ea = isExpression(oa)) ea.accept(this); else if (auto ta = isType(oa)) ta.accept(this); if (result) return; } } } override void visit(IsExp e) { //printf("IsExp.reliesOnTident('%s')\n", e.toChars()); e.targ.accept(this); } override void visit(UnaExp e) { //printf("UnaExp.reliesOnTident('%s')\n", e.toChars()); e.e1.accept(this); } override void visit(DotTemplateInstanceExp e) { //printf("DotTemplateInstanceExp.reliesOnTident('%s')\n", e.toChars()); visit(cast(UnaExp)e); if (!result && e.ti.tiargs) { foreach (oa; *e.ti.tiargs) { if (auto ea = isExpression(oa)) ea.accept(this); else if (auto ta = isType(oa)) ta.accept(this); if (result) return; } } } override void visit(CallExp e) { //printf("CallExp.reliesOnTident('%s')\n", e.toChars()); visit(cast(UnaExp)e); if (!result && e.arguments) { foreach (ea; *e.arguments) { ea.accept(this); if (result) return; } } } override void visit(CastExp e) { //printf("CallExp.reliesOnTident('%s')\n", e.toChars()); visit(cast(UnaExp)e); // e.to can be null for cast() with no type if (!result && e.to) e.to.accept(this); } override void visit(SliceExp e) { //printf("SliceExp.reliesOnTident('%s')\n", e.toChars()); visit(cast(UnaExp)e); if (!result && e.lwr) e.lwr.accept(this); if (!result && e.upr) e.upr.accept(this); } override void visit(IntervalExp e) { //printf("IntervalExp.reliesOnTident('%s')\n", e.toChars()); e.lwr.accept(this); if (!result) e.upr.accept(this); } override void visit(ArrayExp e) { //printf("ArrayExp.reliesOnTident('%s')\n", e.toChars()); visit(cast(UnaExp)e); if (!result && e.arguments) { foreach (ea; *e.arguments) ea.accept(this); } } override void visit(BinExp e) { //printf("BinExp.reliesOnTident('%s')\n", e.toChars()); e.e1.accept(this); if (!result) e.e2.accept(this); } override void visit(CondExp e) { //printf("BinExp.reliesOnTident('%s')\n", e.toChars()); e.econd.accept(this); if (!result) visit(cast(BinExp)e); } } if (!t) return false; assert(tparams); scope ReliesOnTident v = new ReliesOnTident(tparams, iStart); t.accept(v); return v.result; } /*********************************************************** */ extern (C++) class TemplateParameter : RootObject { Loc loc; Identifier ident; /* True if this is a part of precedent parameter specialization pattern. * * template A(T : X!TL, alias X, TL...) {} * // X and TL are dependent template parameter * * A dependent template parameter should return MATCH.exact in matchArg() * to respect the match level of the corresponding precedent parameter. */ bool dependent; /* ======================== TemplateParameter =============================== */ extern (D) this(const ref Loc loc, Identifier ident) { this.loc = loc; this.ident = ident; } TemplateTypeParameter isTemplateTypeParameter() { return null; } TemplateValueParameter isTemplateValueParameter() { return null; } TemplateAliasParameter isTemplateAliasParameter() { return null; } TemplateThisParameter isTemplateThisParameter() { return null; } TemplateTupleParameter isTemplateTupleParameter() { return null; } abstract TemplateParameter syntaxCopy(); abstract bool declareParameter(Scope* sc); abstract void print(RootObject oarg, RootObject oded); abstract RootObject specialization(); abstract RootObject defaultArg(Loc instLoc, Scope* sc); abstract bool hasDefaultArg(); override const(char)* toChars() { return this.ident.toChars(); } override DYNCAST dyncast() const pure @nogc nothrow @safe { return DYNCAST.templateparameter; } /******************************************* * Match to a particular TemplateParameter. * Input: * instLoc location that the template is instantiated. * tiargs[] actual arguments to template instance * i i'th argument * parameters[] template parameters * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] */ MATCH matchArg(Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { RootObject oarg; if (i < tiargs.dim) oarg = (*tiargs)[i]; else { // Get default argument instead oarg = defaultArg(instLoc, sc); if (!oarg) { assert(i < dedtypes.dim); // It might have already been deduced oarg = (*dedtypes)[i]; if (!oarg) goto Lnomatch; } } return matchArg(sc, oarg, i, parameters, dedtypes, psparam); Lnomatch: if (psparam) *psparam = null; return MATCH.nomatch; } abstract MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam); /* Create dummy argument based on parameter. */ abstract void* dummyArg(); void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Syntax: * ident : specType = defaultType */ extern (C++) class TemplateTypeParameter : TemplateParameter { Type specType; // if !=null, this is the type specialization Type defaultType; extern (D) __gshared Type tdummy = null; extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) { super(loc, ident); this.ident = ident; this.specType = specType; this.defaultType = defaultType; } override final TemplateTypeParameter isTemplateTypeParameter() { return this; } override TemplateParameter syntaxCopy() { return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null); } override final bool declareParameter(Scope* sc) { //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars()); auto ti = new TypeIdentifier(loc, ident); Declaration ad = new AliasDeclaration(loc, ident, ti); return sc.insert(ad) !is null; } override final void print(RootObject oarg, RootObject oded) { printf(" %s\n", ident.toChars()); Type t = isType(oarg); Type ta = isType(oded); assert(ta); if (specType) printf("\tSpecialization: %s\n", specType.toChars()); if (defaultType) printf("\tDefault: %s\n", defaultType.toChars()); printf("\tParameter: %s\n", t ? t.toChars() : "NULL"); printf("\tDeduced Type: %s\n", ta.toChars()); } override final RootObject specialization() { return specType; } override final RootObject defaultArg(Loc instLoc, Scope* sc) { Type t = defaultType; if (t) { t = t.syntaxCopy(); t = t.typeSemantic(loc, sc); // use the parameter loc } return t; } override final bool hasDefaultArg() { return defaultType !is null; } override final MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { //printf("TemplateTypeParameter.matchArg('%s')\n", ident.toChars()); MATCH m = MATCH.exact; Type ta = isType(oarg); if (!ta) { //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); goto Lnomatch; } //printf("ta is %s\n", ta.toChars()); if (specType) { if (!ta || ta == tdummy) goto Lnomatch; //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), specType.toChars()); MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes); if (m2 <= MATCH.nomatch) { //printf("\tfailed deduceType\n"); goto Lnomatch; } if (m2 < m) m = m2; if ((*dedtypes)[i]) { Type t = cast(Type)(*dedtypes)[i]; if (dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 goto Lnomatch; /* This is a self-dependent parameter. For example: * template X(T : T*) {} * template X(T : S!T, alias S) {} */ //printf("t = %s ta = %s\n", t.toChars(), ta.toChars()); ta = t; } } else { if ((*dedtypes)[i]) { // Must match already deduced type Type t = cast(Type)(*dedtypes)[i]; if (!t.equals(ta)) { //printf("t = %s ta = %s\n", t.toChars(), ta.toChars()); goto Lnomatch; } } else { // So that matches with specializations are better m = MATCH.convert; } } (*dedtypes)[i] = ta; if (psparam) *psparam = new AliasDeclaration(loc, ident, ta); //printf("\tm = %d\n", m); return dependent ? MATCH.exact : m; Lnomatch: if (psparam) *psparam = null; //printf("\tm = %d\n", MATCH.nomatch); return MATCH.nomatch; } override final void* dummyArg() { Type t = specType; if (!t) { // Use this for alias-parameter's too (?) if (!tdummy) tdummy = new TypeIdentifier(loc, ident); t = tdummy; } return cast(void*)t; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Syntax: * this ident : specType = defaultType */ extern (C++) final class TemplateThisParameter : TemplateTypeParameter { extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) { super(loc, ident, specType, defaultType); } override TemplateThisParameter isTemplateThisParameter() { return this; } override TemplateParameter syntaxCopy() { return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Syntax: * valType ident : specValue = defaultValue */ extern (C++) final class TemplateValueParameter : TemplateParameter { Type valType; Expression specValue; Expression defaultValue; extern (D) __gshared Expression[void*] edummies; extern (D) this(const ref Loc loc, Identifier ident, Type valType, Expression specValue, Expression defaultValue) { super(loc, ident); this.ident = ident; this.valType = valType; this.specValue = specValue; this.defaultValue = defaultValue; } override TemplateValueParameter isTemplateValueParameter() { return this; } override TemplateParameter syntaxCopy() { return new TemplateValueParameter(loc, ident, valType.syntaxCopy(), specValue ? specValue.syntaxCopy() : null, defaultValue ? defaultValue.syntaxCopy() : null); } override bool declareParameter(Scope* sc) { auto v = new VarDeclaration(loc, valType, ident, null); v.storage_class = STC.templateparameter; return sc.insert(v) !is null; } override void print(RootObject oarg, RootObject oded) { printf(" %s\n", ident.toChars()); Expression ea = isExpression(oded); if (specValue) printf("\tSpecialization: %s\n", specValue.toChars()); printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL"); } override RootObject specialization() { return specValue; } override RootObject defaultArg(Loc instLoc, Scope* sc) { Expression e = defaultValue; if (e) { e = e.syntaxCopy(); uint olderrs = global.errors; if ((e = e.expressionSemantic(sc)) is null) return null; if ((e = resolveProperties(sc, e)) is null) return null; e = e.resolveLoc(instLoc, sc); // use the instantiated loc e = e.optimize(WANTvalue); if (global.errors != olderrs) e = new ErrorExp(); } return e; } override bool hasDefaultArg() { return defaultValue !is null; } override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { //printf("TemplateValueParameter.matchArg('%s')\n", ident.toChars()); MATCH m = MATCH.exact; Expression ei = isExpression(oarg); Type vt; if (!ei && oarg) { Dsymbol si = isDsymbol(oarg); FuncDeclaration f = si ? si.isFuncDeclaration() : null; if (!f || !f.fbody || f.needThis()) goto Lnomatch; ei = new VarExp(loc, f); ei = ei.expressionSemantic(sc); /* If a function is really property-like, and then * it's CTFEable, ei will be a literal expression. */ uint olderrors = global.startGagging(); ei = resolveProperties(sc, ei); ei = ei.ctfeInterpret(); if (global.endGagging(olderrors) || ei.op == TOK.error) goto Lnomatch; /* https://issues.dlang.org/show_bug.cgi?id=14520 * A property-like function can match to both * TemplateAlias and ValueParameter. But for template overloads, * it should always prefer alias parameter to be consistent * template match result. * * template X(alias f) { enum X = 1; } * template X(int val) { enum X = 2; } * int f1() { return 0; } // CTFEable * int f2(); // body-less function is not CTFEable * enum x1 = X!f1; // should be 1 * enum x2 = X!f2; // should be 1 * * e.g. The x1 value must be same even if the f1 definition will be moved * into di while stripping body code. */ m = MATCH.convert; } if (ei && ei.op == TOK.variable) { // Resolve const variables that we had skipped earlier ei = ei.ctfeInterpret(); } //printf("\tvalType: %s, ty = %d\n", valType.toChars(), valType.ty); vt = valType.typeSemantic(loc, sc); //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars()); //printf("vt = %s\n", vt.toChars()); if (ei.type) { MATCH m2 = ei.implicitConvTo(vt); //printf("m: %d\n", m); if (m2 < m) m = m2; if (m <= MATCH.nomatch) goto Lnomatch; ei = ei.implicitCastTo(sc, vt); ei = ei.ctfeInterpret(); } if (specValue) { if (ei is null || (cast(void*)ei.type in edummies && edummies[cast(void*)ei.type] == ei)) goto Lnomatch; Expression e = specValue; sc = sc.startCTFE(); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); e = e.implicitCastTo(sc, vt); e = e.ctfeInterpret(); ei = ei.syntaxCopy(); sc = sc.startCTFE(); ei = ei.expressionSemantic(sc); sc = sc.endCTFE(); ei = ei.implicitCastTo(sc, vt); ei = ei.ctfeInterpret(); //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars()); //printf("\te : %s, %s\n", e.toChars(), e.type.toChars()); if (!ei.equals(e)) goto Lnomatch; } else { if ((*dedtypes)[i]) { // Must match already deduced value Expression e = cast(Expression)(*dedtypes)[i]; if (!ei || !ei.equals(e)) goto Lnomatch; } } (*dedtypes)[i] = ei; if (psparam) { Initializer _init = new ExpInitializer(loc, ei); Declaration sparam = new VarDeclaration(loc, vt, ident, _init); sparam.storage_class = STC.manifest; *psparam = sparam; } return dependent ? MATCH.exact : m; Lnomatch: //printf("\tno match\n"); if (psparam) *psparam = null; return MATCH.nomatch; } override void* dummyArg() { Expression e = specValue; if (!e) { // Create a dummy value auto pe = cast(void*)valType in edummies; if (!pe) { e = valType.defaultInit(Loc.initial); edummies[cast(void*)valType] = e; } else e = *pe; } return cast(void*)e; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Syntax: * specType ident : specAlias = defaultAlias */ extern (C++) final class TemplateAliasParameter : TemplateParameter { Type specType; RootObject specAlias; RootObject defaultAlias; extern (D) __gshared Dsymbol sdummy = null; extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) { super(loc, ident); this.ident = ident; this.specType = specType; this.specAlias = specAlias; this.defaultAlias = defaultAlias; } override TemplateAliasParameter isTemplateAliasParameter() { return this; } override TemplateParameter syntaxCopy() { return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias)); } override bool declareParameter(Scope* sc) { auto ti = new TypeIdentifier(loc, ident); Declaration ad = new AliasDeclaration(loc, ident, ti); return sc.insert(ad) !is null; } override void print(RootObject oarg, RootObject oded) { printf(" %s\n", ident.toChars()); Dsymbol sa = isDsymbol(oded); assert(sa); printf("\tParameter alias: %s\n", sa.toChars()); } override RootObject specialization() { return specAlias; } override RootObject defaultArg(Loc instLoc, Scope* sc) { RootObject da = defaultAlias; Type ta = isType(defaultAlias); if (ta) { if (ta.ty == Tinstance) { // If the default arg is a template, instantiate for each type da = ta.syntaxCopy(); } } RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc return o; } override bool hasDefaultArg() { return defaultAlias !is null; } override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { //printf("TemplateAliasParameter.matchArg('%s')\n", ident.toChars()); MATCH m = MATCH.exact; Type ta = isType(oarg); RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg); Expression ea = isExpression(oarg); if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_)) sa = (cast(ThisExp)ea).var; else if (ea && ea.op == TOK.scope_) sa = (cast(ScopeExp)ea).sds; if (sa) { if ((cast(Dsymbol)sa).isAggregateDeclaration()) m = MATCH.convert; /* specType means the alias must be a declaration with a type * that matches specType. */ if (specType) { Declaration d = (cast(Dsymbol)sa).isDeclaration(); if (!d) goto Lnomatch; if (!d.type.equals(specType)) goto Lnomatch; } } else { sa = oarg; if (ea) { if (specType) { if (!ea.type.equals(specType)) goto Lnomatch; } } else if (ta && ta.ty == Tinstance && !specAlias) { /* Specialized parameter should be preferred * match to the template type parameter. * template X(alias a) {} // a == this * template X(alias a : B!A, alias B, A...) {} // B!A => ta */ } else if (sa && sa == TemplateTypeParameter.tdummy) { /* https://issues.dlang.org/show_bug.cgi?id=2025 * Aggregate Types should preferentially * match to the template type parameter. * template X(alias a) {} // a == this * template X(T) {} // T => sa */ } else goto Lnomatch; } if (specAlias) { if (sa == sdummy) goto Lnomatch; Dsymbol sx = isDsymbol(sa); if (sa != specAlias && sx) { Type talias = isType(specAlias); if (!talias) goto Lnomatch; TemplateInstance ti = sx.isTemplateInstance(); if (!ti && sx.parent) { ti = sx.parent.isTemplateInstance(); if (ti && ti.name != sx.ident) goto Lnomatch; } if (!ti) goto Lnomatch; Type t = new TypeInstance(Loc.initial, ti); MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); if (m2 <= MATCH.nomatch) goto Lnomatch; } } else if ((*dedtypes)[i]) { // Must match already deduced symbol RootObject si = (*dedtypes)[i]; if (!sa || si != sa) goto Lnomatch; } (*dedtypes)[i] = sa; if (psparam) { if (Dsymbol s = isDsymbol(sa)) { *psparam = new AliasDeclaration(loc, ident, s); } else if (Type t = isType(sa)) { *psparam = new AliasDeclaration(loc, ident, t); } else { assert(ea); // Declare manifest constant Initializer _init = new ExpInitializer(loc, ea); auto v = new VarDeclaration(loc, null, ident, _init); v.storage_class = STC.manifest; v.dsymbolSemantic(sc); *psparam = v; } } return dependent ? MATCH.exact : m; Lnomatch: if (psparam) *psparam = null; //printf("\tm = %d\n", MATCH.nomatch); return MATCH.nomatch; } override void* dummyArg() { RootObject s = specAlias; if (!s) { if (!sdummy) sdummy = new Dsymbol(); s = sdummy; } return cast(void*)s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Syntax: * ident ... */ extern (C++) final class TemplateTupleParameter : TemplateParameter { extern (D) this(const ref Loc loc, Identifier ident) { super(loc, ident); this.ident = ident; } override TemplateTupleParameter isTemplateTupleParameter() { return this; } override TemplateParameter syntaxCopy() { return new TemplateTupleParameter(loc, ident); } override bool declareParameter(Scope* sc) { auto ti = new TypeIdentifier(loc, ident); Declaration ad = new AliasDeclaration(loc, ident, ti); return sc.insert(ad) !is null; } override void print(RootObject oarg, RootObject oded) { printf(" %s... [", ident.toChars()); Tuple v = isTuple(oded); assert(v); //printf("|%d| ", v.objects.dim); for (size_t i = 0; i < v.objects.dim; i++) { if (i) printf(", "); RootObject o = v.objects[i]; Dsymbol sa = isDsymbol(o); if (sa) printf("alias: %s", sa.toChars()); Type ta = isType(o); if (ta) printf("type: %s", ta.toChars()); Expression ea = isExpression(o); if (ea) printf("exp: %s", ea.toChars()); assert(!isTuple(o)); // no nested Tuple arguments } printf("]\n"); } override RootObject specialization() { return null; } override RootObject defaultArg(Loc instLoc, Scope* sc) { return null; } override bool hasDefaultArg() { return false; } override MATCH matchArg(Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { /* The rest of the actual arguments (tiargs[]) form the match * for the variadic parameter. */ assert(i + 1 == dedtypes.dim); // must be the last one Tuple ovar; if (Tuple u = isTuple((*dedtypes)[i])) { // It has already been deduced ovar = u; } else if (i + 1 == tiargs.dim && isTuple((*tiargs)[i])) ovar = isTuple((*tiargs)[i]); else { ovar = new Tuple(); //printf("ovar = %p\n", ovar); if (i < tiargs.dim) { //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim); ovar.objects.setDim(tiargs.dim - i); for (size_t j = 0; j < ovar.objects.dim; j++) ovar.objects[j] = (*tiargs)[i + j]; } } return matchArg(sc, ovar, i, parameters, dedtypes, psparam); } override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) { //printf("TemplateTupleParameter.matchArg('%s')\n", ident.toChars()); Tuple ovar = isTuple(oarg); if (!ovar) return MATCH.nomatch; if ((*dedtypes)[i]) { Tuple tup = isTuple((*dedtypes)[i]); if (!tup) return MATCH.nomatch; if (!match(tup, ovar)) return MATCH.nomatch; } (*dedtypes)[i] = ovar; if (psparam) *psparam = new TupleDeclaration(loc, ident, &ovar.objects); return dependent ? MATCH.exact : MATCH.convert; } override void* dummyArg() { return null; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Given: * foo!(args) => * name = foo * tiargs = args */ extern (C++) class TemplateInstance : ScopeDsymbol { Identifier name; // Array of Types/Expressions of template // instance arguments [int*, char, 10*10] Objects* tiargs; // Array of Types/Expressions corresponding // to TemplateDeclaration.parameters // [int, char, 100] Objects tdtypes; Dsymbol tempdecl; // referenced by foo.bar.abc Dsymbol enclosing; // if referencing local symbols, this is the context Dsymbol aliasdecl; // !=null if instance is an alias for its sole member TemplateInstance inst; // refer to existing instance ScopeDsymbol argsym; // argument symbol table int inuse; // for recursive expansion detection int nest; // for recursive pretty printing detection bool semantictiargsdone; // has semanticTiargs() been done? bool havetempdecl; // if used second constructor bool gagged; // if the instantiation is done with error gagging hash_t hash; // cached result of toHash() Expressions* fargs; // for function template, these are the function arguments TemplateInstances* deferred; Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[] // Used to determine the instance needs code generation. // Note that these are inaccurate until semantic analysis phase completed. TemplateInstance tinst; // enclosing template instance TemplateInstance tnext; // non-first instantiated instances Module minst; // the top module that instantiated this instance extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) { super(null); static if (LOG) { printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null"); } this.loc = loc; this.name = ident; this.tiargs = tiargs; } /***************** * This constructor is only called when we figured out which function * template to instantiate. */ extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) { super(null); static if (LOG) { printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars()); } this.loc = loc; this.name = td.ident; this.tiargs = tiargs; this.tempdecl = td; this.semantictiargsdone = true; this.havetempdecl = true; assert(tempdecl._scope); } extern (D) static Objects* arraySyntaxCopy(Objects* objs) { Objects* a = null; if (objs) { a = new Objects(objs.dim); for (size_t i = 0; i < objs.dim; i++) (*a)[i] = objectSyntaxCopy((*objs)[i]); } return a; } override Dsymbol syntaxCopy(Dsymbol s) { TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null); ti.tiargs = arraySyntaxCopy(tiargs); TemplateDeclaration td; if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null) td.ScopeDsymbol.syntaxCopy(ti); else ScopeDsymbol.syntaxCopy(ti); return ti; } // resolve real symbol override final Dsymbol toAlias() { static if (LOG) { printf("TemplateInstance.toAlias()\n"); } if (!inst) { // Maybe we can resolve it if (_scope) { dsymbolSemantic(this, _scope); } if (!inst) { error("cannot resolve forward reference"); errors = true; return this; } } if (inst != this) return inst.toAlias(); if (aliasdecl) { return aliasdecl.toAlias(); } return inst; } override const(char)* kind() const { return "template instance"; } override bool oneMember(Dsymbol* ps, Identifier ident) { *ps = null; return true; } override const(char)* toChars() { OutBuffer buf; toCBufferInstance(this, &buf); return buf.extractString(); } override final const(char)* toPrettyCharsHelper() { OutBuffer buf; toCBufferInstance(this, &buf, true); return buf.extractString(); } /************************************** * Given an error instantiating the TemplateInstance, * give the nested TemplateInstance instantiations that got * us here. Those are a list threaded into the nested scopes. */ final void printInstantiationTrace() { if (global.gag) return; const(uint) max_shown = 6; const(char)* format = "instantiated from here: `%s`"; // determine instantiation depth and number of recursive instantiations int n_instantiations = 1; int n_totalrecursions = 0; for (TemplateInstance cur = this; cur; cur = cur.tinst) { ++n_instantiations; // If two instantiations use the same declaration, they are recursive. // (this works even if they are instantiated from different places in the // same template). // In principle, we could also check for multiple-template recursion, but it's // probably not worthwhile. if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) ++n_totalrecursions; } // show full trace only if it's short or verbose is on if (n_instantiations <= max_shown || global.params.verbose) { for (TemplateInstance cur = this; cur; cur = cur.tinst) { cur.errors = true; errorSupplemental(cur.loc, format, cur.toChars()); } } else if (n_instantiations - n_totalrecursions <= max_shown) { // By collapsing recursive instantiations into a single line, // we can stay under the limit. int recursionDepth = 0; for (TemplateInstance cur = this; cur; cur = cur.tinst) { cur.errors = true; if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) { ++recursionDepth; } else { if (recursionDepth) errorSupplemental(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars()); else errorSupplemental(cur.loc, format, cur.toChars()); recursionDepth = 0; } } } else { // Even after collapsing the recursions, the depth is too deep. // Just display the first few and last few instantiations. uint i = 0; for (TemplateInstance cur = this; cur; cur = cur.tinst) { cur.errors = true; if (i == max_shown / 2) errorSupplemental(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2) errorSupplemental(cur.loc, format, cur.toChars()); ++i; } } } /************************************* * Lazily generate identifier for template instance. * This is because 75% of the ident's are never needed. */ override final Identifier getIdent() { if (!ident && inst && !errors) ident = genIdent(tiargs); // need an identifier for name mangling purposes. return ident; } /************************************* * Compare proposed template instantiation with existing template instantiation. * Note that this is not commutative because of the auto ref check. * Params: * o = existing template instantiation * Returns: * 0 for match, 1 for no match */ override final int compare(RootObject o) { TemplateInstance ti = cast(TemplateInstance)o; //printf("this = %p, ti = %p\n", this, ti); assert(tdtypes.dim == ti.tdtypes.dim); // Nesting must match if (enclosing != ti.enclosing) { //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : ""); goto Lnotequals; } //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) goto Lnotequals; /* Template functions may have different instantiations based on * "auto ref" parameters. */ if (auto fd = ti.toAlias().isFuncDeclaration()) { if (!fd.errors) { auto fparameters = fd.getParameters(null); size_t nfparams = Parameter.dim(fparameters); // Num function parameters for (size_t j = 0; j < nfparams; j++) { Parameter fparam = Parameter.getNth(fparameters, j); if (fparam.storageClass & STC.autoref) // if "auto ref" { if (!fargs) goto Lnotequals; if (fargs.dim <= j) break; Expression farg = (*fargs)[j]; if (farg.isLvalue()) { if (!(fparam.storageClass & STC.ref_)) goto Lnotequals; // auto ref's don't match } else { if (fparam.storageClass & STC.ref_) goto Lnotequals; // auto ref's don't match } } } } } return 0; Lnotequals: return 1; } final hash_t toHash() { if (!hash) { hash = cast(size_t)cast(void*)enclosing; hash += arrayObjectHash(&tdtypes); hash += hash == 0; } return hash; } /*********************************************** * Returns true if this is not instantiated in non-root module, and * is a part of non-speculative instantiatiation. * * Note: minst does not stabilize until semantic analysis is completed, * so don't call this function during semantic analysis to return precise result. */ final bool needsCodegen() { // Now -allInst is just for the backward compatibility. if (global.params.allInst) { //printf("%s minst = %s, enclosing (%s).isNonRoot = %d\n", // toPrettyChars(), minst ? minst.toChars() : NULL, // enclosing ? enclosing.toPrettyChars() : NULL, enclosing && enclosing.inNonRoot()); if (enclosing) { /* https://issues.dlang.org/show_bug.cgi?id=14588 * If the captured context is not a function * (e.g. class), the instance layout determination is guaranteed, * because the semantic/semantic2 pass will be executed * even for non-root instances. */ if (!enclosing.isFuncDeclaration()) return true; /* https://issues.dlang.org/show_bug.cgi?id=14834 * If the captured context is a function, * this excessive instantiation may cause ODR violation, because * -allInst and others doesn't guarantee the semantic3 execution * for that function. * * If the enclosing is also an instantiated function, * we have to rely on the ancestor's needsCodegen() result. */ if (TemplateInstance ti = enclosing.isInstantiated()) return ti.needsCodegen(); /* https://issues.dlang.org/show_bug.cgi?id=13415 * If and only if the enclosing scope needs codegen, * this nested templates would also need code generation. */ return !enclosing.inNonRoot(); } return true; } if (!minst) { // If this is a speculative instantiation, // 1. do codegen if ancestors really needs codegen. // 2. become non-speculative if siblings are not speculative TemplateInstance tnext = this.tnext; TemplateInstance tinst = this.tinst; // At first, disconnect chain first to prevent infinite recursion. this.tnext = null; this.tinst = null; // Determine necessity of tinst before tnext. if (tinst && tinst.needsCodegen()) { minst = tinst.minst; // cache result assert(minst); assert(minst.isRoot() || minst.rootImports()); return true; } if (tnext && (tnext.needsCodegen() || tnext.minst)) { minst = tnext.minst; // cache result assert(minst); return minst.isRoot() || minst.rootImports(); } // Elide codegen because this is really speculative. return false; } /* Even when this is reached to the codegen pass, * a non-root nested template should not generate code, * due to avoid ODR violation. */ if (enclosing && enclosing.inNonRoot()) { if (tinst) { auto r = tinst.needsCodegen(); minst = tinst.minst; // cache result return r; } if (tnext) { auto r = tnext.needsCodegen(); minst = tnext.minst; // cache result return r; } return false; } /* The issue is that if the importee is compiled with a different -debug * setting than the importer, the importer may believe it exists * in the compiled importee when it does not, when the instantiation * is behind a conditional debug declaration. */ // workaround for https://issues.dlang.org/show_bug.cgi?id=11239 if (global.params.useUnitTests || global.params.debuglevel) { // Prefer instantiations from root modules, to maximize link-ability. if (minst.isRoot()) return true; TemplateInstance tnext = this.tnext; TemplateInstance tinst = this.tinst; this.tnext = null; this.tinst = null; if (tinst && tinst.needsCodegen()) { minst = tinst.minst; // cache result assert(minst); assert(minst.isRoot() || minst.rootImports()); return true; } if (tnext && tnext.needsCodegen()) { minst = tnext.minst; // cache result assert(minst); assert(minst.isRoot() || minst.rootImports()); return true; } // https://issues.dlang.org/show_bug.cgi?id=2500 case if (minst.rootImports()) return true; // Elide codegen because this is not included in root instances. return false; } else { // Prefer instantiations from non-root module, to minimize object code size. /* If a TemplateInstance is ever instantiated by non-root modules, * we do not have to generate code for it, * because it will be generated when the non-root module is compiled. * * But, if the non-root 'minst' imports any root modules, it might still need codegen. * * The problem is if A imports B, and B imports A, and both A * and B instantiate the same template, does the compilation of A * or the compilation of B do the actual instantiation? * * See https://issues.dlang.org/show_bug.cgi?id=2500. */ if (!minst.isRoot() && !minst.rootImports()) return false; TemplateInstance tnext = this.tnext; this.tnext = null; if (tnext && !tnext.needsCodegen() && tnext.minst) { minst = tnext.minst; // cache result assert(!minst.isRoot()); return false; } // Do codegen because this is not included in non-root instances. return true; } } /********************************************** * Find template declaration corresponding to template instance. * * Returns: * false if finding fails. * Note: * This function is reentrant against error occurrence. If returns false, * any members of this object won't be modified, and repetition call will * reproduce same error. */ extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym) { if (pwithsym) *pwithsym = null; if (havetempdecl) return true; //printf("TemplateInstance.findTempDecl() %s\n", toChars()); if (!tempdecl) { /* Given: * foo!( ... ) * figure out which TemplateDeclaration foo refers to. */ Identifier id = name; Dsymbol scopesym; Dsymbol s = sc.search(loc, id, &scopesym); if (!s) { s = sc.search_correct(id); if (s) error("template `%s` is not defined, did you mean %s?", id.toChars(), s.toChars()); else error("template `%s` is not defined", id.toChars()); return false; } static if (LOG) { printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind()); if (s.parent) printf("s.parent = '%s'\n", s.parent.toChars()); } if (pwithsym) *pwithsym = scopesym.isWithScopeSymbol(); /* We might have found an alias within a template when * we really want the template. */ TemplateInstance ti; if (s.parent && (ti = s.parent.isTemplateInstance()) !is null) { if (ti.tempdecl && ti.tempdecl.ident == id) { /* This is so that one can refer to the enclosing * template, even if it has the same name as a member * of the template, if it has a !(arguments) */ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); assert(td); if (td.overroot) // if not start of overloaded list of TemplateDeclaration's td = td.overroot; // then get the start s = td; } } if (!updateTempDecl(sc, s)) { return false; } } assert(tempdecl); // Look for forward references auto tovers = tempdecl.isOverloadSet(); foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) { Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; int r = overloadApply(dstart, (Dsymbol s) { auto td = s.isTemplateDeclaration(); if (!td) return 0; if (td.semanticRun == PASS.init) { if (td._scope) { // Try to fix forward reference. Ungag errors while doing so. Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } if (td.semanticRun == PASS.init) { error("`%s` forward references template declaration `%s`", toChars(), td.toChars()); return 1; } } return 0; }); if (r) return false; } return true; } /********************************************** * Confirm s is a valid template, then store it. * Input: * sc * s candidate symbol of template. It may be: * TemplateDeclaration * FuncDeclaration with findTemplateDeclRoot() != NULL * OverloadSet which contains candidates * Returns: * true if updating succeeds. */ extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s) { if (s) { Identifier id = name; s = s.toAlias(); /* If an OverloadSet, look for a unique member that is a template declaration */ OverloadSet os = s.isOverloadSet(); if (os) { s = null; for (size_t i = 0; i < os.a.dim; i++) { Dsymbol s2 = os.a[i]; if (FuncDeclaration f = s2.isFuncDeclaration()) s2 = f.findTemplateDeclRoot(); else s2 = s2.isTemplateDeclaration(); if (s2) { if (s) { tempdecl = os; return true; } s = s2; } } if (!s) { error("template `%s` is not defined", id.toChars()); return false; } } OverDeclaration od = s.isOverDeclaration(); if (od) { tempdecl = od; // TODO: more strict check return true; } /* It should be a TemplateDeclaration, not some other symbol */ if (FuncDeclaration f = s.isFuncDeclaration()) tempdecl = f.findTemplateDeclRoot(); else tempdecl = s.isTemplateDeclaration(); if (!tempdecl) { if (!s.parent && global.errors) return false; if (!s.parent && s.getType()) { Dsymbol s2 = s.getType().toDsymbol(sc); if (!s2) { .error(loc, "`%s` is not a valid template instance, because `%s` is not a template declaration but a type (`%s == %s`)", toChars(), id.toChars(), id.toChars(), s.getType.kind()); return false; } s = s2; } debug { //if (!s.parent) printf("s = %s %s\n", s.kind(), s.toChars()); } //assert(s.parent); TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null; if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl) { /* This is so that one can refer to the enclosing * template, even if it has the same name as a member * of the template, if it has a !(arguments) */ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); assert(td); if (td.overroot) // if not start of overloaded list of TemplateDeclaration's td = td.overroot; // then get the start tempdecl = td; } else { error("`%s` is not a template declaration, it is a %s", id.toChars(), s.kind()); return false; } } } return (tempdecl !is null); } /********************************** * Run semantic of tiargs as arguments of template. * Input: * loc * sc * tiargs array of template arguments * flags 1: replace const variables with their initializers * 2: don't devolve Parameter to Type * Returns: * false if one or more arguments have errors. */ extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags) { // Run semantic on each argument, place results in tiargs[] //printf("+TemplateInstance.semanticTiargs()\n"); if (!tiargs) return true; bool err = false; for (size_t j = 0; j < tiargs.dim; j++) { RootObject o = (*tiargs)[j]; Type ta = isType(o); Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); if (ta) { //printf("type %s\n", ta.toChars()); // It might really be an Expression or an Alias ta.resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0); if (ea) goto Lexpr; if (sa) goto Ldsym; if (ta is null) { assert(global.errors); ta = Type.terror; } Ltype: if (ta.ty == Ttuple) { // Expand tuple TypeTuple tt = cast(TypeTuple)ta; size_t dim = tt.arguments.dim; tiargs.remove(j); if (dim) { tiargs.reserve(dim); for (size_t i = 0; i < dim; i++) { Parameter arg = (*tt.arguments)[i]; if (flags & 2 && (arg.ident || arg.userAttribDecl)) tiargs.insert(j + i, arg); else tiargs.insert(j + i, arg.type); } } j--; continue; } if (ta.ty == Terror) { err = true; continue; } (*tiargs)[j] = ta.merge2(); } else if (ea) { Lexpr: //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); if (flags & 1) // only used by __traits { ea = ea.expressionSemantic(sc); // must not interpret the args, excepting template parameters if (ea.op != TOK.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter)) { ea = ea.optimize(WANTvalue); } } else { sc = sc.startCTFE(); ea = ea.expressionSemantic(sc); sc = sc.endCTFE(); if (ea.op == TOK.variable) { /* This test is to skip substituting a const var with * its initializer. The problem is the initializer won't * match with an 'alias' parameter. Instead, do the * const substitution in TemplateValueParameter.matchArg(). */ } else if (definitelyValueParameter(ea)) { if (ea.checkValue()) // check void expression ea = new ErrorExp(); uint olderrs = global.errors; ea = ea.ctfeInterpret(); if (global.errors != olderrs) ea = new ErrorExp(); } } //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); if (ea.op == TOK.tuple) { // Expand tuple TupleExp te = cast(TupleExp)ea; size_t dim = te.exps.dim; tiargs.remove(j); if (dim) { tiargs.reserve(dim); for (size_t i = 0; i < dim; i++) tiargs.insert(j + i, (*te.exps)[i]); } j--; continue; } if (ea.op == TOK.error) { err = true; continue; } (*tiargs)[j] = ea; if (ea.op == TOK.type) { ta = ea.type; goto Ltype; } if (ea.op == TOK.scope_) { sa = (cast(ScopeExp)ea).sds; goto Ldsym; } if (ea.op == TOK.function_) { FuncExp fe = cast(FuncExp)ea; /* A function literal, that is passed to template and * already semanticed as function pointer, never requires * outer frame. So convert it to global function is valid. */ if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer) { // change to non-nested fe.fd.tok = TOK.function_; fe.fd.vthis = null; } else if (fe.td) { /* If template argument is a template lambda, * get template declaration itself. */ //sa = fe.td; //goto Ldsym; } } if (ea.op == TOK.dotVariable && !(flags & 1)) { // translate expression to dsymbol. sa = (cast(DotVarExp)ea).var; goto Ldsym; } if (ea.op == TOK.template_) { sa = (cast(TemplateExp)ea).td; goto Ldsym; } if (ea.op == TOK.dotTemplateDeclaration && !(flags & 1)) { // translate expression to dsymbol. sa = (cast(DotTemplateExp)ea).td; goto Ldsym; } } else if (sa) { Ldsym: //printf("dsym %s %s\n", sa.kind(), sa.toChars()); if (sa.errors) { err = true; continue; } TupleDeclaration d = sa.toAlias().isTupleDeclaration(); if (d) { // Expand tuple tiargs.remove(j); tiargs.insert(j, d.objects); j--; continue; } if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration()) { FuncDeclaration f = fa.toAliasFunc(); if (!fa.hasOverloads && f.isUnique()) { // Strip FuncAlias only when the aliased function // does not have any overloads. sa = f; } } (*tiargs)[j] = sa; TemplateDeclaration td = sa.isTemplateDeclaration(); if (td && td.semanticRun == PASS.init && td.literal) { td.dsymbolSemantic(sc); } FuncDeclaration fd = sa.isFuncDeclaration(); if (fd) fd.functionSemantic(); } else if (isParameter(o)) { } else { assert(0); } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } version (none) { printf("-TemplateInstance.semanticTiargs()\n"); for (size_t j = 0; j < tiargs.dim; j++) { RootObject o = (*tiargs)[j]; Type ta = isType(o); Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); Tuple va = isTuple(o); printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); } } return !err; } /********************************** * Run semantic on the elements of tiargs. * Input: * sc * Returns: * false if one or more arguments have errors. * Note: * This function is reentrant against error occurrence. If returns false, * all elements of tiargs won't be modified. */ extern (D) final bool semanticTiargs(Scope* sc) { //printf("+TemplateInstance.semanticTiargs() %s\n", toChars()); if (semantictiargsdone) return true; if (semanticTiargs(loc, sc, tiargs, 0)) { // cache the result iff semantic analysis succeeded entirely semantictiargsdone = 1; return true; } return false; } extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs) { if (havetempdecl) { TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); assert(tempdecl); assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.dim); if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2)) { error("incompatible arguments for template instantiation"); return false; } // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary? return true; } static if (LOG) { printf("TemplateInstance.findBestMatch()\n"); } uint errs = global.errors; TemplateDeclaration td_last = null; Objects dedtypes; /* Since there can be multiple TemplateDeclaration's with the same * name, look for the best match. */ auto tovers = tempdecl.isOverloadSet(); foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) { TemplateDeclaration td_best; TemplateDeclaration td_ambig; MATCH m_best = MATCH.nomatch; Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; overloadApply(dstart, (Dsymbol s) { auto td = s.isTemplateDeclaration(); if (!td) return 0; if (td.inuse) { td.error(loc, "recursive template expansion"); return 1; } if (td == td_best) // skip duplicates return 0; //printf("td = %s\n", td.toPrettyChars()); // If more arguments than parameters, // then this is no match. if (td.parameters.dim < tiargs.dim) { if (!td.isVariadic()) return 0; } dedtypes.setDim(td.parameters.dim); dedtypes.zero(); assert(td.semanticRun != PASS.init); MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0); //printf("matchWithInstance = %d\n", m); if (m <= MATCH.nomatch) // no match at all return 0; if (m < m_best) goto Ltd_best; if (m > m_best) goto Ltd; // Disambiguate by picking the most specialized TemplateDeclaration { MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } td_ambig = td; return 0; Ltd_best: // td_best is the best match so far td_ambig = null; return 0; Ltd: // td is the new best match td_ambig = null; td_best = td; m_best = m; tdtypes.setDim(dedtypes.dim); memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * (void*).sizeof); return 0; }); if (td_ambig) { .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`", td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(), td_best.loc.toChars(), td_best.toChars(), td_ambig.loc.toChars(), td_ambig.toChars()); return false; } if (td_best) { if (!td_last) td_last = td_best; else if (td_last != td_best) { ScopeDsymbol.multiplyDefined(loc, td_last, td_best); return false; } } } if (td_last) { /* https://issues.dlang.org/show_bug.cgi?id=7469 * Normalize tiargs by using corresponding deduced * template value parameters and tuples for the correct mangling. * * By doing this before hasNestedArgs, CTFEable local variable will be * accepted as a value parameter. For example: * * void foo() { * struct S(int n) {} // non-global template * const int num = 1; // CTFEable local variable * S!num s; // S!1 is instantiated, not S!num * } */ size_t dim = td_last.parameters.dim - (td_last.isVariadic() ? 1 : 0); for (size_t i = 0; i < dim; i++) { if (tiargs.dim <= i) tiargs.push(tdtypes[i]); assert(i < tiargs.dim); auto tvp = (*td_last.parameters)[i].isTemplateValueParameter(); if (!tvp) continue; assert(tdtypes[i]); // tdtypes[i] is already normalized to the required type in matchArg (*tiargs)[i] = tdtypes[i]; } if (td_last.isVariadic() && tiargs.dim == dim && tdtypes[dim]) { Tuple va = isTuple(tdtypes[dim]); assert(va); for (size_t i = 0; i < va.objects.dim; i++) tiargs.push(va.objects[i]); } } else if (errors && inst) { // instantiation was failed with error reporting assert(global.errors); return false; } else { auto tdecl = tempdecl.isTemplateDeclaration(); if (errs != global.errors) errorSupplemental(loc, "while looking for match for `%s`", toChars()); else if (tdecl && !tdecl.overnext) { // Only one template, so we can give better error message error("does not match template declaration `%s`", tdecl.toChars()); } else .error(loc, "%s `%s.%s` does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars()); return false; } /* The best match is td_last */ tempdecl = td_last; static if (LOG) { printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars()); } return (errs == global.errors); } /***************************************************** * Determine if template instance is really a template function, * and that template function needs to infer types from the function * arguments. * * Like findBestMatch, iterate possible template candidates, * but just looks only the necessity of type inference. */ extern (D) final bool needsTypeInference(Scope* sc, int flag = 0) { //printf("TemplateInstance.needsTypeInference() %s\n", toChars()); if (semanticRun != PASS.init) return false; uint olderrs = global.errors; Objects dedtypes; size_t count = 0; auto tovers = tempdecl.isOverloadSet(); foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) { Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; int r = overloadApply(dstart, (Dsymbol s) { auto td = s.isTemplateDeclaration(); if (!td) return 0; if (td.inuse) { td.error(loc, "recursive template expansion"); return 1; } /* If any of the overloaded template declarations need inference, * then return true */ if (!td.onemember) return 0; if (auto td2 = td.onemember.isTemplateDeclaration()) { if (!td2.onemember || !td2.onemember.isFuncDeclaration()) return 0; if (tiargs.dim >= td.parameters.dim - (td.isVariadic() ? 1 : 0)) return 0; return 1; } auto fd = td.onemember.isFuncDeclaration(); if (!fd || fd.type.ty != Tfunction) return 0; foreach (tp; *td.parameters) { if (tp.isTemplateThisParameter()) return 1; } /* Determine if the instance arguments, tiargs, are all that is necessary * to instantiate the template. */ //printf("tp = %p, td.parameters.dim = %d, tiargs.dim = %d\n", tp, td.parameters.dim, tiargs.dim); auto tf = cast(TypeFunction)fd.type; if (size_t dim = Parameter.dim(tf.parameters)) { auto tp = td.isVariadic(); if (tp && td.parameters.dim > 1) return 1; if (!tp && tiargs.dim < td.parameters.dim) { // Can remain tiargs be filled by default arguments? foreach (size_t i; tiargs.dim .. td.parameters.dim) { if (!(*td.parameters)[i].hasDefaultArg()) return 1; } } foreach (size_t i; 0 .. dim) { // 'auto ref' needs inference. if (Parameter.getNth(tf.parameters, i).storageClass & STC.auto_) return 1; } } if (!flag) { /* Calculate the need for overload resolution. * When only one template can match with tiargs, inference is not necessary. */ dedtypes.setDim(td.parameters.dim); dedtypes.zero(); if (td.semanticRun == PASS.init) { if (td._scope) { // Try to fix forward reference. Ungag errors while doing so. Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } if (td.semanticRun == PASS.init) { error("`%s` forward references template declaration `%s`", toChars(), td.toChars()); return 1; } } MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0); if (m <= MATCH.nomatch) return 0; } /* If there is more than one function template which matches, we may * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430) */ return ++count > 1 ? 1 : 0; }); if (r) return true; } if (olderrs != global.errors) { if (!global.gag) { errorSupplemental(loc, "while looking for match for `%s`", toChars()); semanticRun = PASS.semanticdone; inst = this; } errors = true; } //printf("false\n"); return false; } /***************************************** * Determines if a TemplateInstance will need a nested * generation of the TemplateDeclaration. * Sets enclosing property if so, and returns != 0; */ extern (D) final bool hasNestedArgs(Objects* args, bool isstatic) { int nested = 0; //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars()); version (none) { if (!enclosing) { if (TemplateInstance ti = tempdecl.isInstantiated()) enclosing = ti.enclosing; } } /* A nested instance happens when an argument references a local * symbol that is on the stack. */ for (size_t i = 0; i < args.dim; i++) { RootObject o = (*args)[i]; Expression ea = isExpression(o); Dsymbol sa = isDsymbol(o); Tuple va = isTuple(o); if (ea) { if (ea.op == TOK.variable) { sa = (cast(VarExp)ea).var; goto Lsa; } if (ea.op == TOK.this_) { sa = (cast(ThisExp)ea).var; goto Lsa; } if (ea.op == TOK.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; else sa = (cast(FuncExp)ea).fd; goto Lsa; } // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent. if (ea.op != TOK.int64 && ea.op != TOK.float64 && ea.op != TOK.complex80 && ea.op != TOK.null_ && ea.op != TOK.string_ && ea.op != TOK.arrayLiteral && ea.op != TOK.assocArrayLiteral && ea.op != TOK.structLiteral) { ea.error("expression `%s` is not a valid template value argument", ea.toChars()); errors = true; } } else if (sa) { Lsa: sa = sa.toAlias(); TemplateDeclaration td = sa.isTemplateDeclaration(); if (td) { TemplateInstance ti = sa.toParent().isTemplateInstance(); if (ti && ti.enclosing) sa = ti; } TemplateInstance ti = sa.isTemplateInstance(); Declaration d = sa.isDeclaration(); if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin())) { // if module level template if (isstatic) { Dsymbol dparent = sa.toParent2(); if (!dparent) goto L1; else if (!enclosing) enclosing = dparent; else if (enclosing != dparent) { /* Select the more deeply nested of the two. * Error if one is not nested inside the other. */ for (Dsymbol p = enclosing; p; p = p.parent) { if (p == dparent) goto L1; // enclosing is most nested } for (Dsymbol p = dparent; p; p = p.parent) { if (p == enclosing) { enclosing = dparent; goto L1; // dparent is most nested } } error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars()); errors = true; } L1: //printf("\tnested inside %s\n", enclosing.toChars()); nested |= 1; } else { error("cannot use local `%s` as parameter to non-global template `%s`", sa.toChars(), tempdecl.toChars()); errors = true; } } } else if (va) { nested |= cast(int)hasNestedArgs(&va.objects, isstatic); } } //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested); return nested != 0; } /***************************************** * Append 'this' to the specific module members[] */ extern (D) final Dsymbols* appendToModuleMember() { Module mi = minst; // instantiated . inserted module if (global.params.useUnitTests || global.params.debuglevel) { // Turn all non-root instances to speculative if (mi && !mi.isRoot()) mi = null; } //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n", // toPrettyChars(), // enclosing ? enclosing.toPrettyChars() : null, // mi ? mi.toPrettyChars() : null); if (!mi || mi.isRoot()) { /* If the instantiated module is speculative or root, insert to the * member of a root module. Then: * - semantic3 pass will get called on the instance members. * - codegen pass will get a selection chance to do/skip it. */ static Dsymbol getStrictEnclosing(TemplateInstance ti) { do { if (ti.enclosing) return ti.enclosing; ti = ti.tempdecl.isInstantiated(); } while (ti); return null; } Dsymbol enc = getStrictEnclosing(this); // insert target is made stable by using the module // where tempdecl is declared. mi = (enc ? enc : tempdecl).getModule(); if (!mi.isRoot()) mi = mi.importedFrom; assert(mi.isRoot()); } else { /* If the instantiated module is non-root, insert to the member of the * non-root module. Then: * - semantic3 pass won't be called on the instance. * - codegen pass won't reach to the instance. */ } //printf("\t-. mi = %s\n", mi.toPrettyChars()); if (memberOf is mi) // already a member { debug // make sure it really is a member { auto a = mi.members; for (size_t i = 0; 1; ++i) { assert(i != a.dim); if (this == (*a)[i]) break; } } return null; } Dsymbols* a = mi.members; a.push(this); memberOf = mi; if (mi.semanticRun >= PASS.semantic2done && mi.isRoot()) Module.addDeferredSemantic2(this); if (mi.semanticRun >= PASS.semantic3done && mi.isRoot()) Module.addDeferredSemantic3(this); return a; } /**************************************************** * Declare parameters of template instance, initialize them with the * template instance arguments. */ extern (D) final void declareParameters(Scope* sc) { TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); assert(tempdecl); //printf("TemplateInstance.declareParameters()\n"); for (size_t i = 0; i < tdtypes.dim; i++) { TemplateParameter tp = (*tempdecl.parameters)[i]; //RootObject *o = (*tiargs)[i]; RootObject o = tdtypes[i]; // initializer for tp //printf("\ttdtypes[%d] = %p\n", i, o); tempdecl.declareParameter(sc, tp, o); } } /**************************************** * This instance needs an identifier for name mangling purposes. * Create one by taking the template declaration name and adding * the type signature for it. */ extern (D) final Identifier genIdent(Objects* args) { //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars()); assert(args is tiargs); OutBuffer buf; mangleToBuffer(this, &buf); //printf("\tgenIdent = %s\n", buf.peekString()); return Identifier.idPool(buf.peekSlice()); } extern (D) final void expandMembers(Scope* sc2) { for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.setScope(sc2); } for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; s.importAll(sc2); } for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s.toChars(), s, s.kind(), this.toChars()); //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars()); //if (enclosing) // s.parent = sc.parent; //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars()); s.dsymbolSemantic(sc2); //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars()); Module.runDeferredSemantic(); } } extern (D) final void tryExpandMembers(Scope* sc2) { __gshared int nest; // extracted to a function to allow windows SEH to work without destructors in the same function //printf("%d\n", nest); if (++nest > 500) { global.gag = 0; // ensure error message gets printed error("recursive expansion"); fatal(); } expandMembers(sc2); nest--; } extern (D) final void trySemantic3(Scope* sc2) { // extracted to a function to allow windows SEH to work without destructors in the same function __gshared int nest; //printf("%d\n", nest); if (++nest > 300) { global.gag = 0; // ensure error message gets printed error("recursive expansion"); fatal(); } semantic3(this, sc2); --nest; } override final inout(TemplateInstance) isTemplateInstance() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /************************************** * IsExpression can evaluate the specified type speculatively, and even if * it instantiates any symbols, they are normally unnecessary for the * final executable. * However, if those symbols leak to the actual code, compiler should remark * them as non-speculative to generate their code and link to the final executable. */ void unSpeculative(Scope* sc, RootObject o) { if (!o) return; if (Tuple tup = isTuple(o)) { for (size_t i = 0; i < tup.objects.dim; i++) { unSpeculative(sc, tup.objects[i]); } return; } Dsymbol s = getDsymbol(o); if (!s) return; if (Declaration d = s.isDeclaration()) { if (VarDeclaration vd = d.isVarDeclaration()) o = vd.type; else if (AliasDeclaration ad = d.isAliasDeclaration()) { o = ad.getType(); if (!o) o = ad.toAlias(); } else o = d.toAlias(); s = getDsymbol(o); if (!s) return; } if (TemplateInstance ti = s.isTemplateInstance()) { // If the instance is already non-speculative, // or it is leaked to the speculative scope. if (ti.minst !is null || sc.minst is null) return; // Remark as non-speculative instance. ti.minst = sc.minst; if (!ti.tinst) ti.tinst = sc.tinst; unSpeculative(sc, ti.tempdecl); } if (TemplateInstance ti = s.isInstantiated()) unSpeculative(sc, ti); } /********************************** * Return true if e could be valid only as a template value parameter. * Return false if it might be an alias or tuple. * (Note that even in this case, it could still turn out to be a value). */ bool definitelyValueParameter(Expression e) { // None of these can be value parameters if (e.op == TOK.tuple || e.op == TOK.scope_ || e.op == TOK.type || e.op == TOK.dotType || e.op == TOK.template_ || e.op == TOK.dotTemplateDeclaration || e.op == TOK.function_ || e.op == TOK.error || e.op == TOK.this_ || e.op == TOK.super_) return false; if (e.op != TOK.dotVariable) return true; /* Template instantiations involving a DotVar expression are difficult. * In most cases, they should be treated as a value parameter, and interpreted. * But they might also just be a fully qualified name, which should be treated * as an alias. */ // x.y.f cannot be a value FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration(); if (f) return false; while (e.op == TOK.dotVariable) { e = (cast(DotVarExp)e).e1; } // this.x.y and super.x.y couldn't possibly be valid values. if (e.op == TOK.this_ || e.op == TOK.super_) return false; // e.type.x could be an alias if (e.op == TOK.dotType) return false; // var.x.y is the only other possible form of alias if (e.op != TOK.variable) return true; VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); // func.x.y is not an alias if (!v) return true; // https://issues.dlang.org/show_bug.cgi?id=16685 // var.x.y where var is a constant available at compile time if (v.storage_class & STC.manifest) return true; // TODO: Should we force CTFE if it is a global constant? return false; } /*********************************************************** */ extern (C++) final class TemplateMixin : TemplateInstance { TypeQualified tqual; extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs) { super(loc, tqual.idents.dim ? cast(Identifier)tqual.idents[tqual.idents.dim - 1] : (cast(TypeIdentifier)tqual).ident, tiargs ? tiargs : new Objects()); //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : ""); this.ident = ident; this.tqual = tqual; } override Dsymbol syntaxCopy(Dsymbol s) { auto tm = new TemplateMixin(loc, ident, cast(TypeQualified)tqual.syntaxCopy(), tiargs); return TemplateInstance.syntaxCopy(tm); } override const(char)* kind() const { return "mixin"; } override bool oneMember(Dsymbol* ps, Identifier ident) { return Dsymbol.oneMember(ps, ident); } override int apply(Dsymbol_apply_ft_t fp, void* param) { if (_scope) // if fwd reference dsymbolSemantic(this, null); // try to resolve it if (members) { for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; if (s) { if (s.apply(fp, param)) return 1; } } } return 0; } override bool hasPointers() { //printf("TemplateMixin.hasPointers() %s\n", toChars()); if (members) { for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; //printf(" s = %s %s\n", s.kind(), s.toChars()); if (s.hasPointers()) { return true; } } } return false; } override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { //printf("TemplateMixin.setFieldOffset() %s\n", toChars()); if (_scope) // if fwd reference dsymbolSemantic(this, null); // try to resolve it if (members) { for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; //printf("\t%s\n", s.toChars()); s.setFieldOffset(ad, poffset, isunion); } } } override const(char)* toChars() { OutBuffer buf; toCBufferInstance(this, &buf); return buf.extractString(); } extern (D) bool findTempDecl(Scope* sc) { // Follow qualifications to find the TemplateDeclaration if (!tempdecl) { Expression e; Type t; Dsymbol s; tqual.resolve(loc, sc, &e, &t, &s); if (!s) { error("is not defined"); return false; } s = s.toAlias(); tempdecl = s.isTemplateDeclaration(); OverloadSet os = s.isOverloadSet(); /* If an OverloadSet, look for a unique member that is a template declaration */ if (os) { Dsymbol ds = null; for (size_t i = 0; i < os.a.dim; i++) { Dsymbol s2 = os.a[i].isTemplateDeclaration(); if (s2) { if (ds) { tempdecl = os; break; } ds = s2; } } } if (!tempdecl) { error("`%s` isn't a template", s.toChars()); return false; } } assert(tempdecl); // Look for forward references auto tovers = tempdecl.isOverloadSet(); foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) { Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; int r = overloadApply(dstart, (Dsymbol s) { auto td = s.isTemplateDeclaration(); if (!td) return 0; if (td.semanticRun == PASS.init) { if (td._scope) td.dsymbolSemantic(td._scope); else { semanticRun = PASS.init; return 1; } } return 0; }); if (r) return false; } return true; } override inout(TemplateMixin) isTemplateMixin() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /************************************ * This struct is needed for TemplateInstance to be the key in an associative array. * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary. */ struct TemplateInstanceBox { TemplateInstance ti; this(TemplateInstance ti) { this.ti = ti; this.ti.toHash(); assert(this.ti.hash); } size_t toHash() const @trusted pure nothrow { assert(ti.hash); return ti.hash; } bool opEquals(ref const TemplateInstanceBox s) @trusted const { bool res = void; if (ti.inst && s.ti.inst) /* This clause is only used when an instance with errors * is replaced with a correct instance. */ res = ti is s.ti; else /* Used when a proposed instance is used to see if there's * an existing instance. */ res = (cast()s.ti).compare(cast()ti) == 0; debug (FindExistingInstance) ++(res ? nHits : nCollisions); return res; } debug (FindExistingInstance) { __gshared uint nHits, nCollisions; shared static ~this() { printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n", nHits, nCollisions); } } } ================================================ FILE: gcc/d/dmd/dversion.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/dversion.d, _dversion.d) * Documentation: https://dlang.org/phobos/dmd_dversion.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dversion.d */ module dmd.dversion; import dmd.arraytypes; import dmd.cond; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.globals; import dmd.identifier; import dmd.root.outbuffer; import dmd.visitor; /*********************************************************** * DebugSymbol's happen for statements like: * debug = identifier; * debug = integer; */ extern (C++) final class DebugSymbol : Dsymbol { uint level; extern (D) this(const ref Loc loc, Identifier ident) { super(ident); this.loc = loc; } extern (D) this(const ref Loc loc, uint level) { this.level = level; this.loc = loc; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto ds = new DebugSymbol(loc, ident); ds.level = level; return ds; } override const(char)* toChars() const nothrow { if (ident) return ident.toChars(); else { OutBuffer buf; buf.print(level); return buf.extractString(); } } override void addMember(Scope* sc, ScopeDsymbol sds) { //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); Module m = sds.isModule(); // Do not add the member to the symbol table, // just make sure subsequent debug declarations work. if (ident) { if (!m) { error("declaration must be at module level"); errors = true; } else { if (findCondition(m.debugidsNot, ident)) { error("defined after use"); errors = true; } if (!m.debugids) m.debugids = new Identifiers(); m.debugids.push(ident); } } else { if (!m) { error("level declaration must be at module level"); errors = true; } else m.debuglevel = level; } } override const(char)* kind() const nothrow { return "debug"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * VersionSymbol's happen for statements like: * version = identifier; * version = integer; */ extern (C++) final class VersionSymbol : Dsymbol { uint level; extern (D) this(const ref Loc loc, Identifier ident) { super(ident); this.loc = loc; } extern (D) this(const ref Loc loc, uint level) { this.level = level; this.loc = loc; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto ds = ident ? new VersionSymbol(loc, ident) : new VersionSymbol(loc, level); return ds; } override const(char)* toChars() nothrow { if (ident) return ident.toChars(); else { OutBuffer buf; buf.print(level); return buf.extractString(); } } override void addMember(Scope* sc, ScopeDsymbol sds) { //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); Module m = sds.isModule(); // Do not add the member to the symbol table, // just make sure subsequent debug declarations work. if (ident) { VersionCondition.checkReserved(loc, ident.toString()); if (!m) { error("declaration must be at module level"); errors = true; } else { if (findCondition(m.versionidsNot, ident)) { error("defined after use"); errors = true; } if (!m.versionids) m.versionids = new Identifiers(); m.versionids.push(ident); } } else { if (!m) { error("level declaration must be at module level"); errors = true; } else m.versionlevel = level; } } override const(char)* kind() const nothrow { return "version"; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/entity.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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; 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; } 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 ABOVE {"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT // "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN {"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL {"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE {"lessdot", 0x022D6}, // LESS-THAN WITH DOT {"lesseqgtr", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN {"lesseqqgtr", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN {"LessEqualGreater", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN {"LessFullEqual", 0x02266}, // LESS-THAN OVER EQUAL TO {"LessGreater", 0x02276}, // LESS-THAN OR GREATER-THAN {"lessgtr", 0x02276}, // LESS-THAN OR GREATER-THAN {"LessLess", 0x02AA1}, // DOUBLE NESTED LESS-THAN {"lesssim", 0x02272}, // LESS-THAN OR EQUIVALENT TO {"LessSlantEqual", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO {"LessTilde", 0x02272}, // LESS-THAN OR EQUIVALENT TO {"lfisht", 0x0297C}, // LEFT FISH TAIL {"lfloor", 0x0230A}, // LEFT FLOOR {"Lfr", 0x1D50F}, // MATHEMATICAL FRAKTUR CAPITAL L {"lfr", 0x1D529}, // MATHEMATICAL FRAKTUR SMALL L {"lg", 0x02276}, // LESS-THAN OR GREATER-THAN {"lgE", 0x02A91}, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL {"Lgr", 0x0039B}, // GREEK CAPITAL LETTER LAMDA {"lgr", 0x003BB}, // GREEK SMALL LETTER LAMDA {"lHar", 0x02962}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN {"lhard", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS {"lharu", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS {"lharul", 0x0296A}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH {"lhblk", 0x02584}, // LOWER HALF BLOCK {"LJcy", 0x00409}, // CYRILLIC CAPITAL LETTER LJE {"ljcy", 0x00459}, // CYRILLIC SMALL LETTER LJE {"ll", 0x0226A}, // MUCH LESS-THAN {"Ll", 0x022D8}, // VERY MUCH LESS-THAN {"llarr", 0x021C7}, // LEFTWARDS PAIRED ARROWS {"llcorner", 0x0231E}, // BOTTOM LEFT CORNER {"Lleftarrow", 0x021DA}, // LEFTWARDS TRIPLE ARROW {"llhard", 0x0296B}, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH {"lltri", 0x025FA}, // LOWER LEFT TRIANGLE {"Lmidot", 0x0013F}, // LATIN CAPITAL LETTER L WITH MIDDLE DOT {"lmidot", 0x00140}, // LATIN SMALL LETTER L WITH MIDDLE DOT {"lmoust", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION {"lmoustache", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION {"lnap", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE {"lnapprox", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE {"lnE", 0x02268}, // LESS-THAN BUT NOT EQUAL TO {"lne", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO {"lneq", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO {"lneqq", 0x02268}, // LESS-THAN BUT NOT EQUAL TO {"lnsim", 0x022E6}, // LESS-THAN BUT NOT EQUIVALENT TO {"loang", 0x027EC}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET {"loarr", 0x021FD}, // LEFTWARDS OPEN-HEADED ARROW {"lobrk", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET {"longleftarrow", 0x027F5}, // LONG LEFTWARDS ARROW {"LongLeftArrow", 0x027F5}, // LONG LEFTWARDS ARROW {"Longleftarrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW {"longleftrightarrow", 0x027F7}, // LONG LEFT RIGHT ARROW {"LongLeftRightArrow", 0x027F7}, // LONG LEFT RIGHT ARROW {"Longleftrightarrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW {"longmapsto", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR {"longrightarrow", 0x027F6}, // LONG RIGHTWARDS ARROW {"LongRightArrow", 0x027F6}, // LONG RIGHTWARDS ARROW {"Longrightarrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW {"looparrowleft", 0x021AB}, // LEFTWARDS ARROW WITH LOOP {"looparrowright", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP {"lopar", 0x02985}, // LEFT WHITE PARENTHESIS {"Lopf", 0x1D543}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L {"lopf", 0x1D55D}, // MATHEMATICAL DOUBLE-STRUCK SMALL L {"loplus", 0x02A2D}, // PLUS SIGN IN LEFT HALF CIRCLE {"lotimes", 0x02A34}, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE {"lowast", 0x02217}, // ASTERISK OPERATOR {"lowbar", 0x0005F}, // LOW LINE {"LowerLeftArrow", 0x02199}, // SOUTH WEST ARROW {"LowerRightArrow", 0x02198}, // SOUTH EAST ARROW {"loz", 0x025CA}, // LOZENGE {"lozenge", 0x025CA}, // LOZENGE {"lozf", 0x029EB}, // BLACK LOZENGE {"lpar", 0x00028}, // LEFT PARENTHESIS {"lparlt", 0x02993}, // LEFT ARC LESS-THAN BRACKET {"lrarr", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW {"lrcorner", 0x0231F}, // BOTTOM RIGHT CORNER {"lrhar", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON {"lrhard", 0x0296D}, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH {"lrm", 0x0200E}, // LEFT-TO-RIGHT MARK {"lrtri", 0x022BF}, // RIGHT TRIANGLE {"lsaquo", 0x02039}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK {"Lscr", 0x02112}, // SCRIPT CAPITAL L {"lscr", 0x1D4C1}, // MATHEMATICAL SCRIPT SMALL L {"lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS {"Lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS {"lsim", 0x02272}, // LESS-THAN OR EQUIVALENT TO {"lsime", 0x02A8D}, // LESS-THAN ABOVE SIMILAR OR EQUAL {"lsimg", 0x02A8F}, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN {"lsqb", 0x0005B}, // LEFT SQUARE BRACKET {"lsquo", 0x02018}, // LEFT SINGLE QUOTATION MARK {"lsquor", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK {"Lstrok", 0x00141}, // LATIN CAPITAL LETTER L WITH STROKE {"lstrok", 0x00142}, // LATIN SMALL LETTER L WITH STROKE {"lt", 0x0003C}, // LESS-THAN SIGN {"LT", 0x0003C}, // LESS-THAN SIGN {"Lt", 0x0226A}, // MUCH LESS-THAN {"ltcc", 0x02AA6}, // LESS-THAN CLOSED BY CURVE {"ltcir", 0x02A79}, // LESS-THAN WITH CIRCLE INSIDE {"ltdot", 0x022D6}, // LESS-THAN WITH DOT {"lthree", 0x022CB}, // LEFT SEMIDIRECT PRODUCT {"ltimes", 0x022C9}, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT {"ltlarr", 0x02976}, // LESS-THAN ABOVE LEFTWARDS ARROW {"ltquest", 0x02A7B}, // LESS-THAN WITH QUESTION MARK ABOVE {"ltri", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE {"ltrie", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO {"ltrif", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE {"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET {"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON {"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP // "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke // "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke ]; immutable NameId[] namesM = [ {"macr", 0x000AF}, // MACRON {"male", 0x02642}, // MALE SIGN {"malt", 0x02720}, // MALTESE CROSS {"maltese", 0x02720}, // MALTESE CROSS {"map", 0x021A6}, // RIGHTWARDS ARROW FROM BAR {"Map", 0x02905}, // RIGHTWARDS TWO-HEADED ARROW FROM BAR {"mapsto", 0x021A6}, // RIGHTWARDS ARROW FROM BAR {"mapstodown", 0x021A7}, // DOWNWARDS ARROW FROM BAR {"mapstoleft", 0x021A4}, // LEFTWARDS ARROW FROM BAR {"mapstoup", 0x021A5}, // UPWARDS ARROW FROM BAR {"marker", 0x025AE}, // BLACK VERTICAL RECTANGLE {"mcomma", 0x02A29}, // MINUS SIGN WITH COMMA ABOVE {"Mcy", 0x0041C}, // CYRILLIC CAPITAL LETTER EM {"mcy", 0x0043C}, // CYRILLIC SMALL LETTER EM {"mdash", 0x02014}, // EM DASH {"mDDot", 0x0223A}, // GEOMETRIC PROPORTION {"measuredangle", 0x02221}, // MEASURED ANGLE {"MediumSpace", 0x0205F}, // MEDIUM MATHEMATICAL SPACE {"Mellintrf", 0x02133}, // SCRIPT CAPITAL M {"Mfr", 0x1D510}, // MATHEMATICAL FRAKTUR CAPITAL M {"mfr", 0x1D52A}, // MATHEMATICAL FRAKTUR SMALL M {"Mgr", 0x0039C}, // GREEK CAPITAL LETTER MU {"mgr", 0x003BC}, // GREEK SMALL LETTER MU {"mho", 0x02127}, // INVERTED OHM SIGN {"micro", 0x000B5}, // MICRO SIGN {"mid", 0x02223}, // DIVIDES {"midast", 0x0002A}, // ASTERISK {"midcir", 0x02AF0}, // VERTICAL LINE WITH CIRCLE BELOW {"middot", 0x000B7}, // MIDDLE DOT {"minus", 0x02212}, // MINUS SIGN {"minusb", 0x0229F}, // SQUARED MINUS {"minusd", 0x02238}, // DOT MINUS {"minusdu", 0x02A2A}, // MINUS SIGN WITH DOT BELOW {"MinusPlus", 0x02213}, // MINUS-OR-PLUS SIGN {"mlcp", 0x02ADB}, // TRANSVERSAL INTERSECTION {"mldr", 0x02026}, // HORIZONTAL ELLIPSIS {"mnplus", 0x02213}, // MINUS-OR-PLUS SIGN {"models", 0x022A7}, // MODELS {"Mopf", 0x1D544}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M {"mopf", 0x1D55E}, // MATHEMATICAL DOUBLE-STRUCK SMALL M {"mp", 0x02213}, // MINUS-OR-PLUS SIGN {"Mscr", 0x02133}, // SCRIPT CAPITAL M {"mscr", 0x1D4C2}, // MATHEMATICAL SCRIPT SMALL M {"mstpos", 0x0223E}, // INVERTED LAZY S {"Mu", 0x0039C}, // GREEK CAPITAL LETTER MU {"mu", 0x003BC}, // GREEK SMALL LETTER MU {"multimap", 0x022B8}, // MULTIMAP {"mumap", 0x022B8}, // MULTIMAP ]; immutable NameId[] namesN = [ {"nabla", 0x02207}, // NABLA {"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE {"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE // "nang", 0x02220;0x020D2}, // ANGLE with vertical line {"nap", 0x02249}, // NOT ALMOST EQUAL TO // "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash // "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash {"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE {"napprox", 0x02249}, // NOT ALMOST EQUAL TO {"natur", 0x0266E}, // MUSIC NATURAL SIGN {"natural", 0x0266E}, // MUSIC NATURAL SIGN {"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N {"nbsp", 0x000A0}, // NO-BREAK SPACE // "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash // "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash {"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR {"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON {"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON {"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA {"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA {"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO // "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash {"ncup", 0x02A42}, // UNION WITH OVERBAR {"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN {"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN {"ndash", 0x02013}, // EN DASH {"ne", 0x02260}, // NOT EQUAL TO {"nearhk", 0x02924}, // NORTH EAST ARROW WITH HOOK {"nearr", 0x02197}, // NORTH EAST ARROW {"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW {"nearrow", 0x02197}, // NORTH EAST ARROW // "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash {"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE {"nequiv", 0x02262}, // NOT IDENTICAL TO {"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW // "nesim", 0x02242;0x00338}, // MINUS TILDE with slash {"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN {"NestedLessLess", 0x0226A}, // MUCH LESS-THAN {"NewLine", 0x0000A}, // LINE FEED (LF) {"nexist", 0x02204}, // THERE DOES NOT EXIST {"nexists", 0x02204}, // THERE DOES NOT EXIST {"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N {"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N // "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash {"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO {"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO // "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash // "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash // "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash // "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash {"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU {"ngr", 0x003BD}, // GREEK SMALL LETTER NU {"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO // "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line {"ngt", 0x0226F}, // NOT GREATER-THAN {"ngtr", 0x0226F}, // NOT GREATER-THAN // "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash {"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE {"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE {"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE {"ni", 0x0220B}, // CONTAINS AS MEMBER {"nis", 0x022FC}, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE {"nisd", 0x022FA}, // CONTAINS WITH LONG HORIZONTAL STROKE {"niv", 0x0220B}, // CONTAINS AS MEMBER {"NJcy", 0x0040A}, // CYRILLIC CAPITAL LETTER NJE {"njcy", 0x0045A}, // CYRILLIC SMALL LETTER NJE {"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE {"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE {"nldr", 0x02025}, // TWO DOT LEADER // "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash {"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO {"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE {"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE {"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE {"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE {"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO // "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash // "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash // "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash {"nless", 0x0226E}, // NOT LESS-THAN // "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash {"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO // "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line {"nlt", 0x0226E}, // NOT LESS-THAN {"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF {"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO // "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash {"nmid", 0x02224}, // DOES NOT DIVIDE {"NoBreak", 0x02060}, // WORD JOINER {"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE {"Nopf", 0x02115}, // DOUBLE-STRUCK CAPITAL N {"nopf", 0x1D55F}, // MATHEMATICAL DOUBLE-STRUCK SMALL N {"not", 0x000AC}, // NOT SIGN {"Not", 0x02AEC}, // DOUBLE STROKE NOT SIGN {"NotCongruent", 0x02262}, // NOT IDENTICAL TO {"NotCupCap", 0x0226D}, // NOT EQUIVALENT TO {"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO {"NotElement", 0x02209}, // NOT AN ELEMENT OF {"NotEqual", 0x02260}, // NOT EQUAL TO // "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash {"NotExists", 0x02204}, // THERE DOES NOT EXIST {"NotGreater", 0x0226F}, // NOT GREATER-THAN {"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO // "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash // "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash {"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN // "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash {"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO // "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash // "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash {"notin", 0x02209}, // NOT AN ELEMENT OF // "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash // "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash {"notinva", 0x02209}, // NOT AN ELEMENT OF {"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR {"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR {"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF // "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash {"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO {"NotLess", 0x0226E}, // NOT LESS-THAN {"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO {"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN // "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash // "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash {"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO // "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash // "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash {"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR {"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR {"NotPrecedes", 0x02280}, // DOES NOT PRECEDE // "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL {"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP // "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash {"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL // "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash {"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO // "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash {"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO // "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line {"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO {"NotSucceeds", 0x02281}, // DOES NOT SUCCEED // "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL // "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash // "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line {"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO {"NotTilde", 0x02241}, // NOT TILDE {"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO {"NotTildeFullEqual", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO {"NotTildeTilde", 0x02249}, // NOT ALMOST EQUAL TO {"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE {"npar", 0x02226}, // NOT PARALLEL TO {"nparallel", 0x02226}, // NOT PARALLEL TO // "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash // "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash {"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE {"npr", 0x02280}, // DOES NOT PRECEDE {"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL // "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"nprec", 0x02280}, // DOES NOT PRECEDE // "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE {"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE // "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash // "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash {"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE {"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE {"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP {"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL {"nsc", 0x02281}, // DOES NOT SUCCEED {"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL // "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N {"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N {"nshortmid", 0x02224}, // DOES NOT DIVIDE {"nshortparallel", 0x02226}, // NOT PARALLEL TO {"nsim", 0x02241}, // NOT TILDE {"nsime", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO {"nsimeq", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO {"nsmid", 0x02224}, // DOES NOT DIVIDE {"nspar", 0x02226}, // NOT PARALLEL TO {"nsqsube", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO {"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO {"nsub", 0x02284}, // NOT A SUBSET OF {"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO // "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash // "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line {"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO // "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash {"nsucc", 0x02281}, // DOES NOT SUCCEED // "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"nsup", 0x02285}, // NOT A SUPERSET OF {"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO // "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash // "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line {"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO // "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash {"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN {"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE {"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE {"ntlg", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN {"ntriangleleft", 0x022EA}, // NOT NORMAL SUBGROUP OF {"ntrianglelefteq", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO {"ntriangleright", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP {"ntrianglerighteq", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL {"Nu", 0x0039D}, // GREEK CAPITAL LETTER NU {"nu", 0x003BD}, // GREEK SMALL LETTER NU {"num", 0x00023}, // NUMBER SIGN {"numero", 0x02116}, // NUMERO SIGN {"numsp", 0x02007}, // FIGURE SPACE // "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line {"nvdash", 0x022AC}, // DOES NOT PROVE {"nvDash", 0x022AD}, // NOT TRUE {"nVdash", 0x022AE}, // DOES NOT FORCE {"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE // "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line // "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line {"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE {"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR {"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE // "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line // "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line // "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line {"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE // "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line // "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line {"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK {"nwarr", 0x02196}, // NORTH WEST ARROW {"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW {"nwarrow", 0x02196}, // NORTH WEST ARROW {"nwnear", 0x02927}, // NORTH WEST ARROW AND NORTH EAST ARROW ]; immutable NameId[] namesO = [ {"Oacgr", 0x0038C}, // GREEK CAPITAL LETTER OMICRON WITH TONOS {"oacgr", 0x003CC}, // GREEK SMALL LETTER OMICRON WITH TONOS {"Oacute", 0x000D3}, // LATIN CAPITAL LETTER O WITH ACUTE {"oacute", 0x000F3}, // LATIN SMALL LETTER O WITH ACUTE {"oast", 0x0229B}, // CIRCLED ASTERISK OPERATOR {"ocir", 0x0229A}, // CIRCLED RING OPERATOR {"Ocirc", 0x000D4}, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX {"ocirc", 0x000F4}, // LATIN SMALL LETTER O WITH CIRCUMFLEX {"Ocy", 0x0041E}, // CYRILLIC CAPITAL LETTER O {"ocy", 0x0043E}, // CYRILLIC SMALL LETTER O {"odash", 0x0229D}, // CIRCLED DASH {"Odblac", 0x00150}, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE {"odblac", 0x00151}, // LATIN SMALL LETTER O WITH DOUBLE ACUTE {"odiv", 0x02A38}, // CIRCLED DIVISION SIGN {"odot", 0x02299}, // CIRCLED DOT OPERATOR {"odsold", 0x029BC}, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN {"OElig", 0x00152}, // LATIN CAPITAL LIGATURE OE {"oelig", 0x00153}, // LATIN SMALL LIGATURE OE {"ofcir", 0x029BF}, // CIRCLED BULLET {"Ofr", 0x1D512}, // MATHEMATICAL FRAKTUR CAPITAL O {"ofr", 0x1D52C}, // MATHEMATICAL FRAKTUR SMALL O {"ogon", 0x002DB}, // OGONEK {"Ogr", 0x0039F}, // GREEK CAPITAL LETTER OMICRON {"ogr", 0x003BF}, // GREEK SMALL LETTER OMICRON {"Ograve", 0x000D2}, // LATIN CAPITAL LETTER O WITH GRAVE {"ograve", 0x000F2}, // LATIN SMALL LETTER O WITH GRAVE {"ogt", 0x029C1}, // CIRCLED GREATER-THAN {"OHacgr", 0x0038F}, // GREEK CAPITAL LETTER OMEGA WITH TONOS {"ohacgr", 0x003CE}, // GREEK SMALL LETTER OMEGA WITH TONOS {"ohbar", 0x029B5}, // CIRCLE WITH HORIZONTAL BAR {"OHgr", 0x003A9}, // GREEK CAPITAL LETTER OMEGA {"ohgr", 0x003C9}, // GREEK SMALL LETTER OMEGA {"ohm", 0x003A9}, // GREEK CAPITAL LETTER OMEGA {"oint", 0x0222E}, // CONTOUR INTEGRAL {"olarr", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW {"olcir", 0x029BE}, // CIRCLED WHITE BULLET {"olcross", 0x029BB}, // CIRCLE WITH SUPERIMPOSED X {"oline", 0x0203E}, // OVERLINE {"olt", 0x029C0}, // CIRCLED LESS-THAN {"Omacr", 0x0014C}, // LATIN CAPITAL LETTER O WITH MACRON {"omacr", 0x0014D}, // LATIN SMALL LETTER O WITH MACRON {"Omega", 0x003A9}, // GREEK CAPITAL LETTER OMEGA {"omega", 0x003C9}, // GREEK SMALL LETTER OMEGA {"Omicron", 0x0039F}, // GREEK CAPITAL LETTER OMICRON {"omicron", 0x003BF}, // GREEK SMALL LETTER OMICRON {"omid", 0x029B6}, // CIRCLED VERTICAL BAR {"ominus", 0x02296}, // CIRCLED MINUS {"Oopf", 0x1D546}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O {"oopf", 0x1D560}, // MATHEMATICAL DOUBLE-STRUCK SMALL O {"opar", 0x029B7}, // CIRCLED PARALLEL {"OpenCurlyDoubleQuote", 0x0201C}, // LEFT DOUBLE QUOTATION MARK {"OpenCurlyQuote", 0x02018}, // LEFT SINGLE QUOTATION MARK {"operp", 0x029B9}, // CIRCLED PERPENDICULAR {"oplus", 0x02295}, // CIRCLED PLUS {"or", 0x02228}, // LOGICAL OR {"Or", 0x02A54}, // DOUBLE LOGICAL OR {"orarr", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW {"ord", 0x02A5D}, // LOGICAL OR WITH HORIZONTAL DASH {"order", 0x02134}, // SCRIPT SMALL O {"orderof", 0x02134}, // SCRIPT SMALL O {"ordf", 0x000AA}, // FEMININE ORDINAL INDICATOR {"ordm", 0x000BA}, // MASCULINE ORDINAL INDICATOR {"origof", 0x022B6}, // ORIGINAL OF {"oror", 0x02A56}, // TWO INTERSECTING LOGICAL OR {"orslope", 0x02A57}, // SLOPING LARGE OR {"orv", 0x02A5B}, // LOGICAL OR WITH MIDDLE STEM {"oS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S {"oscr", 0x02134}, // SCRIPT SMALL O {"Oscr", 0x1D4AA}, // MATHEMATICAL SCRIPT CAPITAL O {"Oslash", 0x000D8}, // LATIN CAPITAL LETTER O WITH STROKE {"oslash", 0x000F8}, // LATIN SMALL LETTER O WITH STROKE {"osol", 0x02298}, // CIRCLED DIVISION SLASH {"Otilde", 0x000D5}, // LATIN CAPITAL LETTER O WITH TILDE {"otilde", 0x000F5}, // LATIN SMALL LETTER O WITH TILDE {"otimes", 0x02297}, // CIRCLED TIMES {"Otimes", 0x02A37}, // MULTIPLICATION SIGN IN DOUBLE CIRCLE {"otimesas", 0x02A36}, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT {"Ouml", 0x000D6}, // LATIN CAPITAL LETTER O WITH DIAERESIS {"ouml", 0x000F6}, // LATIN SMALL LETTER O WITH DIAERESIS {"ovbar", 0x0233D}, // APL FUNCTIONAL SYMBOL CIRCLE STILE {"OverBar", 0x0203E}, // OVERLINE {"OverBrace", 0x023DE}, // TOP CURLY BRACKET {"OverBracket", 0x023B4}, // TOP SQUARE BRACKET {"OverParenthesis", 0x023DC}, // TOP PARENTHESIS ]; immutable NameId[] namesP = [ {"par", 0x02225}, // PARALLEL TO {"para", 0x000B6}, // PILCROW SIGN {"parallel", 0x02225}, // PARALLEL TO {"parsim", 0x02AF3}, // PARALLEL WITH TILDE OPERATOR {"parsl", 0x02AFD}, // DOUBLE SOLIDUS OPERATOR {"part", 0x02202}, // PARTIAL DIFFERENTIAL {"PartialD", 0x02202}, // PARTIAL DIFFERENTIAL {"Pcy", 0x0041F}, // CYRILLIC CAPITAL LETTER PE {"pcy", 0x0043F}, // CYRILLIC SMALL LETTER PE {"percnt", 0x00025}, // PERCENT SIGN {"period", 0x0002E}, // FULL STOP {"permil", 0x02030}, // PER MILLE SIGN {"perp", 0x022A5}, // UP TACK {"pertenk", 0x02031}, // PER TEN THOUSAND SIGN {"Pfr", 0x1D513}, // MATHEMATICAL FRAKTUR CAPITAL P {"pfr", 0x1D52D}, // MATHEMATICAL FRAKTUR SMALL P {"Pgr", 0x003A0}, // GREEK CAPITAL LETTER PI {"pgr", 0x003C0}, // GREEK SMALL LETTER PI {"PHgr", 0x003A6}, // GREEK CAPITAL LETTER PHI {"phgr", 0x003C6}, // GREEK SMALL LETTER PHI {"Phi", 0x003A6}, // GREEK CAPITAL LETTER PHI {"phi", 0x003C6}, // GREEK SMALL LETTER PHI {"phiv", 0x003D5}, // GREEK PHI SYMBOL {"phmmat", 0x02133}, // SCRIPT CAPITAL M {"phone", 0x0260E}, // BLACK TELEPHONE {"Pi", 0x003A0}, // GREEK CAPITAL LETTER PI {"pi", 0x003C0}, // GREEK SMALL LETTER PI {"pitchfork", 0x022D4}, // PITCHFORK {"piv", 0x003D6}, // GREEK PI SYMBOL {"planck", 0x0210F}, // PLANCK CONSTANT OVER TWO PI {"planckh", 0x0210E}, // PLANCK CONSTANT {"plankv", 0x0210F}, // PLANCK CONSTANT OVER TWO PI {"plus", 0x0002B}, // PLUS SIGN {"plusacir", 0x02A23}, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE {"plusb", 0x0229E}, // SQUARED PLUS {"pluscir", 0x02A22}, // PLUS SIGN WITH SMALL CIRCLE ABOVE {"plusdo", 0x02214}, // DOT PLUS {"plusdu", 0x02A25}, // PLUS SIGN WITH DOT BELOW {"pluse", 0x02A72}, // PLUS SIGN ABOVE EQUALS SIGN {"PlusMinus", 0x000B1}, // PLUS-MINUS SIGN {"plusmn", 0x000B1}, // PLUS-MINUS SIGN {"plussim", 0x02A26}, // PLUS SIGN WITH TILDE BELOW {"plustwo", 0x02A27}, // PLUS SIGN WITH SUBSCRIPT TWO {"pm", 0x000B1}, // PLUS-MINUS SIGN {"Poincareplane", 0x0210C}, // BLACK-LETTER CAPITAL H {"pointint", 0x02A15}, // INTEGRAL AROUND A POINT OPERATOR {"Popf", 0x02119}, // DOUBLE-STRUCK CAPITAL P {"popf", 0x1D561}, // MATHEMATICAL DOUBLE-STRUCK SMALL P {"pound", 0x000A3}, // POUND SIGN {"pr", 0x0227A}, // PRECEDES {"Pr", 0x02ABB}, // DOUBLE PRECEDES {"prap", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO {"prcue", 0x0227C}, // PRECEDES OR EQUAL TO {"pre", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN {"prE", 0x02AB3}, // PRECEDES ABOVE EQUALS SIGN {"prec", 0x0227A}, // PRECEDES {"precapprox", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO {"preccurlyeq", 0x0227C}, // PRECEDES OR EQUAL TO {"Precedes", 0x0227A}, // PRECEDES {"PrecedesEqual", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN {"PrecedesSlantEqual", 0x0227C}, // PRECEDES OR EQUAL TO {"PrecedesTilde", 0x0227E}, // PRECEDES OR EQUIVALENT TO {"preceq", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN {"precnapprox", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO {"precneqq", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO {"precnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO {"precsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO {"prime", 0x02032}, // PRIME {"Prime", 0x02033}, // DOUBLE PRIME {"primes", 0x02119}, // DOUBLE-STRUCK CAPITAL P {"prnap", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO {"prnE", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO {"prnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO {"prod", 0x0220F}, // N-ARY PRODUCT {"Product", 0x0220F}, // N-ARY PRODUCT {"profalar", 0x0232E}, // ALL AROUND-PROFILE {"profline", 0x02312}, // ARC {"profsurf", 0x02313}, // SEGMENT {"prop", 0x0221D}, // PROPORTIONAL TO {"Proportion", 0x02237}, // PROPORTION {"Proportional", 0x0221D}, // PROPORTIONAL TO {"propto", 0x0221D}, // PROPORTIONAL TO {"prsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO {"prurel", 0x022B0}, // PRECEDES UNDER RELATION {"Pscr", 0x1D4AB}, // MATHEMATICAL SCRIPT CAPITAL P {"pscr", 0x1D4C5}, // MATHEMATICAL SCRIPT SMALL P {"PSgr", 0x003A8}, // GREEK CAPITAL LETTER PSI {"psgr", 0x003C8}, // GREEK SMALL LETTER PSI {"Psi", 0x003A8}, // GREEK CAPITAL LETTER PSI {"psi", 0x003C8}, // GREEK SMALL LETTER PSI {"puncsp", 0x02008}, // PUNCTUATION SPACE ]; immutable NameId[] namesQ = [ {"Qfr", 0x1D514}, // MATHEMATICAL FRAKTUR CAPITAL Q {"qfr", 0x1D52E}, // MATHEMATICAL FRAKTUR SMALL Q {"qint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR {"Qopf", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q {"qopf", 0x1D562}, // MATHEMATICAL DOUBLE-STRUCK SMALL Q {"qprime", 0x02057}, // QUADRUPLE PRIME {"Qscr", 0x1D4AC}, // MATHEMATICAL SCRIPT CAPITAL Q {"qscr", 0x1D4C6}, // MATHEMATICAL SCRIPT SMALL Q {"quaternions", 0x0210D}, // DOUBLE-STRUCK CAPITAL H {"quatint", 0x02A16}, // QUATERNION INTEGRAL OPERATOR {"quest", 0x0003F}, // QUESTION MARK {"questeq", 0x0225F}, // QUESTIONED EQUAL TO {"quot", 0x00022}, // QUOTATION MARK {"QUOT", 0x00022}, // QUOTATION MARK ]; immutable NameId[] namesR = [ {"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW // "race", 0x0223D;0x00331}, // REVERSED TILDE with underline {"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE {"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE {"radic", 0x0221A}, // SQUARE ROOT {"raemptyv", 0x029B3}, // EMPTY SET WITH RIGHT ARROW ABOVE {"rang", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET {"Rang", 0x027EB}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET {"rangd", 0x02992}, // RIGHT ANGLE BRACKET WITH DOT {"range", 0x029A5}, // REVERSED ANGLE WITH UNDERBAR {"rangle", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET {"raquo", 0x000BB}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK {"rarr", 0x02192}, // RIGHTWARDS ARROW {"Rarr", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW {"rArr", 0x021D2}, // RIGHTWARDS DOUBLE ARROW {"rarrap", 0x02975}, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO {"rarrb", 0x021E5}, // RIGHTWARDS ARROW TO BAR {"rarrbfs", 0x02920}, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND {"rarrc", 0x02933}, // WAVE ARROW POINTING DIRECTLY RIGHT {"rarrfs", 0x0291E}, // RIGHTWARDS ARROW TO BLACK DIAMOND {"rarrhk", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK {"rarrlp", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP {"rarrpl", 0x02945}, // RIGHTWARDS ARROW WITH PLUS BELOW {"rarrsim", 0x02974}, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR {"rarrtl", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL {"Rarrtl", 0x02916}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL {"rarrw", 0x0219D}, // RIGHTWARDS WAVE ARROW {"ratail", 0x0291A}, // RIGHTWARDS ARROW-TAIL {"rAtail", 0x0291C}, // RIGHTWARDS DOUBLE ARROW-TAIL {"ratio", 0x02236}, // RATIO {"rationals", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q {"rbarr", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW {"rBarr", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW {"RBarr", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW {"rbbrk", 0x02773}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT {"rbrace", 0x0007D}, // RIGHT CURLY BRACKET {"rbrack", 0x0005D}, // RIGHT SQUARE BRACKET {"rbrke", 0x0298C}, // RIGHT SQUARE BRACKET WITH UNDERBAR {"rbrksld", 0x0298E}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER {"rbrkslu", 0x02990}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER {"Rcaron", 0x00158}, // LATIN CAPITAL LETTER R WITH CARON {"rcaron", 0x00159}, // LATIN SMALL LETTER R WITH CARON {"Rcedil", 0x00156}, // LATIN CAPITAL LETTER R WITH CEDILLA {"rcedil", 0x00157}, // LATIN SMALL LETTER R WITH CEDILLA {"rceil", 0x02309}, // RIGHT CEILING {"rcub", 0x0007D}, // RIGHT CURLY BRACKET {"Rcy", 0x00420}, // CYRILLIC CAPITAL LETTER ER {"rcy", 0x00440}, // CYRILLIC SMALL LETTER ER {"rdca", 0x02937}, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS {"rdldhar", 0x02969}, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN {"rdquo", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK {"rdquor", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK {"rdsh", 0x021B3}, // DOWNWARDS ARROW WITH TIP RIGHTWARDS {"Re", 0x0211C}, // BLACK-LETTER CAPITAL R {"real", 0x0211C}, // BLACK-LETTER CAPITAL R {"realine", 0x0211B}, // SCRIPT CAPITAL R {"realpart", 0x0211C}, // BLACK-LETTER CAPITAL R {"reals", 0x0211D}, // DOUBLE-STRUCK CAPITAL R {"rect", 0x025AD}, // WHITE RECTANGLE {"reg", 0x000AE}, // REGISTERED SIGN {"REG", 0x000AE}, // REGISTERED SIGN {"ReverseElement", 0x0220B}, // CONTAINS AS MEMBER {"ReverseEquilibrium", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON {"ReverseUpEquilibrium", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT {"rfisht", 0x0297D}, // RIGHT FISH TAIL {"rfloor", 0x0230B}, // RIGHT FLOOR {"Rfr", 0x0211C}, // BLACK-LETTER CAPITAL R {"rfr", 0x1D52F}, // MATHEMATICAL FRAKTUR SMALL R {"Rgr", 0x003A1}, // GREEK CAPITAL LETTER RHO {"rgr", 0x003C1}, // GREEK SMALL LETTER RHO {"rHar", 0x02964}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN {"rhard", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS {"rharu", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS {"rharul", 0x0296C}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH {"Rho", 0x003A1}, // GREEK CAPITAL LETTER RHO {"rho", 0x003C1}, // GREEK SMALL LETTER RHO {"rhov", 0x003F1}, // GREEK RHO SYMBOL {"RightAngleBracket", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET {"rightarrow", 0x02192}, // RIGHTWARDS ARROW {"RightArrow", 0x02192}, // RIGHTWARDS ARROW {"Rightarrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW {"RightArrowBar", 0x021E5}, // RIGHTWARDS ARROW TO BAR {"RightArrowLeftArrow", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW {"rightarrowtail", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL {"RightCeiling", 0x02309}, // RIGHT CEILING {"RightDoubleBracket", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET {"RightDownTeeVector", 0x0295D}, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR {"RightDownVector", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS {"RightDownVectorBar", 0x02955}, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR {"RightFloor", 0x0230B}, // RIGHT FLOOR {"rightharpoondown", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS {"rightharpoonup", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS {"rightleftarrows", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW {"rightleftharpoons", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON {"rightrightarrows", 0x021C9}, // RIGHTWARDS PAIRED ARROWS {"rightsquigarrow", 0x0219D}, // RIGHTWARDS WAVE ARROW {"RightTee", 0x022A2}, // RIGHT TACK {"RightTeeArrow", 0x021A6}, // RIGHTWARDS ARROW FROM BAR {"RightTeeVector", 0x0295B}, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR {"rightthreetimes", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT {"RightTriangle", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP {"RightTriangleBar", 0x029D0}, // VERTICAL BAR BESIDE RIGHT TRIANGLE {"RightTriangleEqual", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO {"RightUpDownVector", 0x0294F}, // UP BARB RIGHT DOWN BARB RIGHT HARPOON {"RightUpTeeVector", 0x0295C}, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR {"RightUpVector", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS {"RightUpVectorBar", 0x02954}, // UPWARDS HARPOON WITH BARB RIGHT TO BAR {"RightVector", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS {"RightVectorBar", 0x02953}, // RIGHTWARDS HARPOON WITH BARB UP TO BAR {"ring", 0x002DA}, // RING ABOVE {"risingdotseq", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO {"rlarr", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW {"rlhar", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON {"rlm", 0x0200F}, // RIGHT-TO-LEFT MARK {"rmoust", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION {"rmoustache", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION {"rnmid", 0x02AEE}, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH {"roang", 0x027ED}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET {"roarr", 0x021FE}, // RIGHTWARDS OPEN-HEADED ARROW {"robrk", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET {"ropar", 0x02986}, // RIGHT WHITE PARENTHESIS {"Ropf", 0x0211D}, // DOUBLE-STRUCK CAPITAL R {"ropf", 0x1D563}, // MATHEMATICAL DOUBLE-STRUCK SMALL R {"roplus", 0x02A2E}, // PLUS SIGN IN RIGHT HALF CIRCLE {"rotimes", 0x02A35}, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE {"RoundImplies", 0x02970}, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD {"rpar", 0x00029}, // RIGHT PARENTHESIS {"rpargt", 0x02994}, // RIGHT ARC GREATER-THAN BRACKET {"rppolint", 0x02A12}, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE {"rrarr", 0x021C9}, // RIGHTWARDS PAIRED ARROWS {"Rrightarrow", 0x021DB}, // RIGHTWARDS TRIPLE ARROW {"rsaquo", 0x0203A}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK {"Rscr", 0x0211B}, // SCRIPT CAPITAL R {"rscr", 0x1D4C7}, // MATHEMATICAL SCRIPT SMALL R {"rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS {"Rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS {"rsqb", 0x0005D}, // RIGHT SQUARE BRACKET {"rsquo", 0x02019}, // RIGHT SINGLE QUOTATION MARK {"rsquor", 0x02019}, // RIGHT SINGLE QUOTATION MARK {"rthree", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT {"rtimes", 0x022CA}, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT {"rtri", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE {"rtrie", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO {"rtrif", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE {"rtriltri", 0x029CE}, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE {"RuleDelayed", 0x029F4}, // RULE-DELAYED {"ruluhar", 0x02968}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP {"rx", 0x0211E}, // PRESCRIPTION TAKE ]; immutable NameId[] namesS = [ {"Sacute", 0x0015A}, // LATIN CAPITAL LETTER S WITH ACUTE {"sacute", 0x0015B}, // LATIN SMALL LETTER S WITH ACUTE {"sbquo", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK {"sc", 0x0227B}, // SUCCEEDS {"Sc", 0x02ABC}, // DOUBLE SUCCEEDS {"scap", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO {"Scaron", 0x00160}, // LATIN CAPITAL LETTER S WITH CARON {"scaron", 0x00161}, // LATIN SMALL LETTER S WITH CARON {"sccue", 0x0227D}, // SUCCEEDS OR EQUAL TO {"sce", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN {"scE", 0x02AB4}, // SUCCEEDS ABOVE EQUALS SIGN {"Scedil", 0x0015E}, // LATIN CAPITAL LETTER S WITH CEDILLA {"scedil", 0x0015F}, // LATIN SMALL LETTER S WITH CEDILLA {"Scirc", 0x0015C}, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX {"scirc", 0x0015D}, // LATIN SMALL LETTER S WITH CIRCUMFLEX {"scnap", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO {"scnE", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO {"scnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO {"scpolint", 0x02A13}, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE {"scsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO {"Scy", 0x00421}, // CYRILLIC CAPITAL LETTER ES {"scy", 0x00441}, // CYRILLIC SMALL LETTER ES {"sdot", 0x022C5}, // DOT OPERATOR {"sdotb", 0x022A1}, // SQUARED DOT OPERATOR {"sdote", 0x02A66}, // EQUALS SIGN WITH DOT BELOW {"searhk", 0x02925}, // SOUTH EAST ARROW WITH HOOK {"searr", 0x02198}, // SOUTH EAST ARROW {"seArr", 0x021D8}, // SOUTH EAST DOUBLE ARROW {"searrow", 0x02198}, // SOUTH EAST ARROW {"sect", 0x000A7}, // SECTION SIGN {"semi", 0x0003B}, // SEMICOLON {"seswar", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW {"setminus", 0x02216}, // SET MINUS {"setmn", 0x02216}, // SET MINUS {"sext", 0x02736}, // SIX POINTED BLACK STAR {"sfgr", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA {"Sfr", 0x1D516}, // MATHEMATICAL FRAKTUR CAPITAL S {"sfr", 0x1D530}, // MATHEMATICAL FRAKTUR SMALL S {"sfrown", 0x02322}, // FROWN {"Sgr", 0x003A3}, // GREEK CAPITAL LETTER SIGMA {"sgr", 0x003C3}, // GREEK SMALL LETTER SIGMA {"sharp", 0x0266F}, // MUSIC SHARP SIGN {"SHCHcy", 0x00429}, // CYRILLIC CAPITAL LETTER SHCHA {"shchcy", 0x00449}, // CYRILLIC SMALL LETTER SHCHA {"SHcy", 0x00428}, // CYRILLIC CAPITAL LETTER SHA {"shcy", 0x00448}, // CYRILLIC SMALL LETTER SHA {"ShortDownArrow", 0x02193}, // DOWNWARDS ARROW {"ShortLeftArrow", 0x02190}, // LEFTWARDS ARROW {"shortmid", 0x02223}, // DIVIDES {"shortparallel", 0x02225}, // PARALLEL TO {"ShortRightArrow", 0x02192}, // RIGHTWARDS ARROW {"ShortUpArrow", 0x02191}, // UPWARDS ARROW {"shy", 0x000AD}, // SOFT HYPHEN {"Sigma", 0x003A3}, // GREEK CAPITAL LETTER SIGMA {"sigma", 0x003C3}, // GREEK SMALL LETTER SIGMA {"sigmaf", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA {"sigmav", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA {"sim", 0x0223C}, // TILDE OPERATOR {"simdot", 0x02A6A}, // TILDE OPERATOR WITH DOT ABOVE {"sime", 0x02243}, // ASYMPTOTICALLY EQUAL TO {"simeq", 0x02243}, // ASYMPTOTICALLY EQUAL TO {"simg", 0x02A9E}, // SIMILAR OR GREATER-THAN {"simgE", 0x02AA0}, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN {"siml", 0x02A9D}, // SIMILAR OR LESS-THAN {"simlE", 0x02A9F}, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN {"simne", 0x02246}, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO {"simplus", 0x02A24}, // PLUS SIGN WITH TILDE ABOVE {"simrarr", 0x02972}, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW {"slarr", 0x02190}, // LEFTWARDS ARROW {"SmallCircle", 0x02218}, // RING OPERATOR {"smallsetminus", 0x02216}, // SET MINUS {"smashp", 0x02A33}, // SMASH PRODUCT {"smeparsl", 0x029E4}, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE {"smid", 0x02223}, // DIVIDES {"smile", 0x02323}, // SMILE {"smt", 0x02AAA}, // SMALLER THAN {"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO // "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL {"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN {"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN {"sol", 0x0002F}, // SOLIDUS {"solb", 0x029C4}, // SQUARED RISING DIAGONAL SLASH {"solbar", 0x0233F}, // APL FUNCTIONAL SYMBOL SLASH BAR {"Sopf", 0x1D54A}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S {"sopf", 0x1D564}, // MATHEMATICAL DOUBLE-STRUCK SMALL S {"spades", 0x02660}, // BLACK SPADE SUIT {"spadesuit", 0x02660}, // BLACK SPADE SUIT {"spar", 0x02225}, // PARALLEL TO {"sqcap", 0x02293}, // SQUARE CAP // "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs {"sqcup", 0x02294}, // SQUARE CUP // "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs {"Sqrt", 0x0221A}, // SQUARE ROOT {"sqsub", 0x0228F}, // SQUARE IMAGE OF {"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO {"sqsubset", 0x0228F}, // SQUARE IMAGE OF {"sqsubseteq", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO {"sqsup", 0x02290}, // SQUARE ORIGINAL OF {"sqsupe", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO {"sqsupset", 0x02290}, // SQUARE ORIGINAL OF {"sqsupseteq", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO {"squ", 0x025A1}, // WHITE SQUARE {"square", 0x025A1}, // WHITE SQUARE {"Square", 0x025A1}, // WHITE SQUARE {"SquareIntersection", 0x02293}, // SQUARE CAP {"SquareSubset", 0x0228F}, // SQUARE IMAGE OF {"SquareSubsetEqual", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO {"SquareSuperset", 0x02290}, // SQUARE ORIGINAL OF {"SquareSupersetEqual", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO {"SquareUnion", 0x02294}, // SQUARE CUP {"squarf", 0x025AA}, // BLACK SMALL SQUARE {"squf", 0x025AA}, // BLACK SMALL SQUARE {"srarr", 0x02192}, // RIGHTWARDS ARROW {"Sscr", 0x1D4AE}, // MATHEMATICAL SCRIPT CAPITAL S {"sscr", 0x1D4C8}, // MATHEMATICAL SCRIPT SMALL S {"ssetmn", 0x02216}, // SET MINUS {"ssmile", 0x02323}, // SMILE {"sstarf", 0x022C6}, // STAR OPERATOR {"Star", 0x022C6}, // STAR OPERATOR {"star", 0x02606}, // WHITE STAR {"starf", 0x02605}, // BLACK STAR {"straightepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL {"straightphi", 0x003D5}, // GREEK PHI SYMBOL {"strns", 0x000AF}, // MACRON {"sub", 0x02282}, // SUBSET OF {"Sub", 0x022D0}, // DOUBLE SUBSET {"subdot", 0x02ABD}, // SUBSET WITH DOT {"sube", 0x02286}, // SUBSET OF OR EQUAL TO {"subE", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN {"subedot", 0x02AC3}, // SUBSET OF OR EQUAL TO WITH DOT ABOVE {"submult", 0x02AC1}, // SUBSET WITH MULTIPLICATION SIGN BELOW {"subne", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO {"subnE", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO {"subplus", 0x02ABF}, // SUBSET WITH PLUS SIGN BELOW {"subrarr", 0x02979}, // SUBSET ABOVE RIGHTWARDS ARROW {"subset", 0x02282}, // SUBSET OF {"Subset", 0x022D0}, // DOUBLE SUBSET {"subseteq", 0x02286}, // SUBSET OF OR EQUAL TO {"subseteqq", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN {"SubsetEqual", 0x02286}, // SUBSET OF OR EQUAL TO {"subsetneq", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO {"subsetneqq", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO {"subsim", 0x02AC7}, // SUBSET OF ABOVE TILDE OPERATOR {"subsub", 0x02AD5}, // SUBSET ABOVE SUBSET {"subsup", 0x02AD3}, // SUBSET ABOVE SUPERSET {"succ", 0x0227B}, // SUCCEEDS {"succapprox", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO {"succcurlyeq", 0x0227D}, // SUCCEEDS OR EQUAL TO {"Succeeds", 0x0227B}, // SUCCEEDS {"SucceedsEqual", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN {"SucceedsSlantEqual", 0x0227D}, // SUCCEEDS OR EQUAL TO {"SucceedsTilde", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO {"succeq", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN {"succnapprox", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO {"succneqq", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO {"succnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO {"succsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO {"SuchThat", 0x0220B}, // CONTAINS AS MEMBER {"sum", 0x02211}, // N-ARY SUMMATION {"Sum", 0x02211}, // N-ARY SUMMATION {"sung", 0x0266A}, // EIGHTH NOTE {"sup", 0x02283}, // SUPERSET OF {"Sup", 0x022D1}, // DOUBLE SUPERSET {"sup1", 0x000B9}, // SUPERSCRIPT ONE {"sup2", 0x000B2}, // SUPERSCRIPT TWO {"sup3", 0x000B3}, // SUPERSCRIPT THREE {"supdot", 0x02ABE}, // SUPERSET WITH DOT {"supdsub", 0x02AD8}, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET {"supe", 0x02287}, // SUPERSET OF OR EQUAL TO {"supE", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN {"supedot", 0x02AC4}, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE {"Superset", 0x02283}, // SUPERSET OF {"SupersetEqual", 0x02287}, // SUPERSET OF OR EQUAL TO {"suphsol", 0x027C9}, // SUPERSET PRECEDING SOLIDUS {"suphsub", 0x02AD7}, // SUPERSET BESIDE SUBSET {"suplarr", 0x0297B}, // SUPERSET ABOVE LEFTWARDS ARROW {"supmult", 0x02AC2}, // SUPERSET WITH MULTIPLICATION SIGN BELOW {"supne", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO {"supnE", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO {"supplus", 0x02AC0}, // SUPERSET WITH PLUS SIGN BELOW {"supset", 0x02283}, // SUPERSET OF {"Supset", 0x022D1}, // DOUBLE SUPERSET {"supseteq", 0x02287}, // SUPERSET OF OR EQUAL TO {"supseteqq", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN {"supsetneq", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO {"supsetneqq", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO {"supsim", 0x02AC8}, // SUPERSET OF ABOVE TILDE OPERATOR {"supsub", 0x02AD4}, // SUPERSET ABOVE SUBSET {"supsup", 0x02AD6}, // SUPERSET ABOVE SUPERSET {"swarhk", 0x02926}, // SOUTH WEST ARROW WITH HOOK {"swarr", 0x02199}, // SOUTH WEST ARROW {"swArr", 0x021D9}, // SOUTH WEST DOUBLE ARROW {"swarrow", 0x02199}, // SOUTH WEST ARROW {"swnwar", 0x0292A}, // SOUTH WEST ARROW AND NORTH WEST ARROW {"szlig", 0x000DF}, // LATIN SMALL LETTER SHARP S ]; immutable NameId[] namesT = [ {"Tab", 0x00009}, // CHARACTER TABULATION {"target", 0x02316}, // POSITION INDICATOR {"Tau", 0x003A4}, // GREEK CAPITAL LETTER TAU {"tau", 0x003C4}, // GREEK SMALL LETTER TAU {"tbrk", 0x023B4}, // TOP SQUARE BRACKET {"Tcaron", 0x00164}, // LATIN CAPITAL LETTER T WITH CARON {"tcaron", 0x00165}, // LATIN SMALL LETTER T WITH CARON {"Tcedil", 0x00162}, // LATIN CAPITAL LETTER T WITH CEDILLA {"tcedil", 0x00163}, // LATIN SMALL LETTER T WITH CEDILLA {"Tcy", 0x00422}, // CYRILLIC CAPITAL LETTER TE {"tcy", 0x00442}, // CYRILLIC SMALL LETTER TE {"tdot", 0x020DB}, // COMBINING THREE DOTS ABOVE {"telrec", 0x02315}, // TELEPHONE RECORDER {"Tfr", 0x1D517}, // MATHEMATICAL FRAKTUR CAPITAL T {"tfr", 0x1D531}, // MATHEMATICAL FRAKTUR SMALL T {"Tgr", 0x003A4}, // GREEK CAPITAL LETTER TAU {"tgr", 0x003C4}, // GREEK SMALL LETTER TAU {"there4", 0x02234}, // THEREFORE {"therefore", 0x02234}, // THEREFORE {"Therefore", 0x02234}, // THEREFORE {"Theta", 0x00398}, // GREEK CAPITAL LETTER THETA {"theta", 0x003B8}, // GREEK SMALL LETTER THETA {"thetasym", 0x003D1}, // GREEK THETA SYMBOL {"thetav", 0x003D1}, // GREEK THETA SYMBOL {"THgr", 0x00398}, // GREEK CAPITAL LETTER THETA {"thgr", 0x003B8}, // GREEK SMALL LETTER THETA {"thickapprox", 0x02248}, // ALMOST EQUAL TO {"thicksim", 0x0223C}, // TILDE OPERATOR // "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em {"thinsp", 0x02009}, // THIN SPACE {"ThinSpace", 0x02009}, // THIN SPACE {"thkap", 0x02248}, // ALMOST EQUAL TO {"thksim", 0x0223C}, // TILDE OPERATOR {"THORN", 0x000DE}, // LATIN CAPITAL LETTER THORN {"thorn", 0x000FE}, // LATIN SMALL LETTER THORN {"tilde", 0x002DC}, // SMALL TILDE {"Tilde", 0x0223C}, // TILDE OPERATOR {"TildeEqual", 0x02243}, // ASYMPTOTICALLY EQUAL TO {"TildeFullEqual", 0x02245}, // APPROXIMATELY EQUAL TO {"TildeTilde", 0x02248}, // ALMOST EQUAL TO {"times", 0x000D7}, // MULTIPLICATION SIGN {"timesb", 0x022A0}, // SQUARED TIMES {"timesbar", 0x02A31}, // MULTIPLICATION SIGN WITH UNDERBAR {"timesd", 0x02A30}, // MULTIPLICATION SIGN WITH DOT ABOVE {"tint", 0x0222D}, // TRIPLE INTEGRAL {"toea", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW {"top", 0x022A4}, // DOWN TACK {"topbot", 0x02336}, // APL FUNCTIONAL SYMBOL I-BEAM {"topcir", 0x02AF1}, // DOWN TACK WITH CIRCLE BELOW {"Topf", 0x1D54B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T {"topf", 0x1D565}, // MATHEMATICAL DOUBLE-STRUCK SMALL T {"topfork", 0x02ADA}, // PITCHFORK WITH TEE TOP {"tosa", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW {"tprime", 0x02034}, // TRIPLE PRIME {"trade", 0x02122}, // TRADE MARK SIGN {"TRADE", 0x02122}, // TRADE MARK SIGN {"triangle", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE {"triangledown", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE {"triangleleft", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE {"trianglelefteq", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO {"triangleq", 0x0225C}, // DELTA EQUAL TO {"triangleright", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE {"trianglerighteq", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO {"tridot", 0x025EC}, // WHITE UP-POINTING TRIANGLE WITH DOT {"trie", 0x0225C}, // DELTA EQUAL TO {"triminus", 0x02A3A}, // MINUS SIGN IN TRIANGLE {"TripleDot", 0x020DB}, // COMBINING THREE DOTS ABOVE {"triplus", 0x02A39}, // PLUS SIGN IN TRIANGLE {"trisb", 0x029CD}, // TRIANGLE WITH SERIFS AT BOTTOM {"tritime", 0x02A3B}, // MULTIPLICATION SIGN IN TRIANGLE {"trpezium", 0x023E2}, // WHITE TRAPEZIUM {"Tscr", 0x1D4AF}, // MATHEMATICAL SCRIPT CAPITAL T {"tscr", 0x1D4C9}, // MATHEMATICAL SCRIPT SMALL T {"TScy", 0x00426}, // CYRILLIC CAPITAL LETTER TSE {"tscy", 0x00446}, // CYRILLIC SMALL LETTER TSE {"TSHcy", 0x0040B}, // CYRILLIC CAPITAL LETTER TSHE {"tshcy", 0x0045B}, // CYRILLIC SMALL LETTER TSHE {"Tstrok", 0x00166}, // LATIN CAPITAL LETTER T WITH STROKE {"tstrok", 0x00167}, // LATIN SMALL LETTER T WITH STROKE {"twixt", 0x0226C}, // BETWEEN {"twoheadleftarrow", 0x0219E}, // LEFTWARDS TWO HEADED ARROW {"twoheadrightarrow", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW ]; immutable NameId[] namesU = [ {"Uacgr", 0x0038E}, // GREEK CAPITAL LETTER UPSILON WITH TONOS {"uacgr", 0x003CD}, // GREEK SMALL LETTER UPSILON WITH TONOS {"Uacute", 0x000DA}, // LATIN CAPITAL LETTER U WITH ACUTE {"uacute", 0x000FA}, // LATIN SMALL LETTER U WITH ACUTE {"uarr", 0x02191}, // UPWARDS ARROW {"Uarr", 0x0219F}, // UPWARDS TWO HEADED ARROW {"uArr", 0x021D1}, // UPWARDS DOUBLE ARROW {"Uarrocir", 0x02949}, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE {"Ubrcy", 0x0040E}, // CYRILLIC CAPITAL LETTER SHORT U {"ubrcy", 0x0045E}, // CYRILLIC SMALL LETTER SHORT U {"Ubreve", 0x0016C}, // LATIN CAPITAL LETTER U WITH BREVE {"ubreve", 0x0016D}, // LATIN SMALL LETTER U WITH BREVE {"Ucirc", 0x000DB}, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX {"ucirc", 0x000FB}, // LATIN SMALL LETTER U WITH CIRCUMFLEX {"Ucy", 0x00423}, // CYRILLIC CAPITAL LETTER U {"ucy", 0x00443}, // CYRILLIC SMALL LETTER U {"udarr", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW {"Udblac", 0x00170}, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE {"udblac", 0x00171}, // LATIN SMALL LETTER U WITH DOUBLE ACUTE {"udhar", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT {"udiagr", 0x003B0}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS {"Udigr", 0x003AB}, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA {"udigr", 0x003CB}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA {"ufisht", 0x0297E}, // UP FISH TAIL {"Ufr", 0x1D518}, // MATHEMATICAL FRAKTUR CAPITAL U {"ufr", 0x1D532}, // MATHEMATICAL FRAKTUR SMALL U {"Ugr", 0x003A5}, // GREEK CAPITAL LETTER UPSILON {"ugr", 0x003C5}, // GREEK SMALL LETTER UPSILON {"Ugrave", 0x000D9}, // LATIN CAPITAL LETTER U WITH GRAVE {"ugrave", 0x000F9}, // LATIN SMALL LETTER U WITH GRAVE {"uHar", 0x02963}, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT {"uharl", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS {"uharr", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS {"uhblk", 0x02580}, // UPPER HALF BLOCK {"ulcorn", 0x0231C}, // TOP LEFT CORNER {"ulcorner", 0x0231C}, // TOP LEFT CORNER {"ulcrop", 0x0230F}, // TOP LEFT CROP {"ultri", 0x025F8}, // UPPER LEFT TRIANGLE {"Umacr", 0x0016A}, // LATIN CAPITAL LETTER U WITH MACRON {"umacr", 0x0016B}, // LATIN SMALL LETTER U WITH MACRON {"uml", 0x000A8}, // DIAERESIS {"UnderBar", 0x0005F}, // LOW LINE {"UnderBrace", 0x023DF}, // BOTTOM CURLY BRACKET {"UnderBracket", 0x023B5}, // BOTTOM SQUARE BRACKET {"UnderParenthesis", 0x023DD}, // BOTTOM PARENTHESIS {"Union", 0x022C3}, // N-ARY UNION {"UnionPlus", 0x0228E}, // MULTISET UNION {"Uogon", 0x00172}, // LATIN CAPITAL LETTER U WITH OGONEK {"uogon", 0x00173}, // LATIN SMALL LETTER U WITH OGONEK {"Uopf", 0x1D54C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U {"uopf", 0x1D566}, // MATHEMATICAL DOUBLE-STRUCK SMALL U {"uparrow", 0x02191}, // UPWARDS ARROW {"UpArrow", 0x02191}, // UPWARDS ARROW {"Uparrow", 0x021D1}, // UPWARDS DOUBLE ARROW {"UpArrowBar", 0x02912}, // UPWARDS ARROW TO BAR {"UpArrowDownArrow", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW {"updownarrow", 0x02195}, // UP DOWN ARROW {"UpDownArrow", 0x02195}, // UP DOWN ARROW {"Updownarrow", 0x021D5}, // UP DOWN DOUBLE ARROW {"UpEquilibrium", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT {"upharpoonleft", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS {"upharpoonright", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS {"uplus", 0x0228E}, // MULTISET UNION {"UpperLeftArrow", 0x02196}, // NORTH WEST ARROW {"UpperRightArrow", 0x02197}, // NORTH EAST ARROW {"upsi", 0x003C5}, // GREEK SMALL LETTER UPSILON {"Upsi", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL {"upsih", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL {"Upsilon", 0x003A5}, // GREEK CAPITAL LETTER UPSILON {"upsilon", 0x003C5}, // GREEK SMALL LETTER UPSILON {"UpTee", 0x022A5}, // UP TACK {"UpTeeArrow", 0x021A5}, // UPWARDS ARROW FROM BAR {"upuparrows", 0x021C8}, // UPWARDS PAIRED ARROWS {"urcorn", 0x0231D}, // TOP RIGHT CORNER {"urcorner", 0x0231D}, // TOP RIGHT CORNER {"urcrop", 0x0230E}, // TOP RIGHT CROP {"Uring", 0x0016E}, // LATIN CAPITAL LETTER U WITH RING ABOVE {"uring", 0x0016F}, // LATIN SMALL LETTER U WITH RING ABOVE {"urtri", 0x025F9}, // UPPER RIGHT TRIANGLE {"Uscr", 0x1D4B0}, // MATHEMATICAL SCRIPT CAPITAL U {"uscr", 0x1D4CA}, // MATHEMATICAL SCRIPT SMALL U {"utdot", 0x022F0}, // UP RIGHT DIAGONAL ELLIPSIS {"Utilde", 0x00168}, // LATIN CAPITAL LETTER U WITH TILDE {"utilde", 0x00169}, // LATIN SMALL LETTER U WITH TILDE {"utri", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE {"utrif", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE {"uuarr", 0x021C8}, // UPWARDS PAIRED ARROWS {"Uuml", 0x000DC}, // LATIN CAPITAL LETTER U WITH DIAERESIS {"uuml", 0x000FC}, // LATIN SMALL LETTER U WITH DIAERESIS {"uwangle", 0x029A7}, // OBLIQUE ANGLE OPENING DOWN ]; immutable NameId[] namesV = [ {"vangrt", 0x0299C}, // RIGHT ANGLE VARIANT WITH SQUARE {"varepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL {"varkappa", 0x003F0}, // GREEK KAPPA SYMBOL {"varnothing", 0x02205}, // EMPTY SET {"varphi", 0x003D5}, // GREEK PHI SYMBOL {"varpi", 0x003D6}, // GREEK PI SYMBOL {"varpropto", 0x0221D}, // PROPORTIONAL TO {"varr", 0x02195}, // UP DOWN ARROW {"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW {"varrho", 0x003F1}, // GREEK RHO SYMBOL {"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA // "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members // "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members // "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members // "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members {"vartheta", 0x003D1}, // GREEK THETA SYMBOL {"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF {"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP {"vBar", 0x02AE8}, // SHORT UP TACK WITH UNDERBAR {"Vbar", 0x02AEB}, // DOUBLE UP TACK {"vBarv", 0x02AE9}, // SHORT UP TACK ABOVE SHORT DOWN TACK {"Vcy", 0x00412}, // CYRILLIC CAPITAL LETTER VE {"vcy", 0x00432}, // CYRILLIC SMALL LETTER VE {"vdash", 0x022A2}, // RIGHT TACK {"vDash", 0x022A8}, // TRUE {"Vdash", 0x022A9}, // FORCES {"VDash", 0x022AB}, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE {"Vdashl", 0x02AE6}, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL {"vee", 0x02228}, // LOGICAL OR {"Vee", 0x022C1}, // N-ARY LOGICAL OR {"veebar", 0x022BB}, // XOR {"veeeq", 0x0225A}, // EQUIANGULAR TO {"vellip", 0x022EE}, // VERTICAL ELLIPSIS {"verbar", 0x0007C}, // VERTICAL LINE {"Verbar", 0x02017}, // DOUBLE VERTICAL LINE {"vert", 0x0007C}, // VERTICAL LINE {"Vert", 0x02017}, // DOUBLE VERTICAL LINE {"VerticalBar", 0x02223}, // DIVIDES {"VerticalLine", 0x0007C}, // VERTICAL LINE {"VerticalSeparator", 0x02758}, // LIGHT VERTICAL BAR {"VerticalTilde", 0x02240}, // WREATH PRODUCT {"VeryThinSpace", 0x0200A}, // HAIR SPACE {"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V {"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V {"vltri", 0x022B2}, // NORMAL SUBGROUP OF // "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line // "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line {"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V {"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V {"vprop", 0x0221D}, // PROPORTIONAL TO {"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP {"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V {"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V // "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members // "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members // "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members // "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members {"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE {"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE ]; immutable NameId[] namesW = [ {"Wcirc", 0x00174}, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX {"wcirc", 0x00175}, // LATIN SMALL LETTER W WITH CIRCUMFLEX {"wedbar", 0x02A5F}, // LOGICAL AND WITH UNDERBAR {"wedge", 0x02227}, // LOGICAL AND {"Wedge", 0x022C0}, // N-ARY LOGICAL AND {"wedgeq", 0x02259}, // ESTIMATES {"weierp", 0x02118}, // SCRIPT CAPITAL P {"Wfr", 0x1D51A}, // MATHEMATICAL FRAKTUR CAPITAL W {"wfr", 0x1D534}, // MATHEMATICAL FRAKTUR SMALL W {"Wopf", 0x1D54E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W {"wopf", 0x1D568}, // MATHEMATICAL DOUBLE-STRUCK SMALL W {"wp", 0x02118}, // SCRIPT CAPITAL P {"wr", 0x02240}, // WREATH PRODUCT {"wreath", 0x02240}, // WREATH PRODUCT {"Wscr", 0x1D4B2}, // MATHEMATICAL SCRIPT CAPITAL W {"wscr", 0x1D4CC}, // MATHEMATICAL SCRIPT SMALL W ]; immutable NameId[] namesX = [ {"xcap", 0x022C2}, // N-ARY INTERSECTION {"xcirc", 0x025EF}, // LARGE CIRCLE {"xcup", 0x022C3}, // N-ARY UNION {"xdtri", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE {"Xfr", 0x1D51B}, // MATHEMATICAL FRAKTUR CAPITAL X {"xfr", 0x1D535}, // MATHEMATICAL FRAKTUR SMALL X {"Xgr", 0x0039E}, // GREEK CAPITAL LETTER XI {"xgr", 0x003BE}, // GREEK SMALL LETTER XI {"xharr", 0x027F7}, // LONG LEFT RIGHT ARROW {"xhArr", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW {"Xi", 0x0039E}, // GREEK CAPITAL LETTER XI {"xi", 0x003BE}, // GREEK SMALL LETTER XI {"xlarr", 0x027F5}, // LONG LEFTWARDS ARROW {"xlArr", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW {"xmap", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR {"xnis", 0x022FB}, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE {"xodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR {"Xopf", 0x1D54F}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X {"xopf", 0x1D569}, // MATHEMATICAL DOUBLE-STRUCK SMALL X {"xoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR {"xotime", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR {"xrarr", 0x027F6}, // LONG RIGHTWARDS ARROW {"xrArr", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW {"Xscr", 0x1D4B3}, // MATHEMATICAL SCRIPT CAPITAL X {"xscr", 0x1D4CD}, // MATHEMATICAL SCRIPT SMALL X {"xsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR {"xuplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS {"xutri", 0x025B3}, // WHITE UP-POINTING TRIANGLE {"xvee", 0x022C1}, // N-ARY LOGICAL OR {"xwedge", 0x022C0}, // N-ARY LOGICAL AND ]; immutable NameId[] namesY = [ {"Yacute", 0x000DD}, // LATIN CAPITAL LETTER Y WITH ACUTE {"yacute", 0x000FD}, // LATIN SMALL LETTER Y WITH ACUTE {"YAcy", 0x0042F}, // CYRILLIC CAPITAL LETTER YA {"yacy", 0x0044F}, // CYRILLIC SMALL LETTER YA {"Ycirc", 0x00176}, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX {"ycirc", 0x00177}, // LATIN SMALL LETTER Y WITH CIRCUMFLEX {"Ycy", 0x0042B}, // CYRILLIC CAPITAL LETTER YERU {"ycy", 0x0044B}, // CYRILLIC SMALL LETTER YERU {"yen", 0x000A5}, // YEN SIGN {"Yfr", 0x1D51C}, // MATHEMATICAL FRAKTUR CAPITAL Y {"yfr", 0x1D536}, // MATHEMATICAL FRAKTUR SMALL Y {"YIcy", 0x00407}, // CYRILLIC CAPITAL LETTER YI {"yicy", 0x00457}, // CYRILLIC SMALL LETTER YI {"Yopf", 0x1D550}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y {"yopf", 0x1D56A}, // MATHEMATICAL DOUBLE-STRUCK SMALL Y {"Yscr", 0x1D4B4}, // MATHEMATICAL SCRIPT CAPITAL Y {"yscr", 0x1D4CE}, // MATHEMATICAL SCRIPT SMALL Y {"YUcy", 0x0042E}, // CYRILLIC CAPITAL LETTER YU {"yucy", 0x0044E}, // CYRILLIC SMALL LETTER YU {"yuml", 0x000FF}, // LATIN SMALL LETTER Y WITH DIAERESIS {"Yuml", 0x00178}, // LATIN CAPITAL LETTER Y WITH DIAERESIS ]; immutable NameId[] namesZ = [ {"Zacute", 0x00179}, // LATIN CAPITAL LETTER Z WITH ACUTE {"zacute", 0x0017A}, // LATIN SMALL LETTER Z WITH ACUTE {"Zcaron", 0x0017D}, // LATIN CAPITAL LETTER Z WITH CARON {"zcaron", 0x0017E}, // LATIN SMALL LETTER Z WITH CARON {"Zcy", 0x00417}, // CYRILLIC CAPITAL LETTER ZE {"zcy", 0x00437}, // CYRILLIC SMALL LETTER ZE {"Zdot", 0x0017B}, // LATIN CAPITAL LETTER Z WITH DOT ABOVE {"zdot", 0x0017C}, // LATIN SMALL LETTER Z WITH DOT ABOVE {"zeetrf", 0x02128}, // BLACK-LETTER CAPITAL Z {"ZeroWidthSpace", 0x0200B}, // ZERO WIDTH SPACE {"Zeta", 0x00396}, // GREEK CAPITAL LETTER ZETA {"zeta", 0x003B6}, // GREEK SMALL LETTER ZETA {"Zfr", 0x02128}, // BLACK-LETTER CAPITAL Z {"zfr", 0x1D537}, // MATHEMATICAL FRAKTUR SMALL Z {"Zgr", 0x00396}, // GREEK CAPITAL LETTER ZETA {"zgr", 0x003B6}, // GREEK SMALL LETTER ZETA {"ZHcy", 0x00416}, // CYRILLIC CAPITAL LETTER ZHE {"zhcy", 0x00436}, // CYRILLIC SMALL LETTER ZHE {"zigrarr", 0x021DD}, // RIGHTWARDS SQUIGGLE ARROW {"Zopf", 0x02124}, // DOUBLE-STRUCK CAPITAL Z {"zopf", 0x1D56B}, // MATHEMATICAL DOUBLE-STRUCK SMALL Z {"Zscr", 0x1D4B5}, // MATHEMATICAL SCRIPT CAPITAL Z {"zscr", 0x1D4CF}, // MATHEMATICAL SCRIPT SMALL Z {"zwj", 0x0200D}, // ZERO WIDTH JOINER {"zwnj", 0x0200C}, // ZERO WIDTH NON-JOINER ]; // @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 ]; public int HtmlNamedEntity(const(char)* p, size_t length) { int tableIndex = tolower(*p) - 'a'; if (tableIndex >= 0 && tableIndex < 26) { foreach (entity; namesTable[tableIndex]) { if (entity.name == p[0 .. length]) return entity.value; } } return -1; } ================================================ FILE: gcc/d/dmd/enum.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/enum.h */ #pragma once #include "dsymbol.h" #include "declaration.h" class Identifier; class Type; class Expression; class EnumDeclaration : public ScopeDsymbol { public: /* The separate, and distinct, cases are: * 1. enum { ... } * 2. enum : memtype { ... } * 3. enum id { ... } * 4. enum id : memtype { ... } * 5. enum id : memtype; * 6. enum id; */ Type *type; // the TypeEnum Type *memtype; // type of the members Prot protection; Expression *maxval; Expression *minval; Expression *defaultval; // default initializer bool isdeprecated; bool added; int inuse; Dsymbol *syntaxCopy(Dsymbol *s); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); bool oneMember(Dsymbol **ps, Identifier *ident); Type *getType(); const char *kind() const; Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); bool isDeprecated(); // is Dsymbol deprecated? Prot prot(); Expression *getMaxMinValue(const Loc &loc, Identifier *id); bool isSpecial() const; Expression *getDefaultValue(const Loc &loc); Type *getMemtype(const Loc &loc); EnumDeclaration *isEnumDeclaration() { return this; } Symbol *sinit; void accept(Visitor *v) { v->visit(this); } }; class EnumMember : public VarDeclaration { public: /* Can take the following forms: * 1. id * 2. id = value * 3. type id = value */ Expression *&value(); // A cast() is injected to 'value' after semantic(), // but 'origValue' will preserve the original value, // or previous value + 1 if none was specified. Expression *origValue; Type *origType; EnumDeclaration *ed; Dsymbol *syntaxCopy(Dsymbol *s); const char *kind() const; Expression *getVarExp(const Loc &loc, Scope *sc); EnumMember *isEnumMember() { return this; } void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/errors.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/errors.d, _errors.d) * Documentation: https://dlang.org/phobos/dmd_errors.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d */ module dmd.errors; import core.stdc.stdarg; import dmd.globals; /** * Print an error message, increasing the global error count. * Params: * loc = location of error * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void error(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); verror(loc, format, ap); va_end(ap); } /** * Same as above, but allows Loc() literals to be passed. * Params: * loc = location of error * format = printf-style format specification * ... = printf-style variadic arguments */ extern (D) void error(Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); verror(loc, format, ap); va_end(ap); } /** * Same as above, but takes a filename and line information arguments as separate parameters. * Params: * filename = source file of error * linnum = line in the source file * charnum = column number on the line * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) { const loc = Loc(filename, linnum, charnum); va_list ap; va_start(ap, format); verror(loc, format, ap); va_end(ap); } /** * Print additional details about an error message. * Doesn't increase the error count or print an additional error prefix. * Params: * loc = location of error * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); verrorSupplemental(loc, format, ap); va_end(ap); } /** * Print a warning message, increasing the global warning count. * Params: * loc = location of warning * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void warning(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); vwarning(loc, format, ap); va_end(ap); } /** * Print additional details about a warning message. * Doesn't increase the warning count or print an additional warning prefix. * Params: * loc = location of warning * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); vwarningSupplemental(loc, format, ap); va_end(ap); } /** * Print a deprecation message, may increase the global warning or error count * depending on whether deprecations are ignored. * Params: * loc = location of deprecation * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); vdeprecation(loc, format, ap); va_end(ap); } /** * Print additional details about a deprecation message. * Doesn't increase the error count, or print an additional deprecation prefix. * Params: * loc = location of deprecation * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); vdeprecationSupplemental(loc, format, ap); va_end(ap); } /** * Print a verbose message. * Doesn't prefix or highlight messages. * Params: * loc = location of message * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void message(const ref Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); vmessage(loc, format, ap); va_end(ap); } /** * Same as above, but doesn't take a location argument. * Params: * format = printf-style format specification * ... = printf-style variadic arguments */ extern (C++) void message(const(char)* format, ...) { va_list ap; va_start(ap, format); vmessage(Loc.initial, format, ap); va_end(ap); } /** * Same as $(D error), but takes a va_list parameter, and optionally additional message prefixes. * Params: * loc = location of error * format = printf-style format specification * ap = printf-style variadic arguments * p1 = additional message prefix * p2 = additional message prefix * header = title of error message */ extern (C++) void verror(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: "); /** * Same as $(D errorSupplemental), but takes a va_list parameter. * Params: * loc = location of error * format = printf-style format specification * ap = printf-style variadic arguments */ extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap); /** * Same as $(D warning), but takes a va_list parameter. * Params: * loc = location of warning * format = printf-style format specification * ap = printf-style variadic arguments */ extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap); /** * Same as $(D warningSupplemental), but takes a va_list parameter. * Params: * loc = location of warning * format = printf-style format specification * ap = printf-style variadic arguments */ extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap); /** * Same as $(D deprecation), but takes a va_list parameter, and optionally additional message prefixes. * Params: * loc = location of deprecation * format = printf-style format specification * ap = printf-style variadic arguments * p1 = additional message prefix * p2 = additional message prefix */ extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null); /** * Same as $(D message), but takes a va_list parameter. * Params: * loc = location of message * format = printf-style format specification * ap = printf-style variadic arguments */ extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap); /** * Same as $(D deprecationSupplemental), but takes a va_list parameter. * Params: * loc = location of deprecation * format = printf-style format specification * ap = printf-style variadic arguments */ extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap); /** * Call this after printing out fatal error messages to clean up and exit * the compiler. */ extern (C++) void fatal(); /** * Try to stop forgetting to remove the breakpoints from * release builds. */ extern (C++) void halt(); ================================================ FILE: gcc/d/dmd/errors.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/errors.h */ #pragma once #include #include struct Loc; bool isConsoleColorSupported(); #if defined(__GNUC__) #define D_ATTRIBUTE_FORMAT(m, n) __attribute__((format(printf, m, n))) __attribute__((nonnull (m))) #else #define D_ATTRIBUTE_FORMAT(m, n) #endif // Print a warning, deprecation, or error, accepts printf-like format specifiers. D_ATTRIBUTE_FORMAT(2, 3) void warning(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void deprecation(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void error(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(4, 5) void error(const char *filename, unsigned linnum, unsigned charnum, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 0) void verror(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: "); D_ATTRIBUTE_FORMAT(2, 0) void verrorSupplemental(const Loc& loc, const char *format, va_list ap); D_ATTRIBUTE_FORMAT(2, 0) void vwarning(const Loc& loc, const char *format, va_list); D_ATTRIBUTE_FORMAT(2, 0) void vwarningSupplemental(const Loc& loc, const char *format, va_list ap); D_ATTRIBUTE_FORMAT(2, 0) void vdeprecation(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); D_ATTRIBUTE_FORMAT(2, 0) void vdeprecationSupplemental(const Loc& loc, const char *format, va_list ap); D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...); D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...); D_ATTRIBUTE_FORMAT(2, 0) void vmessage(const Loc& loc, const char *format, va_list); #if defined(__GNUC__) || defined(__clang__) #define D_ATTRIBUTE_NORETURN __attribute__((noreturn)) #elif _MSC_VER #define D_ATTRIBUTE_NORETURN __declspec(noreturn) #else #define D_ATTRIBUTE_NORETURN #endif // Called after printing out fatal error messages. D_ATTRIBUTE_NORETURN void fatal(); D_ATTRIBUTE_NORETURN void halt(); ================================================ FILE: gcc/d/dmd/escape.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/escape.d, _escape.d) * Documentation: https://dlang.org/phobos/dmd_escape.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/escape.d */ module dmd.escape; import core.stdc.stdio : printf; import dmd.aggregate; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.root.rootobject; import dmd.tokens; import dmd.visitor; import dmd.arraytypes; /****************************************** * Array literal is going to be allocated on the GC heap. * Check its elements to see if any would escape by going on the heap. * Params: * sc = used to determine current function and module * ae = array literal expression * gag = do not print error messages * Returns: * true if any elements escaped */ bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag) { bool errors; if (ae.basis) errors = checkNewEscape(sc, ae.basis, gag); foreach (ex; *ae.elements) { if (ex) errors |= checkNewEscape(sc, ex, gag); } return errors; } /****************************************** * Associative array literal is going to be allocated on the GC heap. * Check its elements to see if any would escape by going on the heap. * Params: * sc = used to determine current function and module * ae = associative array literal expression * gag = do not print error messages * Returns: * true if any elements escaped */ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) { bool errors; foreach (ex; *ae.keys) { if (ex) errors |= checkNewEscape(sc, ex, gag); } foreach (ex; *ae.values) { if (ex) errors |= checkNewEscape(sc, ex, gag); } return errors; } /**************************************** * Function parameter par is being initialized to arg, * and par may escape. * Detect if scoped values can escape this way. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * fdc = function being called, `null` if called indirectly * par = identifier of function parameter * arg = initializer for param * gag = do not print error messages * Returns: * true if pointers to the stack can escape via assignment */ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier par, Expression arg, bool gag) { enum log = false; if (log) printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg ? arg.toChars() : "null", par ? par.toChars() : "null"); //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers()); if (!arg.type.hasPointers()) return false; EscapeByResults er; escapeByValue(arg, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim) return false; bool result = false; /* 'v' is assigned unsafely to 'par' */ void unsafeAssign(VarDeclaration v, const char* desc) { if (global.params.vsafe && sc.func.setUnsafe()) { if (!gag) error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", desc, v.toChars(), par ? par.toChars() : "unnamed", fdc ? fdc.toPrettyChars() : "indirectly"); result = true; } } foreach (VarDeclaration v; er.byvalue) { if (log) printf("byvalue %s\n", v.toChars()); if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); notMaybeScope(v); if (v.isScope()) { unsafeAssign(v, "scope variable"); } else if (v.storage_class & STC.variadic && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { unsafeAssign(v, "variadic variable"); } } else { /* v is not 'scope', and is assigned to a parameter that may escape. * Therefore, v can never be 'scope'. */ if (log) printf("no infer for %s in %s loc %s, fdc %s, %d\n", v.toChars(), sc.func.ident.toChars(), sc.func.loc.toChars(), fdc.ident.toChars(), __LINE__); v.doNotInferScope = true; } } foreach (VarDeclaration v; er.byref) { if (log) printf("byref %s\n", v.toChars()); if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); notMaybeScope(v); if ((v.storage_class & (STC.ref_ | STC.out_)) == 0 && p == sc.func) { unsafeAssign(v, "reference to local variable"); continue; } } foreach (FuncDeclaration fd; er.byfunc) { //printf("fd = %s, %d\n", fd.toChars(), fd.tookAddressOf); VarDeclarations vars; findAllOuterAccessedVariables(fd, &vars); foreach (v; vars) { //printf("v = %s\n", v.toChars()); assert(!v.isDataseg()); // these are not put in the closureVars[] Dsymbol p = v.toParent2(); notMaybeScope(v); if ((v.storage_class & (STC.ref_ | STC.out_ | STC.scope_)) && p == sc.func) { unsafeAssign(v, "reference to local"); continue; } } } foreach (Expression ee; er.byexp) { if (sc.func.setUnsafe()) { if (!gag) error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`", ee.toChars(), par ? par.toChars() : "unnamed"); result = true; } } return result; } /**************************************** * Given an AssignExp, determine if the lvalue will cause * the contents of the rvalue to escape. * Print error messages when these are detected. * Infer 'scope' for the lvalue where possible, in order * to eliminate the error. * Params: * sc = used to determine current function and module * e = AssignExp or CatAssignExp to check for any pointers to the stack * gag = do not print error messages * Returns: * true if pointers to the stack can escape via assignment */ bool checkAssignEscape(Scope* sc, Expression e, bool gag) { enum log = false; if (log) printf("checkAssignEscape(e: %s)\n", e.toChars()); if (e.op != TOK.assign && e.op != TOK.blit && e.op != TOK.construct && e.op != TOK.concatenateAssign && e.op != TOK.concatenateElemAssign && e.op != TOK.concatenateDcharAssign) return false; auto ae = cast(BinExp)e; Expression e1 = ae.e1; Expression e2 = ae.e2; //printf("type = %s, %d\n", e1.type.toChars(), e1.type.hasPointers()); if (!e1.type.hasPointers()) return false; if (e1.op == TOK.slice) return false; EscapeByResults er; escapeByValue(e2, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim) return false; VarDeclaration va = expToVariable(e1); if (va && e.op == TOK.concatenateElemAssign) { /* https://issues.dlang.org/show_bug.cgi?id=17842 * Draw an equivalence between: * *q = p; * and: * va ~= e; * since we are not assigning to va, but are assigning indirectly through va. */ va = null; } if (va && e1.op == TOK.dotVariable && va.type.toBasetype().ty == Tclass) { /* https://issues.dlang.org/show_bug.cgi?id=17949 * Draw an equivalence between: * *q = p; * and: * va.field = e2; * since we are not assigning to va, but are assigning indirectly through class reference va. */ va = null; } if (log && va) printf("va: %s\n", va.toChars()); // Try to infer 'scope' for va if in a function not marked @system bool inferScope = false; if (va && sc.func && sc.func.type && sc.func.type.ty == Tfunction) inferScope = (cast(TypeFunction)sc.func.type).trust != TRUST.system; //printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0); // Determine if va is a parameter that is an indirect reference const bool vaIsRef = va && va.storage_class & STC.parameter && (va.storage_class & (STC.ref_ | STC.out_) || va.type.toBasetype().ty == Tclass); bool result = false; foreach (VarDeclaration v; er.byvalue) { if (log) printf("byvalue: %s\n", v.toChars()); if (v.isDataseg()) continue; if (v == va) continue; Dsymbol p = v.toParent2(); if (va && !vaIsRef && !va.isScope() && !v.isScope() && (va.storage_class & v.storage_class & (STC.maybescope | STC.variadic)) == STC.maybescope && p == sc.func) { /* Add v to va's list of dependencies */ va.addMaybe(v); continue; } if (!(va && va.isScope()) || vaIsRef) notMaybeScope(v); if (v.isScope()) { if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_) && sc.func.setUnsafe()) { if (!gag) error(ae.loc, "scope variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); result = true; continue; } // If va's lifetime encloses v's, then error if (va && (va.enclosesLifetimeOf(v) && !(v.storage_class & (STC.parameter | STC.temp)) || // va is class reference ae.e1.op == TOK.dotVariable && va.type.toBasetype().ty == Tclass && (va.enclosesLifetimeOf(v) || !va.isScope()) || vaIsRef || va.storage_class & (STC.ref_ | STC.out_) && !(v.storage_class & STC.temp)) && sc.func.setUnsafe()) { if (!gag) error(ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars()); result = true; continue; } if (va && !va.isDataseg() && !va.doNotInferScope) { if (!va.isScope() && inferScope) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; va.storage_class |= v.storage_class & STC.return_; } continue; } if (sc.func.setUnsafe()) { if (!gag) error(ae.loc, "scope variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); result = true; } } else if (v.storage_class & STC.variadic && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (va && !va.isDataseg() && !va.doNotInferScope) { if (!va.isScope() && inferScope) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } continue; } if (sc.func.setUnsafe()) { if (!gag) error(ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); result = true; } } } else { /* v is not 'scope', and we didn't check the scope of where we assigned it to. * It may escape via that assignment, therefore, v can never be 'scope'. */ //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); v.doNotInferScope = true; } } ByRef: foreach (VarDeclaration v; er.byref) { if (log) printf("byref: %s\n", v.toChars()); if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); // If va's lifetime encloses v's, then error if (va && (va.enclosesLifetimeOf(v) && !(v.storage_class & STC.parameter) || va.storage_class & STC.ref_ || va.isDataseg()) && sc.func.setUnsafe()) { if (!gag) error(ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars()); result = true; continue; } if (va && v.storage_class & (STC.ref_ | STC.out_)) { Dsymbol pva = va.toParent2(); for (Dsymbol pv = p; pv; ) { pv = pv.toParent2(); if (pva == pv) // if v is nested inside pva { if (sc.func.setUnsafe()) { if (!gag) error(ae.loc, "reference `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars()); result = true; continue ByRef; } break; } } } if (!(va && va.isScope())) notMaybeScope(v); if ((v.storage_class & (STC.ref_ | STC.out_)) == 0 && p == sc.func) { if (va && !va.isDataseg() && !va.doNotInferScope) { if (!va.isScope() && inferScope) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } continue; } if (sc.func.setUnsafe()) { if (!gag) error(ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); result = true; } continue; } } foreach (FuncDeclaration fd; er.byfunc) { if (log) printf("byfunc: %s, %d\n", fd.toChars(), fd.tookAddressOf); VarDeclarations vars; findAllOuterAccessedVariables(fd, &vars); /* https://issues.dlang.org/show_bug.cgi?id=16037 * If assigning the address of a delegate to a scope variable, * then uncount that address of. This is so it won't cause a * closure to be allocated. */ if (va && va.isScope() && fd.tookAddressOf && global.params.vsafe) --fd.tookAddressOf; foreach (v; vars) { //printf("v = %s\n", v.toChars()); assert(!v.isDataseg()); // these are not put in the closureVars[] Dsymbol p = v.toParent2(); if (!(va && va.isScope())) notMaybeScope(v); if ((v.storage_class & (STC.ref_ | STC.out_ | STC.scope_)) && p == sc.func) { if (va && !va.isDataseg() && !va.doNotInferScope) { /* Don't infer STC.scope_ for va, because then a closure * won't be generated for sc.func. */ //if (!va.isScope() && inferScope) //va.storage_class |= STC.scope_ | STC.scopeinferred; continue; } if (sc.func.setUnsafe()) { if (!gag) error(ae.loc, "reference to local `%s` assigned to non-scope `%s` in @safe code", v.toChars(), e1.toChars()); result = true; } continue; } } } foreach (Expression ee; er.byexp) { if (log) printf("byexp: %s\n", ee.toChars()); /* Do not allow slicing of a static array returned by a function */ if (va && ee.op == TOK.call && ee.type.toBasetype().ty == Tsarray && va.type.toBasetype().ty == Tarray && !(va.storage_class & STC.temp)) { if (!gag) deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`", ee.toChars(), va.toChars()); //result = true; continue; } if (va && !va.isDataseg() && !va.doNotInferScope) { if (!va.isScope() && inferScope) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } continue; } if (sc.func.setUnsafe()) { if (!gag) error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee.toChars(), e1.toChars()); result = true; } } return result; } /************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame when throwing `e`. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * e = expression to check for any pointers to the stack * gag = do not print error messages * Returns: * true if pointers to the stack can escape */ bool checkThrowEscape(Scope* sc, Expression e, bool gag) { //printf("[%s] checkThrowEscape, e = %s\n", e.loc.toChars(), e.toChars()); EscapeByResults er; escapeByValue(e, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim) return false; bool result = false; foreach (VarDeclaration v; er.byvalue) { //printf("byvalue %s\n", v.toChars()); if (v.isDataseg()) continue; if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown // despite being `scope` { if (sc._module && sc._module.isRoot()) { // Only look for errors if in module listed on command line if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029 { if (!gag) error(e.loc, "scope variable `%s` may not be thrown", v.toChars()); result = true; } continue; } } else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); v.doNotInferScope = true; } } return result; } /************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame by being placed into a GC allocated object. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * e = expression to check for any pointers to the stack * gag = do not print error messages * Returns: * true if pointers to the stack can escape */ bool checkNewEscape(Scope* sc, Expression e, bool gag) { //printf("[%s] checkNewEscape, e = %s\n", e.loc.toChars(), e.toChars()); enum log = false; if (log) printf("[%s] checkNewEscape, e: `%s`\n", e.loc.toChars(), e.toChars()); EscapeByResults er; escapeByValue(e, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim) return false; bool result = false; foreach (VarDeclaration v; er.byvalue) { if (log) printf("byvalue `%s`\n", v.toChars()); if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); if (v.isScope()) { if (sc._module && sc._module.isRoot() && /* This case comes up when the ReturnStatement of a __foreachbody is * checked for escapes by the caller of __foreachbody. Skip it. * * struct S { static int opApply(int delegate(S*) dg); } * S* foo() { * foreach (S* s; S) // create __foreachbody for body of foreach * return s; // s is inferred as 'scope' but incorrectly tested in foo() * return null; } */ !(p.parent == sc.func)) { // Only look for errors if in module listed on command line if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029 { if (!gag) error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); result = true; } continue; } } else if (v.storage_class & STC.variadic && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!gag) error(e.loc, "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); result = false; } } else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); v.doNotInferScope = true; } } foreach (VarDeclaration v; er.byref) { if (log) printf("byref `%s`\n", v.toChars()); void escapingRef(VarDeclaration v) { if (!gag) { const(char)* kind = (v.storage_class & STC.parameter) ? "parameter" : "local"; error(e.loc, "copying `%s` into allocated memory escapes a reference to %s variable `%s`", e.toChars(), kind, v.toChars()); } result = true; } if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); if ((v.storage_class & (STC.ref_ | STC.out_)) == 0) { if (p == sc.func) { escapingRef(v); continue; } } /* Check for returning a ref variable by 'ref', but should be 'return ref' * Infer the addition of 'return', or set result to be the offending expression. */ if (v.storage_class & (STC.ref_ | STC.out_)) { if (global.params.useDIP25 && sc._module && sc._module.isRoot()) { // Only look for errors if in module listed on command line if (p == sc.func) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); escapingRef(v); continue; } // Don't need to be concerned if v's parent does not return a ref FuncDeclaration fd = p.isFuncDeclaration(); if (fd && fd.type && fd.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)fd.type; if (tf.isref) { if (!gag) error(e.loc, "storing reference to outer local variable `%s` into allocated memory causes it to escape", v.toChars()); result = true; continue; } } } } } foreach (Expression ee; er.byexp) { if (log) printf("byexp %s\n", ee.toChars()); if (!gag) error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape", ee.toChars()); result = true; } return result; } /************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame by returning 'e' by value. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * e = expression to check for any pointers to the stack * gag = do not print error messages * Returns: * true if pointers to the stack can escape */ bool checkReturnEscape(Scope* sc, Expression e, bool gag) { //printf("[%s] checkReturnEscape, e = %s\n", e.loc.toChars(), e.toChars()); return checkReturnEscapeImpl(sc, e, false, gag); } /************************************ * Detect cases where returning 'e' by ref can result in a reference to the stack * being returned. * Print error messages when these are detected. * Params: * sc = used to determine current function and module * e = expression to check * gag = do not print error messages * Returns: * true if references to the stack can escape */ bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag) { version (none) { printf("[%s] checkReturnEscapeRef, e = %s\n", e.loc.toChars(), e.toChars()); printf("current function %s\n", sc.func.toChars()); printf("parent2 function %s\n", sc.func.toParent2().toChars()); } return checkReturnEscapeImpl(sc, e, true, gag); } /*************************************** * Implementation of checking for escapes in `return`. * Params: * sc = used to determine current function and module * e = expression to check * gag = do not print error messages * Returns: * true if references to the stack can escape */ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { enum log = false; if (log) printf("[%s] checkReturnEscapeImpl, refs: %d e: `%s`\n", e.loc.toChars(), refs, e.toChars()); EscapeByResults er; if (refs) escapeByRef(e, &er); else escapeByValue(e, &er); if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim) return false; bool result = false; foreach (VarDeclaration v; er.byvalue) { if (log) printf("byvalue `%s`\n", v.toChars()); if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); if ((v.isScope() || (v.storage_class & STC.maybescope)) && !(v.storage_class & STC.return_) && v.isParameter() && sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func) { inferReturn(sc.func, v); // infer addition of 'return' continue; } if (v.isScope()) { if (v.storage_class & STC.return_) continue; if (sc._module && sc._module.isRoot() && /* This case comes up when the ReturnStatement of a __foreachbody is * checked for escapes by the caller of __foreachbody. Skip it. * * struct S { static int opApply(int delegate(S*) dg); } * S* foo() { * foreach (S* s; S) // create __foreachbody for body of foreach * return s; // s is inferred as 'scope' but incorrectly tested in foo() * return null; } */ !(!refs && p.parent == sc.func)) { // Only look for errors if in module listed on command line if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029 { if (!gag) error(e.loc, "scope variable `%s` may not be returned", v.toChars()); result = true; } continue; } } else if (v.storage_class & STC.variadic && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!gag) error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); result = false; } } else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); v.doNotInferScope = true; } } foreach (VarDeclaration v; er.byref) { if (log) printf("byref `%s`\n", v.toChars()); void escapingRef(VarDeclaration v) { if (!gag) { const(char)* msg; if (v.storage_class & STC.parameter) msg = "returning `%s` escapes a reference to parameter `%s`, perhaps annotate with `return`"; else msg = "returning `%s` escapes a reference to local variable `%s`"; error(e.loc, msg, e.toChars(), v.toChars()); } result = true; } if (v.isDataseg()) continue; Dsymbol p = v.toParent2(); if ((v.storage_class & (STC.ref_ | STC.out_)) == 0) { if (p == sc.func) { escapingRef(v); continue; } FuncDeclaration fd = p.isFuncDeclaration(); if (fd && sc.func.flags & FUNCFLAG.returnInprocess) { /* Code like: * int x; * auto dg = () { return &x; } * Making it: * auto dg = () return { return &x; } * Because dg.ptr points to x, this is returning dt.ptr+offset */ if (global.params.vsafe) sc.func.storage_class |= STC.return_; } } /* Check for returning a ref variable by 'ref', but should be 'return ref' * Infer the addition of 'return', or set result to be the offending expression. */ if ( (v.storage_class & (STC.ref_ | STC.out_)) && !(v.storage_class & (STC.return_ | STC.foreach_))) { if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func) { inferReturn(sc.func, v); // infer addition of 'return' } else if (global.params.useDIP25 && sc._module && sc._module.isRoot()) { // Only look for errors if in module listed on command line if (p == sc.func) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); escapingRef(v); continue; } // Don't need to be concerned if v's parent does not return a ref FuncDeclaration fd = p.isFuncDeclaration(); if (fd && fd.type && fd.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)fd.type; if (tf.isref) { if (!gag) error(e.loc, "escaping reference to outer local variable `%s`", v.toChars()); result = true; continue; } } } } } foreach (Expression ee; er.byexp) { if (log) printf("byexp %s\n", ee.toChars()); if (!gag) error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars()); result = true; } return result; } /************************************* * Variable v needs to have 'return' inferred for it. * Params: * fd = function that v is a parameter to * v = parameter that needs to be STC.return_ */ private void inferReturn(FuncDeclaration fd, VarDeclaration v) { // v is a local in the current function //printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars()); v.storage_class |= STC.return_; TypeFunction tf = cast(TypeFunction)fd.type; if (v == fd.vthis) { /* v is the 'this' reference, so mark the function */ fd.storage_class |= STC.return_; if (tf.ty == Tfunction) { //printf("'this' too %p %s\n", tf, sc.func.toChars()); tf.isreturn = true; } } else { // Perform 'return' inference on parameter if (tf.ty == Tfunction && tf.parameters) { const dim = Parameter.dim(tf.parameters); foreach (const i; 0 .. dim) { Parameter p = Parameter.getNth(tf.parameters, i); if (p.ident == v.ident) { p.storageClass |= STC.return_; break; // there can be only one } } } } } /**************************************** * e is an expression to be returned by value, and that value contains pointers. * Walk e to determine which variables are possibly being * returned by value, such as: * int* function(int* p) { return p; } * If e is a form of &p, determine which variables have content * which is being returned as ref, such as: * int* function(int i) { return &i; } * Multiple variables can be inserted, because of expressions like this: * int function(bool b, int i, int* p) { return b ? &i : p; } * * No side effects. * * Params: * e = expression to be returned by value * er = where to place collected data */ private void escapeByValue(Expression e, EscapeByResults* er) { //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars()); extern (C++) final class EscapeVisitor : Visitor { alias visit = Visitor.visit; public: EscapeByResults* er; extern (D) this(EscapeByResults* er) { this.er = er; } override void visit(Expression e) { } override void visit(AddrExp e) { /* Taking the address of struct literal is normally not * allowed, but CTFE can generate one out of a new expression, * but it'll be placed in static data so no need to check it. */ if (e.e1.op != TOK.structLiteral) escapeByRef(e.e1, er); } override void visit(SymOffExp e) { VarDeclaration v = e.var.isVarDeclaration(); if (v) er.byref.push(v); } override void visit(VarExp e) { VarDeclaration v = e.var.isVarDeclaration(); if (v) er.byvalue.push(v); } override void visit(ThisExp e) { if (e.var) er.byvalue.push(e.var); } override void visit(DotVarExp e) { auto t = e.e1.type.toBasetype(); if (t.ty == Tstruct) e.e1.accept(this); } override void visit(DelegateExp e) { Type t = e.e1.type.toBasetype(); if (t.ty == Tclass || t.ty == Tpointer) escapeByValue(e.e1, er); else escapeByRef(e.e1, er); er.byfunc.push(e.func); } override void visit(FuncExp e) { if (e.fd.tok == TOK.delegate_) er.byfunc.push(e.fd); } override void visit(TupleExp e) { assert(0); // should have been lowered by now } override void visit(ArrayLiteralExp e) { Type tb = e.type.toBasetype(); if (tb.ty == Tsarray || tb.ty == Tarray) { if (e.basis) e.basis.accept(this); foreach (el; *e.elements) { if (el) el.accept(this); } } } override void visit(StructLiteralExp e) { if (e.elements) { foreach (ex; *e.elements) { if (ex) ex.accept(this); } } } override void visit(NewExp e) { Type tb = e.newtype.toBasetype(); if (tb.ty == Tstruct && !e.member && e.arguments) { foreach (ex; *e.arguments) { if (ex) ex.accept(this); } } } override void visit(CastExp e) { Type tb = e.type.toBasetype(); if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray) { escapeByRef(e.e1, er); } else e.e1.accept(this); } override void visit(SliceExp e) { if (e.e1.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); Type tb = e.type.toBasetype(); if (v) { if (tb.ty == Tsarray) return; if (v.storage_class & STC.variadic) { er.byvalue.push(v); return; } } } Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tsarray) { Type tb = e.type.toBasetype(); if (tb.ty != Tsarray) escapeByRef(e.e1, er); } else e.e1.accept(this); } override void visit(IndexExp e) { if (e.e1.type.toBasetype().ty == Tsarray) { e.e1.accept(this); } } override void visit(BinExp e) { Type tb = e.type.toBasetype(); if (tb.ty == Tpointer) { e.e1.accept(this); e.e2.accept(this); } } override void visit(BinAssignExp e) { e.e1.accept(this); } override void visit(AssignExp e) { e.e1.accept(this); } override void visit(CommaExp e) { e.e2.accept(this); } override void visit(CondExp e) { e.e1.accept(this); e.e2.accept(this); } override void visit(CallExp e) { //printf("CallExp(): %s\n", e.toChars()); /* Check each argument that is * passed as 'return scope'. */ Type t1 = e.e1.type.toBasetype(); TypeFunction tf; TypeDelegate dg; if (t1.ty == Tdelegate) { dg = cast(TypeDelegate)t1; tf = cast(TypeFunction)(cast(TypeDelegate)t1).next; } else if (t1.ty == Tfunction) tf = cast(TypeFunction)t1; else return; if (e.arguments && e.arguments.dim) { /* j=1 if _arguments[] is first argument, * skip it because it is not passed by ref */ int j = (tf.linkage == LINK.d && tf.varargs == 1); for (size_t i = j; i < e.arguments.dim; ++i) { Expression arg = (*e.arguments)[i]; size_t nparams = Parameter.dim(tf.parameters); if (i - j < nparams && i >= j) { Parameter p = Parameter.getNth(tf.parameters, i - j); const stc = tf.parameterStorageClass(null, p); if ((stc & (STC.scope_)) && (stc & STC.return_)) arg.accept(this); else if ((stc & (STC.ref_)) && (stc & STC.return_)) escapeByRef(arg, er); } } } // If 'this' is returned, check it too if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction) { DotVarExp dve = cast(DotVarExp)e.e1; FuncDeclaration fd = dve.var.isFuncDeclaration(); AggregateDeclaration ad; if (global.params.vsafe && tf.isreturn && fd && (ad = fd.isThis()) !is null) { if (ad.isClassDeclaration() || tf.isscope) // this is 'return scope' dve.e1.accept(this); else if (ad.isStructDeclaration()) // this is 'return ref' escapeByRef(dve.e1, er); } else if (dve.var.storage_class & STC.return_ || tf.isreturn) { if (dve.var.storage_class & STC.scope_) dve.e1.accept(this); else if (dve.var.storage_class & STC.ref_) escapeByRef(dve.e1, er); } } /* If returning the result of a delegate call, the .ptr * field of the delegate must be checked. */ if (dg) { if (tf.isreturn) e.e1.accept(this); } /* If it's a nested function that is 'return scope' */ if (e.e1.op == TOK.variable) { VarExp ve = cast(VarExp)e.e1; FuncDeclaration fd = ve.var.isFuncDeclaration(); if (fd && fd.isNested()) { if (tf.isreturn && tf.isscope) er.byexp.push(e); } } } } scope EscapeVisitor v = new EscapeVisitor(er); e.accept(v); } /**************************************** * e is an expression to be returned by 'ref'. * Walk e to determine which variables are possibly being * returned by ref, such as: * ref int function(int i) { return i; } * If e is a form of *p, determine which variables have content * which is being returned as ref, such as: * ref int function(int* p) { return *p; } * Multiple variables can be inserted, because of expressions like this: * ref int function(bool b, int i, int* p) { return b ? i : *p; } * * No side effects. * * Params: * e = expression to be returned by 'ref' * er = where to place collected data */ private void escapeByRef(Expression e, EscapeByResults* er) { //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars()); extern (C++) final class EscapeRefVisitor : Visitor { alias visit = Visitor.visit; public: EscapeByResults* er; extern (D) this(EscapeByResults* er) { this.er = er; } override void visit(Expression e) { } override void visit(VarExp e) { auto v = e.var.isVarDeclaration(); if (v) { if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init) { /* If compiler generated ref temporary * (ref v = ex; ex) * look at the initializer instead */ if (ExpInitializer ez = v._init.isExpInitializer()) { assert(ez.exp && ez.exp.op == TOK.construct); Expression ex = (cast(ConstructExp)ez.exp).e2; ex.accept(this); } } else er.byref.push(v); } } override void visit(ThisExp e) { if (e.var) er.byref.push(e.var); } override void visit(PtrExp e) { escapeByValue(e.e1, er); } override void visit(IndexExp e) { Type tb = e.e1.type.toBasetype(); if (e.e1.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (v && v.storage_class & STC.variadic) { er.byref.push(v); return; } } } if (tb.ty == Tsarray) { e.e1.accept(this); } else if (tb.ty == Tarray) { escapeByValue(e.e1, er); } } override void visit(StructLiteralExp e) { if (e.elements) { foreach (ex; *e.elements) { if (ex) ex.accept(this); } } er.byexp.push(e); } override void visit(DotVarExp e) { Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tclass) escapeByValue(e.e1, er); else e.e1.accept(this); } override void visit(BinAssignExp e) { e.e1.accept(this); } override void visit(AssignExp e) { e.e1.accept(this); } override void visit(CommaExp e) { e.e2.accept(this); } override void visit(CondExp e) { e.e1.accept(this); e.e2.accept(this); } override void visit(CallExp e) { /* If the function returns by ref, check each argument that is * passed as 'return ref'. */ Type t1 = e.e1.type.toBasetype(); TypeFunction tf; if (t1.ty == Tdelegate) tf = cast(TypeFunction)(cast(TypeDelegate)t1).next; else if (t1.ty == Tfunction) tf = cast(TypeFunction)t1; else return; if (tf.isref) { if (e.arguments && e.arguments.dim) { /* j=1 if _arguments[] is first argument, * skip it because it is not passed by ref */ int j = (tf.linkage == LINK.d && tf.varargs == 1); for (size_t i = j; i < e.arguments.dim; ++i) { Expression arg = (*e.arguments)[i]; size_t nparams = Parameter.dim(tf.parameters); if (i - j < nparams && i >= j) { Parameter p = Parameter.getNth(tf.parameters, i - j); const stc = tf.parameterStorageClass(null, p); if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_)) arg.accept(this); else if ((stc & STC.scope_) && (stc & STC.return_)) { if (arg.op == TOK.delegate_) { DelegateExp de = cast(DelegateExp)arg; if (de.func.isNested()) er.byexp.push(de); } else escapeByValue(arg, er); } } } } // If 'this' is returned by ref, check it too if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction) { DotVarExp dve = cast(DotVarExp)e.e1; if (dve.var.storage_class & STC.return_ || tf.isreturn) { if (dve.var.storage_class & STC.scope_ || tf.isscope) escapeByValue(dve.e1, er); else if (dve.var.storage_class & STC.ref_ || tf.isref) dve.e1.accept(this); } } // If it's a delegate, check it too if (e.e1.op == TOK.variable && t1.ty == Tdelegate) { escapeByValue(e.e1, er); } /* If it's a nested function that is 'return ref' */ if (e.e1.op == TOK.variable) { VarExp ve = cast(VarExp)e.e1; FuncDeclaration fd = ve.var.isFuncDeclaration(); if (fd && fd.isNested()) { if (tf.isreturn) er.byexp.push(e); } } } else er.byexp.push(e); } } scope EscapeRefVisitor v = new EscapeRefVisitor(er); e.accept(v); } /************************************ * Aggregate the data collected by the escapeBy??() functions. */ private struct EscapeByResults { VarDeclarations byref; // array into which variables being returned by ref are inserted VarDeclarations byvalue; // array into which variables with values containing pointers are inserted FuncDeclarations byfunc; // nested functions that are turned into delegates Expressions byexp; // array into which temporaries being returned by ref are inserted } /************************* * Find all variables accessed by this delegate that are * in functions enclosing it. * Params: * fd = function * vars = array to append found variables to */ void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* vars) { //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars()); for (auto p = fd.parent; p; p = p.parent) { auto fdp = p.isFuncDeclaration(); if (fdp) { foreach (v; fdp.closureVars) { foreach (const fdv; v.nestedrefs) { if (fdv == fd) { //printf("accessed: %s, type %s\n", v.toChars(), v.type.toChars()); vars.push(v); } } } } } } /*********************************** * Turn off STC.maybescope for variable `v`. * This exists in order to find where STC.maybescope is getting turned off. * Params: * v = variable */ version (none) { void notMaybeScope(string file = __FILE__, int line = __LINE__)(VarDeclaration v) { printf("%.*s(%d): notMaybeScope('%s')\n", cast(int)file.length, file.ptr, line, v.toChars()); v.storage_class &= ~STC.maybescope; } } else { void notMaybeScope(VarDeclaration v) { v.storage_class &= ~STC.maybescope; } } /********************************************** * Have some variables that are maybescopes that were * assigned values from other maybescope variables. * Now that semantic analysis of the function is * complete, we can finalize this by turning off * maybescope for array elements that cannot be scope. * * `va` `v` => `va` `v` * maybe maybe => scope scope * scope scope => scope scope * scope maybe => scope scope * maybe scope => scope scope * - - => - - * - maybe => - - * - scope => error * maybe - => scope - * scope - => scope - * Params: * array = array of variables that were assigned to from maybescope variables */ void eliminateMaybeScopes(VarDeclaration[] array) { enum log = false; if (log) printf("eliminateMaybeScopes()\n"); bool changes; do { changes = false; foreach (va; array) { if (log) printf(" va = %s\n", va.toChars()); if (!(va.storage_class & (STC.maybescope | STC.scope_))) { if (va.maybes) { foreach (v; *va.maybes) { if (log) printf(" v = %s\n", v.toChars()); if (v.storage_class & STC.maybescope) { // v cannot be scope since it is assigned to a non-scope va notMaybeScope(v); changes = true; } } } } } } while (changes); } ================================================ FILE: gcc/d/dmd/expression.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/expression.d, _expression.d) * Documentation: https://dlang.org/phobos/dmd_expression.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d */ module dmd.expression; import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.apply; import dmd.arrayop; import dmd.arraytypes; import dmd.gluelayer; import dmd.canthrow; import dmd.complex; import dmd.constfold; import dmd.ctfeexpr; import dmd.ctorflow; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.delegatize; import dmd.dimport; 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.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.inline; import dmd.mtype; import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.optimize; import dmd.root.ctfloat; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.safe; import dmd.sideeffect; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.utf; import dmd.visitor; enum LOGSEMANTIC = false; void emplaceExp(T : Expression, Args...)(void* p, Args args) { scope tmp = new T(args); memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T)); } void emplaceExp(T : UnionExp)(T* p, Expression e) { memcpy(p, cast(void*)e, e.size); } /**************************************** * Find the first non-comma expression. * Params: * e = Expressions connected by commas * Returns: * left-most non-comma expression */ inout(Expression) firstComma(inout Expression e) { Expression ex = cast()e; while (ex.op == TOK.comma) ex = (cast(CommaExp)ex).e1; return cast(inout)ex; } /**************************************** * Find the last non-comma expression. * Params: * e = Expressions connected by commas * Returns: * right-most non-comma expression */ inout(Expression) lastComma(inout Expression e) { Expression ex = cast()e; while (ex.op == TOK.comma) ex = (cast(CommaExp)ex).e2; return cast(inout)ex; } /***************************************** * Determine if `this` is available by walking up the enclosing * scopes until a function is found. * * Params: * sc = where to start looking for the enclosing function * Returns: * Found function if it satisfies `isThis()`, otherwise `null` */ FuncDeclaration hasThis(Scope* sc) { //printf("hasThis()\n"); Dsymbol p = sc.parent; while (p && p.isTemplateMixin()) p = p.parent; FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); // Go upwards until we find the enclosing member function FuncDeclaration fd = fdthis; while (1) { if (!fd) { goto Lno; } if (!fd.isNested()) break; Dsymbol parent = fd.parent; while (1) { if (!parent) goto Lno; TemplateInstance ti = parent.isTemplateInstance(); if (ti) parent = ti.parent; else break; } fd = parent.isFuncDeclaration(); } if (!fd.isThis()) { goto Lno; } assert(fd.vthis); return fd; Lno: return null; // don't have 'this' available } /*********************************** * Determine if a `this` is needed to access `d`. * Params: * sc = context * d = declaration to check * Returns: * true means a `this` is needed */ bool isNeedThisScope(Scope* sc, Declaration d) { if (sc.intypeof == 1) return false; AggregateDeclaration ad = d.isThis(); if (!ad) return false; //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars()); for (Dsymbol s = sc.parent; s; s = s.toParent2()) { //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2()); if (AggregateDeclaration ad2 = s.isAggregateDeclaration()) { if (ad2 == ad) return false; else if (ad2.isNested()) continue; else return true; } if (FuncDeclaration f = s.isFuncDeclaration()) { if (f.isMember2()) break; } } return true; } /****************************** * check e is exp.opDispatch!(tiargs) or not * It's used to switch to UFCS the semantic analysis path */ bool isDotOpDispatch(Expression e) { return e.op == TOK.dotTemplateInstance && (cast(DotTemplateInstanceExp)e).ti.name == Id.opDispatch; } /**************************************** * Expand tuples. * Input: * exps aray of Expressions * Output: * exps rewritten in place */ extern (C++) void expandTuples(Expressions* exps) { //printf("expandTuples()\n"); if (exps) { for (size_t i = 0; i < exps.dim; i++) { Expression arg = (*exps)[i]; if (!arg) continue; // Look for tuple with 0 members if (arg.op == TOK.type) { TypeExp e = cast(TypeExp)arg; if (e.type.toBasetype().ty == Ttuple) { TypeTuple tt = cast(TypeTuple)e.type.toBasetype(); if (!tt.arguments || tt.arguments.dim == 0) { exps.remove(i); if (i == exps.dim) return; i--; continue; } } } // Inline expand all the tuples while (arg.op == TOK.tuple) { TupleExp te = cast(TupleExp)arg; exps.remove(i); // remove arg exps.insert(i, te.exps); // replace with tuple contents if (i == exps.dim) return; // empty tuple, no more arguments (*exps)[i] = Expression.combine(te.e0, (*exps)[i]); arg = (*exps)[i]; } } } } /**************************************** * Expand alias this tuples. */ extern (C++) TupleDeclaration isAliasThisTuple(Expression e) { if (!e.type) return null; Type t = e.type.toBasetype(); Lagain: if (Dsymbol s = t.toDsymbol(null)) { AggregateDeclaration ad = s.isAggregateDeclaration(); if (ad) { s = ad.aliasthis; if (s && s.isVarDeclaration()) { TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); if (td && td.isexp) return td; } if (Type att = t.aliasthisOf()) { t = att; goto Lagain; } } } return null; } extern (C++) int expandAliasThisTuples(Expressions* exps, size_t starti = 0) { if (!exps || exps.dim == 0) return -1; for (size_t u = starti; u < exps.dim; u++) { Expression exp = (*exps)[u]; TupleDeclaration td = isAliasThisTuple(exp); if (td) { exps.remove(u); foreach (i, o; *td.objects) { Expression e = isExpression(o); assert(e); assert(e.op == TOK.dSymbol); DsymbolExp se = cast(DsymbolExp)e; Declaration d = se.s.isDeclaration(); assert(d); e = new DotVarExp(exp.loc, exp, d); assert(d.type); e.type = d.type; exps.insert(u + i, e); } version (none) { printf("expansion ->\n"); foreach (e; exps) { printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars()); } } return cast(int)u; } } return -1; } /**************************************** * If `s` is a function template, i.e. the only member of a template * and that member is a function, return that template. * Params: * s = symbol that might be a function template * Returns: * template for that function, otherwise null */ extern (C++) TemplateDeclaration getFuncTemplateDecl(Dsymbol s) { FuncDeclaration f = s.isFuncDeclaration(); if (f && f.parent) { TemplateInstance ti = f.parent.isTemplateInstance(); if (ti && !ti.isTemplateMixin() && ti.tempdecl && (cast(TemplateDeclaration)ti.tempdecl).onemember && ti.tempdecl.ident == f.ident) { return cast(TemplateDeclaration)ti.tempdecl; } } return null; } /************************************************ * If we want the value of this expression, but do not want to call * the destructor on it. */ Expression valueNoDtor(Expression e) { auto ex = lastComma(e); if (ex.op == TOK.call) { /* The struct value returned from the function is transferred * so do not call the destructor on it. * Recognize: * ((S _ctmp = S.init), _ctmp).this(...) * and make sure the destructor is not called on _ctmp * BUG: if ex is a CommaExp, we should go down the right side. */ CallExp ce = cast(CallExp)ex; if (ce.e1.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)ce.e1; if (dve.var.isCtorDeclaration()) { // It's a constructor call if (dve.e1.op == TOK.comma) { CommaExp comma = cast(CommaExp)dve.e1; if (comma.e2.op == TOK.variable) { VarExp ve = cast(VarExp)comma.e2; VarDeclaration ctmp = ve.var.isVarDeclaration(); if (ctmp) { ctmp.storage_class |= STC.nodtor; assert(!ce.isLvalue()); } } } } } } else if (ex.op == TOK.variable) { auto vtmp = (cast(VarExp)ex).var.isVarDeclaration(); if (vtmp && (vtmp.storage_class & STC.rvalue)) { vtmp.storage_class |= STC.nodtor; } } return e; } /********************************************* * If e is an instance of a struct, and that struct has a copy constructor, * rewrite e as: * (tmp = e),tmp * Input: * sc just used to specify the scope of created temporary variable */ private Expression callCpCtor(Scope* sc, Expression e) { Type tv = e.type.baseElemOf(); if (tv.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)tv).sym; if (sd.postblit) { /* Create a variable tmp, and replace the argument e with: * (tmp = e),tmp * and let AssignExp() handle the construction. * This is not the most efficient, ideally tmp would be constructed * directly onto the stack. */ auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); tmp.storage_class |= STC.nodtor; tmp.dsymbolSemantic(sc); Expression de = new DeclarationExp(e.loc, tmp); Expression ve = new VarExp(e.loc, tmp); de.type = Type.tvoid; ve.type = e.type; e = Expression.combine(de, ve); } } return e; } /************************************************ * Handle the postblit call on lvalue, or the move of rvalue. */ Expression doCopyOrMove(Scope *sc, Expression e) { if (e.op == TOK.question) { auto ce = cast(CondExp)e; ce.e1 = doCopyOrMove(sc, ce.e1); ce.e2 = doCopyOrMove(sc, ce.e2); } else { e = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); } return e; } /****************************************************************/ /* A type meant as a union of all the Expression types, * to serve essentially as a Variant that will sit on the stack * during CTFE to reduce memory consumption. */ struct UnionExp { // yes, default constructor does nothing extern (D) this(Expression e) { memcpy(&this, cast(void*)e, e.size); } /* Extract pointer to Expression */ extern (C++) Expression exp() { return cast(Expression)&u; } /* Convert to an allocated Expression */ extern (C++) Expression copy() { Expression e = exp(); //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op)); assert(e.size <= u.sizeof); if (e.op == TOK.cantExpression) return CTFEExp.cantexp; if (e.op == TOK.voidExpression) return CTFEExp.voidexp; if (e.op == TOK.break_) return CTFEExp.breakexp; if (e.op == TOK.continue_) return CTFEExp.continueexp; if (e.op == TOK.goto_) return CTFEExp.gotoexp; return e.copy(); } private: union __AnonStruct__u { char[__traits(classInstanceSize, Expression)] exp; char[__traits(classInstanceSize, IntegerExp)] integerexp; char[__traits(classInstanceSize, ErrorExp)] errorexp; char[__traits(classInstanceSize, RealExp)] realexp; char[__traits(classInstanceSize, ComplexExp)] complexexp; char[__traits(classInstanceSize, SymOffExp)] symoffexp; char[__traits(classInstanceSize, StringExp)] stringexp; char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp; char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp; char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp; char[__traits(classInstanceSize, NullExp)] nullexp; char[__traits(classInstanceSize, DotVarExp)] dotvarexp; char[__traits(classInstanceSize, AddrExp)] addrexp; char[__traits(classInstanceSize, IndexExp)] indexexp; char[__traits(classInstanceSize, SliceExp)] sliceexp; // Ensure that the union is suitably aligned. real_t for_alignment_only; } __AnonStruct__u u; } /******************************** * Test to see if two reals are the same. * Regard NaN's as equivalent. * Regard +0 and -0 as different. */ int RealEquals(real_t x1, real_t x2) { return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2); } /************************ TypeDotIdExp ************************************/ /* Things like: * int.size * foo.size * (foo).size * cast(foo).size */ DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) { return new DotIdExp(loc, new TypeExp(loc, type), ident); } /*************************************************** * Given an Expression, find the variable it really is. * * For example, `a[index]` is really `a`, and `s.f` is really `s`. * Params: * e = Expression to look at * Returns: * variable if there is one, null if not */ VarDeclaration expToVariable(Expression e) { while (1) { switch (e.op) { case TOK.variable: return (cast(VarExp)e).var.isVarDeclaration(); case TOK.dotVariable: e = (cast(DotVarExp)e).e1; continue; case TOK.index: { IndexExp ei = cast(IndexExp)e; e = ei.e1; Type ti = e.type.toBasetype(); if (ti.ty == Tsarray) continue; return null; } case TOK.slice: { SliceExp ei = cast(SliceExp)e; e = ei.e1; Type ti = e.type.toBasetype(); if (ti.ty == Tsarray) continue; return null; } case TOK.this_: case TOK.super_: return (cast(ThisExp)e).var.isVarDeclaration(); default: return null; } } } enum OwnedBy : int { code, // normal code expression in AST ctfe, // value expression for CTFE cache, // constant value cached for CTFE } enum WANTvalue = 0; // default enum WANTexpand = 1; // expand const/immutable variables if possible /*********************************************************** * http://dlang.org/spec/expression.html#expression */ extern (C++) abstract class Expression : RootObject { Loc loc; // file location Type type; // !=null means that semantic() has been run TOK op; // to minimize use of dynamic_cast ubyte size; // # of bytes in Expression so we can copy() it ubyte parens; // if this is a parenthesized expression extern (D) this(const ref Loc loc, TOK op, int size) { //printf("Expression::Expression(op = %d) this = %p\n", op, this); this.loc = loc; this.op = op; this.size = cast(ubyte)size; } static void _init() { CTFEExp.cantexp = new CTFEExp(TOK.cantExpression); CTFEExp.voidexp = new CTFEExp(TOK.voidExpression); CTFEExp.breakexp = new CTFEExp(TOK.break_); CTFEExp.continueexp = new CTFEExp(TOK.continue_); CTFEExp.gotoexp = new CTFEExp(TOK.goto_); CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext); } /********************************* * Does *not* do a deep copy. */ final Expression copy() { Expression e; if (!size) { debug { fprintf(stderr, "No expression copy for: %s\n", toChars()); printf("op = %d\n", op); } assert(0); } e = cast(Expression)mem.xmalloc(size); //printf("Expression::copy(op = %d) e = %p\n", op, e); return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size); } Expression syntaxCopy() { //printf("Expression::syntaxCopy()\n"); //print(); return copy(); } // kludge for template.isExpression() override final DYNCAST dyncast() const { return DYNCAST.expression; } override const(char)* toChars() { OutBuffer buf; HdrGenState hgs; toCBuffer(this, &buf, &hgs); return buf.extractString(); } final void error(const(char)* format, ...) const { if (type != Type.terror) { va_list ap; va_start(ap, format); .verror(loc, format, ap); va_end(ap); } } final void errorSupplemental(const(char)* format, ...) { if (type == Type.terror) return; va_list ap; va_start(ap, format); .verrorSupplemental(loc, format, ap); va_end(ap); } final void warning(const(char)* format, ...) const { if (type != Type.terror) { va_list ap; va_start(ap, format); .vwarning(loc, format, ap); va_end(ap); } } final void deprecation(const(char)* format, ...) const { if (type != Type.terror) { va_list ap; va_start(ap, format); .vdeprecation(loc, format, ap); va_end(ap); } } /********************************** * Combine e1 and e2 by CommaExp if both are not NULL. */ extern (D) static Expression combine(Expression e1, Expression e2) { if (e1) { if (e2) { e1 = new CommaExp(e1.loc, e1, e2); e1.type = e2.type; } } else e1 = e2; return e1; } extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) { return combine(combine(e1, e2), e3); } extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) { return combine(combine(e1, e2), combine(e3, e4)); } /********************************** * If 'e' is a tree of commas, returns the rightmost expression * by stripping off it from the tree. The remained part of the tree * is returned via e0. * Otherwise 'e' is directly returned and e0 is set to NULL. */ extern (D) static Expression extractLast(Expression e, out Expression e0) { if (e.op != TOK.comma) { return e; } CommaExp ce = cast(CommaExp)e; if (ce.e2.op != TOK.comma) { e0 = ce.e1; return ce.e2; } else { e0 = e; Expression* pce = &ce.e2; while ((cast(CommaExp)(*pce)).e2.op == TOK.comma) { pce = &(cast(CommaExp)(*pce)).e2; } assert((*pce).op == TOK.comma); ce = cast(CommaExp)(*pce); *pce = ce.e1; return ce.e2; } } extern (D) static Expressions* arraySyntaxCopy(Expressions* exps) { Expressions* a = null; if (exps) { a = new Expressions(exps.dim); foreach (i, e; *exps) { (*a)[i] = e ? e.syntaxCopy() : null; } } return a; } dinteger_t toInteger() { //printf("Expression %s\n", Token::toChars(op)); error("integer constant expression expected instead of `%s`", toChars()); return 0; } uinteger_t toUInteger() { //printf("Expression %s\n", Token::toChars(op)); return cast(uinteger_t)toInteger(); } real_t toReal() { error("floating point constant expression expected instead of `%s`", toChars()); return CTFloat.zero; } real_t toImaginary() { error("floating point constant expression expected instead of `%s`", toChars()); return CTFloat.zero; } complex_t toComplex() { error("floating point constant expression expected instead of `%s`", toChars()); return complex_t(CTFloat.zero); } StringExp toStringExp() { return null; } /*************************************** * Return !=0 if expression is an lvalue. */ bool isLvalue() { return false; } /******************************* * Give error if we're not an lvalue. * If we can, convert expression to be an lvalue. */ Expression toLvalue(Scope* sc, Expression e) { if (!e) e = this; else if (!loc.isValid()) loc = e.loc; if (e.op == TOK.type) error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind()); else error("`%s` is not an lvalue and cannot be modified", e.toChars()); return new ErrorExp(); } Expression modifiableLvalue(Scope* sc, Expression e) { //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars()); // See if this expression is a modifiable lvalue (i.e. not const) if (checkModifiable(sc) == 1) { assert(type); if (!type.isMutable()) { if (op == TOK.dotVariable) { if (isNeedThisScope(sc, (cast(DotVarExp) this).var)) for (Dsymbol s = sc.func; s; s = s.toParent2()) { FuncDeclaration ff = s.isFuncDeclaration(); if (!ff) break; if (!ff.type.isMutable) { error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod)); return new ErrorExp(); } } } error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars()); return new ErrorExp(); } else if (!type.isAssignable()) { error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members", toChars(), type.toChars()); return new ErrorExp(); } } return toLvalue(sc, e); } final Expression implicitCastTo(Scope* sc, Type t) { return .implicitCastTo(this, sc, t); } final MATCH implicitConvTo(Type t) { return .implicitConvTo(this, t); } final Expression castTo(Scope* sc, Type t) { return .castTo(this, sc, t); } /**************************************** * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc. */ Expression resolveLoc(const ref Loc loc, Scope* sc) { this.loc = loc; return this; } /**************************************** * Check that the expression has a valid type. * If not, generates an error "... has no type". * Returns: * true if the expression is not valid. * Note: * When this function returns true, `checkValue()` should also return true. */ bool checkType() { return false; } /**************************************** * Check that the expression has a valid value. * If not, generates an error "... has no value". * Returns: * true if the expression is not valid or has void type. */ bool checkValue() { if (type && type.toBasetype().ty == Tvoid) { error("expression `%s` is `void` and has no value", toChars()); //print(); assert(0); if (!global.gag) type = Type.terror; return true; } return false; } extern (D) final bool checkScalar() { if (op == TOK.error) return true; if (type.toBasetype().ty == Terror) return true; if (!type.isscalar()) { error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars()); return true; } return checkValue(); } extern (D) final bool checkNoBool() { if (op == TOK.error) return true; if (type.toBasetype().ty == Terror) return true; if (type.toBasetype().ty == Tbool) { error("operation not allowed on `bool` `%s`", toChars()); return true; } return false; } extern (D) final bool checkIntegral() { if (op == TOK.error) return true; if (type.toBasetype().ty == Terror) return true; if (!type.isintegral()) { error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars()); return true; } return checkValue(); } extern (D) final bool checkArithmetic() { if (op == TOK.error) return true; if (type.toBasetype().ty == Terror) return true; if (!type.isintegral() && !type.isfloating()) { error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars()); return true; } return checkValue(); } final bool checkDeprecated(Scope* sc, Dsymbol s) { return s.checkDeprecated(loc, sc); } extern (D) final bool checkDisabled(Scope* sc, Dsymbol s) { if (auto d = s.isDeclaration()) { return d.checkDisabled(loc, sc); } return false; } /********************************************* * Calling function f. * Check the purity, i.e. if we're in a pure function * we can only call other pure functions. * Returns true if error occurs. */ extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f) { if (!sc.func) return false; if (sc.func == f) return false; if (sc.intypeof == 1) return false; if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; /* Given: * void f() { * pure void g() { * /+pure+/ void h() { * /+pure+/ void i() { } * } * } * } * g() can call h() but not f() * i() can call h() and g() but not f() */ // Find the closest pure parent of the calling function FuncDeclaration outerfunc = sc.func; FuncDeclaration calledparent = f; if (outerfunc.isInstantiated()) { // The attributes of outerfunc should be inferred from the call of f. } else if (f.isInstantiated()) { // The attributes of f are inferred from its body. } else if (f.isFuncLiteralDeclaration()) { // The attributes of f are always inferred in its declared place. } else { /* Today, static local functions are impure by default, but they cannot * violate purity of enclosing functions. * * auto foo() pure { // non instantiated function * static auto bar() { // static, without pure attribute * impureFunc(); // impure call * // Although impureFunc is called inside bar, f(= impureFunc) * // is not callable inside pure outerfunc(= foo <- bar). * } * * bar(); * // Although bar is called inside foo, f(= bar) is callable * // bacause calledparent(= foo) is same with outerfunc(= foo). * } */ while (outerfunc.toParent2() && outerfunc.isPureBypassingInference() == PURE.impure && outerfunc.toParent2().isFuncDeclaration()) { outerfunc = outerfunc.toParent2().isFuncDeclaration(); if (outerfunc.type.ty == Terror) return true; } while (calledparent.toParent2() && calledparent.isPureBypassingInference() == PURE.impure && calledparent.toParent2().isFuncDeclaration()) { calledparent = calledparent.toParent2().isFuncDeclaration(); if (calledparent.type.ty == Terror) return true; } } // If the caller has a pure parent, then either the called func must be pure, // OR, they must have the same pure parent. if (!f.isPure() && calledparent != outerfunc) { FuncDeclaration ff = outerfunc; if (sc.flags & SCOPE.compile ? ff.isPureBypassingInference() >= PURE.weak : ff.setImpure()) { error("`pure` %s `%s` cannot call impure %s `%s`", ff.kind(), ff.toPrettyChars(), f.kind(), f.toPrettyChars()); return true; } } return false; } /******************************************* * Accessing variable v. * Check for purity and safety violations. * Returns true if error occurs. */ extern (D) final bool checkPurity(Scope* sc, VarDeclaration v) { //printf("v = %s %s\n", v.type.toChars(), v.toChars()); /* Look for purity and safety violations when accessing variable v * from current function. */ if (!sc.func) return false; if (sc.intypeof == 1) return false; // allow violations inside typeof(expression) if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; // allow violations inside compile-time evaluated expressions and debug conditionals if (v.ident == Id.ctfe) return false; // magic variable never violates pure and safe if (v.isImmutable()) return false; // always safe and pure to access immutables... if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) return false; // or const global/parameter values which have no mutable indirections if (v.storage_class & STC.manifest) return false; // ...or manifest constants if (v.type.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)v.type).sym; if (sd.hasNoFields) return false; } bool err = false; if (v.isDataseg()) { // https://issues.dlang.org/show_bug.cgi?id=7533 // Accessing implicit generated __gate is pure. if (v.ident == Id.gate) return false; /* Accessing global mutable state. * Therefore, this function and all its immediately enclosing * functions must be pure. */ /* Today, static local functions are impure by default, but they cannot * violate purity of enclosing functions. * * auto foo() pure { // non instantiated function * static auto bar() { // static, without pure attribute * globalData++; // impure access * // Although globalData is accessed inside bar, * // it is not accessible inside pure foo. * } * } */ for (Dsymbol s = sc.func; s; s = s.toParent2()) { FuncDeclaration ff = s.isFuncDeclaration(); if (!ff) break; if (sc.flags & SCOPE.compile ? ff.isPureBypassingInference() >= PURE.weak : ff.setImpure()) { error("`pure` %s `%s` cannot access mutable static data `%s`", ff.kind(), ff.toPrettyChars(), v.toChars()); err = true; break; } /* If the enclosing is an instantiated function or a lambda, its * attribute inference result is preferred. */ if (ff.isInstantiated()) break; if (ff.isFuncLiteralDeclaration()) break; } } else { /* Given: * void f() { * int fx; * pure void g() { * int gx; * /+pure+/ void h() { * int hx; * /+pure+/ void i() { } * } * } * } * i() can modify hx and gx but not fx */ Dsymbol vparent = v.toParent2(); for (Dsymbol s = sc.func; !err && s; s = s.toParent2()) { if (s == vparent) break; if (AggregateDeclaration ad = s.isAggregateDeclaration()) { if (ad.isNested()) continue; break; } FuncDeclaration ff = s.isFuncDeclaration(); if (!ff) break; if (ff.isNested() || ff.isThis()) { if (ff.type.isImmutable() || ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod)) { OutBuffer ffbuf; OutBuffer vbuf; MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod); MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod); error("%s%s `%s` cannot access %sdata `%s`", ffbuf.peekString(), ff.kind(), ff.toPrettyChars(), vbuf.peekString(), v.toChars()); err = true; break; } continue; } break; } } /* Do not allow safe functions to access __gshared data */ if (v.storage_class & STC.gshared) { if (sc.func.setUnsafe()) { error("`@safe` %s `%s` cannot access `__gshared` data `%s`", sc.func.kind(), sc.func.toChars(), v.toChars()); err = true; } } return err; } /********************************************* * Calling function f. * Check the safety, i.e. if we're in a @safe function * we can only call @safe or @trusted functions. * Returns true if error occurs. */ extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f) { if (!sc.func) return false; if (sc.func == f) return false; if (sc.intypeof == 1) return false; if (sc.flags & SCOPE.ctfe) return false; if (!f.isSafe() && !f.isTrusted()) { if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { if (!loc.isValid()) // e.g. implicitly generated dtor loc = sc.func.loc; const prettyChars = f.toPrettyChars(); error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), prettyChars); .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); return true; } } return false; } /********************************************* * Calling function f. * Check the @nogc-ness, i.e. if we're in a @nogc function * we can only call other @nogc functions. * Returns true if error occurs. */ extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f) { if (!sc.func) return false; if (sc.func == f) return false; if (sc.intypeof == 1) return false; if (sc.flags & SCOPE.ctfe) return false; if (!f.isNogc()) { if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC() && !(sc.flags & SCOPE.debug_)) { if (loc.linnum == 0) // e.g. implicitly generated dtor loc = sc.func.loc; error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); return true; } } return false; } /******************************************** * Check that the postblit is callable if t is an array of structs. * Returns true if error happens. */ extern (D) final bool checkPostblit(Scope* sc, Type t) { t = t.baseElemOf(); if (t.ty == Tstruct) { // https://issues.dlang.org/show_bug.cgi?id=11395 // Require TypeInfo generation for array concatenation semanticTypeInfo(sc, t); StructDeclaration sd = (cast(TypeStruct)t).sym; if (sd.postblit) { if (sd.postblit.checkDisabled(loc, sc)) return true; //checkDeprecated(sc, sd.postblit); // necessary? checkPurity(sc, sd.postblit); checkSafety(sc, sd.postblit); checkNogc(sc, sd.postblit); //checkAccess(sd, loc, sc, sd.postblit); // necessary? return false; } } return false; } extern (D) final bool checkRightThis(Scope* sc) { if (op == TOK.error) return true; if (op == TOK.variable && type.ty != Terror) { VarExp ve = cast(VarExp)this; if (isNeedThisScope(sc, ve.var)) { //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n", // sc.intypeof, sc.getStructClassScope(), func, fdthis); error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars()); return true; } } return false; } /******************************* * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) * Returns true if error occurs. */ extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null) { //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); if (!type || !type.isShared()) return false; // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. switch (rmwOp) { case TOK.plusPlus: case TOK.prePlusPlus: rmwOp = TOK.addAssign; break; case TOK.minusMinus: case TOK.preMinusMinus: rmwOp = TOK.minAssign; break; default: break; } error("read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead.", Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1"); return true; } /*************************************** * Parameters: * sc: scope * flag: 1: do not issue error message for invalid modification * Returns: * 0: is not modifiable * 1: is modifiable in default == being related to type.isMutable() * 2: is modifiable, because this is a part of initializing. */ int checkModifiable(Scope* sc, int flag = 0) { return type ? 1 : 0; // default modifiable } /***************************** * If expression can be tested for true or false, * returns the modified expression. * Otherwise returns ErrorExp. */ Expression toBoolean(Scope* sc) { // Default is 'yes' - do nothing Expression e = this; Type t = type; Type tb = type.toBasetype(); Type att = null; Lagain: // Structs can be converted to bool using opCast(bool)() if (tb.ty == Tstruct) { AggregateDeclaration ad = (cast(TypeStruct)tb).sym; /* Don't really need to check for opCast first, but by doing so we * get better error messages if it isn't there. */ Dsymbol fd = search_function(ad, Id._cast); if (fd) { e = new CastExp(loc, e, Type.tbool); e = e.expressionSemantic(sc); return e; } // Forward to aliasthis. if (ad.aliasthis && tb != att) { if (!att && tb.checkAliasThisRec()) att = tb; e = resolveAliasThis(sc, e); t = e.type; tb = e.type.toBasetype(); goto Lagain; } } if (!t.isBoolean()) { if (tb != Type.terror) error("expression `%s` of type `%s` does not have a boolean value", toChars(), t.toChars()); return new ErrorExp(); } return e; } /************************************************ * Destructors are attached to VarDeclarations. * Hence, if expression returns a temp that needs a destructor, * make sure and create a VarDeclaration for that temp. */ Expression addDtorHook(Scope* sc) { return this; } /****************************** * Take address of expression. */ final Expression addressOf() { //printf("Expression::addressOf()\n"); debug { assert(op == TOK.error || isLvalue()); } Expression e = new AddrExp(loc, this); e.type = type.pointerTo(); return e; } /****************************** * If this is a reference, dereference it. */ final Expression deref() { //printf("Expression::deref()\n"); // type could be null if forward referencing an 'auto' variable if (type && type.ty == Treference) { Expression e = new PtrExp(loc, this); e.type = (cast(TypeReference)type).next; return e; } return this; } final Expression optimize(int result, bool keepLvalue = false) { return Expression_optimize(this, result, keepLvalue); } // Entry point for CTFE. // A compile-time result is required. Give an error if not possible final Expression ctfeInterpret() { return .ctfeInterpret(this); } final int isConst() { return .isConst(this); } /******************************** * Does this expression statically evaluate to a boolean 'result' (true or false)? */ bool isBool(bool result) { return false; } bool hasCode() { return true; } void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class IntegerExp : Expression { private dinteger_t value; extern (D) this(const ref Loc loc, dinteger_t value, Type type) { super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp)); //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : ""); assert(type); if (!type.isscalar()) { //printf("%s, loc = %d\n", toChars(), loc.linnum); if (type.ty != Terror) error("integral constant must be scalar type, not `%s`", type.toChars()); type = Type.terror; } this.type = type; this.value = normalize(type.toBasetype().ty, value); } extern (D) this(dinteger_t value) { super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp)); this.type = Type.tint32; this.value = cast(d_int32)value; } static IntegerExp create(Loc loc, dinteger_t value, Type type) { return new IntegerExp(loc, value, type); } static IntegerExp createi(Loc loc, int value, Type type) { return new IntegerExp(loc, value, type); } override bool equals(RootObject o) { if (this == o) return true; if ((cast(Expression)o).op == TOK.int64) { IntegerExp ne = cast(IntegerExp)o; if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value) { return true; } } return false; } override dinteger_t toInteger() { // normalize() is necessary until we fix all the paints of 'type' return value = normalize(type.toBasetype().ty, value); } override real_t toReal() { // normalize() is necessary until we fix all the paints of 'type' const ty = type.toBasetype().ty; const val = normalize(ty, value); value = val; return (ty == Tuns64) ? real_t(cast(d_uns64)val) : real_t(cast(d_int64)val); } override real_t toImaginary() { return CTFloat.zero; } override complex_t toComplex() { return complex_t(toReal()); } override bool isBool(bool result) { bool r = toInteger() != 0; return result ? r : !r; } override Expression toLvalue(Scope* sc, Expression e) { if (!e) e = this; else if (!loc.isValid()) loc = e.loc; e.error("cannot modify constant `%s`", e.toChars()); return new ErrorExp(); } override void accept(Visitor v) { v.visit(this); } dinteger_t getInteger() { return value; } void setInteger(dinteger_t value) { this.value = normalize(type.toBasetype().ty, value); } static dinteger_t normalize(TY ty, dinteger_t value) { /* 'Normalize' the value of the integer to be in range of the type */ dinteger_t result; switch (ty) { case Tbool: result = (value != 0); break; case Tint8: result = cast(d_int8)value; break; case Tchar: case Tuns8: result = cast(d_uns8)value; break; case Tint16: result = cast(d_int16)value; break; case Twchar: case Tuns16: result = cast(d_uns16)value; break; case Tint32: result = cast(d_int32)value; break; case Tdchar: case Tuns32: result = cast(d_uns32)value; break; case Tint64: result = cast(d_int64)value; break; case Tuns64: result = cast(d_uns64)value; break; case Tpointer: if (Target.ptrsize == 4) result = cast(d_uns32)value; else if (Target.ptrsize == 8) result = cast(d_uns64)value; else assert(0); break; default: break; } return result; } } /*********************************************************** * Use this expression for error recovery. * It should behave as a 'sink' to prevent further cascaded error messages. */ extern (C++) final class ErrorExp : Expression { extern (D) this() { super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp)); type = Type.terror; } override Expression toLvalue(Scope* sc, Expression e) { return this; } override void accept(Visitor v) { v.visit(this); } extern (C++) __gshared ErrorExp errorexp; // handy shared value } /*********************************************************** * An uninitialized value, * generated from void initializers. */ extern (C++) final class VoidInitExp : Expression { VarDeclaration var; /// the variable from where the void value came from, null if not known /// Useful for error messages extern (D) this(VarDeclaration var) { super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp)); this.var = var; this.type = var.type; } override const(char)* toChars() const { return "void"; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class RealExp : Expression { real_t value; extern (D) this(const ref Loc loc, real_t value, Type type) { super(loc, TOK.float64, __traits(classInstanceSize, RealExp)); //printf("RealExp::RealExp(%Lg)\n", value); this.value = value; this.type = type; } static RealExp create(Loc loc, real_t value, Type type) { return new RealExp(loc, value, type); } override bool equals(RootObject o) { if (this == o) return true; if ((cast(Expression)o).op == TOK.float64) { RealExp ne = cast(RealExp)o; if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealEquals(value, ne.value)) { return true; } } return false; } override dinteger_t toInteger() { return cast(sinteger_t)toReal(); } override uinteger_t toUInteger() { return cast(uinteger_t)toReal(); } override real_t toReal() { return type.isreal() ? value : CTFloat.zero; } override real_t toImaginary() { return type.isreal() ? CTFloat.zero : value; } override complex_t toComplex() { return complex_t(toReal(), toImaginary()); } override bool isBool(bool result) { return result ? cast(bool)value : !cast(bool)value; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ComplexExp : Expression { complex_t value; extern (D) this(const ref Loc loc, complex_t value, Type type) { super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp)); this.value = value; this.type = type; //printf("ComplexExp::ComplexExp(%s)\n", toChars()); } static ComplexExp create(Loc loc, complex_t value, Type type) { return new ComplexExp(loc, value, type); } override bool equals(RootObject o) { if (this == o) return true; if ((cast(Expression)o).op == TOK.complex80) { ComplexExp ne = cast(ComplexExp)o; if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealEquals(creall(value), creall(ne.value)) && RealEquals(cimagl(value), cimagl(ne.value))) { return true; } } return false; } override dinteger_t toInteger() { return cast(sinteger_t)toReal(); } override uinteger_t toUInteger() { return cast(uinteger_t)toReal(); } override real_t toReal() { return creall(value); } override real_t toImaginary() { return cimagl(value); } override complex_t toComplex() { return value; } override bool isBool(bool result) { if (result) return cast(bool)value; else return !value; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class IdentifierExp : Expression { Identifier ident; extern (D) this(const ref Loc loc, Identifier ident) { super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp)); this.ident = ident; } static IdentifierExp create(Loc loc, Identifier ident) { return new IdentifierExp(loc, ident); } override final bool isLvalue() { return true; } override final Expression toLvalue(Scope* sc, Expression e) { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DollarExp : IdentifierExp { extern (D) this(const ref Loc loc) { super(loc, Id.dollar); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Won't be generated by parser. */ extern (C++) final class DsymbolExp : Expression { Dsymbol s; bool hasOverloads; extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) { super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp)); this.s = s; this.hasOverloads = hasOverloads; } override bool isLvalue() { return true; } override Expression toLvalue(Scope* sc, Expression e) { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#this */ extern (C++) class ThisExp : Expression { VarDeclaration var; extern (D) this(const ref Loc loc) { super(loc, TOK.this_, __traits(classInstanceSize, ThisExp)); //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); } override final bool isBool(bool result) { return result ? true : false; } override final bool isLvalue() { // Class `this` should be an rvalue; struct `this` should be an lvalue. return type.toBasetype().ty != Tclass; } override final Expression toLvalue(Scope* sc, Expression e) { if (type.toBasetype().ty == Tclass) { // Class `this` is an rvalue; struct `this` is an lvalue. return Expression.toLvalue(sc, e); } return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#super */ extern (C++) final class SuperExp : ThisExp { extern (D) this(const ref Loc loc) { super(loc); op = TOK.super_; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#null */ extern (C++) final class NullExp : Expression { ubyte committed; // !=0 if type is committed extern (D) this(const ref Loc loc, Type type = null) { super(loc, TOK.null_, __traits(classInstanceSize, NullExp)); this.type = type; } override bool equals(RootObject o) { if (o && o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; if (e.op == TOK.null_ && type.equals(e.type)) { return true; } } return false; } override bool isBool(bool result) { return result ? false : true; } override StringExp toStringExp() { if (implicitConvTo(Type.tstring)) { auto se = new StringExp(loc, cast(char*)mem.xcalloc(1, 1), 0); se.type = Type.tstring; return se; } return null; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#string_literals */ extern (C++) final class StringExp : Expression { union { char* string; // if sz == 1 wchar* wstring; // if sz == 2 dchar* dstring; // if sz == 4 } // (const if ownedByCtfe == OwnedBy.code) size_t len; // number of code units ubyte sz = 1; // 1: char, 2: wchar, 4: dchar ubyte committed; // !=0 if type is committed char postfix = 0; // 'c', 'w', 'd' OwnedBy ownedByCtfe = OwnedBy.code; extern (D) this(const ref Loc loc, char* string) { super(loc, TOK.string_, __traits(classInstanceSize, StringExp)); this.string = string; this.len = strlen(string); this.sz = 1; // work around LDC bug #1286 } extern (D) this(const ref Loc loc, void* string, size_t len) { super(loc, TOK.string_, __traits(classInstanceSize, StringExp)); this.string = cast(char*)string; this.len = len; this.sz = 1; // work around LDC bug #1286 } extern (D) this(const ref Loc loc, void* string, size_t len, char postfix) { super(loc, TOK.string_, __traits(classInstanceSize, StringExp)); this.string = cast(char*)string; this.len = len; this.postfix = postfix; this.sz = 1; // work around LDC bug #1286 } static StringExp create(Loc loc, char* s) { return new StringExp(loc, s); } static StringExp create(Loc loc, void* string, size_t len) { return new StringExp(loc, string, len); } override bool equals(RootObject o) { //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars()); if (o && o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; if (e.op == TOK.string_) { return compare(o) == 0; } } return false; } /********************************** * Return the number of code units the string would be if it were re-encoded * as tynto. * Params: * tynto = code unit type of the target encoding * Returns: * number of code units */ final size_t numberOfCodeUnits(int tynto = 0) const { int encSize; switch (tynto) { case 0: return len; case Tchar: encSize = 1; break; case Twchar: encSize = 2; break; case Tdchar: encSize = 4; break; default: assert(0); } if (sz == encSize) return len; size_t result = 0; dchar c; switch (sz) { case 1: for (size_t u = 0; u < len;) { if (const p = utf_decodeChar(string, len, u, c)) { error("%s", p); return 0; } result += utf_codeLength(encSize, c); } break; case 2: for (size_t u = 0; u < len;) { if (const p = utf_decodeWchar(wstring, len, u, c)) { error("%s", p); return 0; } result += utf_codeLength(encSize, c); } break; case 4: foreach (u; 0 .. len) { result += utf_codeLength(encSize, dstring[u]); } break; default: assert(0); } return result; } /********************************************** * Write the contents of the string to dest. * Use numberOfCodeUnits() to determine size of result. * Params: * dest = destination * tyto = encoding type of the result * zero = add terminating 0 */ void writeTo(void* dest, bool zero, int tyto = 0) const { int encSize; switch (tyto) { case 0: encSize = sz; break; case Tchar: encSize = 1; break; case Twchar: encSize = 2; break; case Tdchar: encSize = 4; break; default: assert(0); } if (sz == encSize) { memcpy(dest, string, len * sz); if (zero) memset(dest + len * sz, 0, sz); } else assert(0); } /********************************************* * Get the code unit at index i * Params: * i = index * Returns: * code unit at index i */ final dchar getCodeUnit(size_t i) const pure { assert(i < len); final switch (sz) { case 1: return string[i]; case 2: return wstring[i]; case 4: return dstring[i]; } } /********************************************* * Set the code unit at index i to c * Params: * i = index * c = code unit to set it to */ final void setCodeUnit(size_t i, dchar c) { assert(i < len); final switch (sz) { case 1: string[i] = cast(char)c; break; case 2: wstring[i] = cast(wchar)c; break; case 4: dstring[i] = c; break; } } /************************************************** * If the string data is UTF-8 and can be accessed directly, * return a pointer to it. * Do not assume a terminating 0. * Returns: * pointer to string data if possible, null if not */ char* toPtr() { return (sz == 1) ? string : null; } override StringExp toStringExp() { return this; } /**************************************** * Convert string to char[]. */ StringExp toUTF8(Scope* sc) { if (sz != 1) { // Convert to UTF-8 string committed = 0; Expression e = castTo(sc, Type.tchar.arrayOf()); e = e.optimize(WANTvalue); assert(e.op == TOK.string_); StringExp se = cast(StringExp)e; assert(se.sz == 1); return se; } return this; } override int compare(RootObject obj) { //printf("StringExp::compare()\n"); // Used to sort case statement expressions so we can do an efficient lookup StringExp se2 = cast(StringExp)obj; // This is a kludge so isExpression() in template.c will return 5 // for StringExp's. if (!se2) return 5; assert(se2.op == TOK.string_); size_t len1 = len; size_t len2 = se2.len; //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2); if (len1 == len2) { switch (sz) { case 1: return memcmp(string, se2.string, len1); case 2: { wchar* s1 = cast(wchar*)string; wchar* s2 = cast(wchar*)se2.string; foreach (u; 0 .. len) { if (s1[u] != s2[u]) return s1[u] - s2[u]; } } break; case 4: { dchar* s1 = cast(dchar*)string; dchar* s2 = cast(dchar*)se2.string; foreach (u; 0 .. len) { if (s1[u] != s2[u]) return s1[u] - s2[u]; } } break; default: assert(0); } } return cast(int)(len1 - len2); } override bool isBool(bool result) { return result ? true : false; } override bool isLvalue() { /* string literal is rvalue in default, but * conversion to reference of static array is only allowed. */ return (type && type.toBasetype().ty == Tsarray); } override Expression toLvalue(Scope* sc, Expression e) { //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); } override Expression modifiableLvalue(Scope* sc, Expression e) { error("cannot modify string literal `%s`", toChars()); return new ErrorExp(); } uint charAt(uinteger_t i) const { uint value; switch (sz) { case 1: value = (cast(char*)string)[cast(size_t)i]; break; case 2: value = (cast(ushort*)string)[cast(size_t)i]; break; case 4: value = (cast(uint*)string)[cast(size_t)i]; break; default: assert(0); } return value; } /******************************** * Convert string contents to a 0 terminated string, * allocated by mem.xmalloc(). */ extern (D) final const(char)[] toStringz() const { auto nbytes = len * sz; char* s = cast(char*)mem.xmalloc(nbytes + sz); writeTo(s, true); return s[0 .. nbytes]; } extern (D) const(char)[] peekSlice() const { assert(sz == 1); return this.string[0 .. len]; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TupleExp : Expression { /* Tuple-field access may need to take out its side effect part. * For example: * foo().tupleof * is rewritten as: * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...)) * The declaration of temporary variable __tup will be stored in TupleExp.e0. */ Expression e0; Expressions* exps; extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) { super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp)); //printf("TupleExp(this = %p)\n", this); this.e0 = e0; this.exps = exps; } extern (D) this(const ref Loc loc, Expressions* exps) { super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp)); //printf("TupleExp(this = %p)\n", this); this.exps = exps; } extern (D) this(const ref Loc loc, TupleDeclaration tup) { super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp)); this.exps = new Expressions(); this.exps.reserve(tup.objects.dim); foreach (o; *tup.objects) { if (Dsymbol s = getDsymbol(o)) { /* If tuple element represents a symbol, translate to DsymbolExp * to supply implicit 'this' if needed later. */ Expression e = new DsymbolExp(loc, s); this.exps.push(e); } else if (o.dyncast() == DYNCAST.expression) { auto e = (cast(Expression)o).copy(); e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669 this.exps.push(e); } else if (o.dyncast() == DYNCAST.type) { Type t = cast(Type)o; Expression e = new TypeExp(loc, t); this.exps.push(e); } else { error("`%s` is not an expression", o.toChars()); } } } override Expression syntaxCopy() { return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps)); } override bool equals(RootObject o) { if (this == o) return true; if ((cast(Expression)o).op == TOK.tuple) { TupleExp te = cast(TupleExp)o; if (exps.dim != te.exps.dim) return false; if (e0 && !e0.equals(te.e0) || !e0 && te.e0) return false; foreach (i, e1; *exps) { Expression e2 = (*te.exps)[i]; if (!e1.equals(e2)) return false; } return true; } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * [ e1, e2, e3, ... ] * * http://dlang.org/spec/expression.html#array_literals */ extern (C++) final class ArrayLiteralExp : Expression { /** If !is null, elements[] can be sparse and basis is used for the * "default" element value. In other words, non-null elements[i] overrides * this 'basis' value. */ Expression basis; Expressions* elements; OwnedBy ownedByCtfe = OwnedBy.code; extern (D) this(const ref Loc loc, Type type, Expressions* elements) { super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); this.type = type; this.elements = elements; } extern (D) this(const ref Loc loc, Type type, Expression e) { super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); this.type = type; elements = new Expressions(); elements.push(e); } extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) { super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); this.type = type; this.basis = basis; this.elements = elements; } static ArrayLiteralExp create(Loc loc, Expressions* elements) { return new ArrayLiteralExp(loc, null, elements); } override Expression syntaxCopy() { return new ArrayLiteralExp(loc, null, basis ? basis.syntaxCopy() : null, arraySyntaxCopy(elements)); } override bool equals(RootObject o) { if (this == o) return true; if (o && o.dyncast() == DYNCAST.expression && (cast(Expression)o).op == TOK.arrayLiteral) { ArrayLiteralExp ae = cast(ArrayLiteralExp)o; if (elements.dim != ae.elements.dim) return false; if (elements.dim == 0 && !type.equals(ae.type)) { return false; } foreach (i, e1; *elements) { Expression e2 = (*ae.elements)[i]; if (!e1) e1 = basis; if (!e2) e2 = ae.basis; if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) return false; } return true; } return false; } Expression getElement(size_t i) { auto el = (*elements)[i]; if (!el) el = basis; return el; } override bool isBool(bool result) { size_t dim = elements ? elements.dim : 0; return result ? (dim != 0) : (dim == 0); } override StringExp toStringExp() { TY telem = type.nextOf().toBasetype().ty; if (telem == Tchar || telem == Twchar || telem == Tdchar || (telem == Tvoid && (!elements || elements.dim == 0))) { ubyte sz = 1; if (telem == Twchar) sz = 2; else if (telem == Tdchar) sz = 4; OutBuffer buf; if (elements) { foreach (i; 0 .. elements.dim) { auto ch = getElement(i); if (ch.op != TOK.int64) return null; if (sz == 1) buf.writeByte(cast(uint)ch.toInteger()); else if (sz == 2) buf.writeword(cast(uint)ch.toInteger()); else buf.write4(cast(uint)ch.toInteger()); } } char prefix; if (sz == 1) { prefix = 'c'; buf.writeByte(0); } else if (sz == 2) { prefix = 'w'; buf.writeword(0); } else { prefix = 'd'; buf.write4(0); } const(size_t) len = buf.offset / sz - 1; auto se = new StringExp(loc, buf.extractData(), len, prefix); se.sz = sz; se.type = type; return se; } return null; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * [ key0 : value0, key1 : value1, ... ] * * http://dlang.org/spec/expression.html#associative_array_literals */ extern (C++) final class AssocArrayLiteralExp : Expression { Expressions* keys; Expressions* values; OwnedBy ownedByCtfe = OwnedBy.code; extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) { super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp)); assert(keys.dim == values.dim); this.keys = keys; this.values = values; } override bool equals(RootObject o) { if (this == o) return true; if (o && o.dyncast() == DYNCAST.expression && (cast(Expression)o).op == TOK.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)o; if (keys.dim != ae.keys.dim) return false; size_t count = 0; foreach (i, key; *keys) { foreach (j, akey; *ae.keys) { if (key.equals(akey)) { if (!(*values)[i].equals((*ae.values)[j])) return false; ++count; } } } return count == keys.dim; } return false; } override Expression syntaxCopy() { return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values)); } override bool isBool(bool result) { size_t dim = keys.dim; return result ? (dim != 0) : (dim == 0); } override void accept(Visitor v) { v.visit(this); } } enum stageScrub = 0x1; /// scrubReturnValue is running enum stageSearchPointers = 0x2; /// hasNonConstPointers is running enum stageOptimize = 0x4; /// optimize is running enum stageApply = 0x8; /// apply is running enum stageInlineScan = 0x10; /// inlineScan is running enum stageToCBuffer = 0x20; /// toCBuffer is running /*********************************************************** * sd( e1, e2, e3, ... ) */ extern (C++) final class StructLiteralExp : Expression { StructDeclaration sd; /// which aggregate this is for Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip Type stype; /// final type of result (can be different from sd's type) bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol Symbol* sym; /// back end symbol to initialize with literal OwnedBy ownedByCtfe = OwnedBy.code; /** pointer to the origin instance of the expression. * once a new expression is created, origin is set to 'this'. * anytime when an expression copy is created, 'origin' pointer is set to * 'origin' pointer value of the original expression. */ StructLiteralExp origin; /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp inlinecopy; /** anytime when recursive function is calling, 'stageflags' marks with bit flag of * current stage and unmarks before return from this function. * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' * (with infinite recursion) of this expression. */ int stageflags; extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) { super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp)); this.sd = sd; if (!elements) elements = new Expressions(); this.elements = elements; this.stype = stype; this.origin = this; //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars()); } static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null) { return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype); } override bool equals(RootObject o) { if (this == o) return true; if (o && o.dyncast() == DYNCAST.expression && (cast(Expression)o).op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)o; if (!type.equals(se.type)) return false; if (elements.dim != se.elements.dim) return false; foreach (i, e1; *elements) { Expression e2 = (*se.elements)[i]; if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) return false; } return true; } return false; } override Expression syntaxCopy() { auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype); exp.origin = this; return exp; } /************************************** * Gets expression at offset of type. * Returns NULL if not found. */ Expression getField(Type type, uint offset) { //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", // /*toChars()*/"", type.toChars(), offset); Expression e = null; int i = getFieldIndex(type, offset); if (i != -1) { //printf("\ti = %d\n", i); if (i == sd.fields.dim - 1 && sd.isNested()) return null; assert(i < elements.dim); e = (*elements)[i]; if (e) { //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars()); /* If type is a static array, and e is an initializer for that array, * then the field initializer should be an array literal of e. */ if (e.type.castMod(0) != type.castMod(0) && type.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)type; size_t length = cast(size_t)tsa.dim.toInteger(); auto z = new Expressions(length); foreach (ref q; *z) q = e.copy(); e = new ArrayLiteralExp(loc, type, z); } else { e = e.copy(); e.type = type; } if (useStaticInit && e.op == TOK.structLiteral && e.type.needsNested()) { StructLiteralExp se = cast(StructLiteralExp)e; se.useStaticInit = true; } } } return e; } /************************************ * Get index of field. * Returns -1 if not found. */ int getFieldIndex(Type type, uint offset) { /* Find which field offset is by looking at the field offsets */ if (elements.dim) { foreach (i, v; sd.fields) { if (offset == v.offset && type.size() == v.type.size()) { /* context field might not be filled. */ if (i == sd.fields.dim - 1 && sd.isNested()) return cast(int)i; Expression e = (*elements)[i]; if (e) { return cast(int)i; } break; } } } return -1; } override Expression addDtorHook(Scope* sc) { /* If struct requires a destructor, rewrite as: * (S tmp = S()),tmp * so that the destructor can be hung on tmp. */ if (sd.dtor && sc.func) { /* Make an identifier for the temporary of the form: * __sl%s%d, where %s is the struct name */ const(size_t) len = 10; char[len + 1] buf; buf[len] = 0; strcpy(buf.ptr, "__sl"); strncat(buf.ptr, sd.ident.toChars(), len - 4 - 1); assert(buf[len] == 0); auto tmp = copyToTemp(0, buf.ptr, this); Expression ae = new DeclarationExp(loc, tmp); Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp)); e = e.expressionSemantic(sc); return e; } return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Mainly just a placeholder */ extern (C++) final class TypeExp : Expression { extern (D) this(const ref Loc loc, Type type) { super(loc, TOK.type, __traits(classInstanceSize, TypeExp)); //printf("TypeExp::TypeExp(%s)\n", type.toChars()); this.type = type; } override Expression syntaxCopy() { return new TypeExp(loc, type.syntaxCopy()); } override bool checkType() { error("type `%s` is not an expression", toChars()); return true; } override bool checkValue() { error("type `%s` has no value", toChars()); return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Mainly just a placeholder of * Package, Module, Nspace, and TemplateInstance (including TemplateMixin) * * A template instance that requires IFTI: * foo!tiargs(fargs) // foo!tiargs * is left until CallExp::semantic() or resolveProperties() */ extern (C++) final class ScopeExp : Expression { ScopeDsymbol sds; extern (D) this(const ref Loc loc, ScopeDsymbol sds) { super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp)); //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars()); //static int count; if (++count == 38) *(char*)0=0; this.sds = sds; assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp } override Expression syntaxCopy() { return new ScopeExp(loc, cast(ScopeDsymbol)sds.syntaxCopy(null)); } override bool checkType() { if (sds.isPackage()) { error("%s `%s` has no type", sds.kind(), sds.toChars()); return true; } if (auto ti = sds.isTemplateInstance()) { //assert(ti.needsTypeInference(sc)); if (ti.tempdecl && ti.semantictiargsdone && ti.semanticRun == PASS.init) { error("partial %s `%s` has no type", sds.kind(), toChars()); return true; } } return false; } override bool checkValue() { error("%s `%s` has no value", sds.kind(), sds.toChars()); return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Mainly just a placeholder */ extern (C++) final class TemplateExp : Expression { TemplateDeclaration td; FuncDeclaration fd; extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) { super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp)); //printf("TemplateExp(): %s\n", td.toChars()); this.td = td; this.fd = fd; } override bool isLvalue() { return fd !is null; } override Expression toLvalue(Scope* sc, Expression e) { if (!fd) return Expression.toLvalue(sc, e); assert(sc); return resolve(loc, sc, fd, true); } override bool checkType() { error("%s `%s` has no type", td.kind(), toChars()); return true; } override bool checkValue() { error("%s `%s` has no value", td.kind(), toChars()); return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * thisexp.new(newargs) newtype(arguments) */ extern (C++) final class NewExp : Expression { Expression thisexp; // if !=null, 'this' for class being allocated Expressions* newargs; // Array of Expression's to call new operator Type newtype; Expressions* arguments; // Array of Expression's Expression argprefix; // expression to be evaluated just before arguments[] CtorDeclaration member; // constructor function NewDeclaration allocator; // allocator function bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) { super(loc, TOK.new_, __traits(classInstanceSize, NewExp)); this.thisexp = thisexp; this.newargs = newargs; this.newtype = newtype; this.arguments = arguments; } static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) { return new NewExp(loc, thisexp, newargs, newtype, arguments); } override Expression syntaxCopy() { return new NewExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), newtype.syntaxCopy(), arraySyntaxCopy(arguments)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * thisexp.new(newargs) class baseclasses { } (arguments) */ extern (C++) final class NewAnonClassExp : Expression { Expression thisexp; // if !=null, 'this' for class being allocated Expressions* newargs; // Array of Expression's to call new operator ClassDeclaration cd; // class being instantiated Expressions* arguments; // Array of Expression's to call class constructor extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments) { super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp)); this.thisexp = thisexp; this.newargs = newargs; this.cd = cd; this.arguments = arguments; } override Expression syntaxCopy() { return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cast(ClassDeclaration)cd.syntaxCopy(null), arraySyntaxCopy(arguments)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class SymbolExp : Expression { Declaration var; bool hasOverloads; extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads) { super(loc, op, size); assert(var); this.var = var; this.hasOverloads = hasOverloads; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Offset from symbol */ extern (C++) final class SymOffExp : SymbolExp { dinteger_t offset; extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true) { if (auto v = var.isVarDeclaration()) { // FIXME: This error report will never be handled anyone. // It should be done before the SymOffExp construction. if (v.needThis()) .error(loc, "need `this` for address of `%s`", v.toChars()); hasOverloads = false; } super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads); this.offset = offset; } override bool isBool(bool result) { return result ? true : false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Variable */ extern (C++) final class VarExp : SymbolExp { extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) { if (var.isVarDeclaration()) hasOverloads = false; super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads); //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars()); //if (strcmp(var.ident.toChars(), "func") == 0) assert(0); this.type = var.type; } static VarExp create(Loc loc, Declaration var, bool hasOverloads = true) { return new VarExp(loc, var, hasOverloads); } override bool equals(RootObject o) { if (this == o) return true; if ((cast(Expression)o).op == TOK.variable) { VarExp ne = cast(VarExp)o; if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var) { return true; } } return false; } override int checkModifiable(Scope* sc, int flag) { //printf("VarExp::checkModifiable %s", toChars()); assert(type); return var.checkModify(loc, sc, null, flag); } override bool isLvalue() { if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) return false; return true; } override Expression toLvalue(Scope* sc, Expression e) { if (var.storage_class & STC.manifest) { error("manifest constant `%s` cannot be modified", var.toChars()); return new ErrorExp(); } if (var.storage_class & STC.lazy_) { error("lazy variable `%s` cannot be modified", var.toChars()); return new ErrorExp(); } if (var.ident == Id.ctfe) { error("cannot modify compiler-generated variable `__ctfe`"); return new ErrorExp(); } if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574 { error("cannot modify operator `$`"); return new ErrorExp(); } return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { //printf("VarExp::modifiableLvalue('%s')\n", var.toChars()); if (var.storage_class & STC.manifest) { error("cannot modify manifest constant `%s`", toChars()); return new ErrorExp(); } // See if this expression is a modifiable lvalue (i.e. not const) return Expression.modifiableLvalue(sc, e); } override void accept(Visitor v) { v.visit(this); } override Expression syntaxCopy() { auto ret = super.syntaxCopy(); return ret; } } /*********************************************************** * Overload Set */ extern (C++) final class OverExp : Expression { OverloadSet vars; extern (D) this(const ref Loc loc, OverloadSet s) { super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp)); //printf("OverExp(this = %p, '%s')\n", this, var.toChars()); vars = s; type = Type.tvoid; } override bool isLvalue() { return true; } override Expression toLvalue(Scope* sc, Expression e) { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Function/Delegate literal */ extern (C++) final class FuncExp : Expression { FuncLiteralDeclaration fd; TemplateDeclaration td; TOK tok; extern (D) this(const ref Loc loc, Dsymbol s) { super(loc, TOK.function_, __traits(classInstanceSize, FuncExp)); this.td = s.isTemplateDeclaration(); this.fd = s.isFuncLiteralDeclaration(); if (td) { assert(td.literal); assert(td.members && td.members.dim == 1); fd = (*td.members)[0].isFuncLiteralDeclaration(); } tok = fd.tok; // save original kind of function/delegate/(infer) assert(fd.fbody); } override bool equals(RootObject o) { if (this == o) return true; if (o.dyncast() != DYNCAST.expression) return false; if ((cast(Expression)o).op == TOK.function_) { FuncExp fe = cast(FuncExp)o; return fd == fe.fd; } return false; } extern (D) void genIdent(Scope* sc) { if (fd.ident == Id.empty) { const(char)* s; if (fd.fes) s = "__foreachbody"; else if (fd.tok == TOK.reserved) s = "__lambda"; else if (fd.tok == TOK.delegate_) s = "__dgliteral"; else s = "__funcliteral"; DsymbolTable symtab; if (FuncDeclaration func = sc.parent.isFuncDeclaration()) { if (func.localsymtab is null) { // Inside template constraint, symtab is not set yet. // Initialize it lazily. func.localsymtab = new DsymbolTable(); } symtab = func.localsymtab; } else { ScopeDsymbol sds = sc.parent.isScopeDsymbol(); if (!sds.symtab) { // Inside template constraint, symtab may not be set yet. // Initialize it lazily. assert(sds.isTemplateInstance()); sds.symtab = new DsymbolTable(); } symtab = sds.symtab; } assert(symtab); Identifier id = Identifier.generateId(s, symtab.len() + 1); fd.ident = id; if (td) td.ident = id; symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd); } } override Expression syntaxCopy() { if (td) return new FuncExp(loc, td.syntaxCopy(null)); else if (fd.semanticRun == PASS.init) return new FuncExp(loc, fd.syntaxCopy(null)); else // https://issues.dlang.org/show_bug.cgi?id=13481 // Prevent multiple semantic analysis of lambda body. return new FuncExp(loc, fd); } extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0) { //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars()); if (presult) *presult = null; TypeFunction tof = null; if (to.ty == Tdelegate) { if (tok == TOK.function_) { if (!flag) error("cannot match function literal to delegate type `%s`", to.toChars()); return MATCH.nomatch; } tof = cast(TypeFunction)to.nextOf(); } else if (to.ty == Tpointer && to.nextOf().ty == Tfunction) { if (tok == TOK.delegate_) { if (!flag) error("cannot match delegate literal to function pointer type `%s`", to.toChars()); return MATCH.nomatch; } tof = cast(TypeFunction)to.nextOf(); } if (td) { if (!tof) { L1: if (!flag) error("cannot infer parameter types from `%s`", to.toChars()); return MATCH.nomatch; } // Parameter types inference from 'tof' assert(td._scope); TypeFunction tf = cast(TypeFunction)fd.type; //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); size_t dim = Parameter.dim(tf.parameters); if (Parameter.dim(tof.parameters) != dim || tof.varargs != tf.varargs) goto L1; auto tiargs = new Objects(); tiargs.reserve(td.parameters.dim); foreach (tp; *td.parameters) { size_t u = 0; for (; u < dim; u++) { Parameter p = Parameter.getNth(tf.parameters, u); if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) { break; } } assert(u < dim); Parameter pto = Parameter.getNth(tof.parameters, u); Type t = pto.type; if (t.ty == Terror) goto L1; tiargs.push(t); } // Set target of return type inference if (!tf.next && tof.next) fd.treq = to; auto ti = new TemplateInstance(loc, td, tiargs); Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope); // Reset inference target for the later re-semantic fd.treq = null; if (ex.op == TOK.error) return MATCH.nomatch; if (ex.op != TOK.function_) goto L1; return (cast(FuncExp)ex).matchType(to, sc, presult, flag); } if (!tof || !tof.next) return MATCH.nomatch; assert(type && type != Type.tvoid); TypeFunction tfx = cast(TypeFunction)fd.type; bool convertMatch = (type.ty != to.ty); if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert) { /* If return type is inferred and covariant return, * tweak return statements to required return type. * * interface I {} * class C : Object, I{} * * I delegate() dg = delegate() { return new class C(); } */ convertMatch = true; auto tfy = new TypeFunction(tfx.parameters, tof.next, tfx.varargs, tfx.linkage, STC.undefined_); tfy.mod = tfx.mod; tfy.isnothrow = tfx.isnothrow; tfy.isnogc = tfx.isnogc; tfy.purity = tfx.purity; tfy.isproperty = tfx.isproperty; tfy.isref = tfx.isref; tfy.iswild = tfx.iswild; tfy.deco = tfy.merge().deco; tfx = tfy; } Type tx; if (tok == TOK.delegate_ || tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) { // Allow conversion from implicit function pointer to delegate tx = new TypeDelegate(tfx); tx.deco = tx.merge().deco; } else { assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer); tx = tfx.pointerTo(); } //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); MATCH m = tx.implicitConvTo(to); if (m > MATCH.nomatch) { // MATCH.exact: exact type match // MATCH.constant: covairiant type match (eg. attributes difference) // MATCH.convert: context conversion m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant; if (presult) { (*presult) = cast(FuncExp)copy(); (*presult).type = to; // https://issues.dlang.org/show_bug.cgi?id=12508 // Tweak function body for covariant returns. (*presult).fd.modifyReturns(sc, tof.next); } } else if (!flag) { auto ts = toAutoQualChars(tx, to); error("cannot implicitly convert expression `%s` of type `%s` to `%s`", toChars(), ts[0], ts[1]); } return m; } override const(char)* toChars() { return fd.toChars(); } override bool checkType() { if (td) { error("template lambda has no type"); return true; } return false; } override bool checkValue() { if (td) { error("template lambda has no value"); return true; } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Declaration of a symbol * * D grammar allows declarations only as statements. However in AST representation * it can be part of any expression. This is used, for example, during internal * syntax re-writes to inject hidden symbols. */ extern (C++) final class DeclarationExp : Expression { Dsymbol declaration; extern (D) this(const ref Loc loc, Dsymbol declaration) { super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp)); this.declaration = declaration; } override Expression syntaxCopy() { return new DeclarationExp(loc, declaration.syntaxCopy(null)); } override bool hasCode() { if (auto vd = declaration.isVarDeclaration()) { return !(vd.storage_class & (STC.manifest | STC.static_)); } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * typeid(int) */ extern (C++) final class TypeidExp : Expression { RootObject obj; extern (D) this(const ref Loc loc, RootObject o) { super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp)); this.obj = o; } override Expression syntaxCopy() { return new TypeidExp(loc, objectSyntaxCopy(obj)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * __traits(identifier, args...) */ extern (C++) final class TraitsExp : Expression { Identifier ident; Objects* args; extern (D) this(const ref Loc loc, Identifier ident, Objects* args) { super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp)); this.ident = ident; this.args = args; } override Expression syntaxCopy() { return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class HaltExp : Expression { extern (D) this(const ref Loc loc) { super(loc, TOK.halt, __traits(classInstanceSize, HaltExp)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * is(targ id tok tspec) * is(targ id == tok2) */ extern (C++) final class IsExp : Expression { Type targ; Identifier id; // can be null TOK tok; // ':' or '==' Type tspec; // can be null TOK tok2; // 'struct', 'union', etc. TemplateParameters* parameters; extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) { super(loc, TOK.is_, __traits(classInstanceSize, IsExp)); this.targ = targ; this.id = id; this.tok = tok; this.tspec = tspec; this.tok2 = tok2; this.parameters = parameters; } override Expression syntaxCopy() { // This section is identical to that in TemplateDeclaration::syntaxCopy() TemplateParameters* p = null; if (parameters) { p = new TemplateParameters(parameters.dim); foreach (i, el; *parameters) (*p)[i] = el.syntaxCopy(); } return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) abstract class UnaExp : Expression { Expression e1; Type att1; // Save alias this type to detect recursion extern (D) this(const ref Loc loc, TOK op, int size, Expression e1) { super(loc, op, size); this.e1 = e1; } override Expression syntaxCopy() { UnaExp e = cast(UnaExp)copy(); e.type = null; e.e1 = e.e1.syntaxCopy(); return e; } /******************************** * The type for a unary expression is incompatible. * Print error message. * Returns: * ErrorExp */ final Expression incompatibleTypes() { if (e1.type.toBasetype() == Type.terror) return e1; if (e1.op == TOK.type) { error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op)); } else { error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars()); } return new ErrorExp(); } /********************* * Mark the operand as will never be dereferenced, * which is useful info for @safe checks. * Do before semantic() on operands rewrites them. */ final void setNoderefOperand() { if (e1.op == TOK.dotIdentifier) (cast(DotIdExp)e1).noderef = true; } override final Expression resolveLoc(const ref Loc loc, Scope* sc) { e1 = e1.resolveLoc(loc, sc); return this; } override void accept(Visitor v) { v.visit(this); } } alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression); alias fp2_t = int function(const ref Loc loc, TOK, Expression, Expression); /*********************************************************** */ extern (C++) abstract class BinExp : Expression { Expression e1; Expression e2; Type att1; // Save alias this type to detect recursion Type att2; // Save alias this type to detect recursion extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2) { super(loc, op, size); this.e1 = e1; this.e2 = e2; } override Expression syntaxCopy() { BinExp e = cast(BinExp)copy(); e.type = null; e.e1 = e.e1.syntaxCopy(); e.e2 = e.e2.syntaxCopy(); return e; } /******************************** * The types for a binary expression are incompatible. * Print error message. * Returns: * ErrorExp */ final Expression incompatibleTypes() { if (e1.type.toBasetype() == Type.terror) return e1; if (e2.type.toBasetype() == Type.terror) return e2; // CondExp uses 'a ? b : c' but we're comparing 'b : c' TOK thisOp = (op == TOK.question) ? TOK.colon : op; if (e1.op == TOK.type || e2.op == TOK.type) { error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types", e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op)); } else if (e1.type.equals(e2.type)) { error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`", e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars()); } else { auto ts = toAutoQualChars(e1.type, e2.type); error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`", e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]); } return new ErrorExp(); } extern (D) final Expression checkOpAssignTypes(Scope* sc) { // At that point t1 and t2 are the merged types. type is the original type of the lhs. Type t1 = e1.type; Type t2 = e2.type; // T opAssign floating yields a floating. Prevent truncating conversions (float to int). // See issue 3841. // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? if (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign) { if ((type.isintegral() && t2.isfloating())) { warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars()); } } // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign) { // Any multiplication by an imaginary or complex number yields a complex result. // r *= c, i*=c, r*=i, i*=i are all forbidden operations. const(char)* opstr = Token.toChars(op); if (t1.isreal() && t2.iscomplex()) { error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); return new ErrorExp(); } else if (t1.isimaginary() && t2.iscomplex()) { error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); return new ErrorExp(); } else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) { error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars()); return new ErrorExp(); } } // generate an error if this is a nonsensical += or -=, eg real += imaginary if (op == TOK.addAssign || op == TOK.minAssign) { // Addition or subtraction of a real and an imaginary is a complex result. // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) { error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars()); return new ErrorExp(); } if (type.isreal() || type.isimaginary()) { assert(global.errors || t2.isfloating()); e2 = e2.castTo(sc, t1); } } if (op == TOK.mulAssign) { if (t2.isfloating()) { if (t1.isreal()) { if (t2.isimaginary() || t2.iscomplex()) { e2 = e2.castTo(sc, t1); } } else if (t1.isimaginary()) { if (t2.isimaginary() || t2.iscomplex()) { switch (t1.ty) { case Timaginary32: t2 = Type.tfloat32; break; case Timaginary64: t2 = Type.tfloat64; break; case Timaginary80: t2 = Type.tfloat80; break; default: assert(0); } e2 = e2.castTo(sc, t2); } } } } else if (op == TOK.divAssign) { if (t2.isimaginary()) { if (t1.isreal()) { // x/iv = i(-x/v) // Therefore, the result is 0 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); e2.type = t1; Expression e = new AssignExp(loc, e1, e2); e.type = t1; return e; } else if (t1.isimaginary()) { Type t3; switch (t1.ty) { case Timaginary32: t3 = Type.tfloat32; break; case Timaginary64: t3 = Type.tfloat64; break; case Timaginary80: t3 = Type.tfloat80; break; default: assert(0); } e2 = e2.castTo(sc, t3); Expression e = new AssignExp(loc, e1, e2); e.type = t1; return e; } } } else if (op == TOK.modAssign) { if (t2.iscomplex()) { error("cannot perform modulo complex arithmetic"); return new ErrorExp(); } } return this; } extern (D) final bool checkIntegralBin() { bool r1 = e1.checkIntegral(); bool r2 = e2.checkIntegral(); return (r1 || r2); } extern (D) final bool checkArithmeticBin() { bool r1 = e1.checkArithmetic(); bool r2 = e2.checkArithmetic(); return (r1 || r2); } /********************* * Mark the operands as will never be dereferenced, * which is useful info for @safe checks. * Do before semantic() on operands rewrites them. */ final void setNoderefOperands() { if (e1.op == TOK.dotIdentifier) (cast(DotIdExp)e1).noderef = true; if (e2.op == TOK.dotIdentifier) (cast(DotIdExp)e2).noderef = true; } final Expression reorderSettingAAElem(Scope* sc) { BinExp be = this; if (be.e1.op != TOK.index) return be; auto ie = cast(IndexExp)be.e1; if (ie.e1.type.toBasetype().ty != Taarray) return be; /* Fix evaluation order of setting AA element * https://issues.dlang.org/show_bug.cgi?id=3825 * Rewrite: * aa[k1][k2][k3] op= val; * as: * auto ref __aatmp = aa; * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; * auto ref __aaval = val; * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment */ Expression e0; while (1) { Expression de; ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); e0 = Expression.combine(de, e0); Expression ie1 = ie.e1; if (ie1.op != TOK.index || (cast(IndexExp)ie1).e1.type.toBasetype().ty != Taarray) { break; } ie = cast(IndexExp)ie1; } assert(ie.e1.type.toBasetype().ty == Taarray); Expression de; ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); e0 = Expression.combine(de, e0); be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); return Expression.combine(e0, be); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class BinAssignExp : BinExp { extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2) { super(loc, op, size, e1, e2); } override final bool isLvalue() { return true; } override final Expression toLvalue(Scope* sc, Expression ex) { // Lvalue-ness will be handled in glue layer. return this; } override final Expression modifiableLvalue(Scope* sc, Expression e) { // should check e1.checkModifiable() ? return toLvalue(sc, this); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * https://dlang.org/spec/expression.html#mixin_expressions */ extern (C++) final class CompileExp : Expression { Expressions* exps; extern (D) this(const ref Loc loc, Expressions* exps) { super(loc, TOK.mixin_, __traits(classInstanceSize, CompileExp)); this.exps = exps; } override Expression syntaxCopy() { return new CompileExp(loc, arraySyntaxCopy(exps)); } override bool equals(RootObject o) { if (this == o) return true; if (o && o.dyncast() == DYNCAST.expression && (cast(Expression)o).op == TOK.mixin_) { CompileExp ce = cast(CompileExp)o; if (exps.dim != ce.exps.dim) return false; foreach (i, e1; *exps) { Expression e2 = (*ce.exps)[i]; if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) return false; } return true; } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ImportExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * https://dlang.org/spec/expression.html#assert_expressions */ extern (C++) final class AssertExp : UnaExp { Expression msg; extern (D) this(const ref Loc loc, Expression e, Expression msg = null) { super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e); this.msg = msg; } override Expression syntaxCopy() { return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DotIdExp : UnaExp { Identifier ident; bool noderef; // true if the result of the expression will never be dereferenced bool wantsym; // do not replace Symbol with its initializer during semantic() extern (D) this(const ref Loc loc, Expression e, Identifier ident) { super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e); this.ident = ident; } static DotIdExp create(Loc loc, Expression e, Identifier ident) { return new DotIdExp(loc, e, ident); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Mainly just a placeholder */ extern (C++) final class DotTemplateExp : UnaExp { TemplateDeclaration td; extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) { super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e); this.td = td; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DotVarExp : UnaExp { Declaration var; bool hasOverloads; extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) { if (var.isVarDeclaration()) hasOverloads = false; super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e); //printf("DotVarExp()\n"); this.var = var; this.hasOverloads = hasOverloads; } override int checkModifiable(Scope* sc, int flag) { //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type.toChars()); if (checkUnsafeAccess(sc, this, false, !flag)) return 2; if (e1.op == TOK.this_) return var.checkModify(loc, sc, e1, flag); /* https://issues.dlang.org/show_bug.cgi?id=12764 * If inside a constructor and an expression of type `this.field.var` * is encountered, where `field` is a struct declaration with * default construction disabled, we must make sure that * assigning to `var` does not imply that `field` was initialized */ if (sc.func) { auto ctd = sc.func.isCtorDeclaration(); // if inside a constructor scope and e1 of this DotVarExp // is a DotVarExp, then check if e1.e1 is a `this` identifier if (ctd && e1.op == TOK.dotVariable) { scope dve = cast(DotVarExp)e1; if (dve.e1.op == TOK.this_) { scope v = dve.var.isVarDeclaration(); /* if v is a struct member field with no initializer, no default construction * and v wasn't intialized before */ if (v && v.isField() && v.type.ty == Tstruct && !v._init && !v.ctorinit) { const sd = (cast(TypeStruct)v.type).sym; if (sd.noDefaultCtor) { /* checkModify will consider that this is an initialization * of v while it is actually an assignment of a field of v */ scope modifyLevel = v.checkModify(loc, sc, dve.e1, flag); // reflect that assigning a field of v is not initialization of v v.ctorinit = false; if (modifyLevel == 2) return 1; return modifyLevel; } } } } } //printf("\te1 = %s\n", e1.toChars()); return e1.checkModifiable(sc, flag); } override bool isLvalue() { return true; } override Expression toLvalue(Scope* sc, Expression e) { //printf("DotVarExp::toLvalue(%s)\n", toChars()); if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) { if (VarDeclaration vd = var.isVarDeclaration()) { auto ad = vd.isMember2(); if (ad && ad.fields.dim == sc.ctorflow.fieldinit.length) { foreach (i, f; ad.fields) { if (f == vd) { if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) { /* If the address of vd is taken, assume it is thereby initialized * https://issues.dlang.org/show_bug.cgi?id=15869 */ modifyFieldVar(loc, sc, vd, e1); } break; } } } } } return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { version (none) { printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); printf("e1.type = %s\n", e1.type.toChars()); printf("var.type = %s\n", var.type.toChars()); } return Expression.modifiableLvalue(sc, e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * foo.bar!(args) */ extern (C++) final class DotTemplateInstanceExp : UnaExp { TemplateInstance ti; extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs) { super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); //printf("DotTemplateInstanceExp()\n"); this.ti = new TemplateInstance(loc, name, tiargs); } extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) { super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); this.ti = ti; } override Expression syntaxCopy() { return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs)); } bool findTempDecl(Scope* sc) { static if (LOGSEMANTIC) { printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars()); } if (ti.tempdecl) return true; Expression e = new DotIdExp(loc, e1, ti.name); e = e.expressionSemantic(sc); if (e.op == TOK.dot) e = (cast(DotExp)e).e2; Dsymbol s = null; switch (e.op) { case TOK.overloadSet: s = (cast(OverExp)e).vars; break; case TOK.dotTemplateDeclaration: s = (cast(DotTemplateExp)e).td; break; case TOK.scope_: s = (cast(ScopeExp)e).sds; break; case TOK.dotVariable: s = (cast(DotVarExp)e).var; break; case TOK.variable: s = (cast(VarExp)e).var; break; default: return false; } return ti.updateTempDecl(sc, s); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DelegateExp : UnaExp { FuncDeclaration func; bool hasOverloads; extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true) { super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e); this.func = f; this.hasOverloads = hasOverloads; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DotTypeExp : UnaExp { Dsymbol sym; // symbol that represents a type extern (D) this(const ref Loc loc, Expression e, Dsymbol s) { super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e); this.sym = s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CallExp : UnaExp { Expressions* arguments; // function arguments FuncDeclaration f; // symbol to call bool directcall; // true if a virtual call is devirtualized extern (D) this(const ref Loc loc, Expression e, Expressions* exps) { super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); this.arguments = exps; } extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); } extern (D) this(const ref Loc loc, Expression e, Expression earg1) { super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); auto arguments = new Expressions(); if (earg1) { arguments.setDim(1); (*arguments)[0] = earg1; } this.arguments = arguments; } extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2) { super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); auto arguments = new Expressions(2); (*arguments)[0] = earg1; (*arguments)[1] = earg2; this.arguments = arguments; } /*********************************************************** * Instatiates a new function call expression * Params: * loc = location * fd = the declaration of the function to call * earg1 = the function argument */ extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1) { this(loc, new VarExp(loc, fd, false), earg1); this.f = fd; } static CallExp create(Loc loc, Expression e, Expressions* exps) { return new CallExp(loc, e, exps); } static CallExp create(Loc loc, Expression e) { return new CallExp(loc, e); } static CallExp create(Loc loc, Expression e, Expression earg1) { return new CallExp(loc, e, earg1); } /*********************************************************** * Creates a new function call expression * Params: * loc = location * fd = the declaration of the function to call * earg1 = the function argument */ static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1) { return new CallExp(loc, fd, earg1); } override Expression syntaxCopy() { return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); } override bool isLvalue() { Type tb = e1.type.toBasetype(); if (tb.ty == Tdelegate || tb.ty == Tpointer) tb = tb.nextOf(); if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) { if (e1.op == TOK.dotVariable) if ((cast(DotVarExp)e1).var.isCtorDeclaration()) return false; return true; // function returns a reference } return false; } override Expression toLvalue(Scope* sc, Expression e) { if (isLvalue()) return this; return Expression.toLvalue(sc, e); } override Expression addDtorHook(Scope* sc) { /* Only need to add dtor hook if it's a type that needs destruction. * Use same logic as VarDeclaration::callScopeDtor() */ if (e1.type && e1.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)e1.type; if (tf.isref) return this; } Type tv = type.baseElemOf(); if (tv.ty == Tstruct) { TypeStruct ts = cast(TypeStruct)tv; StructDeclaration sd = ts.sym; if (sd.dtor) { /* Type needs destruction, so declare a tmp * which the back end will recognize and call dtor on */ auto tmp = copyToTemp(0, "__tmpfordtor", this); auto de = new DeclarationExp(loc, tmp); auto ve = new VarExp(loc, tmp); Expression e = new CommaExp(loc, de, ve); e = e.expressionSemantic(sc); return e; } } return this; } override void accept(Visitor v) { v.visit(this); } } FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) { if (e.op == TOK.address) { auto ae1 = (cast(AddrExp)e).e1; if (ae1.op == TOK.variable) { auto ve = cast(VarExp)ae1; if (hasOverloads) *hasOverloads = ve.hasOverloads; return ve.var.isFuncDeclaration(); } if (ae1.op == TOK.dotVariable) { auto dve = cast(DotVarExp)ae1; if (hasOverloads) *hasOverloads = dve.hasOverloads; return dve.var.isFuncDeclaration(); } } else { if (e.op == TOK.symbolOffset) { auto soe = cast(SymOffExp)e; if (hasOverloads) *hasOverloads = soe.hasOverloads; return soe.var.isFuncDeclaration(); } if (e.op == TOK.delegate_) { auto dge = cast(DelegateExp)e; if (hasOverloads) *hasOverloads = dge.hasOverloads; return dge.func.isFuncDeclaration(); } } return null; } /*********************************************************** */ extern (C++) final class AddrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e); } extern (D) this(const ref Loc loc, Expression e, Type t) { this(loc, e); type = t; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e); //if (e.type) // type = ((TypePointer *)e.type).next; } extern (D) this(const ref Loc loc, Expression e, Type t) { super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e); type = t; } override int checkModifiable(Scope* sc, int flag) { if (e1.op == TOK.symbolOffset) { SymOffExp se = cast(SymOffExp)e1; return se.var.checkModify(loc, sc, null, flag); } else if (e1.op == TOK.address) { AddrExp ae = cast(AddrExp)e1; return ae.e1.checkModifiable(sc, flag); } return 1; } override bool isLvalue() { return true; } override Expression toLvalue(Scope* sc, Expression e) { return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars()); return Expression.modifiableLvalue(sc, e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class NegExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class UAddExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ComExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class NotExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { super(loc, TOK.not, __traits(classInstanceSize, NotExp), e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DeleteExp : UnaExp { bool isRAII; // true if called automatically as a result of scoped destruction extern (D) this(const ref Loc loc, Expression e, bool isRAII) { super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e); this.isRAII = isRAII; } override Expression toBoolean(Scope* sc) { error("`delete` does not give a boolean result"); return new ErrorExp(); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Possible to cast to one type while painting to another type */ extern (C++) final class CastExp : UnaExp { Type to; // type to cast to ubyte mod = cast(ubyte)~0; // MODxxxxx extern (D) this(const ref Loc loc, Expression e, Type t) { super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e); this.to = t; } /* For cast(const) and cast(immutable) */ extern (D) this(const ref Loc loc, Expression e, ubyte mod) { super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e); this.mod = mod; } override Expression syntaxCopy() { return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class VectorExp : UnaExp { TypeVector to; // the target vector type before semantic() uint dim = ~0; // number of elements in the vector extern (D) this(const ref Loc loc, Expression e, Type t) { super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e); assert(t.ty == Tvector); to = cast(TypeVector)t; } static VectorExp create(Loc loc, Expression e, Type t) { return new VectorExp(loc, e, t); } override Expression syntaxCopy() { return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy()); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * e1 [lwr .. upr] * * http://dlang.org/spec/expression.html#slice_expressions */ extern (C++) final class SliceExp : UnaExp { Expression upr; // null if implicit 0 Expression lwr; // null if implicit [length - 1] VarDeclaration lengthVar; bool upperIsInBounds; // true if upr <= e1.length bool lowerIsLessThanUpper; // true if lwr <= upr bool arrayop; // an array operation, rather than a slice /************************************************************/ extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) { super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1); this.upr = ie ? ie.upr : null; this.lwr = ie ? ie.lwr : null; } extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) { super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1); this.upr = upr; this.lwr = lwr; } override Expression syntaxCopy() { auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null); se.lengthVar = this.lengthVar; // bug7871 return se; } override int checkModifiable(Scope* sc, int flag) { //printf("SliceExp::checkModifiable %s\n", toChars()); if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice) { return e1.checkModifiable(sc, flag); } return 1; } override bool isLvalue() { /* slice expression is rvalue in default, but * conversion to reference of static array is only allowed. */ return (type && type.toBasetype().ty == Tsarray); } override Expression toLvalue(Scope* sc, Expression e) { //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); } override Expression modifiableLvalue(Scope* sc, Expression e) { error("slice expression `%s` is not a modifiable lvalue", toChars()); return this; } override bool isBool(bool result) { return e1.isBool(result); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ArrayLengthExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * e1 [ a0, a1, a2, a3 ,... ] * * http://dlang.org/spec/expression.html#index_expressions */ extern (C++) final class ArrayExp : UnaExp { Expressions* arguments; // Array of Expression's a0..an size_t currentDimension; // for opDollar VarDeclaration lengthVar; extern (D) this(const ref Loc loc, Expression e1, Expression index = null) { super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1); arguments = new Expressions(); if (index) arguments.push(index); } extern (D) this(const ref Loc loc, Expression e1, Expressions* args) { super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1); arguments = args; } override Expression syntaxCopy() { auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); ae.lengthVar = this.lengthVar; // bug7871 return ae; } override bool isLvalue() { if (type && type.toBasetype().ty == Tvoid) return false; return true; } override Expression toLvalue(Scope* sc, Expression e) { if (type && type.toBasetype().ty == Tvoid) error("`void`s have no value"); return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DotExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CommaExp : BinExp { /// This is needed because AssignExp rewrites CommaExp, hence it needs /// to trigger the deprecation. const bool isGenerated; /// Temporary variable to enable / disable deprecation of comma expression /// depending on the context. /// Since most constructor calls are rewritting, the only place where /// false will be passed will be from the parser. bool allowCommaExp; extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) { super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2); allowCommaExp = isGenerated = generated; } override int checkModifiable(Scope* sc, int flag) { return e2.checkModifiable(sc, flag); } override bool isLvalue() { return e2.isLvalue(); } override Expression toLvalue(Scope* sc, Expression e) { e2 = e2.toLvalue(sc, null); return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { e2 = e2.modifiableLvalue(sc, e); return this; } override bool isBool(bool result) { return e2.isBool(result); } override Expression toBoolean(Scope* sc) { auto ex2 = e2.toBoolean(sc); if (ex2.op == TOK.error) return ex2; e2 = ex2; type = e2.type; return this; } override Expression addDtorHook(Scope* sc) { e2 = e2.addDtorHook(sc); return this; } override void accept(Visitor v) { v.visit(this); } /** * If the argument is a CommaExp, set a flag to prevent deprecation messages * * It's impossible to know from CommaExp.semantic if the result will * be used, hence when there is a result (type != void), a deprecation * message is always emitted. * However, some construct can produce a result but won't use it * (ExpStatement and for loop increment). Those should call this function * to prevent unwanted deprecations to be emitted. * * Params: * exp = An expression that discards its result. * If the argument is null or not a CommaExp, nothing happens. */ static void allow(Expression exp) { if (exp && exp.op == TOK.comma) (cast(CommaExp)exp).allowCommaExp = true; } } /*********************************************************** * Mainly just a placeholder */ extern (C++) final class IntervalExp : Expression { Expression lwr; Expression upr; extern (D) this(const ref Loc loc, Expression lwr, Expression upr) { super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp)); this.lwr = lwr; this.upr = upr; } override Expression syntaxCopy() { return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy()); } override void accept(Visitor v) { v.visit(this); } } extern (C++) final class DelegatePtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1); } override bool isLvalue() { return e1.isLvalue(); } override Expression toLvalue(Scope* sc, Expression e) { e1 = e1.toLvalue(sc, e); return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { if (sc.func.setUnsafe()) { error("cannot modify delegate pointer in `@safe` code `%s`", toChars()); return new ErrorExp(); } return Expression.modifiableLvalue(sc, e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DelegateFuncptrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1); } override bool isLvalue() { return e1.isLvalue(); } override Expression toLvalue(Scope* sc, Expression e) { e1 = e1.toLvalue(sc, e); return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { if (sc.func.setUnsafe()) { error("cannot modify delegate function pointer in `@safe` code `%s`", toChars()); return new ErrorExp(); } return Expression.modifiableLvalue(sc, e); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * e1 [ e2 ] */ extern (C++) final class IndexExp : BinExp { VarDeclaration lengthVar; bool modifiable = false; // assume it is an rvalue bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2); //printf("IndexExp::IndexExp('%s')\n", toChars()); } override Expression syntaxCopy() { auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy()); ie.lengthVar = this.lengthVar; // bug7871 return ie; } override int checkModifiable(Scope* sc, int flag) { if (e1.type.ty == Tsarray || e1.type.ty == Taarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice) { return e1.checkModifiable(sc, flag); } return 1; } override bool isLvalue() { return true; } override Expression toLvalue(Scope* sc, Expression e) { return this; } override Expression modifiableLvalue(Scope* sc, Expression e) { //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); Expression ex = markSettingAAElem(); if (ex.op == TOK.error) return ex; return Expression.modifiableLvalue(sc, e); } Expression markSettingAAElem() { if (e1.type.toBasetype().ty == Taarray) { Type t2b = e2.type.toBasetype(); if (t2b.ty == Tarray && t2b.nextOf().isMutable()) { error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars()); return new ErrorExp(); } modifiable = true; if (e1.op == TOK.index) { Expression ex = (cast(IndexExp)e1).markSettingAAElem(); if (ex.op == TOK.error) return ex; assert(ex == e1); } } return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * For both i++ and i-- */ extern (C++) final class PostExp : BinExp { extern (D) this(TOK op, const ref Loc loc, Expression e) { super(loc, op, __traits(classInstanceSize, PostExp), e, new IntegerExp(loc, 1, Type.tint32)); assert(op == TOK.minusMinus || op == TOK.plusPlus); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * For both ++i and --i */ extern (C++) final class PreExp : UnaExp { extern (D) this(TOK op, const ref Loc loc, Expression e) { super(loc, op, __traits(classInstanceSize, PreExp), e); assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus); } override void accept(Visitor v) { v.visit(this); } } enum MemorySet { blockAssign = 1, // setting the contents of an array referenceInit = 2, // setting the reference of STC.ref_ variable } /*********************************************************** */ extern (C++) class AssignExp : BinExp { int memset; // combination of MemorySet flags /************************************************************/ /* op can be TOK.assign, TOK.construct, or TOK.blit */ extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2); } override final bool isLvalue() { // Array-op 'x[] = y[]' should make an rvalue. // Setting array length 'x.length = v' should make an rvalue. if (e1.op == TOK.slice || e1.op == TOK.arrayLength) { return false; } return true; } override final Expression toLvalue(Scope* sc, Expression ex) { if (e1.op == TOK.slice || e1.op == TOK.arrayLength) { return Expression.toLvalue(sc, ex); } /* In front-end level, AssignExp should make an lvalue of e1. * Taking the address of e1 will be handled in low level layer, * so this function does nothing. */ return this; } override final Expression toBoolean(Scope* sc) { // Things like: // if (a = b) ... // are usually mistakes. error("assignment cannot be used as a condition, perhaps `==` was meant?"); return new ErrorExp(); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ConstructExp : AssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, e1, e2); op = TOK.construct; } // Internal use only. If `v` is a reference variable, the assinment // will become a reference initialization automatically. extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) { auto ve = new VarExp(loc, v); assert(v.type && ve.type); super(loc, ve, e2); op = TOK.construct; if (v.storage_class & (STC.ref_ | STC.out_)) memset |= MemorySet.referenceInit; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class BlitExp : AssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, e1, e2); op = TOK.blit; } // Internal use only. If `v` is a reference variable, the assinment // will become a reference rebinding automatically. extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) { auto ve = new VarExp(loc, v); assert(v.type && ve.type); super(loc, ve, e2); op = TOK.blit; if (v.storage_class & (STC.ref_ | STC.out_)) memset |= MemorySet.referenceInit; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AddAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class MinAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class MulAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DivAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ModAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AndAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class OrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class XorAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PowAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ShlAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ShrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class UshrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * The ~= operator. It can have one of the following operators: * * TOK.concatenateAssign - appending T[] to T[] * TOK.concatenateElemAssign - appending T to T[] * TOK.concatenateDcharAssign - appending dchar to T[] * * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which * of the three it will be set to. */ extern (C++) final class CatAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#add_expressions */ extern (C++) final class AddExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class MinExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#cat_expressions */ extern (C++) final class CatExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#mul_expressions */ extern (C++) final class MulExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#mul_expressions */ extern (C++) final class DivExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#mul_expressions */ extern (C++) final class ModExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#pow_expressions */ extern (C++) final class PowExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ShlExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ShrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class UshrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class AndExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class OrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class XorExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * http://dlang.org/spec/expression.html#andand_expressions * http://dlang.org/spec/expression.html#oror_expressions */ extern (C++) final class LogicalExp : BinExp { extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2); assert(op == TOK.andAnd || op == TOK.orOr); } override Expression toBoolean(Scope* sc) { auto ex2 = e2.toBoolean(sc); if (ex2.op == TOK.error) return ex2; e2 = ex2; return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * `op` is one of: * TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual * * http://dlang.org/spec/expression.html#relation_expressions */ extern (C++) final class CmpExp : BinExp { extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2); assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class InExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * This deletes the key e1 from the associative array e2 */ extern (C++) final class RemoveExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2); type = Type.tbool; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * `==` and `!=` * * TOK.equal and TOK.notEqual * * http://dlang.org/spec/expression.html#equality_expressions */ extern (C++) final class EqualExp : BinExp { extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2); assert(op == TOK.equal || op == TOK.notEqual); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * `is` and `!is` * * TOK.identity and TOK.notIdentity * * http://dlang.org/spec/expression.html#identity_expressions */ extern (C++) final class IdentityExp : BinExp { extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2); assert(op == TOK.identity || op == TOK.notIdentity); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * `econd ? e1 : e2` * * http://dlang.org/spec/expression.html#conditional_expressions */ extern (C++) final class CondExp : BinExp { Expression econd; extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) { super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2); this.econd = econd; } override Expression syntaxCopy() { return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy()); } override int checkModifiable(Scope* sc, int flag) { return e1.checkModifiable(sc, flag) && e2.checkModifiable(sc, flag); } override bool isLvalue() { return e1.isLvalue() && e2.isLvalue(); } override Expression toLvalue(Scope* sc, Expression ex) { // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) CondExp e = cast(CondExp)copy(); e.e1 = e1.toLvalue(sc, null).addressOf(); e.e2 = e2.toLvalue(sc, null).addressOf(); e.type = type.pointerTo(); return new PtrExp(loc, e, type); } override Expression modifiableLvalue(Scope* sc, Expression e) { //error("conditional expression %s is not a modifiable lvalue", toChars()); e1 = e1.modifiableLvalue(sc, e1); e2 = e2.modifiableLvalue(sc, e2); return toLvalue(sc, this); } override Expression toBoolean(Scope* sc) { auto ex1 = e1.toBoolean(sc); auto ex2 = e2.toBoolean(sc); if (ex1.op == TOK.error) return ex1; if (ex2.op == TOK.error) return ex2; e1 = ex1; e2 = ex2; return this; } void hookDtors(Scope* sc) { extern (C++) final class DtorVisitor : StoppableVisitor { alias visit = typeof(super).visit; public: Scope* sc; CondExp ce; VarDeclaration vcond; bool isThen; extern (D) this(Scope* sc, CondExp ce) { this.sc = sc; this.ce = ce; } override void visit(Expression e) { //printf("(e = %s)\n", e.toChars()); } override void visit(DeclarationExp e) { auto v = e.declaration.isVarDeclaration(); if (v && !v.isDataseg()) { if (v._init) { if (auto ei = v._init.isExpInitializer()) ei.exp.accept(this); } if (v.needsScopeDtor()) { if (!vcond) { vcond = copyToTemp(STC.volatile_, "__cond", ce.econd); vcond.dsymbolSemantic(sc); Expression de = new DeclarationExp(ce.econd.loc, vcond); de = de.expressionSemantic(sc); Expression ve = new VarExp(ce.econd.loc, vcond); ce.econd = Expression.combine(de, ve); } //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); Expression ve = new VarExp(vcond.loc, vcond); if (isThen) v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor); else v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor); v.edtor = v.edtor.expressionSemantic(sc); //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); } } } } scope DtorVisitor v = new DtorVisitor(sc, this); //printf("+%s\n", toChars()); v.isThen = true; walkPostorder(e1, v); v.isThen = false; walkPostorder(e2, v); //printf("-%s\n", toChars()); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class DefaultInitExp : Expression { TOK subop; // which of the derived classes this is extern (D) this(const ref Loc loc, TOK subop, int size) { super(loc, TOK.default_, size); this.subop = subop; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class FileInitExp : DefaultInitExp { extern (D) this(const ref Loc loc, TOK tok) { super(loc, tok, __traits(classInstanceSize, FileInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) { //printf("FileInitExp::resolve() %s\n", toChars()); const(char)* s; if (subop == TOK.fileFullPath) s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.name.toChars()); else s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); Expression e = new StringExp(loc, cast(char*)s); e = e.expressionSemantic(sc); e = e.castTo(sc, type); return e; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class LineInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { super(loc, TOK.line, __traits(classInstanceSize, LineInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); e = e.castTo(sc, type); return e; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ModuleInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) { const(char)* s; if (sc.callsc) s = sc.callsc._module.toPrettyChars(); else s = sc._module.toPrettyChars(); Expression e = new StringExp(loc, cast(char*)s); e = e.expressionSemantic(sc); e = e.castTo(sc, type); return e; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class FuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) { const(char)* s; if (sc.callsc && sc.callsc.func) s = sc.callsc.func.Dsymbol.toPrettyChars(); else if (sc.func) s = sc.func.Dsymbol.toPrettyChars(); else s = ""; Expression e = new StringExp(loc, cast(char*)s); e = e.expressionSemantic(sc); e = e.castTo(sc, type); return e; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PrettyFuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) { FuncDeclaration fd; if (sc.callsc && sc.callsc.func) fd = sc.callsc.func; else fd = sc.func; const(char)* s; if (fd) { const(char)* funcStr = fd.Dsymbol.toPrettyChars(); OutBuffer buf; functionToBufferWithIdent(cast(TypeFunction)fd.type, &buf, funcStr); s = buf.extractString(); } else { s = ""; } Expression e = new StringExp(loc, cast(char*)s); e = e.expressionSemantic(sc); e = e.castTo(sc, type); return e; } override void accept(Visitor v) { v.visit(this); } } /** * Objective-C class reference expression. * * Used to get the metaclass of an Objective-C class, `NSObject.Class`. */ extern (C++) final class ObjcClassReferenceExp : Expression { ClassDeclaration classDeclaration; extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration) { super(loc, TOK.objcClassReference, __traits(classInstanceSize, ObjcClassReferenceExp)); this.classDeclaration = classDeclaration; type = objc.getRuntimeMetaclass(classDeclaration).getType(); } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/expression.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/expression.h */ #pragma once #include "complex_t.h" #include "globals.h" #include "arraytypes.h" #include "visitor.h" #include "tokens.h" #include "root/rmem.h" class Type; class TypeVector; struct Scope; class TupleDeclaration; class VarDeclaration; class FuncDeclaration; class FuncLiteralDeclaration; class CtorDeclaration; class NewDeclaration; class Dsymbol; class ScopeDsymbol; class Expression; class Declaration; class StructDeclaration; class TemplateInstance; class TemplateDeclaration; class ClassDeclaration; class OverloadSet; class StringExp; struct UnionExp; #ifdef IN_GCC typedef union tree_node Symbol; #else struct Symbol; // back end symbol #endif void expandTuples(Expressions *exps); TupleDeclaration *isAliasThisTuple(Expression *e); int expandAliasThisTuples(Expressions *exps, size_t starti = 0); bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors = false); TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); bool isTrivialExp(Expression *e); Expression *toDelegate(Expression *e, Type* t, Scope *sc); bool hasSideEffect(Expression *e); bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow); enum OwnedBy { OWNEDcode, // normal code expression in AST OWNEDctfe, // value expression for CTFE OWNEDcache // constant value cached for CTFE }; class Expression : public RootObject { public: Loc loc; // file location Type *type; // !=NULL means that semantic() has been run TOK op; // to minimize use of dynamic_cast unsigned char size; // # of bytes in Expression so we can copy() it unsigned char parens; // if this is a parenthesized expression static void _init(); Expression *copy(); virtual Expression *syntaxCopy(); // kludge for template.isExpression() int dyncast() const { return DYNCAST_EXPRESSION; } const char *toChars(); void error(const char *format, ...) const; void warning(const char *format, ...) const; void deprecation(const char *format, ...) const; virtual dinteger_t toInteger(); virtual uinteger_t toUInteger(); virtual real_t toReal(); virtual real_t toImaginary(); virtual complex_t toComplex(); virtual StringExp *toStringExp(); virtual bool isLvalue(); virtual Expression *toLvalue(Scope *sc, Expression *e); virtual Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *implicitCastTo(Scope *sc, Type *t); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); virtual Expression *resolveLoc(const Loc &loc, Scope *sc); virtual bool checkType(); virtual bool checkValue(); bool checkDeprecated(Scope *sc, Dsymbol *s); virtual int checkModifiable(Scope *sc, int flag = 0); virtual Expression *toBoolean(Scope *sc); virtual Expression *addDtorHook(Scope *sc); Expression *addressOf(); Expression *deref(); Expression *optimize(int result, bool keepLvalue = false); // Entry point for CTFE. // A compile-time result is required. Give an error if not possible Expression *ctfeInterpret(); int isConst(); virtual bool isBool(bool result); virtual bool hasCode() { return true; } virtual void accept(Visitor *v) { v->visit(this); } }; class IntegerExp : public Expression { public: dinteger_t value; static IntegerExp *create(Loc loc, dinteger_t value, Type *type); static IntegerExp *createi(Loc loc, int value, Type *type); bool equals(RootObject *o); dinteger_t toInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); bool isBool(bool result); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } dinteger_t getInteger() { return value; } void setInteger(dinteger_t value); void normalize(); }; class ErrorExp : public Expression { public: Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } static ErrorExp *errorexp; // handy shared value }; class RealExp : public Expression { public: real_t value; static RealExp *create(Loc loc, real_t value, Type *type); bool equals(RootObject *o); dinteger_t toInteger(); uinteger_t toUInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); bool isBool(bool result); void accept(Visitor *v) { v->visit(this); } }; class ComplexExp : public Expression { public: complex_t value; static ComplexExp *create(Loc loc, complex_t value, Type *type); bool equals(RootObject *o); dinteger_t toInteger(); uinteger_t toUInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); bool isBool(bool result); void accept(Visitor *v) { v->visit(this); } }; class IdentifierExp : public Expression { public: Identifier *ident; static IdentifierExp *create(Loc loc, Identifier *ident); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class DollarExp : public IdentifierExp { public: void accept(Visitor *v) { v->visit(this); } }; class DsymbolExp : public Expression { public: Dsymbol *s; bool hasOverloads; bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class ThisExp : public Expression { public: VarDeclaration *var; bool isBool(bool result); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class SuperExp : public ThisExp { public: void accept(Visitor *v) { v->visit(this); } }; class NullExp : public Expression { public: unsigned char committed; // !=0 if type is committed bool equals(RootObject *o); bool isBool(bool result); StringExp *toStringExp(); void accept(Visitor *v) { v->visit(this); } }; class StringExp : public Expression { public: void *string; // char, wchar, or dchar data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar unsigned char committed; // !=0 if type is committed utf8_t postfix; // 'c', 'w', 'd' OwnedBy ownedByCtfe; static StringExp *create(Loc loc, char *s); static StringExp *create(Loc loc, void *s, size_t len); bool equals(RootObject *o); StringExp *toStringExp(); StringExp *toUTF8(Scope *sc); int compare(RootObject *obj); bool isBool(bool result); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); unsigned charAt(uinteger_t i) const; void accept(Visitor *v) { v->visit(this); } size_t numberOfCodeUnits(int tynto = 0) const; void writeTo(void* dest, bool zero, int tyto = 0) const; char *toPtr(); }; // Tuple class TupleExp : public Expression { public: Expression *e0; // side-effect part /* Tuple-field access may need to take out its side effect part. * For example: * foo().tupleof * is rewritten as: * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...)) * The declaration of temporary variable __tup will be stored in TupleExp::e0. */ Expressions *exps; Expression *syntaxCopy(); bool equals(RootObject *o); void accept(Visitor *v) { v->visit(this); } }; class ArrayLiteralExp : public Expression { public: Expression *basis; Expressions *elements; OwnedBy ownedByCtfe; static ArrayLiteralExp *create(Loc loc, Expressions *elements); Expression *syntaxCopy(); bool equals(RootObject *o); Expression *getElement(d_size_t i); bool isBool(bool result); StringExp *toStringExp(); void accept(Visitor *v) { v->visit(this); } }; class AssocArrayLiteralExp : public Expression { public: Expressions *keys; Expressions *values; OwnedBy ownedByCtfe; bool equals(RootObject *o); Expression *syntaxCopy(); bool isBool(bool result); void accept(Visitor *v) { v->visit(this); } }; class StructLiteralExp : public Expression { public: StructDeclaration *sd; // which aggregate this is for Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip Type *stype; // final type of result (can be different from sd's type) bool useStaticInit; // if this is true, use the StructDeclaration's init symbol Symbol *sym; // back end symbol to initialize with literal OwnedBy ownedByCtfe; // pointer to the origin instance of the expression. // once a new expression is created, origin is set to 'this'. // anytime when an expression copy is created, 'origin' pointer is set to // 'origin' pointer value of the original expression. StructLiteralExp *origin; // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp *inlinecopy; // anytime when recursive function is calling, 'stageflags' marks with bit flag of // current stage and unmarks before return from this function. // 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' // (with infinite recursion) of this expression. int stageflags; static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL); bool equals(RootObject *o); Expression *syntaxCopy(); Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); Expression *addDtorHook(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class TypeExp : public Expression { public: Expression *syntaxCopy(); bool checkType(); bool checkValue(); void accept(Visitor *v) { v->visit(this); } }; class ScopeExp : public Expression { public: ScopeDsymbol *sds; Expression *syntaxCopy(); bool checkType(); bool checkValue(); void accept(Visitor *v) { v->visit(this); } }; class TemplateExp : public Expression { public: TemplateDeclaration *td; FuncDeclaration *fd; bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); bool checkType(); bool checkValue(); void accept(Visitor *v) { v->visit(this); } }; class NewExp : public Expression { public: /* thisexp.new(newargs) newtype(arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated Expressions *newargs; // Array of Expression's to call new operator Type *newtype; Expressions *arguments; // Array of Expression's Expression *argprefix; // expression to be evaluated just before arguments[] CtorDeclaration *member; // constructor function NewDeclaration *allocator; // allocator function bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments); Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class NewAnonClassExp : public Expression { public: /* thisexp.new(newargs) class baseclasses { } (arguments) */ Expression *thisexp; // if !NULL, 'this' for class being allocated Expressions *newargs; // Array of Expression's to call new operator ClassDeclaration *cd; // class being instantiated Expressions *arguments; // Array of Expression's to call class constructor Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class SymbolExp : public Expression { public: Declaration *var; bool hasOverloads; void accept(Visitor *v) { v->visit(this); } }; // Offset from symbol class SymOffExp : public SymbolExp { public: dinteger_t offset; bool isBool(bool result); void accept(Visitor *v) { v->visit(this); } }; // Variable class VarExp : public SymbolExp { public: static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true); bool equals(RootObject *o); int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; // Overload Set class OverExp : public Expression { public: OverloadSet *vars; bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; // Function/Delegate literal class FuncExp : public Expression { public: FuncLiteralDeclaration *fd; TemplateDeclaration *td; TOK tok; bool equals(RootObject *o); Expression *syntaxCopy(); const char *toChars(); bool checkType(); bool checkValue(); void accept(Visitor *v) { v->visit(this); } }; // Declaration of a symbol // D grammar allows declarations only as statements. However in AST representation // it can be part of any expression. This is used, for example, during internal // syntax re-writes to inject hidden symbols. class DeclarationExp : public Expression { public: Dsymbol *declaration; Expression *syntaxCopy(); bool hasCode(); void accept(Visitor *v) { v->visit(this); } }; class TypeidExp : public Expression { public: RootObject *obj; Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class TraitsExp : public Expression { public: Identifier *ident; Objects *args; Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class HaltExp : public Expression { public: void accept(Visitor *v) { v->visit(this); } }; class IsExp : public Expression { public: /* is(targ id tok tspec) * is(targ id == tok2) */ Type *targ; Identifier *id; // can be NULL TOK tok; // ':' or '==' Type *tspec; // can be NULL TOK tok2; // 'struct', 'union', etc. TemplateParameters *parameters; Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ class UnaExp : public Expression { public: Expression *e1; Type *att1; // Save alias this type to detect recursion Expression *syntaxCopy(); Expression *incompatibleTypes(); Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class BinExp : public Expression { public: Expression *e1; Expression *e2; Type *att1; // Save alias this type to detect recursion Type *att2; // Save alias this type to detect recursion Expression *syntaxCopy(); Expression *incompatibleTypes(); Expression *reorderSettingAAElem(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class BinAssignExp : public BinExp { public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *ex); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ class CompileExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class ImportExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class AssertExp : public UnaExp { public: Expression *msg; Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class DotIdExp : public UnaExp { public: Identifier *ident; bool noderef; // true if the result of the expression will never be dereferenced bool wantsym; // do not replace Symbol with its initializer during semantic() static DotIdExp *create(Loc loc, Expression *e, Identifier *ident); void accept(Visitor *v) { v->visit(this); } }; class DotTemplateExp : public UnaExp { public: TemplateDeclaration *td; void accept(Visitor *v) { v->visit(this); } }; class DotVarExp : public UnaExp { public: Declaration *var; bool hasOverloads; int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class DotTemplateInstanceExp : public UnaExp { public: TemplateInstance *ti; Expression *syntaxCopy(); bool findTempDecl(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class DelegateExp : public UnaExp { public: FuncDeclaration *func; bool hasOverloads; void accept(Visitor *v) { v->visit(this); } }; class DotTypeExp : public UnaExp { public: Dsymbol *sym; // symbol that represents a type void accept(Visitor *v) { v->visit(this); } }; class CallExp : public UnaExp { public: Expressions *arguments; // function arguments FuncDeclaration *f; // symbol to call bool directcall; // true if a virtual call is devirtualized static CallExp *create(Loc loc, Expression *e, Expressions *exps); static CallExp *create(Loc loc, Expression *e); static CallExp *create(Loc loc, Expression *e, Expression *earg1); static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1); Expression *syntaxCopy(); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *addDtorHook(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class AddrExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class PtrExp : public UnaExp { public: int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class NegExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class UAddExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class ComExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class NotExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class DeleteExp : public UnaExp { public: bool isRAII; Expression *toBoolean(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class CastExp : public UnaExp { public: // Possible to cast to one type while painting to another type Type *to; // type to cast to unsigned char mod; // MODxxxxx Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class VectorExp : public UnaExp { public: TypeVector *to; // the target vector type before semantic() unsigned dim; // number of elements in the vector static VectorExp *create(Loc loc, Expression *e, Type *t); Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class SliceExp : public UnaExp { public: Expression *upr; // NULL if implicit 0 Expression *lwr; // NULL if implicit [length - 1] VarDeclaration *lengthVar; bool upperIsInBounds; // true if upr <= e1.length bool lowerIsLessThanUpper; // true if lwr <= upr bool arrayop; // an array operation, rather than a slice Expression *syntaxCopy(); int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); bool isBool(bool result); void accept(Visitor *v) { v->visit(this); } }; class ArrayLengthExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; class IntervalExp : public Expression { public: Expression *lwr; Expression *upr; Expression *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class DelegatePtrExp : public UnaExp { public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; class DelegateFuncptrExp : public UnaExp { public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; // e1[a0,a1,a2,a3,...] class ArrayExp : public UnaExp { public: Expressions *arguments; // Array of Expression's size_t currentDimension; // for opDollar VarDeclaration *lengthVar; Expression *syntaxCopy(); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ class DotExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class CommaExp : public BinExp { public: bool isGenerated; bool allowCommaExp; int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); bool isBool(bool result); Expression *toBoolean(Scope *sc); Expression *addDtorHook(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class IndexExp : public BinExp { public: VarDeclaration *lengthVar; bool modifiable; bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 Expression *syntaxCopy(); int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *markSettingAAElem(); void accept(Visitor *v) { v->visit(this); } }; /* For both i++ and i-- */ class PostExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; /* For both ++i and --i */ class PreExp : public UnaExp { public: void accept(Visitor *v) { v->visit(this); } }; enum MemorySet { blockAssign = 1, // setting the contents of an array referenceInit = 2 // setting the reference of STCref variable }; class AssignExp : public BinExp { public: int memset; // combination of MemorySet flags bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *ex); Expression *toBoolean(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class ConstructExp : public AssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class BlitExp : public AssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class AddAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class MinAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class MulAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class DivAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class ModAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class AndAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class OrAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class XorAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class PowAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class ShlAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class ShrAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class UshrAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class CatAssignExp : public BinAssignExp { public: void accept(Visitor *v) { v->visit(this); } }; class AddExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class MinExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class CatExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class MulExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class DivExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class ModExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class PowExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class ShlExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class ShrExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class UshrExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class AndExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class OrExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class XorExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class LogicalExp : public BinExp { public: Expression *toBoolean(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class CmpExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class InExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; class RemoveExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; // == and != class EqualExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; // is and !is class IdentityExp : public BinExp { public: void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ class CondExp : public BinExp { public: Expression *econd; Expression *syntaxCopy(); int checkModifiable(Scope *sc, int flag); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *toBoolean(Scope *sc); void hookDtors(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ class DefaultInitExp : public Expression { public: TOK subop; // which of the derived classes this is void accept(Visitor *v) { v->visit(this); } }; class FileInitExp : public DefaultInitExp { public: Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class LineInitExp : public DefaultInitExp { public: Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class ModuleInitExp : public DefaultInitExp { public: Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class FuncInitExp : public DefaultInitExp { public: Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class PrettyFuncInitExp : public DefaultInitExp { public: Expression *resolveLoc(const Loc &loc, Scope *sc); void accept(Visitor *v) { v->visit(this); } }; /****************************************************************/ /* A type meant as a union of all the Expression types, * to serve essentially as a Variant that will sit on the stack * during CTFE to reduce memory consumption. */ struct UnionExp { UnionExp() { } // yes, default constructor does nothing UnionExp(Expression *e) { memcpy(this, (void *)e, e->size); } /* Extract pointer to Expression */ Expression *exp() { return (Expression *)&u; } /* Convert to an allocated Expression */ Expression *copy(); private: union { char exp [sizeof(Expression)]; char integerexp[sizeof(IntegerExp)]; char errorexp [sizeof(ErrorExp)]; char realexp [sizeof(RealExp)]; char complexexp[sizeof(ComplexExp)]; char symoffexp [sizeof(SymOffExp)]; char stringexp [sizeof(StringExp)]; char arrayliteralexp [sizeof(ArrayLiteralExp)]; char assocarrayliteralexp [sizeof(AssocArrayLiteralExp)]; char structliteralexp [sizeof(StructLiteralExp)]; char nullexp [sizeof(NullExp)]; char dotvarexp [sizeof(DotVarExp)]; char addrexp [sizeof(AddrExp)]; char indexexp [sizeof(IndexExp)]; char sliceexp [sizeof(SliceExp)]; // Ensure that the union is suitably aligned. real_t for_alignment_only; } u; }; /****************************************************************/ class ObjcClassReferenceExp : public Expression { ClassDeclaration* classDeclaration; void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/expressionsem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/expressionsem.d, _expressionsem.d) * Documentation: https://dlang.org/phobos/dmd_expressionsem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d */ module dmd.expressionsem; import core.stdc.stdio; import dmd.access; import dmd.aggregate; import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.attrib; import dmd.astcodegen; import dmd.canthrow; import dmd.ctorflow; import dmd.dscope; import dmd.dsymbol; import dmd.declaration; import dmd.dclass; import dmd.dcast; import dmd.delegatize; import dmd.denum; import dmd.dimport; import dmd.dinterpret; import dmd.dmangle; import dmd.dmodule; import dmd.dstruct; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.imphint; import dmd.inline; import dmd.intrange; import dmd.mtype; import dmd.nspace; import dmd.opover; import dmd.optimize; import dmd.parse; import dmd.root.ctfloat; import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.semantic2; import dmd.semantic3; import dmd.sideeffect; import dmd.safe; import dmd.target; import dmd.tokens; import dmd.traits; import dmd.typesem; import dmd.typinf; import dmd.utf; import dmd.utils; import dmd.visitor; enum LOGSEMANTIC = false; /*********************************************************** * Resolve `exp` as a compile-time known string. * Params: * sc = scope * exp = Expression which expected as a string * s = What the string is expected for, will be used in error diagnostic. * Returns: * String literal, or `null` if error happens. */ StringExp semanticString(Scope *sc, Expression exp, const char* s) { sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); exp = resolveProperties(sc, exp); sc = sc.endCTFE(); if (exp.op == TOK.error) return null; auto e = exp; if (exp.type.isString()) { e = e.ctfeInterpret(); if (e.op == TOK.error) return null; } auto se = e.toStringExp(); if (!se) { exp.error("`string` expected for %s, not `(%s)` of type `%s`", s, exp.toChars(), exp.type.toChars()); return null; } return se; } private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) { Expression e0; Expression e1 = Expression.extractLast(ue.e1, e0); // https://issues.dlang.org/show_bug.cgi?id=12585 // Extract the side effect part if ue.e1 is comma. if (!isTrivialExp(e1)) { /* Even if opDollar is needed, 'e1' should be evaluate only once. So * Rewrite: * e1.opIndex( ... use of $ ... ) * e1.opSlice( ... use of $ ... ) * as: * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...) * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...) */ e1 = extractSideEffect(sc, "__dop", e0, e1, false); assert(e1.op == TOK.variable); VarExp ve = cast(VarExp)e1; ve.var.storage_class |= STC.exptemp; // lifetime limited to expression } ue.e1 = e1; return e0; } /************************************** * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. */ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) { assert(!ae.lengthVar); *pe0 = null; AggregateDeclaration ad = isAggregate(ae.e1.type); Dsymbol slice = search_function(ad, Id.slice); //printf("slice = %s %s\n", slice.kind(), slice.toChars()); foreach (i, e; *ae.arguments) { if (i == 0) *pe0 = extractOpDollarSideEffect(sc, ae); if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration())) { Lfallback: if (ae.arguments.dim == 1) return null; ae.error("multi-dimensional slicing requires template `opSlice`"); return new ErrorExp(); } //printf("[%d] e = %s\n", i, e.toChars()); // Create scope for '$' variable for this dimension auto sym = new ArrayScopeSymbol(sc, ae); sym.loc = ae.loc; sym.parent = sc.scopesym; sc = sc.push(sym); ae.lengthVar = null; // Create it only if required ae.currentDimension = i; // Dimension for $, if required e = e.expressionSemantic(sc); e = resolveProperties(sc, e); if (ae.lengthVar && sc.func) { // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); *pe0 = Expression.combine(*pe0, de); } sc = sc.pop(); if (e.op == TOK.interval) { IntervalExp ie = cast(IntervalExp)e; auto tiargs = new Objects(); Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); edim = edim.expressionSemantic(sc); tiargs.push(edim); auto fargs = new Expressions(); fargs.push(ie.lwr); fargs.push(ie.upr); uint xerrors = global.startGagging(); sc = sc.push(); FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, 1); sc = sc.pop(); global.endGagging(xerrors); if (!fslice) goto Lfallback; e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); e = new CallExp(ae.loc, e, fargs); e = e.expressionSemantic(sc); } if (!e.type) { ae.error("`%s` has no value", e.toChars()); e = new ErrorExp(); } if (e.op == TOK.error) return e; (*ae.arguments)[i] = e; } return ae; } /************************************** * Runs semantic on se.lwr and se.upr. Declares a temporary variable * if '$' was used. */ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) { //assert(!ae.lengthVar); if (!ie) return ae; VarDeclaration lengthVar = ae.lengthVar; // create scope for '$' auto sym = new ArrayScopeSymbol(sc, ae); sym.loc = ae.loc; sym.parent = sc.scopesym; sc = sc.push(sym); foreach (i; 0 .. 2) { Expression e = i == 0 ? ie.lwr : ie.upr; e = e.expressionSemantic(sc); e = resolveProperties(sc, e); if (!e.type) { ae.error("`%s` has no value", e.toChars()); return new ErrorExp(); } (i == 0 ? ie.lwr : ie.upr) = e; } if (lengthVar != ae.lengthVar && sc.func) { // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); *pe0 = Expression.combine(*pe0, de); } sc = sc.pop(); return ae; } /****************************** * Perform semantic() on an array of Expressions. */ extern (C++) bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false) { bool err = false; if (exps) { foreach (ref e; *exps) { if (e) { auto e2 = e.expressionSemantic(sc); if (e2.op == TOK.error) err = true; if (preserveErrors || e2.op != TOK.error) e = e2; } } } return err; } /****************************** * Check the tail CallExp is really property function call. * Bugs: * This doesn't appear to do anything. */ private bool checkPropertyCall(Expression e) { e = lastComma(e); if (e.op == TOK.call) { CallExp ce = cast(CallExp)e; TypeFunction tf; if (ce.f) { tf = cast(TypeFunction)ce.f.type; /* If a forward reference to ce.f, try to resolve it */ if (!tf.deco && ce.f.semanticRun < PASS.semanticdone) { ce.f.dsymbolSemantic(null); tf = cast(TypeFunction)ce.f.type; } } else if (ce.e1.type.ty == Tfunction) tf = cast(TypeFunction)ce.e1.type; else if (ce.e1.type.ty == Tdelegate) tf = cast(TypeFunction)ce.e1.type.nextOf(); else if (ce.e1.type.ty == Tpointer && ce.e1.type.nextOf().ty == Tfunction) tf = cast(TypeFunction)ce.e1.type.nextOf(); else assert(0); } return false; } /****************************** * Find symbol in accordance with the UFCS name look up rule */ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) { //printf("searchUFCS(ident = %s)\n", ident.toChars()); Loc loc = ue.loc; // TODO: merge with Scope.search.searchScopes() Dsymbol searchScopes(int flags) { Dsymbol s = null; for (Scope* scx = sc; scx; scx = scx.enclosing) { if (!scx.scopesym) continue; if (scx.scopesym.isModule()) flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed s = scx.scopesym.search(loc, ident, flags); if (s) { // overload set contains only module scope symbols. if (s.isOverloadSet()) break; // selective/renamed imports also be picked up if (AliasDeclaration ad = s.isAliasDeclaration()) { if (ad._import) break; } // See only module scope symbols for UFCS target. Dsymbol p = s.toParent2(); if (p && p.isModule()) break; } s = null; // Stop when we hit a module, but keep going if that is not just under the global scope if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) break; } return s; } int flags = 0; Dsymbol s; if (sc.flags & SCOPE.ignoresymbolvisibility) flags |= IgnoreSymbolVisibility; Dsymbol sold = void; if (global.params.bug10378 || global.params.check10378) { sold = searchScopes(flags | IgnoreSymbolVisibility); if (!global.params.check10378) { s = sold; goto Lsearchdone; } } // First look in local scopes s = searchScopes(flags | SearchLocalsOnly); if (!s) { // Second look in imported modules s = searchScopes(flags | SearchImportsOnly); /** Still find private symbols, so that symbols that weren't access * checked by the compiler remain usable. Once the deprecation is over, * this should be moved to search_correct instead. */ if (!s && !(flags & IgnoreSymbolVisibility)) { s = searchScopes(flags | SearchLocalsOnly | IgnoreSymbolVisibility); if (!s) s = searchScopes(flags | SearchImportsOnly | IgnoreSymbolVisibility); if (s) .deprecation(loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), sc._module.toChars()); } } if (global.params.check10378) { alias snew = s; if (sold !is snew) Scope.deprecation10378(loc, sold, snew); if (global.params.bug10378) s = sold; } Lsearchdone: if (!s) return ue.e1.type.Type.getProperty(loc, ident, 0); FuncDeclaration f = s.isFuncDeclaration(); if (f) { TemplateDeclaration td = getFuncTemplateDecl(f); if (td) { if (td.overroot) td = td.overroot; s = td; } } if (ue.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ue; auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); if (!ti.updateTempDecl(sc, s)) return new ErrorExp(); return new ScopeExp(loc, ti); } else { //printf("-searchUFCS() %s\n", s.toChars()); return new DsymbolExp(loc, s); } } /****************************** * Pull out callable entity with UFCS. */ private Expression resolveUFCS(Scope* sc, CallExp ce) { Loc loc = ce.loc; Expression eleft; Expression e; if (ce.e1.op == TOK.dotIdentifier) { DotIdExp die = cast(DotIdExp)ce.e1; Identifier ident = die.ident; Expression ex = die.semanticX(sc); if (ex != die) { ce.e1 = ex; return null; } eleft = die.e1; Type t = eleft.type.toBasetype(); if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) { /* Built-in types and arrays have no callable properties, so do shortcut. * It is necessary in: e.init() */ } else if (t.ty == Taarray) { if (ident == Id.remove) { /* Transform: * aa.remove(arg) into delete aa[arg] */ if (!ce.arguments || ce.arguments.dim != 1) { ce.error("expected key as argument to `aa.remove()`"); return new ErrorExp(); } if (!eleft.type.isMutable()) { ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars()); return new ErrorExp(); } Expression key = (*ce.arguments)[0]; key = key.expressionSemantic(sc); key = resolveProperties(sc, key); TypeAArray taa = cast(TypeAArray)t; key = key.implicitCastTo(sc, taa.index); if (key.checkValue()) return new ErrorExp(); semanticTypeInfo(sc, taa.index); return new RemoveExp(loc, eleft, key); } } else { // even opDispatch and ufcs must have valid arguments. if (arrayExpressionSemantic(ce.arguments, sc)) return new ErrorExp(); if (Expression ey = die.semanticY(sc, 1)) { if (ey.op == TOK.error) return ey; ce.e1 = ey; if (isDotOpDispatch(ey)) { uint errors = global.startGagging(); e = ce.syntaxCopy().expressionSemantic(sc); if (!global.endGagging(errors)) return e; /* fall down to UFCS */ } else return null; } } e = searchUFCS(sc, die, ident); } else if (ce.e1.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ce.e1; if (Expression ey = dti.semanticY(sc, 1)) { ce.e1 = ey; return null; } eleft = dti.e1; e = searchUFCS(sc, dti, dti.ti.name); } else return null; // Rewrite ce.e1 = e; if (!ce.arguments) ce.arguments = new Expressions(); ce.arguments.shift(eleft); return null; } /****************************** * Pull out property with UFCS. */ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null) { Loc loc = e1.loc; Expression eleft; Expression e; if (e1.op == TOK.dotIdentifier) { DotIdExp die = cast(DotIdExp)e1; eleft = die.e1; e = searchUFCS(sc, die, die.ident); } else if (e1.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti; dti = cast(DotTemplateInstanceExp)e1; eleft = dti.e1; e = searchUFCS(sc, dti, dti.ti.name); } else return null; if (e is null) return null; // Rewrite if (e2) { // run semantic without gagging e2 = e2.expressionSemantic(sc); /* f(e1) = e2 */ Expression ex = e.copy(); auto a1 = new Expressions(1); (*a1)[0] = eleft; ex = new CallExp(loc, ex, a1); ex = ex.trySemantic(sc); /* f(e1, e2) */ auto a2 = new Expressions(2); (*a2)[0] = eleft; (*a2)[1] = e2; e = new CallExp(loc, e, a2); if (ex) { // if fallback setter exists, gag errors e = e.trySemantic(sc); if (!e) { checkPropertyCall(ex); ex = new AssignExp(loc, ex, e2); return ex.expressionSemantic(sc); } } else { // strict setter prints errors if fails e = e.expressionSemantic(sc); } checkPropertyCall(e); return e; } else { /* f(e1) */ auto arguments = new Expressions(1); (*arguments)[0] = eleft; e = new CallExp(loc, e, arguments); e = e.expressionSemantic(sc); checkPropertyCall(e); return e.expressionSemantic(sc); } } /****************************** * If e1 is a property function (template), resolve it. */ Expression resolvePropertiesOnly(Scope* sc, Expression e1) { //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars()); OverloadSet os; FuncDeclaration fd; TemplateDeclaration td; if (e1.op == TOK.dot) { DotExp de = cast(DotExp)e1; if (de.e2.op == TOK.overloadSet) { os = (cast(OverExp)de.e2).vars; goto Los; } } else if (e1.op == TOK.overloadSet) { os = (cast(OverExp)e1).vars; Los: assert(os); foreach (s; os.a) { fd = s.isFuncDeclaration(); td = s.isTemplateDeclaration(); if (fd) { if ((cast(TypeFunction)fd.type).isproperty) return resolveProperties(sc, e1); } else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) { if ((cast(TypeFunction)fd.type).isproperty || (fd.storage_class2 & STC.property) || (td._scope.stc & STC.property)) { return resolveProperties(sc, e1); } } } } else if (e1.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; if (dti.ti.tempdecl && (td = dti.ti.tempdecl.isTemplateDeclaration()) !is null) goto Ltd; } else if (e1.op == TOK.dotTemplateDeclaration) { td = (cast(DotTemplateExp)e1).td; goto Ltd; } else if (e1.op == TOK.scope_) { Dsymbol s = (cast(ScopeExp)e1).sds; TemplateInstance ti = s.isTemplateInstance(); if (ti && !ti.semanticRun && ti.tempdecl) { if ((td = ti.tempdecl.isTemplateDeclaration()) !is null) goto Ltd; } } else if (e1.op == TOK.template_) { td = (cast(TemplateExp)e1).td; Ltd: assert(td); if (td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) { if ((cast(TypeFunction)fd.type).isproperty || (fd.storage_class2 & STC.property) || (td._scope.stc & STC.property)) { return resolveProperties(sc, e1); } } } else if (e1.op == TOK.dotVariable && e1.type.ty == Tfunction) { DotVarExp dve = cast(DotVarExp)e1; fd = dve.var.isFuncDeclaration(); goto Lfd; } else if (e1.op == TOK.variable && e1.type && e1.type.ty == Tfunction && (sc.intypeof || !(cast(VarExp)e1).var.needThis())) { fd = (cast(VarExp)e1).var.isFuncDeclaration(); Lfd: assert(fd); if ((cast(TypeFunction)fd.type).isproperty) return resolveProperties(sc, e1); } return e1; } /**************************************** * Resolve a symbol `s` and wraps it in an expression object. * * Params: * loc = location of use of `s` * sc = context * s = symbol to resolve * hasOverloads = applies if `s` represents a function. * true means it's overloaded and will be resolved later, * false means it's the exact function symbol. * Returns: * `s` turned into an expression, `ErrorExp` if an error occurred */ Expression resolve(const ref Loc loc, Scope *sc, Dsymbol s, bool hasOverloads) { static if (LOGSEMANTIC) { printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars()); } Lagain: Expression e; //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); Dsymbol olds = s; Declaration d = s.isDeclaration(); if (d && (d.storage_class & STC.templateparameter)) { s = s.toAlias(); } else { if (!s.isFuncDeclaration()) // functions are checked after overloading { s.checkDeprecated(loc, sc); if (d) d.checkDisabled(loc, sc); } // https://issues.dlang.org/show_bug.cgi?id=12023 // if 's' is a tuple variable, the tuple is returned. s = s.toAlias(); //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); if (s != olds && !s.isFuncDeclaration()) { s.checkDeprecated(loc, sc); if (d) d.checkDisabled(loc, sc); } } if (auto em = s.isEnumMember()) { return em.getVarExp(loc, sc); } if (auto v = s.isVarDeclaration()) { //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars()); if (!v.type || // during variable type inference !v.type.deco && v.inuse) // during variable type semantic { if (v.inuse) // variable type depends on the variable itself error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); else // variable type cannot be determined error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); return new ErrorExp(); } if (v.type.ty == Terror) return new ErrorExp(); if ((v.storage_class & STC.manifest) && v._init) { if (v.inuse) { error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); return new ErrorExp(); } e = v.expandInitializer(loc); v.inuse++; e = e.expressionSemantic(sc); v.inuse--; return e; } // Change the ancestor lambdas to delegate before hasThis(sc) call. if (v.checkNestedReference(sc, loc)) return new ErrorExp(); if (v.needThis() && hasThis(sc)) e = new DotVarExp(loc, new ThisExp(loc), v); else e = new VarExp(loc, v); e = e.expressionSemantic(sc); return e; } if (auto fld = s.isFuncLiteralDeclaration()) { //printf("'%s' is a function literal\n", fld.toChars()); e = new FuncExp(loc, fld); return e.expressionSemantic(sc); } if (auto f = s.isFuncDeclaration()) { f = f.toAliasFunc(); if (!f.functionSemantic()) return new ErrorExp(); if (!hasOverloads && f.checkForwardRef(loc)) return new ErrorExp(); auto fd = s.isFuncDeclaration(); fd.type = f.type; return new VarExp(loc, fd, hasOverloads); } if (OverDeclaration od = s.isOverDeclaration()) { e = new VarExp(loc, od, true); e.type = Type.tvoid; return e; } if (OverloadSet o = s.isOverloadSet()) { //printf("'%s' is an overload set\n", o.toChars()); return new OverExp(loc, o); } if (Import imp = s.isImport()) { if (!imp.pkg) { .error(loc, "forward reference of import `%s`", imp.toChars()); return new ErrorExp(); } auto ie = new ScopeExp(loc, imp.pkg); return ie.expressionSemantic(sc); } if (Package pkg = s.isPackage()) { auto ie = new ScopeExp(loc, pkg); return ie.expressionSemantic(sc); } if (Module mod = s.isModule()) { auto ie = new ScopeExp(loc, mod); return ie.expressionSemantic(sc); } if (Nspace ns = s.isNspace()) { auto ie = new ScopeExp(loc, ns); return ie.expressionSemantic(sc); } if (Type t = s.getType()) { return (new TypeExp(loc, t)).expressionSemantic(sc); } if (TupleDeclaration tup = s.isTupleDeclaration()) { if (tup.needThis() && hasThis(sc)) e = new DotVarExp(loc, new ThisExp(loc), tup); else e = new TupleExp(loc, tup); e = e.expressionSemantic(sc); return e; } if (TemplateInstance ti = s.isTemplateInstance()) { ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) return new ErrorExp(); s = ti.toAlias(); if (!s.isTemplateInstance()) goto Lagain; e = new ScopeExp(loc, ti); e = e.expressionSemantic(sc); return e; } if (TemplateDeclaration td = s.isTemplateDeclaration()) { Dsymbol p = td.toParent2(); FuncDeclaration fdthis = hasThis(sc); AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad && (td._scope.stc & STC.static_) == 0) { e = new DotTemplateExp(loc, new ThisExp(loc), td); } else e = new TemplateExp(loc, td); e = e.expressionSemantic(sc); return e; } .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars()); return new ErrorExp(); } /************************************************************* * Given var, get the * right `this` pointer if var is in an outer class, but our * existing `this` pointer is in an inner class. * Params: * loc = location to use for error messages * sc = context * ad = struct or class we need the correct `this` for * e1 = existing `this` * var = the specific member of ad we're accessing * flag = if true, return `null` instead of throwing an error * Returns: * Expression representing the `this` for the var */ private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Declaration var, int flag = 0) { //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); L1: Type t = e1.type.toBasetype(); //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); if (e1.op == TOK.objcClassReference) { // We already have an Objective-C class reference, just use that as 'this'. return e1; } else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc && var.isFuncDeclaration && var.isFuncDeclaration.isStatic && var.isFuncDeclaration.selector) { return new ObjcClassReferenceExp(e1.loc, cast(ClassDeclaration) ad); } /* If e1 is not the 'this' pointer for ad */ if (ad && !(t.ty == Tpointer && t.nextOf().ty == Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == Tstruct && (cast(TypeStruct)t).sym == ad)) { ClassDeclaration cd = ad.isClassDeclaration(); ClassDeclaration tcd = t.isClassHandle(); /* e1 is the right this if ad is a base class of e1 */ if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) { /* Only classes can be inner classes with an 'outer' * member pointing to the enclosing class instance */ if (tcd && tcd.isNested()) { /* e1 is the 'this' pointer for an inner class: tcd. * Rewrite it as the 'this' pointer for the outer class. */ e1 = new DotVarExp(loc, e1, tcd.vthis); e1.type = tcd.vthis.type; e1.type = e1.type.addMod(t.mod); // Do not call ensureStaticLinkTo() //e1 = e1.semantic(sc); // Skip up over nested functions, and get the enclosing // class type. int n = 0; Dsymbol s; for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) { FuncDeclaration f = s.isFuncDeclaration(); if (f.vthis) { //printf("rewriting e1 to %s's this\n", f.toChars()); n++; e1 = new VarExp(loc, f.vthis); } else { e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars()); e1 = new ErrorExp(); return e1; } } if (s && s.isClassDeclaration()) { e1.type = s.isClassDeclaration().type; e1.type = e1.type.addMod(t.mod); if (n > 1) e1 = e1.expressionSemantic(sc); } else e1 = e1.expressionSemantic(sc); goto L1; } /* Can't find a path from e1 to ad */ if (flag) return null; e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars()); return new ErrorExp(); } } return e1; } /*************************************** * Pull out any properties. */ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null) { //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null); Loc loc = e1.loc; OverloadSet os; Dsymbol s; Objects* tiargs; Type tthis; if (e1.op == TOK.dot) { DotExp de = cast(DotExp)e1; if (de.e2.op == TOK.overloadSet) { tiargs = null; tthis = de.e1.type; os = (cast(OverExp)de.e2).vars; goto Los; } } else if (e1.op == TOK.overloadSet) { tiargs = null; tthis = null; os = (cast(OverExp)e1).vars; Los: assert(os); FuncDeclaration fd = null; if (e2) { e2 = e2.expressionSemantic(sc); if (e2.op == TOK.error) return new ErrorExp(); e2 = resolveProperties(sc, e2); Expressions a; a.push(e2); for (size_t i = 0; i < os.a.dim; i++) { FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, 1); if (f) { if (f.errors) return new ErrorExp(); fd = f; assert(fd.type.ty == Tfunction); } } if (fd) { Expression e = new CallExp(loc, e1, e2); return e.expressionSemantic(sc); } } { for (size_t i = 0; i < os.a.dim; i++) { FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, 1); if (f) { if (f.errors) return new ErrorExp(); fd = f; assert(fd.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)fd.type; if (!tf.isref && e2) goto Leproplvalue; } } if (fd) { Expression e = new CallExp(loc, e1); if (e2) e = new AssignExp(loc, e, e2); return e.expressionSemantic(sc); } } if (e2) goto Leprop; } else if (e1.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; if (!dti.findTempDecl(sc)) goto Leprop; if (!dti.ti.semanticTiargs(sc)) goto Leprop; tiargs = dti.ti.tiargs; tthis = dti.e1.type; if ((os = dti.ti.tempdecl.isOverloadSet()) !is null) goto Los; if ((s = dti.ti.tempdecl) !is null) goto Lfd; } else if (e1.op == TOK.dotTemplateDeclaration) { DotTemplateExp dte = cast(DotTemplateExp)e1; s = dte.td; tiargs = null; tthis = dte.e1.type; goto Lfd; } else if (e1.op == TOK.scope_) { s = (cast(ScopeExp)e1).sds; TemplateInstance ti = s.isTemplateInstance(); if (ti && !ti.semanticRun && ti.tempdecl) { //assert(ti.needsTypeInference(sc)); if (!ti.semanticTiargs(sc)) goto Leprop; tiargs = ti.tiargs; tthis = null; if ((os = ti.tempdecl.isOverloadSet()) !is null) goto Los; if ((s = ti.tempdecl) !is null) goto Lfd; } } else if (e1.op == TOK.template_) { s = (cast(TemplateExp)e1).td; tiargs = null; tthis = null; goto Lfd; } else if (e1.op == TOK.dotVariable && e1.type && e1.type.toBasetype().ty == Tfunction) { DotVarExp dve = cast(DotVarExp)e1; s = dve.var.isFuncDeclaration(); tiargs = null; tthis = dve.e1.type; goto Lfd; } else if (e1.op == TOK.variable && e1.type && e1.type.toBasetype().ty == Tfunction) { s = (cast(VarExp)e1).var.isFuncDeclaration(); tiargs = null; tthis = null; Lfd: assert(s); if (e2) { e2 = e2.expressionSemantic(sc); if (e2.op == TOK.error) return new ErrorExp(); e2 = resolveProperties(sc, e2); Expressions a; a.push(e2); FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1); if (fd && fd.type) { if (fd.errors) return new ErrorExp(); assert(fd.type.ty == Tfunction); Expression e = new CallExp(loc, e1, e2); return e.expressionSemantic(sc); } } { FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, 1); if (fd && fd.type) { if (fd.errors) return new ErrorExp(); assert(fd.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)fd.type; if (!e2 || tf.isref) { Expression e = new CallExp(loc, e1); if (e2) e = new AssignExp(loc, e, e2); return e.expressionSemantic(sc); } } } if (FuncDeclaration fd = s.isFuncDeclaration()) { // Keep better diagnostic message for invalid property usage of functions assert(fd.type.ty == Tfunction); Expression e = new CallExp(loc, e1, e2); return e.expressionSemantic(sc); } if (e2) goto Leprop; } if (e1.op == TOK.variable) { VarExp ve = cast(VarExp)e1; VarDeclaration v = ve.var.isVarDeclaration(); if (v && ve.checkPurity(sc, v)) return new ErrorExp(); } if (e2) return null; if (e1.type && e1.op != TOK.type) // function type is not a property { /* Look for e1 being a lazy parameter; rewrite as delegate call */ if (e1.op == TOK.variable) { VarExp ve = cast(VarExp)e1; if (ve.var.storage_class & STC.lazy_) { Expression e = new CallExp(loc, e1); return e.expressionSemantic(sc); } } else if (e1.op == TOK.dotVariable) { // Check for reading overlapped pointer field in @safe code. if (checkUnsafeAccess(sc, e1, true, true)) return new ErrorExp(); } else if (e1.op == TOK.dot) { e1.error("expression has no value"); return new ErrorExp(); } else if (e1.op == TOK.call) { CallExp ce = cast(CallExp)e1; // Check for reading overlapped pointer field in @safe code. if (checkUnsafeAccess(sc, ce.e1, true, true)) return new ErrorExp(); } } if (!e1.type) { error(loc, "cannot resolve type for %s", e1.toChars()); e1 = new ErrorExp(); } return e1; Leprop: error(loc, "not a property %s", e1.toChars()); return new ErrorExp(); Leproplvalue: error(loc, "%s is not an lvalue", e1.toChars()); return new ErrorExp(); } extern (C++) Expression resolveProperties(Scope* sc, Expression e) { //printf("resolveProperties(%s)\n", e.toChars()); e = resolvePropertiesX(sc, e); if (e.checkRightThis(sc)) return new ErrorExp(); return e; } /**************************************** * The common type is determined by applying ?: to each pair. * Output: * exps[] properties resolved, implicitly cast to common type, rewritten in place * *pt if pt is not NULL, set to the common type * Returns: * true a semantic error was detected */ private bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type* pt) { /* Still have a problem with: * ubyte[][] = [ cast(ubyte[])"hello", [1]]; * which works if the array literal is initialized top down with the ubyte[][] * type, but fails with this function doing bottom up typing. */ //printf("arrayExpressionToCommonType()\n"); scope IntegerExp integerexp = new IntegerExp(0); scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null); Type t0 = null; Expression e0 = null; size_t j0 = ~0; for (size_t i = 0; i < exps.dim; i++) { Expression e = (*exps)[i]; if (!e) continue; e = resolveProperties(sc, e); if (!e.type) { e.error("`%s` has no value", e.toChars()); t0 = Type.terror; continue; } if (e.op == TOK.type) { e.checkValue(); // report an error "type T has no value" t0 = Type.terror; continue; } if (e.type.ty == Tvoid) { // void expressions do not concur to the determination of the common // type. continue; } if (checkNonAssignmentArrayOp(e)) { t0 = Type.terror; continue; } e = doCopyOrMove(sc, e); if (t0 && !t0.equals(e.type)) { /* This applies ?: to merge the types. It's backwards; * ?: should call this function to merge types. */ condexp.type = null; condexp.e1 = e0; condexp.e2 = e; condexp.loc = e.loc; Expression ex = condexp.expressionSemantic(sc); if (ex.op == TOK.error) e = ex; else { (*exps)[j0] = condexp.e1; e = condexp.e2; } } j0 = i; e0 = e; t0 = e.type; if (e.op != TOK.error) (*exps)[i] = e; } if (!t0) t0 = Type.tvoid; // [] is typed as void[] else if (t0.ty != Terror) { for (size_t i = 0; i < exps.dim; i++) { Expression e = (*exps)[i]; if (!e) continue; e = e.implicitCastTo(sc, t0); //assert(e.op != TOK.error); if (e.op == TOK.error) { /* https://issues.dlang.org/show_bug.cgi?id=13024 * a workaround for the bug in typeMerge - * it should paint e1 and e2 by deduced common type, * but doesn't in this particular case. */ t0 = Type.terror; break; } (*exps)[i] = e; } } if (pt) *pt = t0; return (t0 == Type.terror); } private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2) { Expression e; switch (op) { case TOK.addAssign: e = new AddExp(loc, e1, e2); break; case TOK.minAssign: e = new MinExp(loc, e1, e2); break; case TOK.mulAssign: e = new MulExp(loc, e1, e2); break; case TOK.divAssign: e = new DivExp(loc, e1, e2); break; case TOK.modAssign: e = new ModExp(loc, e1, e2); break; case TOK.andAssign: e = new AndExp(loc, e1, e2); break; case TOK.orAssign: e = new OrExp(loc, e1, e2); break; case TOK.xorAssign: e = new XorExp(loc, e1, e2); break; case TOK.leftShiftAssign: e = new ShlExp(loc, e1, e2); break; case TOK.rightShiftAssign: e = new ShrExp(loc, e1, e2); break; case TOK.unsignedRightShiftAssign: e = new UshrExp(loc, e1, e2); break; default: assert(0); } return e; } /********************* * Rewrite: * array.length op= e2 * as: * array.length = array.length op e2 * or: * auto tmp = &array; * (*tmp).length = (*tmp).length op e2 */ private Expression rewriteOpAssign(BinExp exp) { Expression e; assert(exp.e1.op == TOK.arrayLength); ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; if (ale.e1.op == TOK.variable) { e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); e = new AssignExp(exp.loc, ale.syntaxCopy(), e); } else { /* auto tmp = &array; * (*tmp).length = (*tmp).length op e2 */ auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1)); Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp))); Expression elvalue = e1.syntaxCopy(); e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); e = new AssignExp(exp.loc, elvalue, e); e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); } return e; } /**************************************** * Preprocess arguments to function. * Output: * exps[] tuples expanded, properties resolved, rewritten in place * Returns: * true a semantic error occurred */ private bool preFunctionParameters(Scope* sc, Expressions* exps) { bool err = false; if (exps) { expandTuples(exps); for (size_t i = 0; i < exps.dim; i++) { Expression arg = (*exps)[i]; arg = resolveProperties(sc, arg); if (arg.op == TOK.type) { arg.error("cannot pass type `%s` as a function argument", arg.toChars()); arg = new ErrorExp(); err = true; } else if (checkNonAssignmentArrayOp(arg)) { arg = new ErrorExp(); err = true; } (*exps)[i] = arg; } } return err; } /******************************************** * Issue an error if default construction is disabled for type t. * Default construction is required for arrays and 'out' parameters. * Returns: * true an error was issued */ private bool checkDefCtor(Loc loc, Type t) { t = t.baseElemOf(); if (t.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)t).sym; if (sd.noDefaultCtor) { sd.error(loc, "default construction is disabled"); return true; } } return false; } /**************************************** * Now that we know the exact type of the function we're calling, * the arguments[] need to be adjusted: * 1. implicitly convert argument to the corresponding parameter type * 2. add default arguments for any missing arguments * 3. do default promotions on arguments corresponding to ... * 4. add hidden _arguments[] argument * 5. call copy constructor for struct value arguments * Params: * tf = type of the function * tthis = type of `this` argument, `null` if no `this` argument * arguments = array of actual arguments to function call * fd = the function being called, `null` if called indirectly * prettype = set to return type of function * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none * Returns: * true errors happened */ private bool functionParameters(const ref Loc loc, Scope* sc, TypeFunction tf, Type tthis, Expressions* arguments, FuncDeclaration fd, Type* prettype, Expression* peprefix) { //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); assert(arguments); assert(fd || tf.next); size_t nargs = arguments ? arguments.dim : 0; const size_t nparams = Parameter.dim(tf.parameters); const olderrors = global.errors; bool err = false; *prettype = Type.terror; Expression eprefix = null; *peprefix = null; if (nargs > nparams && tf.varargs == 0) { error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); return true; } // If inferring return type, and semantic3() needs to be run if not already run if (!tf.next && fd.inferRetType) { fd.functionSemantic(); } else if (fd && fd.parent) { TemplateInstance ti = fd.parent.isTemplateInstance(); if (ti && ti.tempdecl) { fd.functionSemantic3(); } } const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) /* If the function return type has wildcards in it, we'll need to figure out the actual type * based on the actual argument types. * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest * of the arguments. */ MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0; bool done = false; foreach (const i; 0 .. n) { Expression arg = (i < nargs) ? (*arguments)[i] : null; if (i < nparams) { bool errorArgs() { error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); return true; } Parameter p = Parameter.getNth(tf.parameters, i); if (!arg) { if (!p.defaultArg) { if (tf.varargs == 2 && i + 1 == nparams) goto L2; return errorArgs(); } arg = p.defaultArg; arg = inlineCopy(arg, sc); // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ arg = arg.resolveLoc(loc, sc); arguments.push(arg); nargs++; } else { if (arg.op == TOK.default_) { arg = arg.resolveLoc(loc, sc); (*arguments)[i] = arg; } } if (tf.varargs == 2 && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic { //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); { MATCH m; if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch) { if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m) goto L2; else if (nargs != nparams) return errorArgs(); goto L1; } } L2: Type tb = p.type.toBasetype(); switch (tb.ty) { case Tsarray: case Tarray: { /* Create a static array variable v of type arg.type: * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; * * The array literal in the initializer of the hidden variable * is now optimized. * https://issues.dlang.org/show_bug.cgi?id=2356 */ Type tbn = (cast(TypeArray)tb).next; // array element type Type tret = p.isLazyArray(); auto elements = new Expressions(nargs - i); foreach (u; 0 .. elements.dim) { Expression a = (*arguments)[i + u]; if (tret && a.implicitConvTo(tret)) { // p is a lazy array of delegates, tret is return type of the delegates a = a.implicitCastTo(sc, tret) .optimize(WANTvalue) .toDelegate(tret, sc); } else a = a.implicitCastTo(sc, tbn); (*elements)[u] = a; } // https://issues.dlang.org/show_bug.cgi?id=14395 // Convert to a static array literal, or its slice. arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements); if (tb.ty == Tarray) { arg = new SliceExp(loc, arg, null, null); arg.type = p.type; } break; } case Tclass: { /* Set arg to be: * new Tclass(arg0, arg1, ..., argn) */ auto args = new Expressions(nargs - i); foreach (u; i .. nargs) (*args)[u - i] = (*arguments)[u]; arg = new NewExp(loc, null, null, p.type, args); break; } default: if (!arg) { error(loc, "not enough arguments"); return true; } break; } arg = arg.expressionSemantic(sc); //printf("\targ = '%s'\n", arg.toChars()); arguments.setDim(i + 1); (*arguments)[i] = arg; nargs = i + 1; done = true; } L1: if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid)) { bool isRef = (p.storageClass & (STC.ref_ | STC.out_)) != 0; if (ubyte wm = arg.type.deduceWild(p.type, isRef)) { wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm; //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch); } } } if (done) break; } if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) && tf.next.hasWild() && (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf()))) { bool errorInout(MOD wildmatch) { const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch); error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s); return true; } if (fd) { /* If the called function may return the reference to * outer inout data, it should be rejected. * * void foo(ref inout(int) x) { * ref inout(int) bar(inout(int)) { return x; } * struct S { ref inout(int) bar() inout { return x; } } * bar(int.init) = 1; // bad! * S().bar() = 1; // bad! * } */ Dsymbol s = null; if (fd.isThis() || fd.isNested()) s = fd.toParent2(); for (; s; s = s.toParent2()) { if (auto ad = s.isAggregateDeclaration()) { if (ad.isNested()) continue; break; } if (auto ff = s.isFuncDeclaration()) { if ((cast(TypeFunction)ff.type).iswild) return errorInout(wildmatch); if (ff.isNested() || ff.isThis()) continue; } break; } } else if (tf.isWild()) return errorInout(wildmatch); } assert(nargs >= nparams); foreach (const i, arg; (*arguments)[0 .. nargs]) { assert(arg); if (i < nparams) { Parameter p = Parameter.getNth(tf.parameters, i); if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid)) { Type tprm = p.type.hasWild() ? p.type.substWildTo(wildmatch) : p.type; if (!tprm.equals(arg.type)) { //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); arg = arg.implicitCastTo(sc, tprm); arg = arg.optimize(WANTvalue, (p.storageClass & (STC.ref_ | STC.out_)) != 0); } } if (p.storageClass & STC.ref_) { arg = arg.toLvalue(sc, arg); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); } else if (p.storageClass & STC.out_) { Type t = arg.type; if (!t.isMutable() || !t.isAssignable()) // check blit assignable { arg.error("cannot modify struct `%s` with immutable members", arg.toChars()); err = true; } else { // Look for misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); err |= checkDefCtor(arg.loc, t); // t must be default constructible } arg = arg.toLvalue(sc, arg); } else if (p.storageClass & STC.lazy_) { // Convert lazy argument to a delegate auto t = (p.type.ty == Tvoid) ? p.type : arg.type; arg = toDelegate(arg, t, sc); } //printf("arg: %s\n", arg.toChars()); //printf("type: %s\n", arg.type.toChars()); //printf("param: %s\n", p.toChars()); if (tf.parameterEscapes(tthis, p)) { /* Argument value can escape from the called function. * Check arg to see if it matters. */ if (global.params.vsafe) err |= checkParamArgumentEscape(sc, fd, p.ident, arg, false); } else { /* Argument value cannot escape from the called function. */ Expression a = arg; if (a.op == TOK.cast_) a = (cast(CastExp)a).e1; if (a.op == TOK.function_) { /* Function literals can only appear once, so if this * appearance was scoped, there cannot be any others. */ FuncExp fe = cast(FuncExp)a; fe.fd.tookAddressOf = 0; } else if (a.op == TOK.delegate_) { /* For passing a delegate to a scoped parameter, * this doesn't count as taking the address of it. * We only worry about 'escaping' references to the function. */ DelegateExp de = cast(DelegateExp)a; if (de.e1.op == TOK.variable) { VarExp ve = cast(VarExp)de.e1; FuncDeclaration f = ve.var.isFuncDeclaration(); if (f) { f.tookAddressOf--; //printf("--tookAddressOf = %d\n", f.tookAddressOf); } } } } arg = arg.optimize(WANTvalue, (p.storageClass & (STC.ref_ | STC.out_)) != 0); } else { // These will be the trailing ... arguments // If not D linkage, do promotions if (tf.linkage != LINK.d) { // Promote bytes, words, etc., to ints arg = integralPromotions(arg, sc); // Promote floats to doubles switch (arg.type.ty) { case Tfloat32: arg = arg.castTo(sc, Type.tfloat64); break; case Timaginary32: arg = arg.castTo(sc, Type.timaginary64); break; default: break; } if (tf.varargs == 1) { const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)"; if (arg.type.ty == Tarray) { arg.error("cannot pass dynamic arrays to `%s` vararg functions", p); err = true; } if (arg.type.ty == Tsarray) { arg.error("cannot pass static arrays to `%s` vararg functions", p); err = true; } } } // Do not allow types that need destructors if (arg.type.needsDestruction()) { arg.error("cannot pass types that need destruction as variadic arguments"); err = true; } // Convert static arrays to dynamic arrays // BUG: I don't think this is right for D2 Type tb = arg.type.toBasetype(); if (tb.ty == Tsarray) { TypeSArray ts = cast(TypeSArray)tb; Type ta = ts.next.arrayOf(); if (ts.size(arg.loc) == 0) arg = new NullExp(arg.loc, ta); else arg = arg.castTo(sc, ta); } if (tb.ty == Tstruct) { //arg = callCpCtor(sc, arg); } // Give error for overloaded function addresses if (arg.op == TOK.symbolOffset) { SymOffExp se = cast(SymOffExp)arg; if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) { arg.error("function `%s` is overloaded", arg.toChars()); err = true; } } if (arg.checkValue()) err = true; arg = arg.optimize(WANTvalue); } (*arguments)[i] = arg; } /* Remaining problems: * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is * implemented by calling a function) we'll defer this for now. * 2. value structs (or static arrays of them) that need to be copy constructed * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the * function gets called (functions normally destroy their parameters) * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned * up properly. Pushing arguments on the stack then cannot fail. */ if (1) { /* TODO: tackle problem 1) */ const bool leftToRight = true; // TODO: something like !fd.isArrayOp if (!leftToRight) assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1); const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1); const ptrdiff_t step = (leftToRight ? 1 : -1); /* Compute indices of last throwing argument and first arg needing destruction. * Used to not set up destructors unless an arg needs destruction on a throw * in a later argument. */ ptrdiff_t lastthrow = -1; ptrdiff_t firstdtor = -1; for (ptrdiff_t i = start; i != end; i += step) { Expression arg = (*arguments)[i]; if (canThrow(arg, sc.func, false)) lastthrow = i; if (firstdtor == -1 && arg.type.needsDestruction()) { Parameter p = (i >= nparams ? null : Parameter.getNth(tf.parameters, i)); if (!(p && (p.storageClass & (STC.lazy_ | STC.ref_ | STC.out_)))) firstdtor = i; } } /* Does problem 3) apply to this call? */ const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0 && (lastthrow - firstdtor) * step > 0); /* If so, initialize 'eprefix' by declaring the gate */ VarDeclaration gate = null; if (needsPrefix) { // eprefix => bool __gate [= false] Identifier idtmp = Identifier.generateId("__gate"); gate = new VarDeclaration(loc, Type.tbool, idtmp, null); gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_; gate.dsymbolSemantic(sc); auto ae = new DeclarationExp(loc, gate); eprefix = ae.expressionSemantic(sc); } for (ptrdiff_t i = start; i != end; i += step) { Expression arg = (*arguments)[i]; Parameter parameter = (i >= nparams ? null : Parameter.getNth(tf.parameters, i)); const bool isRef = (parameter && (parameter.storageClass & (STC.ref_ | STC.out_))); const bool isLazy = (parameter && (parameter.storageClass & STC.lazy_)); /* Skip lazy parameters */ if (isLazy) continue; /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg. * Declare a temporary variable for this arg and append that declaration to 'eprefix', * which will implicitly take care of potential problem 2) for this arg. * 'eprefix' will therefore finally contain all args up to and including the last * potentially throwing arg, excluding all lazy parameters. */ if (gate) { const bool needsDtor = (!isRef && arg.type.needsDestruction() && i != lastthrow); /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor) */ auto tmp = copyToTemp(0, needsDtor ? "__pfx" : "__pfy", !isRef ? arg : arg.addressOf()); tmp.dsymbolSemantic(sc); /* Modify the destructor so it only runs if gate==false, i.e., * only if there was a throw while constructing the args */ if (!needsDtor) { if (tmp.edtor) { assert(i == lastthrow); tmp.edtor = null; } } else { // edtor => (__gate || edtor) assert(tmp.edtor); Expression e = tmp.edtor; e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e); tmp.edtor = e.expressionSemantic(sc); //printf("edtor: %s\n", tmp.edtor.toChars()); } // eprefix => (eprefix, auto __pfx/y = arg) auto ae = new DeclarationExp(loc, tmp); eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc)); // arg => __pfx/y arg = new VarExp(loc, tmp); arg = arg.expressionSemantic(sc); if (isRef) { arg = new PtrExp(loc, arg); arg = arg.expressionSemantic(sc); } /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true), * i.e., disable the dtors right after constructing the last throwing arg. * From now on, the callee will take care of destructing the args because * the args are implicitly moved into function parameters. * * Set gate to null to let the next iterations know they don't need to * append to eprefix anymore. */ if (i == lastthrow) { auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), new IntegerExp(gate.loc, 1, Type.tbool)); eprefix = Expression.combine(eprefix, e.expressionSemantic(sc)); gate = null; } } else { /* No gate, no prefix to append to. * Handle problem 2) by calling the copy constructor for value structs * (or static arrays of them) if appropriate. */ Type tv = arg.type.baseElemOf(); if (!isRef && tv.ty == Tstruct) arg = doCopyOrMove(sc, arg); } (*arguments)[i] = arg; } } //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); // If D linkage and variadic, add _arguments[] as first argument if (tf.linkage == LINK.d && tf.varargs == 1) { assert(arguments.dim >= nparams); auto args = new Parameters(arguments.dim - nparams); for (size_t i = 0; i < arguments.dim - nparams; i++) { auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null); (*args)[i] = arg; } auto tup = new TypeTuple(args); Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc); arguments.insert(0, e); } Type tret = tf.next; if (isCtorCall) { //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(), // wildmatch, tf.isWild(), fd.isReturnIsolated()); if (!tthis) { assert(sc.intypeof || global.errors); tthis = fd.isThis().type.addMod(fd.type.mod); } if (tf.isWild() && !fd.isReturnIsolated()) { if (wildmatch) tret = tret.substWildTo(wildmatch); int offset; if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0)) { const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars(); const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars(); .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2); err = true; } } tret = tthis; } else if (wildmatch && tret) { /* Adjust function return type based on wildmatch */ //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars()); tret = tret.substWildTo(wildmatch); } *prettype = tret; *peprefix = eprefix; return (err || olderrors != global.errors); } private Module loadStdMath() { __gshared Import impStdMath = null; if (!impStdMath) { auto a = new Identifiers(); a.push(Id.std); auto s = new Import(Loc.initial, a, Id.math, null, false); // Module.load will call fatal() if there's no std.math available. // Gag the error here, pushing the error handling to the caller. uint errors = global.startGagging(); s.load(null); if (s.mod) { s.mod.importAll(null); s.mod.dsymbolSemantic(null); } global.endGagging(errors); impStdMath = s; } return impStdMath.mod; } private extern (C++) final class ExpressionSemanticVisitor : Visitor { alias visit = Visitor.visit; Scope* sc; Expression result; this(Scope* sc) { this.sc = sc; } private void setError() { result = new ErrorExp(); } /************************** * Semantically analyze Expression. * Determine types, fold constants, etc. */ override void visit(Expression e) { static if (LOGSEMANTIC) { printf("Expression::semantic() %s\n", e.toChars()); } if (e.type) e.type = e.type.typeSemantic(e.loc, sc); else e.type = Type.tvoid; result = e; } override void visit(IntegerExp e) { assert(e.type); if (e.type.ty == Terror) return setError(); assert(e.type.deco); e.setInteger(e.getInteger()); result = e; } override void visit(RealExp e) { if (!e.type) e.type = Type.tfloat64; else e.type = e.type.typeSemantic(e.loc, sc); result = e; } override void visit(ComplexExp e) { if (!e.type) e.type = Type.tcomplex80; else e.type = e.type.typeSemantic(e.loc, sc); result = e; } override void visit(IdentifierExp exp) { static if (LOGSEMANTIC) { printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars()); } if (exp.type) // This is used as the dummy expression { result = exp; return; } Dsymbol scopesym; Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); if (s) { if (s.errors) return setError(); Expression e; /* See if the symbol was a member of an enclosing 'with' */ WithScopeSymbol withsym = scopesym.isWithScopeSymbol(); if (withsym && withsym.withstate.wthis) { /* Disallow shadowing */ // First find the scope of the with Scope* scwith = sc; while (scwith.scopesym != scopesym) { scwith = scwith.enclosing; assert(scwith); } // Look at enclosing scopes for symbols with the same name, // in the same function for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing) { Dsymbol s2; if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) { exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars()); return setError(); } } s = s.toAlias(); // Same as wthis.ident // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again. // The redudancy should be removed. e = new VarExp(exp.loc, withsym.withstate.wthis); e = new DotIdExp(exp.loc, e, exp.ident); e = e.expressionSemantic(sc); } else { if (withsym) { Declaration d = s.isDeclaration(); if (d) checkAccess(exp.loc, sc, null, d); } /* If f is really a function template, * then replace f with the function template declaration. */ FuncDeclaration f = s.isFuncDeclaration(); if (f) { TemplateDeclaration td = getFuncTemplateDecl(f); if (td) { if (td.overroot) // if not start of overloaded list of TemplateDeclaration's td = td.overroot; // then get the start e = new TemplateExp(exp.loc, td, f); e = e.expressionSemantic(sc); result = e; return; } } // Haven't done overload resolution yet, so pass 1 e = resolve(exp.loc, sc, s, true); } result = e; return; } if (hasThis(sc)) { for (AggregateDeclaration ad = sc.getStructClassScope(); ad;) { if (ad.aliasthis) { Expression e; e = new ThisExp(exp.loc); e = new DotIdExp(exp.loc, e, ad.aliasthis.ident); e = new DotIdExp(exp.loc, e, exp.ident); e = e.trySemantic(sc); if (e) { result = e; return; } } auto cd = ad.isClassDeclaration(); if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) { ad = cd.baseClass; continue; } break; } } if (exp.ident == Id.ctfe) { if (sc.flags & SCOPE.ctfe) { exp.error("variable `__ctfe` cannot be read at compile time"); return setError(); } // Create the magic __ctfe bool variable auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null); vd.storage_class |= STC.temp; vd.semanticRun = PASS.semanticdone; Expression e = new VarExp(exp.loc, vd); e = e.expressionSemantic(sc); result = e; return; } // If we've reached this point and are inside a with() scope then we may // try one last attempt by checking whether the 'wthis' object supports // dynamic dispatching via opDispatch. // This is done by rewriting this expression as wthis.ident. // The innermost with() scope of the hierarchy to satisfy the condition // above wins. // https://issues.dlang.org/show_bug.cgi?id=6400 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing) { if (!sc2.scopesym) continue; if (auto ss = sc2.scopesym.isWithScopeSymbol()) { if (ss.withstate.wthis) { Expression e; e = new VarExp(exp.loc, ss.withstate.wthis); e = new DotIdExp(exp.loc, e, exp.ident); e = e.trySemantic(sc); if (e) { result = e; return; } } } } /* Look for what user might have meant */ if (const n = importHint(exp.ident.toString())) exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr); else if (auto s2 = sc.search_correct(exp.ident)) exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars()); else if (const p = Scope.search_correct_C(exp.ident)) exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p); else exp.error("undefined identifier `%s`", exp.ident.toChars()); result = new ErrorExp(); } override void visit(DsymbolExp e) { result = resolve(e.loc, sc, e.s, e.hasOverloads); } override void visit(ThisExp e) { static if (LOGSEMANTIC) { printf("ThisExp::semantic()\n"); } if (e.type) { result = e; return; } FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable /* Special case for typeof(this) and typeof(super) since both * should work even if they are not inside a non-static member function */ if (!fd && sc.intypeof == 1) { // Find enclosing struct or class for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent) { if (!s) { e.error("`%s` is not in a class or struct scope", e.toChars()); goto Lerr; } ClassDeclaration cd = s.isClassDeclaration(); if (cd) { e.type = cd.type; result = e; return; } StructDeclaration sd = s.isStructDeclaration(); if (sd) { e.type = sd.type; result = e; return; } } } if (!fd) goto Lerr; assert(fd.vthis); e.var = fd.vthis; assert(e.var.parent); e.type = e.var.type; if (e.var.checkNestedReference(sc, e.loc)) return setError(); result = e; return; Lerr: e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); result = new ErrorExp(); } override void visit(SuperExp e) { static if (LOGSEMANTIC) { printf("SuperExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } FuncDeclaration fd = hasThis(sc); ClassDeclaration cd; Dsymbol s; /* Special case for typeof(this) and typeof(super) since both * should work even if they are not inside a non-static member function */ if (!fd && sc.intypeof == 1) { // Find enclosing class for (s = sc.getStructClassScope(); 1; s = s.parent) { if (!s) { e.error("`%s` is not in a class scope", e.toChars()); goto Lerr; } cd = s.isClassDeclaration(); if (cd) { cd = cd.baseClass; if (!cd) { e.error("class `%s` has no `super`", s.toChars()); goto Lerr; } e.type = cd.type; result = e; return; } } } if (!fd) goto Lerr; e.var = fd.vthis; assert(e.var && e.var.parent); s = fd.toParent(); while (s && s.isTemplateInstance()) s = s.toParent(); if (s.isTemplateDeclaration()) // allow inside template constraint s = s.toParent(); assert(s); cd = s.isClassDeclaration(); //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars()); if (!cd) goto Lerr; if (!cd.baseClass) { e.error("no base class for `%s`", cd.toChars()); e.type = e.var.type; } else { e.type = cd.baseClass.type; e.type = e.type.castMod(e.var.type.mod); } if (e.var.checkNestedReference(sc, e.loc)) return setError(); result = e; return; Lerr: e.error("`super` is only allowed in non-static class member functions"); result = new ErrorExp(); } override void visit(NullExp e) { static if (LOGSEMANTIC) { printf("NullExp::semantic('%s')\n", e.toChars()); } // NULL is the same as (void *)0 if (e.type) { result = e; return; } e.type = Type.tnull; result = e; } override void visit(StringExp e) { static if (LOGSEMANTIC) { printf("StringExp::semantic() %s\n", e.toChars()); } if (e.type) { result = e; return; } OutBuffer buffer; size_t newlen = 0; const(char)* p; size_t u; dchar c; switch (e.postfix) { case 'd': for (u = 0; u < e.len;) { p = utf_decodeChar(e.string, e.len, u, c); if (p) { e.error("%s", p); return setError(); } else { buffer.write4(c); newlen++; } } buffer.write4(0); e.dstring = cast(dchar*)buffer.extractData(); e.len = newlen; e.sz = 4; e.type = new TypeDArray(Type.tdchar.immutableOf()); e.committed = 1; break; case 'w': for (u = 0; u < e.len;) { p = utf_decodeChar(e.string, e.len, u, c); if (p) { e.error("%s", p); return setError(); } else { buffer.writeUTF16(c); newlen++; if (c >= 0x10000) newlen++; } } buffer.writeUTF16(0); e.wstring = cast(wchar*)buffer.extractData(); e.len = newlen; e.sz = 2; e.type = new TypeDArray(Type.twchar.immutableOf()); e.committed = 1; break; case 'c': e.committed = 1; goto default; default: e.type = new TypeDArray(Type.tchar.immutableOf()); break; } e.type = e.type.typeSemantic(e.loc, sc); //type = type.immutableOf(); //printf("type = %s\n", type.toChars()); result = e; } override void visit(TupleExp exp) { static if (LOGSEMANTIC) { printf("+TupleExp::semantic(%s)\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (exp.e0) exp.e0 = exp.e0.expressionSemantic(sc); // Run semantic() on each argument bool err = false; for (size_t i = 0; i < exp.exps.dim; i++) { Expression e = (*exp.exps)[i]; e = e.expressionSemantic(sc); if (!e.type) { exp.error("`%s` has no value", e.toChars()); err = true; } else if (e.op == TOK.error) err = true; else (*exp.exps)[i] = e; } if (err) return setError(); expandTuples(exp.exps); exp.type = new TypeTuple(exp.exps); exp.type = exp.type.typeSemantic(exp.loc, sc); //printf("-TupleExp::semantic(%s)\n", toChars()); result = exp; } override void visit(ArrayLiteralExp e) { static if (LOGSEMANTIC) { printf("ArrayLiteralExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } /* Perhaps an empty array literal [ ] should be rewritten as null? */ if (e.basis) e.basis = e.basis.expressionSemantic(sc); if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error)) return setError(); expandTuples(e.elements); Type t0; if (e.basis) e.elements.push(e.basis); bool err = arrayExpressionToCommonType(sc, e.elements, &t0); if (e.basis) e.basis = e.elements.pop(); if (err) return setError(); e.type = t0.arrayOf(); e.type = e.type.typeSemantic(e.loc, sc); /* Disallow array literals of type void being used. */ if (e.elements.dim > 0 && t0.ty == Tvoid) { e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars()); return setError(); } if (global.params.useTypeInfo && Type.dtypeinfo) semanticTypeInfo(sc, e.type); result = e; } override void visit(AssocArrayLiteralExp e) { static if (LOGSEMANTIC) { printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } // Run semantic() on each element bool err_keys = arrayExpressionSemantic(e.keys, sc); bool err_vals = arrayExpressionSemantic(e.values, sc); if (err_keys || err_vals) return setError(); expandTuples(e.keys); expandTuples(e.values); if (e.keys.dim != e.values.dim) { e.error("number of keys is %u, must match number of values %u", e.keys.dim, e.values.dim); return setError(); } Type tkey = null; Type tvalue = null; err_keys = arrayExpressionToCommonType(sc, e.keys, &tkey); err_vals = arrayExpressionToCommonType(sc, e.values, &tvalue); if (err_keys || err_vals) return setError(); if (tkey == Type.terror || tvalue == Type.terror) return setError(); e.type = new TypeAArray(tvalue, tkey); e.type = e.type.typeSemantic(e.loc, sc); semanticTypeInfo(sc, e.type); if (global.params.vsafe) { if (checkAssocArrayLiteralEscape(sc, e, false)) return setError(); } result = e; } override void visit(StructLiteralExp e) { static if (LOGSEMANTIC) { printf("StructLiteralExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } e.sd.size(e.loc); if (e.sd.sizeok != Sizeok.done) return setError(); // run semantic() on each element if (arrayExpressionSemantic(e.elements, sc)) return setError(); expandTuples(e.elements); /* Fit elements[] to the corresponding type of field[]. */ if (!e.sd.fit(e.loc, sc, e.elements, e.stype)) return setError(); /* Fill out remainder of elements[] with default initializers for fields[] */ if (!e.sd.fill(e.loc, e.elements, false)) { /* An error in the initializer needs to be recorded as an error * in the enclosing function or template, since the initializer * will be part of the stuct declaration. */ global.increaseErrorCount(); return setError(); } if (checkFrameAccess(e.loc, sc, e.sd, e.elements.dim)) return setError(); e.type = e.stype ? e.stype : e.sd.type; result = e; } override void visit(TypeExp exp) { if (exp.type.ty == Terror) return setError(); //printf("TypeExp::semantic(%s)\n", type.toChars()); Expression e; Type t; Dsymbol s; dmd.typesem.resolve(exp.type, exp.loc, sc, &e, &t, &s, true); if (e) { //printf("e = %s %s\n", Token::toChars(e.op), e.toChars()); e = e.expressionSemantic(sc); } else if (t) { //printf("t = %d %s\n", t.ty, t.toChars()); exp.type = t.typeSemantic(exp.loc, sc); e = exp; } else if (s) { //printf("s = %s %s\n", s.kind(), s.toChars()); e = resolve(exp.loc, sc, s, true); } else assert(0); if (global.params.vcomplex) exp.type.checkComplexTransition(exp.loc, sc); result = e; } override void visit(ScopeExp exp) { static if (LOGSEMANTIC) { printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars()); } if (exp.type) { result = exp; return; } ScopeDsymbol sds2 = exp.sds; TemplateInstance ti = sds2.isTemplateInstance(); while (ti) { WithScopeSymbol withsym; if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) return setError(); if (withsym && withsym.withstate.wthis) { Expression e = new VarExp(exp.loc, withsym.withstate.wthis); e = new DotTemplateInstanceExp(exp.loc, e, ti); result = e.expressionSemantic(sc); return; } if (ti.needsTypeInference(sc)) { if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) { Dsymbol p = td.toParent2(); FuncDeclaration fdthis = hasThis(sc); AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad && (td._scope.stc & STC.static_) == 0) { Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti.name, ti.tiargs); result = e.expressionSemantic(sc); return; } } else if (OverloadSet os = ti.tempdecl.isOverloadSet()) { FuncDeclaration fdthis = hasThis(sc); AggregateDeclaration ad = os.parent.isAggregateDeclaration(); if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad) { Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti.name, ti.tiargs); result = e.expressionSemantic(sc); return; } } // ti is an instance which requires IFTI. exp.sds = ti; exp.type = Type.tvoid; result = exp; return; } ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) return setError(); Dsymbol s = ti.toAlias(); if (s == ti) { exp.sds = ti; exp.type = Type.tvoid; result = exp; return; } sds2 = s.isScopeDsymbol(); if (sds2) { ti = sds2.isTemplateInstance(); //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); continue; } if (auto v = s.isVarDeclaration()) { if (!v.type) { exp.error("forward reference of %s `%s`", v.kind(), v.toChars()); return setError(); } if ((v.storage_class & STC.manifest) && v._init) { /* When an instance that will be converted to a constant exists, * the instance representation "foo!tiargs" is treated like a * variable name, and its recursive appearance check (note that * it's equivalent with a recursive instantiation of foo) is done * separately from the circular initialization check for the * eponymous enum variable declaration. * * template foo(T) { * enum bool foo = foo; // recursive definition check (v.inuse) * } * template bar(T) { * enum bool bar = bar!T; // recursive instantiation check (ti.inuse) * } */ if (ti.inuse) { exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars()); return setError(); } auto e = v.expandInitializer(exp.loc); ti.inuse++; e = e.expressionSemantic(sc); ti.inuse--; result = e; return; } } //printf("s = %s, '%s'\n", s.kind(), s.toChars()); auto e = resolve(exp.loc, sc, s, true); //printf("-1ScopeExp::semantic()\n"); result = e; return; } //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); //printf("\tparent = '%s'\n", sds2.parent.toChars()); sds2.dsymbolSemantic(sc); // (Aggregate|Enum)Declaration if (auto t = sds2.getType()) { result = (new TypeExp(exp.loc, t)).expressionSemantic(sc); return; } if (auto td = sds2.isTemplateDeclaration()) { result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc); return; } exp.sds = sds2; exp.type = Type.tvoid; //printf("-2ScopeExp::semantic() %s\n", toChars()); result = exp; } override void visit(NewExp exp) { static if (LOGSEMANTIC) { printf("NewExp::semantic() %s\n", exp.toChars()); if (exp.thisexp) printf("\tthisexp = %s\n", exp.thisexp.toChars()); printf("\tnewtype: %s\n", exp.newtype.toChars()); } if (exp.type) // if semantic() already run { result = exp; return; } // https://issues.dlang.org/show_bug.cgi?id=11581 // With the syntax `new T[edim]` or `thisexp.new T[edim]`, // T should be analyzed first and edim should go into arguments iff it's // not a tuple. Expression edim = null; if (!exp.arguments && exp.newtype.ty == Tsarray) { edim = (cast(TypeSArray)exp.newtype).dim; exp.newtype = (cast(TypeNext)exp.newtype).next; } ClassDeclaration cdthis = null; if (exp.thisexp) { exp.thisexp = exp.thisexp.expressionSemantic(sc); if (exp.thisexp.op == TOK.error) return setError(); cdthis = exp.thisexp.type.isClassHandle(); if (!cdthis) { exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars()); return setError(); } sc = sc.push(cdthis); exp.type = exp.newtype.typeSemantic(exp.loc, sc); sc = sc.pop(); } else { exp.type = exp.newtype.typeSemantic(exp.loc, sc); } if (exp.type.ty == Terror) return setError(); if (edim) { if (exp.type.toBasetype().ty == Ttuple) { // --> new T[edim] exp.type = new TypeSArray(exp.type, edim); exp.type = exp.type.typeSemantic(exp.loc, sc); if (exp.type.ty == Terror) return setError(); } else { // --> new T[](edim) exp.arguments = new Expressions(); exp.arguments.push(edim); exp.type = exp.type.arrayOf(); } } exp.newtype = exp.type; // in case type gets cast to something else Type tb = exp.type.toBasetype(); //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); if (arrayExpressionSemantic(exp.newargs, sc) || preFunctionParameters(sc, exp.newargs)) { return setError(); } if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) { return setError(); } if (exp.thisexp && tb.ty != Tclass) { exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars()); return setError(); } size_t nargs = exp.arguments ? exp.arguments.dim : 0; Expression newprefix = null; if (tb.ty == Tclass) { auto cd = (cast(TypeClass)tb).sym; cd.size(exp.loc); if (cd.sizeok != Sizeok.done) return setError(); if (!cd.ctor) cd.ctor = cd.searchCtor(); if (cd.noDefaultCtor && !nargs && !cd.defaultCtor) { exp.error("default construction is disabled for type `%s`", cd.type.toChars()); return setError(); } if (cd.isInterfaceDeclaration()) { exp.error("cannot create instance of interface `%s`", cd.toChars()); return setError(); } if (cd.isAbstract()) { exp.error("cannot create instance of abstract class `%s`", cd.toChars()); for (size_t i = 0; i < cd.vtbl.dim; i++) { FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); if (fd && fd.isAbstract()) { errorSupplemental(exp.loc, "function `%s` is not implemented", fd.toFullSignature()); } } return setError(); } // checkDeprecated() is already done in newtype.typeSemantic(). if (cd.isNested()) { /* We need a 'this' pointer for the nested class. * Ensure we have the right one. */ Dsymbol s = cd.toParent2(); //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars()); if (auto cdn = s.isClassDeclaration()) { if (!cdthis) { // Supply an implicit 'this' and try again exp.thisexp = new ThisExp(exp.loc); for (Dsymbol sp = sc.parent; 1; sp = sp.parent) { if (!sp) { exp.error("outer class `%s` `this` needed to `new` nested class `%s`", cdn.toChars(), cd.toChars()); return setError(); } ClassDeclaration cdp = sp.isClassDeclaration(); if (!cdp) continue; if (cdp == cdn || cdn.isBaseOf(cdp, null)) break; // Add a '.outer' and try again exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer); } exp.thisexp = exp.thisexp.expressionSemantic(sc); if (exp.thisexp.op == TOK.error) return setError(); cdthis = exp.thisexp.type.isClassHandle(); } if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) { //printf("cdthis = %s\n", cdthis.toChars()); exp.error("`this` for nested class must be of type `%s`, not `%s`", cdn.toChars(), exp.thisexp.type.toChars()); return setError(); } if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod)) { exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`", exp.newtype.toChars(), exp.thisexp.type.toChars()); return setError(); } } else if (exp.thisexp) { exp.error("`.new` is only for allocating nested classes"); return setError(); } else if (auto fdn = s.isFuncDeclaration()) { // make sure the parent context fdn of cd is reachable from sc if (!ensureStaticLinkTo(sc.parent, fdn)) { exp.error("outer function context of `%s` is needed to `new` nested class `%s`", fdn.toPrettyChars(), cd.toPrettyChars()); return setError(); } } else assert(0); } else if (exp.thisexp) { exp.error("`.new` is only for allocating nested classes"); return setError(); } if (cd.aggNew) { // Prepend the size argument to newargs[] Expression e = new IntegerExp(exp.loc, cd.size(exp.loc), Type.tsize_t); if (!exp.newargs) exp.newargs = new Expressions(); exp.newargs.shift(e); FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.aggNew, null, tb, exp.newargs); if (!f || f.errors) return setError(); checkFunctionAttributes(exp, sc, f); checkAccess(cd, exp.loc, sc, f); TypeFunction tf = cast(TypeFunction)f.type; Type rettype; if (functionParameters(exp.loc, sc, tf, null, exp.newargs, f, &rettype, &newprefix)) return setError(); exp.allocator = f.isNewDeclaration(); assert(exp.allocator); } else { if (exp.newargs && exp.newargs.dim) { exp.error("no allocator for `%s`", cd.toChars()); return setError(); } } if (cd.ctor) { FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, 0); if (!f || f.errors) return setError(); checkFunctionAttributes(exp, sc, f); checkAccess(cd, exp.loc, sc, f); TypeFunction tf = cast(TypeFunction)f.type; if (!exp.arguments) exp.arguments = new Expressions(); if (functionParameters(exp.loc, sc, tf, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) return setError(); exp.member = f.isCtorDeclaration(); assert(exp.member); } else { if (nargs) { exp.error("no constructor for `%s`", cd.toChars()); return setError(); } } } else if (tb.ty == Tstruct) { auto sd = (cast(TypeStruct)tb).sym; sd.size(exp.loc); if (sd.sizeok != Sizeok.done) return setError(); if (!sd.ctor) sd.ctor = sd.searchCtor(); if (sd.noDefaultCtor && !nargs) { exp.error("default construction is disabled for type `%s`", sd.type.toChars()); return setError(); } // checkDeprecated() is already done in newtype.typeSemantic(). if (sd.aggNew) { // Prepend the uint size argument to newargs[] Expression e = new IntegerExp(exp.loc, sd.size(exp.loc), Type.tsize_t); if (!exp.newargs) exp.newargs = new Expressions(); exp.newargs.shift(e); FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.aggNew, null, tb, exp.newargs); if (!f || f.errors) return setError(); checkFunctionAttributes(exp, sc, f); checkAccess(sd, exp.loc, sc, f); TypeFunction tf = cast(TypeFunction)f.type; Type rettype; if (functionParameters(exp.loc, sc, tf, null, exp.newargs, f, &rettype, &newprefix)) return setError(); exp.allocator = f.isNewDeclaration(); assert(exp.allocator); } else { if (exp.newargs && exp.newargs.dim) { exp.error("no allocator for `%s`", sd.toChars()); return setError(); } } if (sd.ctor && nargs) { FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, 0); if (!f || f.errors) return setError(); checkFunctionAttributes(exp, sc, f); checkAccess(sd, exp.loc, sc, f); TypeFunction tf = cast(TypeFunction)f.type; if (!exp.arguments) exp.arguments = new Expressions(); if (functionParameters(exp.loc, sc, tf, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) return setError(); exp.member = f.isCtorDeclaration(); assert(exp.member); if (checkFrameAccess(exp.loc, sc, sd, sd.fields.dim)) return setError(); } else { if (!exp.arguments) exp.arguments = new Expressions(); if (!sd.fit(exp.loc, sc, exp.arguments, tb)) return setError(); if (!sd.fill(exp.loc, exp.arguments, false)) return setError(); if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0)) return setError(); /* Since a `new` allocation may escape, check each of the arguments for escaping */ if (global.params.vsafe) { foreach (arg; *exp.arguments) { if (arg && checkNewEscape(sc, arg, false)) return setError(); } } } exp.type = exp.type.pointerTo(); } else if (tb.ty == Tarray && nargs) { Type tn = tb.nextOf().baseElemOf(); Dsymbol s = tn.toDsymbol(sc); AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null; if (ad && ad.noDefaultCtor) { exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars()); return setError(); } for (size_t i = 0; i < nargs; i++) { if (tb.ty != Tarray) { exp.error("too many arguments for array"); return setError(); } Expression arg = (*exp.arguments)[i]; arg = resolveProperties(sc, arg); arg = arg.implicitCastTo(sc, Type.tsize_t); arg = arg.optimize(WANTvalue); if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0) { exp.error("negative array index `%s`", arg.toChars()); return setError(); } (*exp.arguments)[i] = arg; tb = (cast(TypeDArray)tb).next.toBasetype(); } } else if (tb.isscalar()) { if (!nargs) { } else if (nargs == 1) { Expression e = (*exp.arguments)[0]; e = e.implicitCastTo(sc, tb); (*exp.arguments)[0] = e; } else { exp.error("more than one argument for construction of `%s`", exp.type.toChars()); return setError(); } exp.type = exp.type.pointerTo(); } else { exp.error("new can only create structs, dynamic arrays or class objects, not `%s`'s", exp.type.toChars()); return setError(); } //printf("NewExp: '%s'\n", toChars()); //printf("NewExp:type '%s'\n", type.toChars()); semanticTypeInfo(sc, exp.type); if (newprefix) { result = Expression.combine(newprefix, exp); return; } result = exp; } override void visit(NewAnonClassExp e) { static if (LOGSEMANTIC) { printf("NewAnonClassExp::semantic() %s\n", e.toChars()); //printf("thisexp = %p\n", thisexp); //printf("type: %s\n", type.toChars()); } Expression d = new DeclarationExp(e.loc, e.cd); sc = sc.push(); // just create new scope sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE d = d.expressionSemantic(sc); sc = sc.pop(); if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot()) { ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module; sds.members.push(e.cd); } Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments); Expression c = new CommaExp(e.loc, d, n); result = c.expressionSemantic(sc); } override void visit(SymOffExp e) { static if (LOGSEMANTIC) { printf("SymOffExp::semantic('%s')\n", e.toChars()); } //var.dsymbolSemantic(sc); if (!e.type) e.type = e.var.type.pointerTo(); if (auto v = e.var.isVarDeclaration()) { if (v.checkNestedReference(sc, e.loc)) return setError(); } else if (auto f = e.var.isFuncDeclaration()) { if (f.checkNestedReference(sc, e.loc)) return setError(); } result = e; } override void visit(VarExp e) { static if (LOGSEMANTIC) { printf("VarExp::semantic(%s)\n", e.toChars()); } if (auto fd = e.var.isFuncDeclaration()) { //printf("L%d fd = %s\n", __LINE__, f.toChars()); if (!fd.functionSemantic()) return setError(); } if (!e.type) e.type = e.var.type; if (e.type && !e.type.deco) e.type = e.type.typeSemantic(e.loc, sc); /* Fix for 1161 doesn't work because it causes protection * problems when instantiating imported templates passing private * variables as alias template parameters. */ //checkAccess(loc, sc, NULL, var); if (auto vd = e.var.isVarDeclaration()) { if (vd.checkNestedReference(sc, e.loc)) return setError(); // https://issues.dlang.org/show_bug.cgi?id=12025 // If the variable is not actually used in runtime code, // the purity violation error is redundant. //checkPurity(sc, vd); } else if (auto fd = e.var.isFuncDeclaration()) { // TODO: If fd isn't yet resolved its overload, the checkNestedReference // call would cause incorrect validation. // Maybe here should be moved in CallExp, or AddrExp for functions. if (fd.checkNestedReference(sc, e.loc)) return setError(); } else if (auto od = e.var.isOverDeclaration()) { e.type = Type.tvoid; // ambiguous type? } result = e; } override void visit(FuncExp exp) { static if (LOGSEMANTIC) { printf("FuncExp::semantic(%s)\n", exp.toChars()); if (exp.fd.treq) printf(" treq = %s\n", exp.fd.treq.toChars()); } if (exp.type) { result = exp; return; } Expression e = exp; uint olderrors; sc = sc.push(); // just create new scope sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE sc.protection = Prot(Prot.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506 /* fd.treq might be incomplete type, * so should not semantic it. * void foo(T)(T delegate(int) dg){} * foo(a=>a); // in IFTI, treq == T delegate(int) */ //if (fd.treq) // fd.treq = fd.treq.dsymbolSemantic(loc, sc); exp.genIdent(sc); // Set target of return type inference if (exp.fd.treq && !exp.fd.type.nextOf()) { TypeFunction tfv = null; if (exp.fd.treq.ty == Tdelegate || (exp.fd.treq.ty == Tpointer && exp.fd.treq.nextOf().ty == Tfunction)) tfv = cast(TypeFunction)exp.fd.treq.nextOf(); if (tfv) { TypeFunction tfl = cast(TypeFunction)exp.fd.type; tfl.next = tfv.nextOf(); } } //printf("td = %p, treq = %p\n", td, fd.treq); if (exp.td) { assert(exp.td.parameters && exp.td.parameters.dim); exp.td.dsymbolSemantic(sc); exp.type = Type.tvoid; // temporary type if (exp.fd.treq) // defer type determination { FuncExp fe; if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch) e = fe; else e = new ErrorExp(); } goto Ldone; } olderrors = global.errors; exp.fd.dsymbolSemantic(sc); if (olderrors == global.errors) { exp.fd.semantic2(sc); if (olderrors == global.errors) exp.fd.semantic3(sc); } if (olderrors != global.errors) { if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf()) (cast(TypeFunction)exp.fd.type).next = Type.terror; e = new ErrorExp(); goto Ldone; } // Type is a "delegate to" or "pointer to" the function literal if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate)) { exp.type = new TypeDelegate(exp.fd.type); exp.type = exp.type.typeSemantic(exp.loc, sc); exp.fd.tok = TOK.delegate_; } else { exp.type = new TypePointer(exp.fd.type); exp.type = exp.type.typeSemantic(exp.loc, sc); //type = fd.type.pointerTo(); /* A lambda expression deduced to function pointer might become * to a delegate literal implicitly. * * auto foo(void function() fp) { return 1; } * assert(foo({}) == 1); * * So, should keep fd.tok == TOKreserve if fd.treq == NULL. */ if (exp.fd.treq && exp.fd.treq.ty == Tpointer) { // change to non-nested exp.fd.tok = TOK.function_; exp.fd.vthis = null; } } exp.fd.tookAddressOf++; Ldone: sc = sc.pop(); result = e; } // used from CallExp::semantic() Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments) { if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.dim) { for (size_t k = 0; k < arguments.dim; k++) { Expression checkarg = (*arguments)[k]; if (checkarg.op == TOK.error) return checkarg; } exp.genIdent(sc); assert(exp.td.parameters && exp.td.parameters.dim); exp.td.dsymbolSemantic(sc); TypeFunction tfl = cast(TypeFunction)exp.fd.type; size_t dim = Parameter.dim(tfl.parameters); if (arguments.dim < dim) { // Default arguments are always typed, so they don't need inference. Parameter p = Parameter.getNth(tfl.parameters, arguments.dim); if (p.defaultArg) dim = arguments.dim; } if ((!tfl.varargs && arguments.dim == dim) || (tfl.varargs && arguments.dim >= dim)) { auto tiargs = new Objects(); tiargs.reserve(exp.td.parameters.dim); for (size_t i = 0; i < exp.td.parameters.dim; i++) { TemplateParameter tp = (*exp.td.parameters)[i]; for (size_t u = 0; u < dim; u++) { Parameter p = Parameter.getNth(tfl.parameters, u); if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) { Expression e = (*arguments)[u]; tiargs.push(e.type); u = dim; // break inner loop } } } auto ti = new TemplateInstance(exp.loc, exp.td, tiargs); return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc); } exp.error("cannot infer function literal type"); return new ErrorExp(); } return exp.expressionSemantic(sc); } override void visit(CallExp exp) { static if (LOGSEMANTIC) { printf("CallExp::semantic() %s\n", exp.toChars()); } if (exp.type) { result = exp; return; // semantic() already run } Type t1; Objects* tiargs = null; // initial list of template arguments Expression ethis = null; Type tthis = null; Expression e1org = exp.e1; if (exp.e1.op == TOK.comma) { /* Rewrite (a,b)(args) as (a,(b(args))) */ auto ce = cast(CommaExp)exp.e1; exp.e1 = ce.e2; ce.e2 = exp; result = ce.expressionSemantic(sc); return; } if (exp.e1.op == TOK.delegate_) { DelegateExp de = cast(DelegateExp)exp.e1; exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); visit(exp); return; } if (exp.e1.op == TOK.function_) { if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) return setError(); // Run e1 semantic even if arguments have any errors FuncExp fe = cast(FuncExp)exp.e1; exp.e1 = callExpSemantic(fe, sc, exp.arguments); if (exp.e1.op == TOK.error) { result = exp.e1; return; } } if (Expression ex = resolveUFCS(sc, exp)) { result = ex; return; } /* This recognizes: * foo!(tiargs)(funcargs) */ if (exp.e1.op == TOK.scope_) { ScopeExp se = cast(ScopeExp)exp.e1; TemplateInstance ti = se.sds.isTemplateInstance(); if (ti) { /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. */ WithScopeSymbol withsym; if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) return setError(); if (withsym && withsym.withstate.wthis) { exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis); exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti); goto Ldotti; } if (ti.needsTypeInference(sc, 1)) { /* Go with partial explicit specialization */ tiargs = ti.tiargs; assert(ti.tempdecl); if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) exp.e1 = new TemplateExp(exp.loc, td); else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) exp.e1 = new VarExp(exp.loc, od); else exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet()); } else { Expression e1x = exp.e1.expressionSemantic(sc); if (e1x.op == TOK.error) { result = e1x; return; } exp.e1 = e1x; } } } /* This recognizes: * expr.foo!(tiargs)(funcargs) */ Ldotti: if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type) { DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1; TemplateInstance ti = se.ti; { /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. */ if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc)) return setError(); if (ti.needsTypeInference(sc, 1)) { /* Go with partial explicit specialization */ tiargs = ti.tiargs; assert(ti.tempdecl); if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) exp.e1 = new DotTemplateExp(exp.loc, se.e1, td); else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) { exp.e1 = new DotVarExp(exp.loc, se.e1, od, true); } else exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet())); } else { Expression e1x = exp.e1.expressionSemantic(sc); if (e1x.op == TOK.error) { result = e1x; return; } exp.e1 = e1x; } } } Lagain: //printf("Lagain: %s\n", toChars()); exp.f = null; if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) { // semantic() run later for these } else { if (exp.e1.op == TOK.dotIdentifier) { DotIdExp die = cast(DotIdExp)exp.e1; exp.e1 = die.expressionSemantic(sc); /* Look for e1 having been rewritten to expr.opDispatch!(string) * We handle such earlier, so go back. * Note that in the rewrite, we carefully did not run semantic() on e1 */ if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type) { goto Ldotti; } } else { __gshared int nest; if (++nest > 500) { exp.error("recursive evaluation of `%s`", exp.toChars()); --nest; return setError(); } Expression ex = unaSemantic(exp, sc); --nest; if (ex) { result = ex; return; } } /* Look for e1 being a lazy parameter */ if (exp.e1.op == TOK.variable) { VarExp ve = cast(VarExp)exp.e1; if (ve.var.storage_class & STC.lazy_) { // lazy parameters can be called without violating purity and safety Type tw = ve.var.type; Type tc = ve.var.type.substWildTo(MODFlags.const_); auto tf = new TypeFunction(null, tc, 0, LINK.d, STC.safe | STC.pure_); (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757 auto t = new TypeDelegate(tf); ve.type = t.typeSemantic(exp.loc, sc); } VarDeclaration v = ve.var.isVarDeclaration(); if (v && ve.checkPurity(sc, v)) return setError(); } if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads) { SymOffExp se = cast(SymOffExp)exp.e1; exp.e1 = new VarExp(se.loc, se.var, true); exp.e1 = exp.e1.expressionSemantic(sc); } else if (exp.e1.op == TOK.dot) { DotExp de = cast(DotExp)exp.e1; if (de.e2.op == TOK.overloadSet) { ethis = de.e1; tthis = de.e1.type; exp.e1 = de.e2; } } else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction) { // Rewrite (*fp)(arguments) to fp(arguments) exp.e1 = (cast(PtrExp)exp.e1).e1; } } t1 = exp.e1.type ? exp.e1.type.toBasetype() : null; if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) return setError(); // Check for call operator overload if (t1) { if (t1.ty == Tstruct) { auto sd = (cast(TypeStruct)t1).sym; sd.size(exp.loc); // Resolve forward references to construct object if (sd.sizeok != Sizeok.done) return setError(); if (!sd.ctor) sd.ctor = sd.searchCtor(); // First look for constructor if (exp.e1.op == TOK.type && sd.ctor) { if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim)) goto Lx; auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); if (!sd.fill(exp.loc, sle.elements, true)) return setError(); if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim)) return setError(); // https://issues.dlang.org/show_bug.cgi?id=14556 // Set concrete type to avoid further redundant semantic(). sle.type = exp.e1.type; /* Constructor takes a mutable object, so don't use * the immutable initializer symbol. */ sle.useStaticInit = false; Expression e = sle; if (auto cf = sd.ctor.isCtorDeclaration()) { e = new DotVarExp(exp.loc, e, cf, true); } else if (auto td = sd.ctor.isTemplateDeclaration()) { e = new DotTemplateExp(exp.loc, e, td); } else if (auto os = sd.ctor.isOverloadSet()) { e = new DotExp(exp.loc, e, new OverExp(exp.loc, os)); } else assert(0); e = new CallExp(exp.loc, e, exp.arguments); e = e.expressionSemantic(sc); result = e; return; } // No constructor, look for overload of opCall if (search_function(sd, Id.call)) goto L1; // overload of opCall, therefore it's a call if (exp.e1.op != TOK.type) { if (sd.aliasthis && exp.e1.type != exp.att1) { if (!exp.att1 && exp.e1.type.checkAliasThisRec()) exp.att1 = exp.e1.type; exp.e1 = resolveAliasThis(sc, exp.e1); goto Lagain; } exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars()); return setError(); } /* It's a struct literal */ Lx: Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type); e = e.expressionSemantic(sc); result = e; return; } else if (t1.ty == Tclass) { L1: // Rewrite as e1.call(arguments) Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); e = new CallExp(exp.loc, e, exp.arguments); e = e.expressionSemantic(sc); result = e; return; } else if (exp.e1.op == TOK.type && t1.isscalar()) { Expression e; // Make sure to use the the enum type itself rather than its // base type // https://issues.dlang.org/show_bug.cgi?id=16346 if (exp.e1.type.ty == Tenum) { t1 = exp.e1.type; } if (!exp.arguments || exp.arguments.dim == 0) { e = t1.defaultInitLiteral(exp.loc); } else if (exp.arguments.dim == 1) { e = (*exp.arguments)[0]; e = e.implicitCastTo(sc, t1); e = new CastExp(exp.loc, e, t1); } else { exp.error("more than one argument for construction of `%s`", t1.toChars()); return setError(); } e = e.expressionSemantic(sc); result = e; return; } } static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments) { FuncDeclaration f = null; foreach (s; os.a) { if (tiargs && s.isFuncDeclaration()) continue; if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1)) { if (f2.errors) return null; if (f) { /* Error if match in more than one overload set, * even if one is a 'better' match than the other. */ ScopeDsymbol.multiplyDefined(loc, f, f2); } else f = f2; } } if (!f) .error(loc, "no overload matches for `%s`", os.toChars()); else if (f.errors) f = null; return f; } bool isSuper = false; if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration) { UnaExp ue = cast(UnaExp)exp.e1; Expression ue1 = ue.e1; Expression ue1old = ue1; // need for 'right this' check VarDeclaration v; if (ue1.op == TOK.variable && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis()) { ue.e1 = new TypeExp(ue1.loc, ue1.type); ue1 = null; } DotVarExp dve; DotTemplateExp dte; Dsymbol s; if (exp.e1.op == TOK.dotVariable) { dve = cast(DotVarExp)exp.e1; dte = null; s = dve.var; tiargs = null; } else { dve = null; dte = cast(DotTemplateExp)exp.e1; s = dte.td; } // Do overload resolution exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue1 ? ue1.type : null, exp.arguments); if (!exp.f || exp.f.errors || exp.f.type.ty == Terror) return setError(); if (exp.f.interfaceVirtual) { /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent */ auto b = exp.f.interfaceVirtual; auto ad2 = b.sym; ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); ue.e1 = ue.e1.expressionSemantic(sc); ue1 = ue.e1; auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim); assert(vi >= 0); exp.f = ad2.vtbl[vi].isFuncDeclaration(); assert(exp.f); } if (exp.f.needThis()) { AggregateDeclaration ad = exp.f.toParent2().isAggregateDeclaration(); ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); if (ue.e1.op == TOK.error) { result = ue.e1; return; } ethis = ue.e1; tthis = ue.e1.type; if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isscope)) { if (global.params.vsafe && checkParamArgumentEscape(sc, exp.f, Id.This, ethis, false)) return setError(); } } /* Cannot call public functions from inside invariant * (because then the invariant would have infinite recursion) */ if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOK.this_ && exp.f.addPostInvariant()) { exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars()); return setError(); } checkFunctionAttributes(exp, sc, exp.f); checkAccess(exp.loc, sc, ue.e1, exp.f); if (!exp.f.needThis()) { exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); } else { if (ue1old.checkRightThis(sc)) return setError(); if (exp.e1.op == TOK.dotVariable) { dve.var = exp.f; exp.e1.type = exp.f.type; } else { exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false); exp.e1 = exp.e1.expressionSemantic(sc); if (exp.e1.op == TOK.error) return setError(); ue = cast(UnaExp)exp.e1; } version (none) { printf("ue.e1 = %s\n", ue.e1.toChars()); printf("f = %s\n", exp.f.toChars()); printf("t = %s\n", t.toChars()); printf("e1 = %s\n", exp.e1.toChars()); printf("e1.type = %s\n", exp.e1.type.toChars()); } // See if we need to adjust the 'this' pointer AggregateDeclaration ad = exp.f.isThis(); ClassDeclaration cd = ue.e1.type.isClassHandle(); if (ad && cd && ad.isClassDeclaration()) { if (ue.e1.op == TOK.dotType) { ue.e1 = (cast(DotTypeExp)ue.e1).e1; exp.directcall = true; } else if (ue.e1.op == TOK.super_) exp.directcall = true; else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211 exp.directcall = true; if (ad != cd) { ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod)); ue.e1 = ue.e1.expressionSemantic(sc); } } } // If we've got a pointer to a function then deference it // https://issues.dlang.org/show_bug.cgi?id=16483 if (exp.e1.type.ty == Tpointer && exp.e1.type.nextOf().ty == Tfunction) { Expression e = new PtrExp(exp.loc, exp.e1); e.type = exp.e1.type.nextOf(); exp.e1 = e; } t1 = exp.e1.type; } else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_) { auto ad = sc.func ? sc.func.isThis() : null; auto cd = ad ? ad.isClassDeclaration() : null; isSuper = exp.e1.op == TOK.super_; if (isSuper) { // Base class constructor call if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) { exp.error("super class constructor call must be in a constructor"); return setError(); } if (!cd.baseClass.ctor) { exp.error("no super class constructor for `%s`", cd.baseClass.toChars()); return setError(); } } else { // `this` call expression must be inside a // constructor if (!ad || !sc.func.isCtorDeclaration()) { exp.error("constructor call must be in a constructor"); return setError(); } // https://issues.dlang.org/show_bug.cgi?id=18719 // If `exp` is a call expression to another constructor // then it means that all struct/class fields will be // initialized after this call. foreach (ref field; sc.ctorflow.fieldinit) { field.csx |= CSX.this_ctor | CSX.deprecate_18719; } } if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt)) { if (sc.inLoop || sc.ctorflow.callSuper & CSX.label) exp.error("constructor calls not allowed in loops or after labels"); if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor)) exp.error("multiple constructor calls"); if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor)) exp.error("an earlier `return` statement skips constructor"); sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor); } tthis = ad.type.addMod(sc.func.type.mod); auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor; if (auto os = ctor.isOverloadSet()) exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments); else exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, 0); if (!exp.f || exp.f.errors) return setError(); checkFunctionAttributes(exp, sc, exp.f); checkAccess(exp.loc, sc, null, exp.f); exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false); exp.e1 = exp.e1.expressionSemantic(sc); t1 = exp.e1.type; // BUG: this should really be done by checking the static // call graph if (exp.f == sc.func) { exp.error("cyclic constructor call"); return setError(); } } else if (exp.e1.op == TOK.overloadSet) { auto os = (cast(OverExp)exp.e1).vars; exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments); if (!exp.f) return setError(); if (ethis) exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false); else exp.e1 = new VarExp(exp.loc, exp.f, false); goto Lagain; } else if (!t1) { exp.error("function expected before `()`, not `%s`", exp.e1.toChars()); return setError(); } else if (t1.ty == Terror) { return setError(); } else if (t1.ty != Tfunction) { TypeFunction tf; const(char)* p; Dsymbol s; exp.f = null; if (exp.e1.op == TOK.function_) { // function literal that direct called is always inferred. assert((cast(FuncExp)exp.e1).fd); exp.f = (cast(FuncExp)exp.e1).fd; tf = cast(TypeFunction)exp.f.type; p = "function literal"; } else if (t1.ty == Tdelegate) { TypeDelegate td = cast(TypeDelegate)t1; assert(td.next.ty == Tfunction); tf = cast(TypeFunction)td.next; p = "delegate"; } else if (t1.ty == Tpointer && (cast(TypePointer)t1).next.ty == Tfunction) { tf = cast(TypeFunction)(cast(TypePointer)t1).next; p = "function pointer"; } else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) { DotVarExp dve = cast(DotVarExp)exp.e1; exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, 2); if (!exp.f) return setError(); if (exp.f.needThis()) { dve.var = exp.f; dve.type = exp.f.type; dve.hasOverloads = false; goto Lagain; } exp.e1 = new VarExp(dve.loc, exp.f, false); Expression e = new CommaExp(exp.loc, dve.e1, exp); result = e.expressionSemantic(sc); return; } else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) { s = (cast(VarExp)exp.e1).var; goto L2; } else if (exp.e1.op == TOK.template_) { s = (cast(TemplateExp)exp.e1).td; L2: exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments); if (!exp.f || exp.f.errors) return setError(); if (exp.f.needThis()) { if (hasThis(sc)) { // Supply an implicit 'this', as in // this.ident exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false); goto Lagain; } else if (isNeedThisScope(sc, exp.f)) { exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); return setError(); } } exp.e1 = new VarExp(exp.e1.loc, exp.f, false); goto Lagain; } else { exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars()); return setError(); } const(char)* failMessage; if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); argExpTypesToCBuffer(&buf, exp.arguments); buf.writeByte(')'); if (tthis) tthis.modToBuffer(&buf); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", p, exp.e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); if (failMessage) errorSupplemental(exp.loc, failMessage); return setError(); } // Purity and safety check should run after testing arguments matching if (exp.f) { exp.checkPurity(sc, exp.f); exp.checkSafety(sc, exp.f); exp.checkNogc(sc, exp.f); if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); } else if (sc.func && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe)) { bool err = false; if (!tf.purity && !(sc.flags & SCOPE.debug_) && sc.func.setImpure()) { exp.error("`pure` %s `%s` cannot call impure %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } if (!tf.isnogc && sc.func.setGC() && !(sc.flags & SCOPE.debug_) ) { exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } if (tf.trust <= TRUST.system && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } if (err) return setError(); } if (t1.ty == Tpointer) { Expression e = new PtrExp(exp.loc, exp.e1); e.type = tf; exp.e1 = e; } t1 = tf; } else if (exp.e1.op == TOK.variable) { // Do overload resolution VarExp ve = cast(VarExp)exp.e1; exp.f = ve.var.isFuncDeclaration(); assert(exp.f); tiargs = null; if (exp.f.overnext) exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, 2); else { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; const(char)* failMessage; if (!tf.callMatch(null, exp.arguments, 0, &failMessage)) { OutBuffer buf; buf.writeByte('('); argExpTypesToCBuffer(&buf, exp.arguments); buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); if (failMessage) errorSupplemental(exp.loc, failMessage); exp.f = null; } } if (!exp.f || exp.f.errors) return setError(); if (exp.f.needThis()) { // Change the ancestor lambdas to delegate before hasThis(sc) call. if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); if (hasThis(sc)) { // Supply an implicit 'this', as in // this.ident exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var); // Note: we cannot use f directly, because further overload resolution // through the supplied 'this' may cause different result. goto Lagain; } else if (isNeedThisScope(sc, exp.f)) { exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); return setError(); } } checkFunctionAttributes(exp, sc, exp.f); checkAccess(exp.loc, sc, null, exp.f); if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); ethis = null; tthis = null; if (ve.hasOverloads) { exp.e1 = new VarExp(ve.loc, exp.f, false); exp.e1.type = exp.f.type; } t1 = exp.f.type; } assert(t1.ty == Tfunction); Expression argprefix; if (!exp.arguments) exp.arguments = new Expressions(); if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, tthis, exp.arguments, exp.f, &exp.type, &argprefix)) return setError(); if (!exp.type) { exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922 // avoid recursive expression printing exp.error("forward reference to inferred return type of function call `%s`", exp.toChars()); return setError(); } if (exp.f && exp.f.tintro) { Type t = exp.type; int offset = 0; TypeFunction tf = cast(TypeFunction)exp.f.tintro; if (tf.next.isBaseOf(t, &offset) && offset) { exp.type = tf.next; result = Expression.combine(argprefix, exp.castTo(sc, t)); return; } } // Handle the case of a direct lambda call if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof) { exp.f.tookAddressOf = 0; } result = Expression.combine(argprefix, exp); if (isSuper) { auto ad = sc.func ? sc.func.isThis() : null; auto cd = ad ? ad.isClassDeclaration() : null; if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody) { // if super is defined in C++, it sets the vtable pointer to the base class // so we have to restore it, but still return 'this' from super() call: // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp) Loc loc = exp.loc; auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr); auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr); auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl); auto superTmpDecl = copyToTemp(0, "__superTmp", result); auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl); auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp); auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl)); Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl))); result = e.expressionSemantic(sc); } } } override void visit(DeclarationExp e) { if (e.type) { result = e; return; } static if (LOGSEMANTIC) { printf("DeclarationExp::semantic() %s\n", e.toChars()); } uint olderrors = global.errors; /* This is here to support extern(linkage) declaration, * where the extern(linkage) winds up being an AttribDeclaration * wrapper. */ Dsymbol s = e.declaration; while (1) { AttribDeclaration ad = s.isAttribDeclaration(); if (ad) { if (ad.decl && ad.decl.dim == 1) { s = (*ad.decl)[0]; continue; } } break; } VarDeclaration v = s.isVarDeclaration(); if (v) { // Do semantic() on initializer first, so: // int a = a; // will be illegal. e.declaration.dsymbolSemantic(sc); s.parent = sc.parent; } //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); // Insert into both local scope and function scope. // Must be unique in both. if (s.ident) { if (!sc.insert(s)) { e.error("declaration `%s` is already defined", s.toPrettyChars()); return setError(); } else if (sc.func) { // https://issues.dlang.org/show_bug.cgi?id=11720 // include Dataseg variables if ((s.isFuncDeclaration() || s.isAggregateDeclaration() || s.isEnumDeclaration() || v && v.isDataseg()) && !sc.func.localsymtab.insert(s)) { // https://issues.dlang.org/show_bug.cgi?id=18266 // set parent so that type semantic does not assert s.parent = sc.parent; Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident); assert(originalSymbol); e.error("declaration `%s` is already defined in another scope in `%s` at line `%d`", s.toPrettyChars(), sc.func.toChars(), originalSymbol.loc.linnum); return setError(); } else { // Disallow shadowing for (Scope* scx = sc.enclosing; scx && scx.func == sc.func; scx = scx.enclosing) { Dsymbol s2; if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) { // allow STC.local symbols to be shadowed // TODO: not really an optimal design auto decl = s2.isDeclaration(); if (!decl || !(decl.storage_class & STC.local)) { e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); return setError(); } } } } } } if (!s.isVarDeclaration()) { Scope* sc2 = sc; if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc)) sc2 = sc.push(); sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc); e.declaration.dsymbolSemantic(sc2); if (sc2 != sc) sc2.pop(); s.parent = sc.parent; } if (global.errors == olderrors) { e.declaration.semantic2(sc); if (global.errors == olderrors) { e.declaration.semantic3(sc); } } // todo: error in declaration should be propagated. e.type = Type.tvoid; result = e; } override void visit(TypeidExp exp) { static if (LOGSEMANTIC) { printf("TypeidExp::semantic() %s\n", exp.toChars()); } Type ta = isType(exp.obj); Expression ea = isExpression(exp.obj); Dsymbol sa = isDsymbol(exp.obj); //printf("ta %p ea %p sa %p\n", ta, ea, sa); if (ta) { dmd.typesem.resolve(ta, exp.loc, sc, &ea, &ta, &sa, true); } if (ea) { if (auto sym = getDsymbol(ea)) ea = resolve(exp.loc, sc, sym, false); else ea = ea.expressionSemantic(sc); ea = resolveProperties(sc, ea); ta = ea.type; if (ea.op == TOK.type) ea = null; } if (!ta) { //printf("ta %p ea %p sa %p\n", ta, ea, sa); exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : "")); return setError(); } if (global.params.vcomplex) ta.checkComplexTransition(exp.loc, sc); Expression e; auto tb = ta.toBasetype(); if (ea && tb.ty == Tclass) { if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp) { error(exp.loc, "Runtime type information is not supported for `extern(C++)` classes"); e = new ErrorExp(); } else { /* Get the dynamic type, which is .classinfo */ ea = ea.expressionSemantic(sc); e = new TypeidExp(ea.loc, ea); e.type = Type.typeinfoclass.type; } } else if (ta.ty == Terror) { e = new ErrorExp(); } else { // Handle this in the glue layer e = new TypeidExp(exp.loc, ta); e.type = getTypeInfoType(exp.loc, ta, sc); semanticTypeInfo(sc, ta); if (ea) { e = new CommaExp(exp.loc, ea, e); // execute ea e = e.expressionSemantic(sc); } } result = e; } override void visit(TraitsExp e) { result = semanticTraits(e, sc); } override void visit(HaltExp e) { static if (LOGSEMANTIC) { printf("HaltExp::semantic()\n"); } e.type = Type.tvoid; result = e; } override void visit(IsExp e) { /* is(targ id tok tspec) * is(targ id : tok2) * is(targ id == tok2) */ //printf("IsExp::semantic(%s)\n", toChars()); if (e.id && !(sc.flags & SCOPE.condition)) { e.error("can only declare type aliases within `static if` conditionals or `static assert`s"); return setError(); } Type tded = null; Scope* sc2 = sc.copy(); // keep sc.flags sc2.tinst = null; sc2.minst = null; sc2.flags |= SCOPE.fullinst; Type t = e.targ.trySemantic(e.loc, sc2); sc2.pop(); if (!t) goto Lno; // errors, so condition is false e.targ = t; if (e.tok2 != TOK.reserved) { switch (e.tok2) { case TOK.struct_: if (e.targ.ty != Tstruct) goto Lno; if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration()) goto Lno; tded = e.targ; break; case TOK.union_: if (e.targ.ty != Tstruct) goto Lno; if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration()) goto Lno; tded = e.targ; break; case TOK.class_: if (e.targ.ty != Tclass) goto Lno; if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) goto Lno; tded = e.targ; break; case TOK.interface_: if (e.targ.ty != Tclass) goto Lno; if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) goto Lno; tded = e.targ; break; case TOK.const_: if (!e.targ.isConst()) goto Lno; tded = e.targ; break; case TOK.immutable_: if (!e.targ.isImmutable()) goto Lno; tded = e.targ; break; case TOK.shared_: if (!e.targ.isShared()) goto Lno; tded = e.targ; break; case TOK.inout_: if (!e.targ.isWild()) goto Lno; tded = e.targ; break; case TOK.super_: // If class or interface, get the base class and interfaces if (e.targ.ty != Tclass) goto Lno; else { ClassDeclaration cd = (cast(TypeClass)e.targ).sym; auto args = new Parameters(); args.reserve(cd.baseclasses.dim); if (cd.semanticRun < PASS.semanticdone) cd.dsymbolSemantic(null); for (size_t i = 0; i < cd.baseclasses.dim; i++) { BaseClass* b = (*cd.baseclasses)[i]; args.push(new Parameter(STC.in_, b.type, null, null, null)); } tded = new TypeTuple(args); } break; case TOK.enum_: if (e.targ.ty != Tenum) goto Lno; if (e.id) tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc); else tded = e.targ; if (tded.ty == Terror) return setError(); break; case TOK.delegate_: if (e.targ.ty != Tdelegate) goto Lno; tded = (cast(TypeDelegate)e.targ).next; // the underlying function type break; case TOK.function_: case TOK.parameters: { if (e.targ.ty != Tfunction) goto Lno; tded = e.targ; /* Generate tuple from function parameter types. */ assert(tded.ty == Tfunction); Parameters* params = (cast(TypeFunction)tded).parameters; size_t dim = Parameter.dim(params); auto args = new Parameters(); args.reserve(dim); for (size_t i = 0; i < dim; i++) { Parameter arg = Parameter.getNth(params, i); assert(arg && arg.type); /* If one of the default arguments was an error, don't return an invalid tuple */ if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error) return setError(); args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); } tded = new TypeTuple(args); break; } case TOK.return_: /* Get the 'return type' for the function, * delegate, or pointer to function. */ if (e.targ.ty == Tfunction) tded = (cast(TypeFunction)e.targ).next; else if (e.targ.ty == Tdelegate) { tded = (cast(TypeDelegate)e.targ).next; tded = (cast(TypeFunction)tded).next; } else if (e.targ.ty == Tpointer && (cast(TypePointer)e.targ).next.ty == Tfunction) { tded = (cast(TypePointer)e.targ).next; tded = (cast(TypeFunction)tded).next; } else goto Lno; break; case TOK.argumentTypes: /* Generate a type tuple of the equivalent types used to determine if a * function argument of this type can be passed in registers. * The results of this are highly platform dependent, and intended * primarly for use in implementing va_arg(). */ tded = Target.toArgTypes(e.targ); if (!tded) goto Lno; // not valid for a parameter break; case TOK.vector: if (e.targ.ty != Tvector) goto Lno; tded = (cast(TypeVector)e.targ).basetype; break; default: assert(0); } // https://issues.dlang.org/show_bug.cgi?id=18753 if (tded) goto Lyes; goto Lno; } else if (e.tspec && !e.id && !(e.parameters && e.parameters.dim)) { /* Evaluate to true if targ matches tspec * is(targ == tspec) * is(targ : tspec) */ e.tspec = e.tspec.typeSemantic(e.loc, sc); //printf("targ = %s, %s\n", targ.toChars(), targ.deco); //printf("tspec = %s, %s\n", tspec.toChars(), tspec.deco); if (e.tok == TOK.colon) { if (e.targ.implicitConvTo(e.tspec)) goto Lyes; else goto Lno; } else /* == */ { if (e.targ.equals(e.tspec)) goto Lyes; else goto Lno; } } else if (e.tspec) { /* Evaluate to true if targ matches tspec. * If true, declare id as an alias for the specialized type. * is(targ == tspec, tpl) * is(targ : tspec, tpl) * is(targ id == tspec) * is(targ id : tspec) * is(targ id == tspec, tpl) * is(targ id : tspec, tpl) */ Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id"); e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null)); Objects dedtypes = Objects(e.parameters.dim); dedtypes.zero(); MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes); //printf("targ: %s\n", targ.toChars()); //printf("tspec: %s\n", tspec.toChars()); if (m <= MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) { goto Lno; } else { tded = cast(Type)dedtypes[0]; if (!tded) tded = e.targ; Objects tiargs = Objects(1); tiargs[0] = e.targ; /* Declare trailing parameters */ for (size_t i = 1; i < e.parameters.dim; i++) { TemplateParameter tp = (*e.parameters)[i]; Declaration s = null; m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); if (m <= MATCH.nomatch) goto Lno; s.dsymbolSemantic(sc); if (!sc.insert(s)) e.error("declaration `%s` is already defined", s.toChars()); unSpeculative(sc, s); } goto Lyes; } } else if (e.id) { /* Declare id as an alias for type targ. Evaluate to true * is(targ id) */ tded = e.targ; goto Lyes; } Lyes: if (e.id) { Dsymbol s; Tuple tup = isTuple(tded); if (tup) s = new TupleDeclaration(e.loc, e.id, &tup.objects); else s = new AliasDeclaration(e.loc, e.id, tded); s.dsymbolSemantic(sc); /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. * More investigation is needed. */ if (!tup && !sc.insert(s)) e.error("declaration `%s` is already defined", s.toChars()); unSpeculative(sc, s); } //printf("Lyes\n"); result = new IntegerExp(e.loc, 1, Type.tbool); return; Lno: //printf("Lno\n"); result = new IntegerExp(e.loc, 0, Type.tbool); } override void visit(BinAssignExp exp) { if (exp.type) { result = exp; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.op == TOK.arrayLength) { // arr.length op= e2; e = rewriteOpAssign(exp); e = e.expressionSemantic(sc); result = e; return; } if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); if (exp.e1.op == TOK.slice) (cast(SliceExp)exp.e1).arrayop = true; // T[] op= ... if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) { // T[] op= T exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); } else if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } exp.type = exp.e1.type; result = arrayOp(exp, sc); return; } exp.e1 = exp.e1.expressionSemantic(sc); exp.e1 = exp.e1.optimize(WANTvalue); exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); exp.type = exp.e1.type; if (auto ad = isAggregate(exp.e1.type)) { if (const s = search_function(ad, Id.opOpAssign)) { error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars()); return setError(); } } if (exp.e1.checkScalar() || exp.e1.checkReadModifyWrite(exp.op, exp.e2)) return setError(); int arith = (exp.op == TOK.addAssign || exp.op == TOK.minAssign || exp.op == TOK.mulAssign || exp.op == TOK.divAssign || exp.op == TOK.modAssign || exp.op == TOK.powAssign); int bitwise = (exp.op == TOK.andAssign || exp.op == TOK.orAssign || exp.op == TOK.xorAssign); int shift = (exp.op == TOK.leftShiftAssign || exp.op == TOK.rightShiftAssign || exp.op == TOK.unsignedRightShiftAssign); if (bitwise && exp.type.toBasetype().ty == Tbool) exp.e2 = exp.e2.implicitCastTo(sc, exp.type); else if (exp.checkNoBool()) return setError(); if ((exp.op == TOK.addAssign || exp.op == TOK.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral()) { result = scaleFactor(exp, sc); return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } if (arith && exp.checkArithmeticBin()) return setError(); if ((bitwise || shift) && exp.checkIntegralBin()) return setError(); if (shift) { if (exp.e2.type.toBasetype().ty != Tvector) exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); } if (!Target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } if (exp.e1.op == TOK.error || exp.e2.op == TOK.error) return setError(); e = exp.checkOpAssignTypes(sc); if (e.op == TOK.error) { result = e; return; } assert(e.op == TOK.assign || e == exp); result = (cast(BinExp)e).reorderSettingAAElem(sc); } private Expression compileIt(CompileExp exp) { OutBuffer buf; if (exp.exps) { foreach (ex; *exp.exps) { sc = sc.startCTFE(); auto e = ex.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); // allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); if (e.op == TOK.error) { //errorSupplemental(exp.loc, "while evaluating `mixin(%s)`", ex.toChars()); return null; } StringExp se = e.toStringExp(); if (se) { se = se.toUTF8(sc); buf.printf("%.*s", cast(int)se.len, se.string); } else buf.printf("%s", e.toChars()); } } uint errors = global.errors; const len = buf.offset; const str = buf.extractString()[0 .. len]; scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); Expression e = p.parseExpression(); if (p.errors) { assert(global.errors != errors); // should have caught all these cases return null; } if (p.token.value != TOK.endOfFile) { exp.error("incomplete mixin expression `%s`", str.ptr); return null; } return e; } override void visit(CompileExp exp) { /* https://dlang.org/spec/expression.html#mixin_expressions */ static if (LOGSEMANTIC) { printf("CompileExp::semantic('%s')\n", exp.toChars()); } auto e = compileIt(exp); if (!e) return setError(); result = e.expressionSemantic(sc); } override void visit(ImportExp e) { static if (LOGSEMANTIC) { printf("ImportExp::semantic('%s')\n", e.toChars()); } auto se = semanticString(sc, e.e1, "file name argument"); if (!se) return setError(); se = se.toUTF8(sc); auto namez = se.toStringz().ptr; if (!global.params.fileImppath) { e.error("need `-J` switch to import text file `%s`", namez); return setError(); } /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory * ('Path Traversal') attacks. * http://cwe.mitre.org/data/definitions/22.html */ auto name = FileName.safeSearchPath(global.filePath, namez); if (!name) { e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); return setError(); } sc._module.contentImportedFiles.push(name); if (global.params.verbose) message("file %.*s\t(%s)", cast(int)se.len, se.string, name); if (global.params.moduleDeps !is null) { OutBuffer* ob = global.params.moduleDeps; Module imod = sc.instantiatingModule(); if (!global.params.moduleDepsFile) ob.writestring("depsFile "); ob.writestring(imod.toPrettyChars()); ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); if (global.params.moduleDepsFile) ob.writestring("string : "); ob.write(se.string, se.len); ob.writestring(" ("); escapePath(ob, name); ob.writestring(")"); ob.writenl(); } { auto f = File(name); if (f.read()) { e.error("cannot read file `%s`", f.toChars()); return setError(); } else { f._ref = 1; se = new StringExp(e.loc, f.buffer, f.len); } } result = se.expressionSemantic(sc); } override void visit(AssertExp exp) { // https://dlang.org/spec/expression.html#assert_expressions static if (LOGSEMANTIC) { printf("AssertExp::semantic('%s')\n", exp.toChars()); } if (Expression ex = unaSemantic(exp, sc)) { result = ex; return; } exp.e1 = resolveProperties(sc, exp.e1); // BUG: see if we can do compile time elimination of the Assert exp.e1 = exp.e1.optimize(WANTvalue); exp.e1 = exp.e1.toBoolean(sc); if (exp.msg) { exp.msg = exp.msg.expressionSemantic(sc); exp.msg = resolveProperties(sc, exp.msg); exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); exp.msg = exp.msg.optimize(WANTvalue); } if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (exp.msg && exp.msg.op == TOK.error) { result = exp.msg; return; } auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg); if (f1 || f2) return setError(); if (exp.e1.isBool(false)) { /* This is an `assert(0)` which means halt program execution */ FuncDeclaration fd = sc.parent.isFuncDeclaration(); if (fd) fd.hasReturnExp |= 4; sc.ctorflow.orCSX(CSX.halt); if (global.params.useAssert == CHECKENABLE.off) { Expression e = new HaltExp(exp.loc); e = e.expressionSemantic(sc); result = e; return; } } exp.type = Type.tvoid; result = exp; } override void visit(DotIdExp exp) { static if (LOGSEMANTIC) { printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op)); } Expression e = exp.semanticY(sc, 1); if (e && isDotOpDispatch(e)) { uint errors = global.startGagging(); e = resolvePropertiesX(sc, e); if (global.endGagging(errors)) e = null; /* fall down to UFCS */ else { result = e; return; } } if (!e) // if failed to find the property { /* If ident is not a valid property, rewrite: * e1.ident * as: * .ident(e1) */ e = resolveUFCSProperties(sc, exp); } result = e; } override void visit(DotTemplateExp e) { if (Expression ex = unaSemantic(e, sc)) { result = ex; return; } result = e; } override void visit(DotVarExp exp) { static if (LOGSEMANTIC) { printf("DotVarExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } exp.var = exp.var.toAlias().isDeclaration(); exp.e1 = exp.e1.expressionSemantic(sc); if (auto tup = exp.var.isTupleDeclaration()) { /* Replace: * e1.tuple(a, b, c) * with: * tuple(e1.a, e1.b, e1.c) */ Expression e0; Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1; auto exps = new Expressions(); exps.reserve(tup.objects.dim); for (size_t i = 0; i < tup.objects.dim; i++) { RootObject o = (*tup.objects)[i]; Expression e; if (o.dyncast() == DYNCAST.expression) { e = cast(Expression)o; if (e.op == TOK.dSymbol) { Dsymbol s = (cast(DsymbolExp)e).s; e = new DotVarExp(exp.loc, ev, s.isDeclaration()); } } else if (o.dyncast() == DYNCAST.dsymbol) { e = new DsymbolExp(exp.loc, cast(Dsymbol)o); } else if (o.dyncast() == DYNCAST.type) { e = new TypeExp(exp.loc, cast(Type)o); } else { exp.error("`%s` is not an expression", o.toChars()); return setError(); } exps.push(e); } Expression e = new TupleExp(exp.loc, e0, exps); e = e.expressionSemantic(sc); result = e; return; } exp.e1 = exp.e1.addDtorHook(sc); Type t1 = exp.e1.type; if (FuncDeclaration fd = exp.var.isFuncDeclaration()) { // for functions, do checks after overload resolution if (!fd.functionSemantic()) return setError(); /* https://issues.dlang.org/show_bug.cgi?id=13843 * If fd obviously has no overloads, we should * normalize AST, and it will give a chance to wrap fd with FuncExp. */ if (fd.isNested() || fd.isFuncLiteralDeclaration()) { // (e1, fd) auto e = resolve(exp.loc, sc, fd, false); result = Expression.combine(exp.e1, e); return; } exp.type = fd.type; assert(exp.type); } else if (OverDeclaration od = exp.var.isOverDeclaration()) { exp.type = Type.tvoid; // ambiguous type? } else { exp.type = exp.var.type; if (!exp.type && global.errors) // var is goofed up, just return error. return setError(); assert(exp.type); if (t1.ty == Tpointer) t1 = t1.nextOf(); exp.type = exp.type.addMod(t1.mod); Dsymbol vparent = exp.var.toParent(); AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1)) exp.e1 = e1x; else { /* Later checkRightThis will report correct error for invalid field variable access. */ Expression e = new VarExp(exp.loc, exp.var); e = e.expressionSemantic(sc); result = e; return; } checkAccess(exp.loc, sc, exp.e1, exp.var); VarDeclaration v = exp.var.isVarDeclaration(); if (v && (v.isDataseg() || (v.storage_class & STC.manifest))) { Expression e = expandVar(WANTvalue, v); if (e) { result = e; return; } } if (v && v.isDataseg()) // fix https://issues.dlang.org/show_bug.cgi?id=8238 { // (e1, v) checkAccess(exp.loc, sc, exp.e1, v); Expression e = new VarExp(exp.loc, v); e = new CommaExp(exp.loc, exp.e1, e); e = e.expressionSemantic(sc); result = e; return; } } //printf("-DotVarExp::semantic('%s')\n", toChars()); result = exp; } override void visit(DotTemplateInstanceExp exp) { static if (LOGSEMANTIC) { printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars()); } // Indicate we need to resolve by UFCS. Expression e = exp.semanticY(sc, 1); if (!e) e = resolveUFCSProperties(sc, exp); result = e; } override void visit(DelegateExp e) { static if (LOGSEMANTIC) { printf("DelegateExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } e.e1 = e.e1.expressionSemantic(sc); e.type = new TypeDelegate(e.func.type); e.type = e.type.typeSemantic(e.loc, sc); FuncDeclaration f = e.func.toAliasFunc(); AggregateDeclaration ad = f.toParent().isAggregateDeclaration(); if (f.needThis()) e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); /* A delegate takes the address of e.e1 in order to set the .ptr field * https://issues.dlang.org/show_bug.cgi?id=18575 */ if (global.params.vsafe && e.e1.type.toBasetype().ty == Tstruct) { if (auto v = expToVariable(e.e1)) { if (!checkAddressVar(sc, e, v)) return setError(); } } if (f.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)f.type; if (!MODmethodConv(e.e1.type.mod, f.type.mod)) { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod); MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod); e.error("%smethod `%s` is not callable using a %s`%s`", funcBuf.peekString(), f.toPrettyChars(), thisBuf.peekString(), e.e1.toChars()); return setError(); } } if (ad && ad.isClassDeclaration() && ad.type != e.e1.type) { // A downcast is required for interfaces // https://issues.dlang.org/show_bug.cgi?id=3706 e.e1 = new CastExp(e.loc, e.e1, ad.type); e.e1 = e.e1.expressionSemantic(sc); } result = e; } override void visit(DotTypeExp exp) { static if (LOGSEMANTIC) { printf("DotTypeExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (auto e = unaSemantic(exp, sc)) { result = e; return; } exp.type = exp.sym.getType().addMod(exp.e1.type.mod); result = exp; } override void visit(AddrExp exp) { static if (LOGSEMANTIC) { printf("AddrExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (Expression ex = unaSemantic(exp, sc)) { result = ex; return; } int wasCond = exp.e1.op == TOK.question; if (exp.e1.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1; TemplateInstance ti = dti.ti; { //assert(ti.needsTypeInference(sc)); ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) // if template failed to expand return setError(); Dsymbol s = ti.toAlias(); FuncDeclaration f = s.isFuncDeclaration(); if (f) { exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f); exp.e1 = exp.e1.expressionSemantic(sc); } } } else if (exp.e1.op == TOK.scope_) { TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance(); if (ti) { //assert(ti.needsTypeInference(sc)); ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) // if template failed to expand return setError(); Dsymbol s = ti.toAlias(); FuncDeclaration f = s.isFuncDeclaration(); if (f) { exp.e1 = new VarExp(exp.e1.loc, f); exp.e1 = exp.e1.expressionSemantic(sc); } } } exp.e1 = exp.e1.toLvalue(sc, null); if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (checkNonAssignmentArrayOp(exp.e1)) return setError(); if (!exp.e1.type) { exp.error("cannot take address of `%s`", exp.e1.toChars()); return setError(); } bool hasOverloads; if (auto f = isFuncAddress(exp, &hasOverloads)) { if (!hasOverloads && f.checkForwardRef(exp.loc)) return setError(); } else if (!exp.e1.type.deco) { if (exp.e1.op == TOK.variable) { VarExp ve = cast(VarExp)exp.e1; Declaration d = ve.var; exp.error("forward reference to %s `%s`", d.kind(), d.toChars()); } else exp.error("forward reference to `%s`", exp.e1.toChars()); return setError(); } exp.type = exp.e1.type.pointerTo(); // See if this should really be a delegate if (exp.e1.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)exp.e1; FuncDeclaration f = dve.var.isFuncDeclaration(); if (f) { f = f.toAliasFunc(); // FIXME, should see overloads // https://issues.dlang.org/show_bug.cgi?id=1983 if (!dve.hasOverloads) f.tookAddressOf++; Expression e; if (f.needThis()) e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads); else // It is a function pointer. Convert &v.f() --> (v, &V.f()) e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads))); e = e.expressionSemantic(sc); result = e; return; } // Look for misaligned pointer in @safe mode if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true)) return setError(); if (global.params.vsafe) { if (VarDeclaration v = expToVariable(dve.e1)) { if (!checkAddressVar(sc, exp, v)) return setError(); } } } else if (exp.e1.op == TOK.variable) { VarExp ve = cast(VarExp)exp.e1; VarDeclaration v = ve.var.isVarDeclaration(); if (v) { if (!checkAddressVar(sc, exp, v)) return setError(); ve.checkPurity(sc, v); } FuncDeclaration f = ve.var.isFuncDeclaration(); if (f) { /* Because nested functions cannot be overloaded, * mark here that we took its address because castTo() * may not be called with an exact match. */ if (!ve.hasOverloads || f.isNested()) f.tookAddressOf++; if (f.isNested()) { if (f.isFuncLiteralDeclaration()) { if (!f.FuncDeclaration.isNested()) { /* Supply a 'null' for a this pointer if no this is available */ Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads); e = e.expressionSemantic(sc); result = e; return; } } Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads); e = e.expressionSemantic(sc); result = e; return; } if (f.needThis()) { if (hasThis(sc)) { /* Should probably supply 'this' after overload resolution, * not before. */ Expression ethis = new ThisExp(exp.loc); Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads); e = e.expressionSemantic(sc); result = e; return; } if (sc.func && !sc.intypeof) { if (sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars()); } } } } } else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.vsafe) { if (VarDeclaration v = expToVariable(exp.e1)) { if (!checkAddressVar(sc, exp, v)) return setError(); } } else if (exp.e1.op == TOK.call) { CallExp ce = cast(CallExp)exp.e1; if (ce.e1.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)ce.e1.type; if (tf.isref && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`", ce.e1.toChars(), sc.func.toChars()); } } } else if (exp.e1.op == TOK.index) { /* For: * int[3] a; * &a[i] * check 'a' the same as for a regular variable */ if (VarDeclaration v = expToVariable(exp.e1)) { if (global.params.vsafe && !checkAddressVar(sc, exp, v)) return setError(); exp.e1.checkPurity(sc, v); } } else if (wasCond) { /* a ? b : c was transformed to *(a ? &b : &c), but we still * need to do safety checks */ assert(exp.e1.op == TOK.star); PtrExp pe = cast(PtrExp)exp.e1; assert(pe.e1.op == TOK.question); CondExp ce = cast(CondExp)pe.e1; assert(ce.e1.op == TOK.address); assert(ce.e2.op == TOK.address); // Re-run semantic on the address expressions only ce.e1.type = null; ce.e1 = ce.e1.expressionSemantic(sc); ce.e2.type = null; ce.e2 = ce.e2.expressionSemantic(sc); } result = exp.optimize(WANTvalue); } override void visit(PtrExp exp) { static if (LOGSEMANTIC) { printf("PtrExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } Type tb = exp.e1.type.toBasetype(); switch (tb.ty) { case Tpointer: exp.type = (cast(TypePointer)tb).next; break; case Tsarray: case Tarray: if (isNonAssignmentArrayOp(exp.e1)) goto default; exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars()); exp.type = (cast(TypeArray)tb).next; exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo()); break; case Terror: return setError(); default: exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars()); goto case Terror; } if (exp.checkValue()) return setError(); result = exp; } override void visit(NegExp exp) { static if (LOGSEMANTIC) { printf("NegExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } fix16997(sc, exp); exp.type = exp.e1.type; Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp.e1)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op)) { result = exp.incompatibleTypes(); return; } if (exp.e1.checkNoBool()) return setError(); if (exp.e1.checkArithmetic()) return setError(); result = exp; } override void visit(UAddExp exp) { static if (LOGSEMANTIC) { printf("UAddExp::semantic('%s')\n", exp.toChars()); } assert(!exp.type); Expression e = exp.op_overload(sc); if (e) { result = e; return; } fix16997(sc, exp); if (!Target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op)) { result = exp.incompatibleTypes(); return; } if (exp.e1.checkNoBool()) return setError(); if (exp.e1.checkArithmetic()) return setError(); result = exp.e1; } override void visit(ComExp exp) { if (exp.type) { result = exp; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } fix16997(sc, exp); exp.type = exp.e1.type; Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp.e1)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op)) { result = exp.incompatibleTypes(); return; } if (exp.e1.checkNoBool()) return setError(); if (exp.e1.checkIntegral()) return setError(); result = exp; } override void visit(NotExp e) { if (e.type) { result = e; return; } e.setNoderefOperand(); // Note there is no operator overload if (Expression ex = unaSemantic(e, sc)) { result = ex; return; } // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (e.e1.op == TOK.type) e.e1 = resolveAliasThis(sc, e.e1); e.e1 = resolveProperties(sc, e.e1); e.e1 = e.e1.toBoolean(sc); if (e.e1.type == Type.terror) { result = e.e1; return; } if (!Target.isVectorOpSupported(e.e1.type.toBasetype(), e.op)) { result = e.incompatibleTypes(); } // https://issues.dlang.org/show_bug.cgi?id=13910 // Today NotExp can take an array as its operand. if (checkNonAssignmentArrayOp(e.e1)) return setError(); e.type = Type.tbool; result = e; } override void visit(DeleteExp exp) { if (!sc.isDeprecated) { // @@@DEPRECATED_2019-02@@@ // 1. Deprecation for 1 year // 2. Error for 1 year // 3. Removal of keyword, "delete" can be used for other identities if (!exp.isRAII) deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); } if (Expression ex = unaSemantic(exp, sc)) { result = ex; return; } exp.e1 = resolveProperties(sc, exp.e1); exp.e1 = exp.e1.modifiableLvalue(sc, null); if (exp.e1.op == TOK.error) { result = exp.e1; return; } exp.type = Type.tvoid; AggregateDeclaration ad = null; Type tb = exp.e1.type.toBasetype(); switch (tb.ty) { case Tclass: { auto cd = (cast(TypeClass)tb).sym; if (cd.isCOMinterface()) { /* Because COM classes are deleted by IUnknown.Release() */ exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars()); return setError(); } ad = cd; break; } case Tpointer: tb = (cast(TypePointer)tb).next.toBasetype(); if (tb.ty == Tstruct) { ad = (cast(TypeStruct)tb).sym; auto f = ad.aggDelete; auto fd = ad.dtor; if (!f) { semanticTypeInfo(sc, tb); break; } /* Construct: * ea = copy e1 to a tmp to do side effects only once * eb = call destructor * ec = call deallocator */ Expression ea = null; Expression eb = null; Expression ec = null; VarDeclaration v = null; if (fd && f) { v = copyToTemp(0, "__tmpea", exp.e1); v.dsymbolSemantic(sc); ea = new DeclarationExp(exp.loc, v); ea.type = v.type; } if (fd) { Expression e = ea ? new VarExp(exp.loc, v) : exp.e1; e = new DotVarExp(Loc.initial, e, fd, false); eb = new CallExp(exp.loc, e); eb = eb.expressionSemantic(sc); } if (f) { Type tpv = Type.tvoid.pointerTo(); Expression e = ea ? new VarExp(exp.loc, v) : exp.e1.castTo(sc, tpv); e = new CallExp(exp.loc, new VarExp(exp.loc, f, false), e); ec = e.expressionSemantic(sc); } ea = Expression.combine(ea, eb, ec); assert(ea); result = ea; return; } break; case Tarray: { Type tv = tb.nextOf().baseElemOf(); if (tv.ty == Tstruct) { ad = (cast(TypeStruct)tv).sym; if (ad.dtor) semanticTypeInfo(sc, ad.type); } break; } default: exp.error("cannot delete type `%s`", exp.e1.type.toChars()); return setError(); } bool err = false; if (ad) { if (ad.dtor) { err |= exp.checkPurity(sc, ad.dtor); err |= exp.checkSafety(sc, ad.dtor); err |= exp.checkNogc(sc, ad.dtor); } if (ad.aggDelete && tb.ty != Tarray) { err |= exp.checkPurity(sc, ad.aggDelete); err |= exp.checkSafety(sc, ad.aggDelete); err |= exp.checkNogc(sc, ad.aggDelete); } if (err) return setError(); } if (!sc.intypeof && sc.func && !exp.isRAII && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars()); err = true; } if (err) return setError(); result = exp; } override void visit(CastExp exp) { static if (LOGSEMANTIC) { printf("CastExp::semantic('%s')\n", exp.toChars()); } //static int x; assert(++x < 10); if (exp.type) { result = exp; return; } if (exp.to) { exp.to = exp.to.typeSemantic(exp.loc, sc); if (exp.to == Type.terror) return setError(); if (!exp.to.hasPointers()) exp.setNoderefOperand(); // When e1 is a template lambda, this cast may instantiate it with // the type 'to'. exp.e1 = inferType(exp.e1, exp.to); } if (auto e = unaSemantic(exp, sc)) { result = e; return; } auto e1x = resolveProperties(sc, exp.e1); if (e1x.op == TOK.error) { result = e1x; return; } if (e1x.checkType()) return setError(); exp.e1 = e1x; if (!exp.e1.type) { exp.error("cannot cast `%s`", exp.e1.toChars()); return setError(); } if (!exp.to) // Handle cast(const) and cast(immutable), etc. { exp.to = exp.e1.type.castMod(exp.mod); exp.to = exp.to.typeSemantic(exp.loc, sc); if (exp.to == Type.terror) return setError(); } if (exp.to.ty == Ttuple) { exp.error("cannot cast `%s` to tuple type `%s`", exp.e1.toChars(), exp.to.toChars()); return setError(); } // cast(void) is used to mark e1 as unused, so it is safe if (exp.to.ty == Tvoid) { exp.type = exp.to; result = exp; return; } if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0) { if (Expression e = exp.op_overload(sc)) { result = e.implicitCastTo(sc, exp.to); return; } } Type t1b = exp.e1.type.toBasetype(); Type tob = exp.to.toBasetype(); if (tob.ty == Tstruct && !tob.equals(t1b)) { /* Look to replace: * cast(S)t * with: * S(t) */ // Rewrite as to.call(e1) Expression e = new TypeExp(exp.loc, exp.to); e = new CallExp(exp.loc, e, exp.e1); e = e.trySemantic(sc); if (e) { result = e; return; } } if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); } // Look for casting to a vector type if (tob.ty == Tvector && t1b.ty != Tvector) { result = new VectorExp(exp.loc, exp.e1, exp.to); return; } Expression ex = exp.e1.castTo(sc, exp.to); if (ex.op == TOK.error) { result = ex; return; } // Check for unsafe casts if (sc.func && !sc.intypeof && !isSafeCast(ex, t1b, tob) && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); return setError(); } result = ex; } override void visit(VectorExp exp) { static if (LOGSEMANTIC) { printf("VectorExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } exp.e1 = exp.e1.expressionSemantic(sc); exp.type = exp.to.typeSemantic(exp.loc, sc); if (exp.e1.op == TOK.error || exp.type.ty == Terror) { result = exp.e1; return; } Type tb = exp.type.toBasetype(); assert(tb.ty == Tvector); TypeVector tv = cast(TypeVector)tb; Type te = tv.elementType(); exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc)); bool checkElem(Expression elem) { if (elem.isConst() == 1) return false; exp.error("constant expression expected, not `%s`", elem.toChars()); return true; } exp.e1 = exp.e1.optimize(WANTvalue); bool res; if (exp.e1.op == TOK.arrayLiteral) { foreach (i; 0 .. exp.dim) { // Do not stop on first error - check all AST nodes even if error found res |= checkElem((cast(ArrayLiteralExp)exp.e1).getElement(i)); } } else if (exp.e1.type.ty == Tvoid) checkElem(exp.e1); result = res ? new ErrorExp() : exp; } override void visit(SliceExp exp) { static if (LOGSEMANTIC) { printf("SliceExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } // operator overloading should be handled in ArrayExp already. if (Expression ex = unaSemantic(exp, sc)) { result = ex; return; } exp.e1 = resolveProperties(sc, exp.e1); if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) { if (exp.lwr || exp.upr) { exp.error("cannot slice type `%s`", exp.e1.toChars()); return setError(); } Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf()); result = e.expressionSemantic(sc); return; } if (!exp.lwr && !exp.upr) { if (exp.e1.op == TOK.arrayLiteral) { // Convert [a,b,c][] to [a,b,c] Type t1b = exp.e1.type.toBasetype(); Expression e = exp.e1; if (t1b.ty == Tsarray) { e = e.copy(); e.type = t1b.nextOf().arrayOf(); } result = e; return; } if (exp.e1.op == TOK.slice) { // Convert e[][] to e[] SliceExp se = cast(SliceExp)exp.e1; if (!se.lwr && !se.upr) { result = se; return; } } if (isArrayOpOperand(exp.e1)) { // Convert (a[]+b[])[] to a[]+b[] result = exp.e1; return; } } if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (exp.e1.type.ty == Terror) return setError(); Type t1b = exp.e1.type.toBasetype(); if (t1b.ty == Tpointer) { if ((cast(TypePointer)t1b).next.ty == Tfunction) { exp.error("cannot slice function pointer `%s`", exp.e1.toChars()); return setError(); } if (!exp.lwr || !exp.upr) { exp.error("need upper and lower bound to slice pointer"); return setError(); } if (sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("pointer slicing not allowed in safe functions"); return setError(); } } else if (t1b.ty == Tarray) { } else if (t1b.ty == Tsarray) { if (!exp.arrayop && global.params.vsafe) { /* Slicing a static array is like taking the address of it. * Perform checks as if e[] was &e */ if (VarDeclaration v = expToVariable(exp.e1)) { if (exp.e1.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)exp.e1; if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) && !(v.storage_class & STC.ref_)) { // because it's a class v = null; } } if (v && !checkAddressVar(sc, exp, v)) return setError(); } } } else if (t1b.ty == Ttuple) { if (!exp.lwr && !exp.upr) { result = exp.e1; return; } if (!exp.lwr || !exp.upr) { exp.error("need upper and lower bound to slice tuple"); return setError(); } } else if (t1b.ty == Tvector) { // Convert e1 to corresponding static array TypeVector tv1 = cast(TypeVector)t1b; t1b = tv1.basetype; t1b = t1b.castMod(tv1.mod); exp.e1.type = t1b; } else { exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars()); return setError(); } /* Run semantic on lwr and upr. */ Scope* scx = sc; if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) { // Create scope for 'length' variable ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); sym.loc = exp.loc; sym.parent = sc.scopesym; sc = sc.push(sym); } if (exp.lwr) { if (t1b.ty == Ttuple) sc = sc.startCTFE(); exp.lwr = exp.lwr.expressionSemantic(sc); exp.lwr = resolveProperties(sc, exp.lwr); if (t1b.ty == Ttuple) sc = sc.endCTFE(); exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t); } if (exp.upr) { if (t1b.ty == Ttuple) sc = sc.startCTFE(); exp.upr = exp.upr.expressionSemantic(sc); exp.upr = resolveProperties(sc, exp.upr); if (t1b.ty == Ttuple) sc = sc.endCTFE(); exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t); } if (sc != scx) sc = sc.pop(); if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror) return setError(); if (t1b.ty == Ttuple) { exp.lwr = exp.lwr.ctfeInterpret(); exp.upr = exp.upr.ctfeInterpret(); uinteger_t i1 = exp.lwr.toUInteger(); uinteger_t i2 = exp.upr.toUInteger(); TupleExp te; TypeTuple tup; size_t length; if (exp.e1.op == TOK.tuple) // slicing an expression tuple { te = cast(TupleExp)exp.e1; tup = null; length = te.exps.dim; } else if (exp.e1.op == TOK.type) // slicing a type tuple { te = null; tup = cast(TypeTuple)t1b; length = Parameter.dim(tup.arguments); } else assert(0); if (i2 < i1 || length < i2) { exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2); return setError(); } size_t j1 = cast(size_t)i1; size_t j2 = cast(size_t)i2; Expression e; if (exp.e1.op == TOK.tuple) { auto exps = new Expressions(j2 - j1); for (size_t i = 0; i < j2 - j1; i++) { (*exps)[i] = (*te.exps)[j1 + i]; } e = new TupleExp(exp.loc, te.e0, exps); } else { auto args = new Parameters(); args.reserve(j2 - j1); for (size_t i = j1; i < j2; i++) { Parameter arg = Parameter.getNth(tup.arguments, i); args.push(arg); } e = new TypeExp(exp.e1.loc, new TypeTuple(args)); } e = e.expressionSemantic(sc); result = e; return; } exp.type = t1b.nextOf().arrayOf(); // Allow typedef[] -> typedef[] if (exp.type.equals(t1b)) exp.type = exp.e1.type; // We might know $ now setLengthVarIfKnown(exp.lengthVar, t1b); if (exp.lwr && exp.upr) { exp.lwr = exp.lwr.optimize(WANTvalue); exp.upr = exp.upr.optimize(WANTvalue); IntRange lwrRange = getIntRange(exp.lwr); IntRange uprRange = getIntRange(exp.upr); if (t1b.ty == Tsarray || t1b.ty == Tarray) { Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); el = el.optimize(WANTvalue); if (el.op == TOK.int64) { // Array length is known at compile-time. Upper is in bounds if it fits length. dinteger_t length = el.toInteger(); auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); exp.upperIsInBounds = bounds.contains(uprRange); } else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0) { // Upper slice expression is '0'. Value is always in bounds. exp.upperIsInBounds = true; } else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) { // Upper slice expression is '$'. Value is always in bounds. exp.upperIsInBounds = true; } } else if (t1b.ty == Tpointer) { exp.upperIsInBounds = true; } else assert(0); exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper); } result = exp; } override void visit(ArrayLengthExp e) { static if (LOGSEMANTIC) { printf("ArrayLengthExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } if (Expression ex = unaSemantic(e, sc)) { result = ex; return; } e.e1 = resolveProperties(sc, e.e1); e.type = Type.tsize_t; result = e; } override void visit(ArrayExp exp) { static if (LOGSEMANTIC) { printf("ArrayExp::semantic('%s')\n", exp.toChars()); } assert(!exp.type); Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (isAggregate(exp.e1.type)) exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars()); else exp.error("only one index allowed to index `%s`", exp.e1.type.toChars()); result = new ErrorExp(); } override void visit(DotExp exp) { static if (LOGSEMANTIC) { printf("DotExp::semantic('%s')\n", exp.toChars()); if (exp.type) printf("\ttype = %s\n", exp.type.toChars()); } exp.e1 = exp.e1.expressionSemantic(sc); exp.e2 = exp.e2.expressionSemantic(sc); if (exp.e1.op == TOK.type) { result = exp.e2; return; } if (exp.e2.op == TOK.type) { result = exp.e2; return; } if (exp.e2.op == TOK.template_) { auto td = (cast(TemplateExp)exp.e2).td; Expression e = new DotTemplateExp(exp.loc, exp.e1, td); result = e.expressionSemantic(sc); return; } if (!exp.type) exp.type = exp.e2.type; result = exp; } override void visit(CommaExp e) { if (e.type) { result = e; return; } // Allow `((a,b),(x,y))` if (e.allowCommaExp) { CommaExp.allow(e.e1); CommaExp.allow(e.e2); } if (Expression ex = binSemanticProp(e, sc)) { result = ex; return; } e.e1 = e.e1.addDtorHook(sc); if (checkNonAssignmentArrayOp(e.e1)) return setError(); e.type = e.e2.type; if (e.type !is Type.tvoid && !e.allowCommaExp && !e.isGenerated) e.error("Using the result of a comma expression is not allowed"); result = e; } override void visit(IntervalExp e) { static if (LOGSEMANTIC) { printf("IntervalExp::semantic('%s')\n", e.toChars()); } if (e.type) { result = e; return; } Expression le = e.lwr; le = le.expressionSemantic(sc); le = resolveProperties(sc, le); Expression ue = e.upr; ue = ue.expressionSemantic(sc); ue = resolveProperties(sc, ue); if (le.op == TOK.error) { result = le; return; } if (ue.op == TOK.error) { result = ue; return; } e.lwr = le; e.upr = ue; e.type = Type.tvoid; result = e; } override void visit(DelegatePtrExp e) { static if (LOGSEMANTIC) { printf("DelegatePtrExp::semantic('%s')\n", e.toChars()); } if (!e.type) { unaSemantic(e, sc); e.e1 = resolveProperties(sc, e.e1); if (e.e1.op == TOK.error) { result = e.e1; return; } e.type = Type.tvoidptr; } result = e; } override void visit(DelegateFuncptrExp e) { static if (LOGSEMANTIC) { printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars()); } if (!e.type) { unaSemantic(e, sc); e.e1 = resolveProperties(sc, e.e1); if (e.e1.op == TOK.error) { result = e.e1; return; } e.type = e.e1.type.nextOf().pointerTo(); } result = e; } override void visit(IndexExp exp) { static if (LOGSEMANTIC) { printf("IndexExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } // operator overloading should be handled in ArrayExp already. if (!exp.e1.type) exp.e1 = exp.e1.expressionSemantic(sc); assert(exp.e1.type); // semantic() should already be run on it if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) { exp.e2 = exp.e2.expressionSemantic(sc); exp.e2 = resolveProperties(sc, exp.e2); Type nt; if (exp.e2.op == TOK.type) nt = new TypeAArray(exp.e1.type, exp.e2.type); else nt = new TypeSArray(exp.e1.type, exp.e2); Expression e = new TypeExp(exp.loc, nt); result = e.expressionSemantic(sc); return; } if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (exp.e1.type.ty == Terror) return setError(); // Note that unlike C we do not implement the int[ptr] Type t1b = exp.e1.type.toBasetype(); if (t1b.ty == Tvector) { // Convert e1 to corresponding static array TypeVector tv1 = cast(TypeVector)t1b; t1b = tv1.basetype; t1b = t1b.castMod(tv1.mod); exp.e1.type = t1b; } /* Run semantic on e2 */ Scope* scx = sc; if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) { // Create scope for 'length' variable ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); sym.loc = exp.loc; sym.parent = sc.scopesym; sc = sc.push(sym); } if (t1b.ty == Ttuple) sc = sc.startCTFE(); exp.e2 = exp.e2.expressionSemantic(sc); exp.e2 = resolveProperties(sc, exp.e2); if (t1b.ty == Ttuple) sc = sc.endCTFE(); if (exp.e2.op == TOK.tuple) { TupleExp te = cast(TupleExp)exp.e2; if (te.exps && te.exps.dim == 1) exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix } if (sc != scx) sc = sc.pop(); if (exp.e2.type == Type.terror) return setError(); if (checkNonAssignmentArrayOp(exp.e1)) return setError(); switch (t1b.ty) { case Tpointer: if ((cast(TypePointer)t1b).next.ty == Tfunction) { exp.error("cannot index function pointer `%s`", exp.e1.toChars()); return setError(); } exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); if (exp.e2.type == Type.terror) return setError(); exp.e2 = exp.e2.optimize(WANTvalue); if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0) { } else if (sc.func && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars()); return setError(); } exp.type = (cast(TypeNext)t1b).next; break; case Tarray: exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); if (exp.e2.type == Type.terror) return setError(); exp.type = (cast(TypeNext)t1b).next; break; case Tsarray: { exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); if (exp.e2.type == Type.terror) return setError(); exp.type = t1b.nextOf(); break; } case Taarray: { TypeAArray taa = cast(TypeAArray)t1b; /* We can skip the implicit conversion if they differ only by * constness * https://issues.dlang.org/show_bug.cgi?id=2684 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b */ if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index)) { exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking if (exp.e2.type == Type.terror) return setError(); } semanticTypeInfo(sc, taa); exp.type = taa.next; break; } case Ttuple: { exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); if (exp.e2.type == Type.terror) return setError(); exp.e2 = exp.e2.ctfeInterpret(); uinteger_t index = exp.e2.toUInteger(); TupleExp te; TypeTuple tup; size_t length; if (exp.e1.op == TOK.tuple) { te = cast(TupleExp)exp.e1; tup = null; length = te.exps.dim; } else if (exp.e1.op == TOK.type) { te = null; tup = cast(TypeTuple)t1b; length = Parameter.dim(tup.arguments); } else assert(0); if (length <= index) { exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length); return setError(); } Expression e; if (exp.e1.op == TOK.tuple) { e = (*te.exps)[cast(size_t)index]; e = Expression.combine(te.e0, e); } else e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); result = e; return; } default: exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars()); return setError(); } // We might know $ now setLengthVarIfKnown(exp.lengthVar, t1b); if (t1b.ty == Tsarray || t1b.ty == Tarray) { Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); el = el.optimize(WANTvalue); if (el.op == TOK.int64) { exp.e2 = exp.e2.optimize(WANTvalue); dinteger_t length = el.toInteger(); if (length) { auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2)); } } } result = exp; } override void visit(PostExp exp) { static if (LOGSEMANTIC) { printf("PostExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (Expression ex = binSemantic(exp, sc)) { result = ex; return; } Expression e1x = resolveProperties(sc, exp.e1); if (e1x.op == TOK.error) { result = e1x; return; } exp.e1 = e1x; Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.checkReadModifyWrite(exp.op)) return setError(); if (exp.e1.op == TOK.slice) { const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement"; exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s); return setError(); } exp.e1 = exp.e1.optimize(WANTvalue); Type t1 = exp.e1.type.toBasetype(); if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == TOK.arrayLength) { /* Check for operator overloading, * but rewrite in terms of ++e instead of e++ */ /* If e1 is not trivial, take a reference to it */ Expression de = null; if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength) { // ref v = e1; auto v = copyToTemp(STC.ref_, "__postref", exp.e1); de = new DeclarationExp(exp.loc, v); exp.e1 = new VarExp(exp.e1.loc, v); } /* Rewrite as: * auto tmp = e1; ++e1; tmp */ auto tmp = copyToTemp(0, "__pitmp", exp.e1); Expression ea = new DeclarationExp(exp.loc, tmp); Expression eb = exp.e1.syntaxCopy(); eb = new PreExp(exp.op == TOK.plusPlus ? TOK.prePlusPlus : TOK.preMinusMinus, exp.loc, eb); Expression ec = new VarExp(exp.loc, tmp); // Combine de,ea,eb,ec if (de) ea = new CommaExp(exp.loc, de, ea); e = new CommaExp(exp.loc, ea, eb); e = new CommaExp(exp.loc, e, ec); e = e.expressionSemantic(sc); result = e; return; } exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); e = exp; if (exp.e1.checkScalar()) return setError(); if (exp.e1.checkNoBool()) return setError(); if (exp.e1.type.ty == Tpointer) e = scaleFactor(exp, sc); else exp.e2 = exp.e2.castTo(sc, exp.e1.type); e.type = exp.e1.type; result = e; } override void visit(PreExp exp) { Expression e = exp.op_overload(sc); // printf("PreExp::semantic('%s')\n", toChars()); if (e) { result = e; return; } // Rewrite as e1+=1 or e1-=1 if (exp.op == TOK.prePlusPlus) e = new AddAssignExp(exp.loc, exp.e1, new IntegerExp(exp.loc, 1, Type.tint32)); else e = new MinAssignExp(exp.loc, exp.e1, new IntegerExp(exp.loc, 1, Type.tint32)); result = e.expressionSemantic(sc); } /* * Get the expression initializer for a specific struct * * Params: * sd = the struct for which the expression initializer is needed * loc = the location of the initializer * sc = the scope where the expression is located * t = the type of the expression * * Returns: * The expression initializer or error expression if any errors occured */ private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t) { if (sd.zeroInit && !sd.isNested()) { // https://issues.dlang.org/show_bug.cgi?id=14606 // Always use BlitExp for the special expression: (struct = 0) return new IntegerExp(loc, 0, Type.tint32); } if (sd.isNested()) { auto sle = new StructLiteralExp(loc, sd, null, t); if (!sd.fill(loc, sle.elements, true)) return new ErrorExp(); if (checkFrameAccess(loc, sc, sd, sle.elements.dim)) return new ErrorExp(); sle.type = t; return sle; } return t.defaultInit(loc); } override void visit(AssignExp exp) { static if (LOGSEMANTIC) { printf("AssignExp::semantic('%s')\n", exp.toChars()); } //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, Token.toChars(exp.e1.op)); //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, Token.toChars(exp.e2.op)); if (exp.type) { result = exp; return; } Expression e1old = exp.e1; if (exp.e2.op == TOK.comma) { /* Rewrite to get rid of the comma from rvalue */ if (!(cast(CommaExp)exp.e2).isGenerated) exp.error("Using the result of a comma expression is not allowed"); Expression e0; exp.e2 = Expression.extractLast(exp.e2, e0); Expression e = Expression.combine(e0, exp); result = e.expressionSemantic(sc); return; } /* Look for operator overloading of a[arguments] = e2. * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been * converted to unary operator overloading already. */ if (exp.e1.op == TOK.array) { Expression res; ArrayExp ae = cast(ArrayExp)exp.e1; ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { assert((*ae.arguments)[0].op == TOK.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { if (ae.e1.op == TOK.error) { result = ae.e1; return; } Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; Type t1b = ae.e1.type.toBasetype(); AggregateDeclaration ad = isAggregate(t1b); if (!ad) break; if (search_function(ad, Id.indexass)) { // Deal with $ res = resolveOpDollar(sc, ae, &e0); if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) goto Lfallback; if (res.op == TOK.error) { result = res; return; } res = exp.e2.expressionSemantic(sc); if (res.op == TOK.error) { result = res; return; } exp.e2 = res; /* Rewrite (a[arguments] = e2) as: * a.opIndexAssign(e2, arguments) */ Expressions* a = ae.arguments.copy(); a.insert(0, exp.e2); res = new DotIdExp(exp.loc, ae.e1, Id.indexass); res = new CallExp(exp.loc, res, a); if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) res = res.trySemantic(sc); else res = res.expressionSemantic(sc); if (res) { res = Expression.combine(e0, res); result = res; return; } } Lfallback: if (maybeSlice && search_function(ad, Id.sliceass)) { // Deal with $ res = resolveOpDollar(sc, ae, ie, &e0); if (res.op == TOK.error) { result = res; return; } res = exp.e2.expressionSemantic(sc); if (res.op == TOK.error) { result = res; return; } exp.e2 = res; /* Rewrite (a[i..j] = e2) as: * a.opSliceAssign(e2, i, j) */ auto a = new Expressions(); a.push(exp.e2); if (ie) { a.push(ie.lwr); a.push(ie.upr); } res = new DotIdExp(exp.loc, ae.e1, Id.sliceass); res = new CallExp(exp.loc, res, a); res = res.expressionSemantic(sc); res = Expression.combine(e0, res); result = res; return; } // No operator overloading member function found yet, but // there might be an alias this to try. if (ad.aliasthis && t1b != ae.att1) { if (!ae.att1 && t1b.checkAliasThisRec()) ae.att1 = t1b; /* Rewrite (a[arguments] op e2) as: * a.aliasthis[arguments] op e2 */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; } break; } ae.e1 = ae1old; // recovery ae.lengthVar = null; } /* Run this.e1 semantic. */ { Expression e1x = exp.e1; /* With UFCS, e.f = value * Could mean: * .f(e, value) * or: * .f(e) = value */ if (e1x.op == TOK.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1x; Expression e = dti.semanticY(sc, 1); if (!e) { result = resolveUFCSProperties(sc, e1x, exp.e2); return; } e1x = e; } else if (e1x.op == TOK.dotIdentifier) { DotIdExp die = cast(DotIdExp)e1x; Expression e = die.semanticY(sc, 1); if (e && isDotOpDispatch(e)) { uint errors = global.startGagging(); e = resolvePropertiesX(sc, e, exp.e2); if (global.endGagging(errors)) e = null; /* fall down to UFCS */ else { result = e; return; } } if (!e) { result = resolveUFCSProperties(sc, e1x, exp.e2); return; } e1x = e; } else { if (e1x.op == TOK.slice) (cast(SliceExp)e1x).arrayop = true; e1x = e1x.expressionSemantic(sc); } /* We have f = value. * Could mean: * f(value) * or: * f() = value */ if (Expression e = resolvePropertiesX(sc, e1x, exp.e2)) { result = e; return; } if (e1x.checkRightThis(sc)) return setError(); exp.e1 = e1x; assert(exp.e1.type); } Type t1 = exp.e1.type.toBasetype(); /* Run this.e2 semantic. * Different from other binary expressions, the analysis of e2 * depends on the result of e1 in assignments. */ { Expression e2x = inferType(exp.e2, t1.baseElemOf()); e2x = e2x.expressionSemantic(sc); e2x = resolveProperties(sc, e2x); if (e2x.op == TOK.type) e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684 if (e2x.op == TOK.error) { result = e2x; return; } if (e2x.checkValue()) return setError(); exp.e2 = e2x; } /* Rewrite tuple assignment as a tuple of assignments. */ { Expression e2x = exp.e2; Ltupleassign: if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple) { TupleExp tup1 = cast(TupleExp)exp.e1; TupleExp tup2 = cast(TupleExp)e2x; size_t dim = tup1.exps.dim; Expression e = null; if (dim != tup2.exps.dim) { exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim); return setError(); } if (dim == 0) { e = new IntegerExp(exp.loc, 0, Type.tint32); e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error e = Expression.combine(tup1.e0, tup2.e0, e); } else { auto exps = new Expressions(dim); for (size_t i = 0; i < dim; i++) { Expression ex1 = (*tup1.exps)[i]; Expression ex2 = (*tup2.exps)[i]; (*exps)[i] = new AssignExp(exp.loc, ex1, ex2); } e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps); } result = e.expressionSemantic(sc); return; } /* Look for form: e1 = e2.aliasthis. */ if (exp.e1.op == TOK.tuple) { TupleDeclaration td = isAliasThisTuple(e2x); if (!td) goto Lnomatch; assert(exp.e1.type.ty == Ttuple); TypeTuple tt = cast(TypeTuple)exp.e1.type; Expression e0; Expression ev = extractSideEffect(sc, "__tup", e0, e2x); auto iexps = new Expressions(); iexps.push(ev); for (size_t u = 0; u < iexps.dim; u++) { Lexpand: Expression e = (*iexps)[u]; Parameter arg = Parameter.getNth(tt.arguments, u); //printf("[%d] iexps.dim = %d, ", u, iexps.dim); //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars()); //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); if (!arg || !e.type.implicitConvTo(arg.type)) { // expand initializer to tuple if (expandAliasThisTuples(iexps, u) != -1) { if (iexps.dim <= u) break; goto Lexpand; } goto Lnomatch; } } e2x = new TupleExp(e2x.loc, e0, iexps); e2x = e2x.expressionSemantic(sc); if (e2x.op == TOK.error) { result = e2x; return; } // Do not need to overwrite this.e2 goto Ltupleassign; } Lnomatch: } /* Inside constructor, if this is the first assignment of object field, * rewrite this to initializing the field. */ if (exp.op == TOK.assign && exp.e1.checkModifiable(sc) == 2) { //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); exp.op = TOK.construct; // https://issues.dlang.org/show_bug.cgi?id=13515 // set Index::modifiable flag for complex AA element initialization if (exp.e1.op == TOK.index) { Expression e1x = (cast(IndexExp)exp.e1).markSettingAAElem(); if (e1x.op == TOK.error) { result = e1x; return; } } } else if (exp.op == TOK.construct && exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_)) { exp.memset |= MemorySet.referenceInit; } /* If it is an assignment from a 'foreign' type, * check for operator overloading. */ if (exp.memset & MemorySet.referenceInit) { // If this is an initialization of a reference, // do nothing } else if (t1.ty == Tstruct) { auto e1x = exp.e1; auto e2x = exp.e2; auto sd = (cast(TypeStruct)t1).sym; if (exp.op == TOK.construct) { Type t2 = e2x.type.toBasetype(); if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) { sd.size(exp.loc); if (sd.sizeok != Sizeok.done) return setError(); if (!sd.ctor) sd.ctor = sd.searchCtor(); // https://issues.dlang.org/show_bug.cgi?id=15661 // Look for the form from last of comma chain. auto e2y = lastComma(e2x); CallExp ce = (e2y.op == TOK.call) ? cast(CallExp)e2y : null; DotVarExp dve = (ce && ce.e1.op == TOK.dotVariable) ? cast(DotVarExp)ce.e1 : null; if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() && e2y.type.implicitConvTo(t1)) { /* Look for form of constructor call which is: * __ctmp.ctor(arguments...) */ /* Before calling the constructor, initialize * variable with a bit copy of the default * initializer */ Expression einit = getInitExp(sd, exp.loc, sc, t1); if (einit.op == TOK.error) { result = einit; return; } auto ae = new BlitExp(exp.loc, exp.e1, einit); ae.type = e1x.type; /* Replace __ctmp being constructed with e1. * We need to copy constructor call expression, * because it may be used in other place. */ auto dvx = cast(DotVarExp)dve.copy(); dvx.e1 = e1x; auto cx = cast(CallExp)ce.copy(); cx.e1 = dvx; Expression e0; Expression.extractLast(e2x, e0); auto e = Expression.combine(e0, ae, cx); e = e.expressionSemantic(sc); result = e; return; } if (sd.postblit) { /* We have a copy constructor for this */ if (e2x.op == TOK.question) { /* Rewrite as: * a ? e1 = b : e1 = c; */ CondExp econd = cast(CondExp)e2x; Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1); Expression ea2 = new ConstructExp(econd.e1.loc, e1x, econd.e2); Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2); result = e.expressionSemantic(sc); return; } if (e2x.isLvalue()) { if (!e2x.type.implicitConvTo(e1x.type)) { exp.error("conversion error from `%s` to `%s`", e2x.type.toChars(), e1x.type.toChars()); return setError(); } /* Rewrite as: * (e1 = e2).postblit(); * * Blit assignment e1 = e2 returns a reference to the original e1, * then call the postblit on it. */ Expression e = e1x.copy(); e.type = e.type.mutableOf(); if (e.type.isShared && !sd.type.isShared) e.type = e.type.unSharedOf(); e = new BlitExp(exp.loc, e, e2x); e = new DotVarExp(exp.loc, e, sd.postblit, false); e = new CallExp(exp.loc, e); result = e.expressionSemantic(sc); return; } else { /* The struct value returned from the function is transferred * so should not call the destructor on it. */ e2x = valueNoDtor(e2x); } } // https://issues.dlang.org/show_bug.cgi?id=19251 // if e2 cannot be converted to e1.type, maybe there is an alias this if (!e2x.implicitConvTo(t1)) { AggregateDeclaration ad2 = isAggregate(e2x.type); if (ad2 && ad2.aliasthis && !(exp.att2 && e2x.type == exp.att2)) { if (!exp.att2 && exp.e2.type.checkAliasThisRec()) exp.att2 = exp.e2.type; /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); result = exp.expressionSemantic(sc); return; } } } else if (!e2x.implicitConvTo(t1)) { sd.size(exp.loc); if (sd.sizeok != Sizeok.done) return setError(); if (!sd.ctor) sd.ctor = sd.searchCtor(); if (sd.ctor) { /* Look for implicit constructor call * Rewrite as: * e1 = init, e1.ctor(e2) */ /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153 * Using `new` to initialize a struct object is a common mistake, but * the error message from the compiler is not very helpful in that * case. If exp.e2 is a NewExp and the type of new is the same as * the type as exp.e1 (struct in this case), then we know for sure * that the user wants to instantiate a struct. This is done to avoid * issuing an error when the user actually wants to call a constructor * which receives a class object. * * Foo f = new Foo2(0); is a valid expression if Foo has a constructor * which receives an instance of a Foo2 class */ if (exp.e2.op == TOK.new_) { auto newExp = cast(NewExp)(exp.e2); if (newExp.newtype && newExp.newtype == t1) { error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", newExp.toChars(), newExp.type.toChars(), t1.toChars()); errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?"); return setError(); } } Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1)); einit.type = e1x.type; Expression e; e = new DotIdExp(exp.loc, e1x, Id.ctor); e = new CallExp(exp.loc, e, e2x); e = new CommaExp(exp.loc, einit, e); e = e.expressionSemantic(sc); result = e; return; } if (search_function(sd, Id.call)) { /* Look for static opCall * https://issues.dlang.org/show_bug.cgi?id=2702 * Rewrite as: * e1 = typeof(e1).opCall(arguments) */ e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); e2x = new CallExp(exp.loc, e2x, exp.e2); e2x = e2x.expressionSemantic(sc); e2x = resolveProperties(sc, e2x); if (e2x.op == TOK.error) { result = e2x; return; } if (e2x.checkValue()) return setError(); } } else // https://issues.dlang.org/show_bug.cgi?id=11355 { AggregateDeclaration ad2 = isAggregate(e2x.type); if (ad2 && ad2.aliasthis && !(exp.att2 && e2x.type == exp.att2)) { if (!exp.att2 && exp.e2.type.checkAliasThisRec()) exp.att2 = exp.e2.type; /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); result = exp.expressionSemantic(sc); return; } } } else if (exp.op == TOK.assign) { if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) { /* * Rewrite: * aa[key] = e2; * as: * ref __aatmp = aa; * ref __aakey = key; * ref __aaval = e2; * (__aakey in __aatmp * ? __aatmp[__aakey].opAssign(__aaval) * : ConstructExp(__aatmp[__aakey], __aaval)); */ IndexExp ie = cast(IndexExp)e1x; Type t2 = e2x.type.toBasetype(); Expression e0 = null; Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1); Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2); Expression ev = extractSideEffect(sc, "__aaval", e0, e2x); AssignExp ae = cast(AssignExp)exp.copy(); ae.e1 = new IndexExp(exp.loc, ea, ek); ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = ae.e1.optimize(WANTvalue); ae.e2 = ev; Expression e = ae.op_overload(sc); if (e) { Expression ey = null; if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) { ey = ev; } else if (!ev.implicitConvTo(ie.type) && sd.ctor) { // Look for implicit constructor call // Rewrite as S().ctor(e2) ey = new StructLiteralExp(exp.loc, sd, null); ey = new DotIdExp(exp.loc, ey, Id.ctor); ey = new CallExp(exp.loc, ey, ev); ey = ey.trySemantic(sc); } if (ey) { Expression ex; ex = new IndexExp(exp.loc, ea, ek); ex = ex.expressionSemantic(sc); ex = ex.optimize(WANTvalue); ex = ex.modifiableLvalue(sc, ex); // allocate new slot ey = new ConstructExp(exp.loc, ex, ey); ey = ey.expressionSemantic(sc); if (ey.op == TOK.error) { result = ey; return; } ex = e; // https://issues.dlang.org/show_bug.cgi?id=14144 // The whole expression should have the common type // of opAssign() return and assigned AA entry. // Even if there's no common type, expression should be typed as void. Type t = null; if (!typeMerge(sc, TOK.question, &t, &ex, &ey)) { ex = new CastExp(ex.loc, ex, Type.tvoid); ey = new CastExp(ey.loc, ey, Type.tvoid); } e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey); } e = Expression.combine(e0, e); e = e.expressionSemantic(sc); result = e; return; } } else { Expression e = exp.op_overload(sc); if (e) { result = e; return; } } } else assert(exp.op == TOK.blit); exp.e1 = e1x; exp.e2 = e2x; } else if (t1.ty == Tclass) { // Disallow assignment operator overloads for same type if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type)) { Expression e = exp.op_overload(sc); if (e) { result = e; return; } } } else if (t1.ty == Tsarray) { // SliceExp cannot have static array type without context inference. assert(exp.e1.op != TOK.slice); Expression e1x = exp.e1; Expression e2x = exp.e2; if (e2x.implicitConvTo(e1x.type)) { if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue())) { if (e1x.checkPostblit(sc, t1)) return setError(); } // e2 matches to t1 because of the implicit length match, so if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op)) { // convert e1 to e1[] // e.g. e1[] = a[] + b[]; auto sle = new SliceExp(e1x.loc, e1x, null, null); sle.arrayop = true; e1x = sle.expressionSemantic(sc); } else { // convert e2 to t1 later // e.g. e1 = [1, 2, 3]; } } else { if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch) { uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger(); uinteger_t dim2 = dim1; if (e2x.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e2x; dim2 = ale.elements ? ale.elements.dim : 0; } else if (e2x.op == TOK.slice) { Type tx = toStaticArrayType(cast(SliceExp)e2x); if (tx) dim2 = (cast(TypeSArray)tx).dim.toInteger(); } if (dim1 != dim2) { exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); return setError(); } } // May be block or element-wise assignment, so // convert e1 to e1[] if (exp.op != TOK.assign) { // If multidimensional static array, treat as one large array const dim = t1.numberOfElems(exp.loc); e1x.type = t1.baseElemOf().sarrayOf(dim); } auto sle = new SliceExp(e1x.loc, e1x, null, null); sle.arrayop = true; e1x = sle.expressionSemantic(sc); } if (e1x.op == TOK.error) { result = e1x; return; } if (e2x.op == TOK.error) { result = e2x; return; } exp.e1 = e1x; exp.e2 = e2x; t1 = e1x.type.toBasetype(); } /* Check the mutability of e1. */ if (exp.e1.op == TOK.arrayLength) { // e1 is not an lvalue, but we let code generator handle it ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; Expression ale1x = ale.e1; ale1x = ale1x.modifiableLvalue(sc, exp.e1); if (ale1x.op == TOK.error) { result = ale1x; return; } ale.e1 = ale1x; Type tn = ale.e1.type.toBasetype().nextOf(); checkDefCtor(ale.loc, tn); semanticTypeInfo(sc, tn); } else if (exp.e1.op == TOK.slice) { Type tn = exp.e1.type.nextOf(); if (exp.op == TOK.assign && !tn.isMutable()) { exp.error("slice `%s` is not mutable", exp.e1.toChars()); return setError(); } if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable()) { exp.error("slice `%s` is not mutable, struct `%s` has immutable members", exp.e1.toChars(), tn.baseElemOf().toChars()); result = new ErrorExp(); return; } // For conditional operator, both branches need conversion. SliceExp se = cast(SliceExp)exp.e1; while (se.e1.op == TOK.slice) se = cast(SliceExp)se.e1; if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray) { se.e1 = se.e1.modifiableLvalue(sc, exp.e1); if (se.e1.op == TOK.error) { result = se.e1; return; } } } else { if (t1.ty == Tsarray && exp.op == TOK.assign) { Type tn = exp.e1.type.nextOf(); if (tn && !tn.baseElemOf().isAssignable()) { exp.error("array `%s` is not mutable, struct `%s` has immutable members", exp.e1.toChars(), tn.baseElemOf().toChars()); result = new ErrorExp(); return; } } Expression e1x = exp.e1; // Try to do a decent error message with the expression // before it got constant folded if (e1x.op != TOK.variable) e1x = e1x.optimize(WANTvalue); if (exp.op == TOK.assign) e1x = e1x.modifiableLvalue(sc, e1old); if (e1x.op == TOK.error) { result = e1x; return; } exp.e1 = e1x; } /* Tweak e2 based on the type of e1. */ Expression e2x = exp.e2; Type t2 = e2x.type.toBasetype(); // If it is a array, get the element type. Note that it may be // multi-dimensional. Type telem = t1; while (telem.ty == Tarray) telem = telem.nextOf(); if (exp.e1.op == TOK.slice && t1.nextOf() && (telem.ty != Tvoid || e2x.op == TOK.null_) && e2x.implicitConvTo(t1.nextOf())) { // Check for block assignment. If it is of type void[], void[][], etc, // '= null' is the only allowable block assignment (Bug 7493) exp.memset |= MemorySet.blockAssign; // make it easy for back end to tell what this is e2x = e2x.implicitCastTo(sc, t1.nextOf()); if (exp.op != TOK.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) return setError(); } else if (exp.e1.op == TOK.slice && (t2.ty == Tarray || t2.ty == Tsarray) && t2.nextOf().implicitConvTo(t1.nextOf())) { // Check element-wise assignment. /* If assigned elements number is known at compile time, * check the mismatch. */ SliceExp se1 = cast(SliceExp)exp.e1; TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1); TypeSArray tsa2 = null; if (e2x.op == TOK.arrayLiteral) tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf((cast(ArrayLiteralExp)e2x).elements.dim); else if (e2x.op == TOK.slice) tsa2 = cast(TypeSArray)toStaticArrayType(cast(SliceExp)e2x); else if (t2.ty == Tsarray) tsa2 = cast(TypeSArray)t2; if (tsa1 && tsa2) { uinteger_t dim1 = tsa1.dim.toInteger(); uinteger_t dim2 = tsa2.dim.toInteger(); if (dim1 != dim2) { exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); return setError(); } } if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue())) { if (exp.e1.checkPostblit(sc, t1.nextOf())) return setError(); } if (0 && global.params.warnings != Diagnostic.off && !global.gag && exp.op == TOK.assign && e2x.op != TOK.slice && e2x.op != TOK.assign && e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ && !(e2x.op == TOK.add || e2x.op == TOK.min || e2x.op == TOK.mul || e2x.op == TOK.div || e2x.op == TOK.mod || e2x.op == TOK.xor || e2x.op == TOK.and || e2x.op == TOK.or || e2x.op == TOK.pow || e2x.op == TOK.tilde || e2x.op == TOK.negate)) { const(char)* e1str = exp.e1.toChars(); const(char)* e2str = e2x.toChars(); exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); } Type t2n = t2.nextOf(); Type t1n = t1.nextOf(); int offset; if (t2n.equivalent(t1n) || t1n.isBaseOf(t2n, &offset) && offset == 0) { /* Allow copy of distinct qualifier elements. * eg. * char[] dst; const(char)[] src; * dst[] = src; * * class C {} class D : C {} * C[2] ca; D[] da; * ca[] = da; */ if (isArrayOpValid(e2x)) { // Don't add CastExp to keep AST for array operations e2x = e2x.copy(); e2x.type = exp.e1.type.constOf(); } else e2x = e2x.castTo(sc, exp.e1.type.constOf()); } else { /* https://issues.dlang.org/show_bug.cgi?id=15778 * A string literal has an array type of immutable * elements by default, and normally it cannot be convertible to * array type of mutable elements. But for element-wise assignment, * elements need to be const at best. So we should give a chance * to change code unit size for polysemous string literal. */ if (e2x.op == TOK.string_) e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf()); else e2x = e2x.implicitCastTo(sc, exp.e1.type); } if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) { if (!sc.intypeof && sc.func && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("cannot copy `void[]` to `void[]` in `@safe` code"); return setError(); } } } else { if (0 && global.params.warnings != Diagnostic.off && !global.gag && exp.op == TOK.assign && t1.ty == Tarray && t2.ty == Tsarray && e2x.op != TOK.slice && t2.implicitConvTo(t1)) { // Disallow ar[] = sa (Converted to ar[] = sa[]) // Disallow da = sa (Converted to da = sa[]) const(char)* e1str = exp.e1.toChars(); const(char)* e2str = e2x.toChars(); const(char)* atypestr = exp.e1.op == TOK.slice ? "element-wise" : "slice"; exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); } if (exp.op == TOK.blit) e2x = e2x.castTo(sc, exp.e1.type); else { e2x = e2x.implicitCastTo(sc, exp.e1.type); // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435 // If the implicit cast has failed and the assign expression is // the initialization of a struct member field if (e2x.op == TOK.error && exp.op == TOK.construct && t1.ty == Tstruct) { scope sd = (cast(TypeStruct)t1).sym; Dsymbol opAssign = search_function(sd, Id.assign); // and the struct defines an opAssign if (opAssign) { // offer more information about the cause of the problem errorSupplemental(exp.loc, "`%s` is the first assignment of `%s` therefore it represents its initialization", exp.toChars(), exp.e1.toChars()); errorSupplemental(exp.loc, "`opAssign` methods are not used for initialization, but for subsequent assignments"); } } } } if (e2x.op == TOK.error) { result = e2x; return; } exp.e2 = e2x; t2 = exp.e2.type.toBasetype(); /* Look for array operations */ if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2)) { // Look for valid array operations if (!(exp.memset & MemorySet.blockAssign) && exp.e1.op == TOK.slice && (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op))) { exp.type = exp.e1.type; if (exp.op == TOK.construct) // https://issues.dlang.org/show_bug.cgi?id=10282 // tweak mutability of e1 element exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf(); result = arrayOp(exp, sc); return; } // Drop invalid array operations in e2 // d = a[] + b[], d = (a[] + b[])[0..2], etc if (checkNonAssignmentArrayOp(exp.e2, !(exp.memset & MemorySet.blockAssign) && exp.op == TOK.assign)) return setError(); // Remains valid array assignments // d = d[], d = [1,2,3], etc } /* Don't allow assignment to classes that were allocated on the stack with: * scope Class c = new Class(); */ if (exp.e1.op == TOK.variable && exp.op == TOK.assign) { VarExp ve = cast(VarExp)exp.e1; VarDeclaration vd = ve.var.isVarDeclaration(); if (vd && (vd.onstack || vd.mynew)) { assert(t1.ty == Tclass); exp.error("cannot rebind scope variables"); } } if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe) { exp.error("cannot modify compiler-generated variable `__ctfe`"); } exp.type = exp.e1.type; assert(exp.type); auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp; checkAssignEscape(sc, res, false); result = res; } override void visit(PowAssignExp exp) { if (exp.type) { result = exp; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.checkReadModifyWrite(exp.op, exp.e2)) return setError(); assert(exp.e1.type && exp.e2.type); if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); // T[] ^^= ... if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) { // T[] ^^= T exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); } else if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } // Check element types are arithmetic Type tb1 = exp.e1.type.nextOf().toBasetype(); Type tb2 = exp.e2.type.toBasetype(); if (tb2.ty == Tarray || tb2.ty == Tsarray) tb2 = tb2.nextOf().toBasetype(); if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating())) { exp.type = exp.e1.type; result = arrayOp(exp, sc); return; } } else { exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); } if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating())) { Expression e0 = null; e = exp.reorderSettingAAElem(sc); e = Expression.extractLast(e, e0); assert(e == exp); if (exp.e1.op == TOK.variable) { // Rewrite: e1 = e1 ^^ e2 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2); e = new AssignExp(exp.loc, exp.e1, e); } else { // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1); auto de = new DeclarationExp(exp.e1.loc, v); auto ve = new VarExp(exp.e1.loc, v); e = new PowExp(exp.loc, ve, exp.e2); e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e); e = new CommaExp(exp.loc, de, e); } e = Expression.combine(e0, e); e = e.expressionSemantic(sc); result = e; return; } result = exp.incompatibleTypes(); } override void visit(CatAssignExp exp) { if (exp.type) { result = exp; return; } //printf("CatAssignExp::semantic() %s\n", exp.toChars()); Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.op == TOK.slice) { SliceExp se = cast(SliceExp)exp.e1; if (se.e1.type.toBasetype().ty == Tsarray) { exp.error("cannot append to static array `%s`", se.e1.type.toChars()); return setError(); } } exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); if (exp.e1.op == TOK.error) { result = exp.e1; return; } if (exp.e2.op == TOK.error) { result = exp.e2; return; } if (checkNonAssignmentArrayOp(exp.e2)) return setError(); Type tb1 = exp.e1.type.toBasetype(); Type tb1next = tb1.nextOf(); Type tb2 = exp.e2.type.toBasetype(); /* Possibilities: * TOK.concatenateAssign: appending T[] to T[] * TOK.concatenateElemAssign: appending T to T[] * TOK.concatenateDcharAssign: appending dchar to T[] */ if ((tb1.ty == Tarray) && (tb2.ty == Tarray || tb2.ty == Tsarray) && (exp.e2.implicitConvTo(exp.e1.type) || (tb2.nextOf().implicitConvTo(tb1next) && (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) { // TOK.concatenateAssign assert(exp.op == TOK.concatenateAssign); if (exp.e1.checkPostblit(sc, tb1next)) return setError(); exp.e2 = exp.e2.castTo(sc, exp.e1.type); } else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next)) { // Append element if (exp.e2.checkPostblit(sc, tb2)) return setError(); if (checkNewEscape(sc, exp.e2, false)) return setError(); exp.op = TOK.concatenateElemAssign; exp.e2 = exp.e2.castTo(sc, tb1next); exp.e2 = doCopyOrMove(sc, exp.e2); } else if (tb1.ty == Tarray && (tb1next.ty == Tchar || tb1next.ty == Twchar) && exp.e2.type.ty != tb1next.ty && exp.e2.implicitConvTo(Type.tdchar)) { // Append dchar to char[] or wchar[] exp.op = TOK.concatenateDcharAssign; exp.e2 = exp.e2.castTo(sc, Type.tdchar); /* Do not allow appending wchar to char[] because if wchar happens * to be a surrogate pair, nothing good can result. */ } else { exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars()); return setError(); } if (exp.e2.checkValue()) return setError(); exp.type = exp.e1.type; auto res = exp.reorderSettingAAElem(sc); if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) && global.params.vsafe) checkAssignEscape(sc, res, false); result = res; } override void visit(AddExp exp) { static if (LOGSEMANTIC) { printf("AddExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } Type tb1 = exp.e1.type.toBasetype(); Type tb2 = exp.e2.type.toBasetype(); bool err = false; if (tb1.ty == Tdelegate || tb1.ty == Tpointer && tb1.nextOf().ty == Tfunction) { err |= exp.e1.checkArithmetic(); } if (tb2.ty == Tdelegate || tb2.ty == Tpointer && tb2.nextOf().ty == Tfunction) { err |= exp.e2.checkArithmetic(); } if (err) return setError(); if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral()) { result = scaleFactor(exp, sc); return; } if (tb1.ty == Tpointer && tb2.ty == Tpointer) { result = exp.incompatibleTypes(); return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } tb1 = exp.e1.type.toBasetype(); if (!Target.isVectorOpSupported(tb1, exp.op, tb2)) { result = exp.incompatibleTypes(); return; } if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal())) { switch (exp.type.toBasetype().ty) { case Tfloat32: case Timaginary32: exp.type = Type.tcomplex32; break; case Tfloat64: case Timaginary64: exp.type = Type.tcomplex64; break; case Tfloat80: case Timaginary80: exp.type = Type.tcomplex80; break; default: assert(0); } } result = exp; } override void visit(MinExp exp) { static if (LOGSEMANTIC) { printf("MinExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); bool err = false; if (t1.ty == Tdelegate || t1.ty == Tpointer && t1.nextOf().ty == Tfunction) { err |= exp.e1.checkArithmetic(); } if (t2.ty == Tdelegate || t2.ty == Tpointer && t2.nextOf().ty == Tfunction) { err |= exp.e2.checkArithmetic(); } if (err) return setError(); if (t1.ty == Tpointer) { if (t2.ty == Tpointer) { // https://dlang.org/spec/expression.html#add_expressions // "If both operands are pointers, and the operator is -, the pointers are // subtracted and the result is divided by the size of the type pointed to // by the operands. It is an error if the pointers point to different types." Type p1 = t1.nextOf(); Type p2 = t2.nextOf(); if (!p1.equivalent(p2)) { // Deprecation to remain for at least a year, after which this should be // changed to an error // See https://github.com/dlang/dmd/pull/7332 deprecation(exp.loc, "cannot subtract pointers to different types: `%s` and `%s`.", t1.toChars(), t2.toChars()); } // Need to divide the result by the stride // Replace (ptr - ptr) with (ptr - ptr) / stride d_int64 stride; // make sure pointer types are compatible if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } exp.type = Type.tptrdiff_t; stride = t2.nextOf().size(); if (stride == 0) { e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); } else { e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t)); e.type = Type.tptrdiff_t; } } else if (t2.isintegral()) e = scaleFactor(exp, sc); else { exp.error("can't subtract `%s` from pointer", t2.toChars()); e = new ErrorExp(); } result = e; return; } if (t2.ty == Tpointer) { exp.type = exp.e2.type; exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars()); return setError(); } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } t1 = exp.e1.type.toBasetype(); t2 = exp.e2.type.toBasetype(); if (!Target.isVectorOpSupported(t1, exp.op, t2)) { result = exp.incompatibleTypes(); return; } if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal())) { switch (exp.type.ty) { case Tfloat32: case Timaginary32: exp.type = Type.tcomplex32; break; case Tfloat64: case Timaginary64: exp.type = Type.tcomplex64; break; case Tfloat80: case Timaginary80: exp.type = Type.tcomplex80; break; default: assert(0); } } result = exp; return; } override void visit(CatExp exp) { // https://dlang.org/spec/expression.html#cat_expressions //printf("CatExp.semantic() %s\n", toChars()); if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } Type tb1 = exp.e1.type.toBasetype(); Type tb2 = exp.e2.type.toBasetype(); auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = checkNonAssignmentArrayOp(exp.e2); if (f1 || f2) return setError(); /* BUG: Should handle things like: * char c; * c ~ ' ' * ' ' ~ c; */ Type tb1next = tb1.nextOf(); Type tb2next = tb2.nextOf(); // Check for: array ~ array if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1))) { /* https://issues.dlang.org/show_bug.cgi?id=9248 * Here to avoid the case of: * void*[] a = [cast(void*)1]; * void*[] b = [cast(void*)2]; * a ~ b; * becoming: * a ~ [cast(void*)b]; */ /* https://issues.dlang.org/show_bug.cgi?id=14682 * Also to avoid the case of: * int[][] a; * a ~ []; * becoming: * a ~ cast(int[])[]; */ goto Lpeer; } // Check for: array ~ element if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) { if (exp.e1.op == TOK.arrayLiteral) { exp.e2 = doCopyOrMove(sc, exp.e2); // https://issues.dlang.org/show_bug.cgi?id=14686 // Postblit call appears in AST, and this is // finally translated to an ArrayLiteralExp in below optimize(). } else if (exp.e1.op == TOK.string_) { // No postblit call exists on character (integer) value. } else { if (exp.e2.checkPostblit(sc, tb2)) return setError(); // Postblit call will be done in runtime helper function } if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) { exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf()); exp.type = tb2.arrayOf(); goto L2elem; } if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert) { exp.e2 = exp.e2.implicitCastTo(sc, tb1next); exp.type = tb1next.arrayOf(); L2elem: if (tb2.ty == Tarray || tb2.ty == Tsarray) { // Make e2 into [e2] exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2); } else if (checkNewEscape(sc, exp.e2, false)) return setError(); result = exp.optimize(WANTvalue); return; } } // Check for: element ~ array if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) { if (exp.e2.op == TOK.arrayLiteral) { exp.e1 = doCopyOrMove(sc, exp.e1); } else if (exp.e2.op == TOK.string_) { } else { if (exp.e1.checkPostblit(sc, tb1)) return setError(); } if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) { exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf()); exp.type = tb1.arrayOf(); goto L1elem; } if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert) { exp.e1 = exp.e1.implicitCastTo(sc, tb2next); exp.type = tb2next.arrayOf(); L1elem: if (tb1.ty == Tarray || tb1.ty == Tsarray) { // Make e1 into [e1] exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1); } else if (checkNewEscape(sc, exp.e1, false)) return setError(); result = exp.optimize(WANTvalue); return; } } Lpeer: if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) { Type t1 = tb1next.mutableOf().constOf().arrayOf(); Type t2 = tb2next.mutableOf().constOf().arrayOf(); if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed) exp.e1.type = t1; else exp.e1 = exp.e1.castTo(sc, t1); if (exp.e2.op == TOK.string_ && !(cast(StringExp)exp.e2).committed) exp.e2.type = t2; else exp.e2 = exp.e2.castTo(sc, t2); } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } exp.type = exp.type.toHeadMutable(); Type tb = exp.type.toBasetype(); if (tb.ty == Tsarray) exp.type = tb.nextOf().arrayOf(); if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) { exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); } if (Type tbn = tb.nextOf()) { if (exp.checkPostblit(sc, tbn)) return setError(); } Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { // Normalize to ArrayLiteralExp or StringExp as far as possible e = exp.optimize(WANTvalue); } else { //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars()); result = exp.incompatibleTypes(); return; } result = e; } override void visit(MulExp exp) { version (none) { printf("MulExp::semantic() %s\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (exp.checkArithmeticBin()) return setError(); if (exp.type.isfloating()) { Type t1 = exp.e1.type; Type t2 = exp.e2.type; if (t1.isreal()) { exp.type = t2; } else if (t2.isreal()) { exp.type = t1; } else if (t1.isimaginary()) { if (t2.isimaginary()) { switch (t1.toBasetype().ty) { case Timaginary32: exp.type = Type.tfloat32; break; case Timaginary64: exp.type = Type.tfloat64; break; case Timaginary80: exp.type = Type.tfloat80; break; default: assert(0); } // iy * iv = -yv exp.e1.type = exp.type; exp.e2.type = exp.type; e = new NegExp(exp.loc, exp); e = e.expressionSemantic(sc); result = e; return; } else exp.type = t2; // t2 is complex } else if (t2.isimaginary()) { exp.type = t1; // t1 is complex } } else if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } result = exp; } override void visit(DivExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (exp.checkArithmeticBin()) return setError(); if (exp.type.isfloating()) { Type t1 = exp.e1.type; Type t2 = exp.e2.type; if (t1.isreal()) { exp.type = t2; if (t2.isimaginary()) { // x/iv = i(-x/v) exp.e2.type = t1; e = new NegExp(exp.loc, exp); e = e.expressionSemantic(sc); result = e; return; } } else if (t2.isreal()) { exp.type = t1; } else if (t1.isimaginary()) { if (t2.isimaginary()) { switch (t1.toBasetype().ty) { case Timaginary32: exp.type = Type.tfloat32; break; case Timaginary64: exp.type = Type.tfloat64; break; case Timaginary80: exp.type = Type.tfloat80; break; default: assert(0); } } else exp.type = t2; // t2 is complex } else if (t2.isimaginary()) { exp.type = t1; // t1 is complex } } else if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } result = exp; } override void visit(ModExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } if (exp.checkArithmeticBin()) return setError(); if (exp.type.isfloating()) { exp.type = exp.e1.type; if (exp.e2.type.iscomplex()) { exp.error("cannot perform modulo complex arithmetic"); return setError(); } } result = exp; } override void visit(PowExp exp) { if (exp.type) { result = exp; return; } //printf("PowExp::semantic() %s\n", toChars()); if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (exp.checkArithmeticBin()) return setError(); if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } // For built-in numeric types, there are several cases. // TODO: backend support, especially for e1 ^^ 2. // First, attempt to fold the expression. e = exp.optimize(WANTvalue); if (e.op != TOK.pow) { e = e.expressionSemantic(sc); result = e; return; } // Determine if we're raising to an integer power. sinteger_t intpow = 0; if (exp.e2.op == TOK.int64 && (cast(sinteger_t)exp.e2.toInteger() == 2 || cast(sinteger_t)exp.e2.toInteger() == 3)) intpow = exp.e2.toInteger(); else if (exp.e2.op == TOK.float64 && (exp.e2.toReal() == real_t(cast(sinteger_t)exp.e2.toReal()))) intpow = cast(sinteger_t)exp.e2.toReal(); // Deal with x^^2, x^^3 immediately, since they are of practical importance. if (intpow == 2 || intpow == 3) { // Replace x^^2 with (tmp = x, tmp*tmp) // Replace x^^3 with (tmp = x, tmp*tmp*tmp) auto tmp = copyToTemp(0, "__powtmp", exp.e1); Expression de = new DeclarationExp(exp.loc, tmp); Expression ve = new VarExp(exp.loc, tmp); /* Note that we're reusing ve. This should be ok. */ Expression me = new MulExp(exp.loc, ve, ve); if (intpow == 3) me = new MulExp(exp.loc, me, ve); e = new CommaExp(exp.loc, de, me); e = e.expressionSemantic(sc); result = e; return; } Module mmath = loadStdMath(); if (!mmath) { e.error("`%s` requires `std.math` for `^^` operators", e.toChars()); return setError(); } e = new ScopeExp(exp.loc, mmath); if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half) { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1); } else { // Replace e1 ^^ e2 with .std.math.pow(e1, e2) e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2); } e = e.expressionSemantic(sc); result = e; return; } override void visit(ShlExp exp) { //printf("ShlExp::semantic(), type = %p\n", type); if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.checkIntegralBin()) return setError(); if (!Target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } exp.e1 = integralPromotions(exp.e1, sc); if (exp.e2.type.toBasetype().ty != Tvector) exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); exp.type = exp.e1.type; result = exp; } override void visit(ShrExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.checkIntegralBin()) return setError(); if (!Target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } exp.e1 = integralPromotions(exp.e1, sc); if (exp.e2.type.toBasetype().ty != Tvector) exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); exp.type = exp.e1.type; result = exp; } override void visit(UshrExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.checkIntegralBin()) return setError(); if (!Target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } exp.e1 = integralPromotions(exp.e1, sc); if (exp.e2.type.toBasetype().ty != Tvector) exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); exp.type = exp.e1.type; result = exp; } override void visit(AndExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) { exp.type = exp.e1.type; result = exp; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } if (exp.checkIntegralBin()) return setError(); result = exp; } override void visit(OrExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) { exp.type = exp.e1.type; result = exp; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } if (exp.checkIntegralBin()) return setError(); result = exp; } override void visit(XorExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) { exp.type = exp.e1.type; result = exp; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } Type tb = exp.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { if (!isArrayOpValid(exp)) { result = arrayOpInvalidError(exp); return; } result = exp; return; } if (!Target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) { result = exp.incompatibleTypes(); return; } if (exp.checkIntegralBin()) return setError(); result = exp; } override void visit(LogicalExp exp) { if (exp.type) { result = exp; return; } exp.setNoderefOperands(); Expression e1x = exp.e1.expressionSemantic(sc); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (e1x.op == TOK.type) e1x = resolveAliasThis(sc, e1x); e1x = resolveProperties(sc, e1x); e1x = e1x.toBoolean(sc); if (sc.flags & SCOPE.condition) { /* If in static if, don't evaluate e2 if we don't have to. */ e1x = e1x.optimize(WANTvalue); if (e1x.isBool(exp.op == TOK.orOr)) { result = new IntegerExp(exp.loc, exp.op == TOK.orOr, Type.tbool); return; } } CtorFlow ctorflow = sc.ctorflow.clone(); Expression e2x = exp.e2.expressionSemantic(sc); sc.merge(exp.loc, ctorflow); ctorflow.freeFieldinit(); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (e2x.op == TOK.type) e2x = resolveAliasThis(sc, e2x); e2x = resolveProperties(sc, e2x); auto f1 = checkNonAssignmentArrayOp(e1x); auto f2 = checkNonAssignmentArrayOp(e2x); if (f1 || f2) return setError(); // Unless the right operand is 'void', the expression is converted to 'bool'. if (e2x.type.ty != Tvoid) e2x = e2x.toBoolean(sc); if (e2x.op == TOK.type || e2x.op == TOK.scope_) { exp.error("`%s` is not an expression", exp.e2.toChars()); return setError(); } if (e1x.op == TOK.error) { result = e1x; return; } if (e2x.op == TOK.error) { result = e2x; return; } // The result type is 'bool', unless the right operand has type 'void'. if (e2x.type.ty == Tvoid) exp.type = Type.tvoid; else exp.type = Type.tbool; exp.e1 = e1x; exp.e2 = e2x; result = exp; } override void visit(CmpExp exp) { static if (LOGSEMANTIC) { printf("CmpExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } exp.setNoderefOperands(); if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); if (t1.ty == Tclass && exp.e2.op == TOK.null_ || t2.ty == Tclass && exp.e1.op == TOK.null_) { exp.error("do not use `null` when comparing class types"); return setError(); } Expression e = exp.op_overload(sc); if (e) { if (!e.type.isscalar() && e.type.equals(exp.e1.type)) { exp.error("recursive `opCmp` expansion"); return setError(); } if (e.op == TOK.call) { e = new CmpExp(exp.op, exp.loc, e, new IntegerExp(exp.loc, 0, Type.tint32)); e = e.expressionSemantic(sc); } result = e; return; } if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = checkNonAssignmentArrayOp(exp.e2); if (f1 || f2) return setError(); exp.type = Type.tbool; // Special handling for array comparisons Expression arrayLowering = null; t1 = exp.e1.type.toBasetype(); t2 = exp.e2.type.toBasetype(); if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) { Type t1next = t1.nextOf(); Type t2next = t2.nextOf(); if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid)) { exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars()); return setError(); } if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { // Lower to object.__cmp(e1, e2) Expression al = new IdentifierExp(exp.loc, Id.empty); al = new DotIdExp(exp.loc, al, Id.object); al = new DotIdExp(exp.loc, al, Id.__cmp); al = al.expressionSemantic(sc); auto arguments = new Expressions(); arguments.push(exp.e1); arguments.push(exp.e2); al = new CallExp(exp.loc, al, arguments); al = new CmpExp(exp.op, exp.loc, al, new IntegerExp(0)); arrayLowering = al; } } else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) { if (t2.ty == Tstruct) exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars()); else exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); return setError(); } else if (t1.iscomplex() || t2.iscomplex()) { exp.error("compare not defined for complex operands"); return setError(); } else if (t1.ty == Taarray || t2.ty == Taarray) { exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op)); return setError(); } else if (!Target.isVectorOpSupported(t1, exp.op, t2)) { result = exp.incompatibleTypes(); return; } else { bool r1 = exp.e1.checkValue(); bool r2 = exp.e2.checkValue(); if (r1 || r2) return setError(); } //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars()); if (arrayLowering) { arrayLowering = arrayLowering.expressionSemantic(sc); result = arrayLowering; return; } result = exp; return; } override void visit(InExp exp) { if (exp.type) { result = exp; return; } if (Expression ex = binSemanticProp(exp, sc)) { result = ex; return; } Expression e = exp.op_overload(sc); if (e) { result = e; return; } Type t2b = exp.e2.type.toBasetype(); switch (t2b.ty) { case Taarray: { TypeAArray ta = cast(TypeAArray)t2b; // Special handling for array keys if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index)) { // Convert key to type of key exp.e1 = exp.e1.implicitCastTo(sc, ta.index); } semanticTypeInfo(sc, ta.index); // Return type is pointer to value exp.type = ta.nextOf().pointerTo(); break; } case Terror: return setError(); default: result = exp.incompatibleTypes(); return; } result = exp; } override void visit(RemoveExp e) { if (Expression ex = binSemantic(e, sc)) { result = ex; return; } result = e; } override void visit(EqualExp exp) { //printf("EqualExp::semantic('%s')\n", exp.toChars()); if (exp.type) { result = exp; return; } exp.setNoderefOperands(); if (auto e = binSemanticProp(exp, sc)) { result = e; return; } if (exp.e1.op == TOK.type || exp.e2.op == TOK.type) { result = exp.incompatibleTypes(); return; } { auto t1 = exp.e1.type; auto t2 = exp.e2.type; if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2)) exp.error("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", t1.toChars(), t2.toChars()); } /* Before checking for operator overloading, check to see if we're * comparing the addresses of two statics. If so, we can just see * if they are the same symbol. */ if (exp.e1.op == TOK.address && exp.e2.op == TOK.address) { AddrExp ae1 = cast(AddrExp)exp.e1; AddrExp ae2 = cast(AddrExp)exp.e2; if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable) { VarExp ve1 = cast(VarExp)ae1.e1; VarExp ve2 = cast(VarExp)ae2.e1; if (ve1.var == ve2.var) { // They are the same, result is 'true' for ==, 'false' for != result = new IntegerExp(exp.loc, (exp.op == TOK.equal), Type.tbool); return; } } } Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); bool needsDirectEq(Type t1, Type t2) { Type t1n = t1.nextOf().toBasetype(); Type t2n = t2.nextOf().toBasetype(); if (((t1n.ty == Tchar || t1n.ty == Twchar || t1n.ty == Tdchar) && (t2n.ty == Tchar || t2n.ty == Twchar || t2n.ty == Tdchar)) || (t1n.ty == Tvoid || t2n.ty == Tvoid)) { return false; } if (t1n.constOf() != t2n.constOf()) return true; Type t = t1n; while (t.toBasetype().nextOf()) t = t.nextOf().toBasetype(); if (t.ty != Tstruct) return false; if (global.params.useTypeInfo && Type.dtypeinfo) semanticTypeInfo(sc, t); return (cast(TypeStruct)t).sym.hasIdentityEquals; } if (auto e = exp.op_overload(sc)) { result = e; return; } if (!(t1.ty == Tarray && t2.ty == Tarray && needsDirectEq(t1, t2))) { if (auto e = typeCombine(exp, sc)) { result = e; return; } } auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = checkNonAssignmentArrayOp(exp.e2); if (f1 || f2) return setError(); exp.type = Type.tbool; // Special handling for array comparisons if (!(t1.ty == Tarray && t2.ty == Tarray && needsDirectEq(t1, t2))) { if (!arrayTypeCompatible(exp.loc, exp.e1.type, exp.e2.type)) { if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) { // Cast both to complex exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); } } } if (t1.ty == Tarray && t2.ty == Tarray) { //printf("Lowering to __equals %s %s\n", e1.toChars(), e2.toChars()); // For e1 and e2 of struct type, lowers e1 == e2 to object.__equals(e1, e2) // and e1 != e2 to !(object.__equals(e1, e2)). Expression __equals = new IdentifierExp(exp.loc, Id.empty); Identifier id = Identifier.idPool("__equals"); __equals = new DotIdExp(exp.loc, __equals, Id.object); __equals = new DotIdExp(exp.loc, __equals, id); auto arguments = new Expressions(); arguments.push(exp.e1); arguments.push(exp.e2); __equals = new CallExp(exp.loc, __equals, arguments); if (exp.op == TOK.notEqual) { __equals = new NotExp(exp.loc, __equals); } __equals = __equals.expressionSemantic(sc); result = __equals; return; } if (exp.e1.type.toBasetype().ty == Taarray) semanticTypeInfo(sc, exp.e1.type.toBasetype()); if (!Target.isVectorOpSupported(t1, exp.op, t2)) { result = exp.incompatibleTypes(); return; } result = exp; } override void visit(IdentityExp exp) { if (exp.type) { result = exp; return; } exp.setNoderefOperands(); if (auto e = binSemanticProp(exp, sc)) { result = e; return; } if (auto e = typeCombine(exp, sc)) { result = e; return; } auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = checkNonAssignmentArrayOp(exp.e2); if (f1 || f2) return setError(); exp.type = Type.tbool; if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) { // Cast both to complex exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); } auto tb1 = exp.e1.type.toBasetype(); auto tb2 = exp.e2.type.toBasetype(); if (!Target.isVectorOpSupported(tb1, exp.op, tb2)) { result = exp.incompatibleTypes(); return; } if (exp.e1.op == TOK.call) exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc); if (exp.e2.op == TOK.call) exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc); if (exp.e1.type.toBasetype().ty == Tsarray || exp.e2.type.toBasetype().ty == Tsarray) exp.deprecation("identity comparison of static arrays " ~ "implicitly coerces them to slices, " ~ "which are compared by reference"); result = exp; } override void visit(CondExp exp) { static if (LOGSEMANTIC) { printf("CondExp::semantic('%s')\n", exp.toChars()); } if (exp.type) { result = exp; return; } if (exp.econd.op == TOK.dotIdentifier) (cast(DotIdExp)exp.econd).noderef = true; Expression ec = exp.econd.expressionSemantic(sc); ec = resolveProperties(sc, ec); ec = ec.toBoolean(sc); CtorFlow ctorflow_root = sc.ctorflow.clone(); Expression e1x = exp.e1.expressionSemantic(sc); e1x = resolveProperties(sc, e1x); CtorFlow ctorflow1 = sc.ctorflow; sc.ctorflow = ctorflow_root; Expression e2x = exp.e2.expressionSemantic(sc); e2x = resolveProperties(sc, e2x); sc.merge(exp.loc, ctorflow1); ctorflow1.freeFieldinit(); if (ec.op == TOK.error) { result = ec; return; } if (ec.type == Type.terror) return setError(); exp.econd = ec; if (e1x.op == TOK.error) { result = e1x; return; } if (e1x.type == Type.terror) return setError(); exp.e1 = e1x; if (e2x.op == TOK.error) { result = e2x; return; } if (e2x.type == Type.terror) return setError(); exp.e2 = e2x; auto f0 = checkNonAssignmentArrayOp(exp.econd); auto f1 = checkNonAssignmentArrayOp(exp.e1); auto f2 = checkNonAssignmentArrayOp(exp.e2); if (f0 || f1 || f2) return setError(); Type t1 = exp.e1.type; Type t2 = exp.e2.type; // If either operand is void the result is void, we have to cast both // the expression to void so that we explicitly discard the expression // value if any // https://issues.dlang.org/show_bug.cgi?id=16598 if (t1.ty == Tvoid || t2.ty == Tvoid) { exp.type = Type.tvoid; exp.e1 = exp.e1.castTo(sc, exp.type); exp.e2 = exp.e2.castTo(sc, exp.type); } else if (t1 == t2) exp.type = t1; else { if (Expression ex = typeCombine(exp, sc)) { result = ex; return; } switch (exp.e1.type.toBasetype().ty) { case Tcomplex32: case Tcomplex64: case Tcomplex80: exp.e2 = exp.e2.castTo(sc, exp.e1.type); break; default: break; } switch (exp.e2.type.toBasetype().ty) { case Tcomplex32: case Tcomplex64: case Tcomplex80: exp.e1 = exp.e1.castTo(sc, exp.e2.type); break; default: break; } if (exp.type.toBasetype().ty == Tarray) { exp.e1 = exp.e1.castTo(sc, exp.type); exp.e2 = exp.e2.castTo(sc, exp.type); } } exp.type = exp.type.merge2(); version (none) { printf("res: %s\n", exp.type.toChars()); printf("e1 : %s\n", exp.e1.type.toChars()); printf("e2 : %s\n", exp.e2.type.toChars()); } /* https://issues.dlang.org/show_bug.cgi?id=14696 * If either e1 or e2 contain temporaries which need dtor, * make them conditional. * Rewrite: * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2) * to: * (auto __cond = cond) ? (... __tmp1) : (... __tmp2) * and replace edtors of __tmp1 and __tmp2 with: * __tmp1.edtor --> __cond && __tmp1.dtor() * __tmp2.edtor --> __cond || __tmp2.dtor() */ exp.hookDtors(sc); result = exp; } override void visit(FileInitExp e) { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; result = e; } override void visit(LineInitExp e) { e.type = Type.tint32; result = e; } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; result = e; } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; if (sc.func) { result = e.resolveLoc(Loc.initial, sc); return; } result = e; } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; if (sc.func) { result = e.resolveLoc(Loc.initial, sc); return; } result = e; } } /********************************** * Try to run semantic routines. * If they fail, return NULL. */ Expression trySemantic(Expression exp, Scope* sc) { //printf("+trySemantic(%s)\n", exp.toChars()); uint errors = global.startGagging(); Expression e = expressionSemantic(exp, sc); if (global.endGagging(errors)) { e = null; } //printf("-trySemantic(%s)\n", exp.toChars()); return e; } /************************** * Helper function for easy error propagation. * If error occurs, returns ErrorExp. Otherwise returns NULL. */ Expression unaSemantic(UnaExp e, Scope* sc) { static if (LOGSEMANTIC) { printf("UnaExp::semantic('%s')\n", e.toChars()); } Expression e1x = e.e1.expressionSemantic(sc); if (e1x.op == TOK.error) return e1x; e.e1 = e1x; return null; } /************************** * Helper function for easy error propagation. * If error occurs, returns ErrorExp. Otherwise returns NULL. */ Expression binSemantic(BinExp e, Scope* sc) { static if (LOGSEMANTIC) { printf("BinExp::semantic('%s')\n", e.toChars()); } Expression e1x = e.e1.expressionSemantic(sc); Expression e2x = e.e2.expressionSemantic(sc); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (e1x.op == TOK.type) e1x = resolveAliasThis(sc, e1x); if (e2x.op == TOK.type) e2x = resolveAliasThis(sc, e2x); if (e1x.op == TOK.error) return e1x; if (e2x.op == TOK.error) return e2x; e.e1 = e1x; e.e2 = e2x; return null; } Expression binSemanticProp(BinExp e, Scope* sc) { if (Expression ex = binSemantic(e, sc)) return ex; Expression e1x = resolveProperties(sc, e.e1); Expression e2x = resolveProperties(sc, e.e2); if (e1x.op == TOK.error) return e1x; if (e2x.op == TOK.error) return e2x; e.e1 = e1x; e.e2 = e2x; return null; } // entrypoint for semantic ExpressionSemanticVisitor extern (C++) Expression expressionSemantic(Expression e, Scope* sc) { scope v = new ExpressionSemanticVisitor(sc); e.accept(v); return v.result; } Expression semanticX(DotIdExp exp, Scope* sc) { //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); if (Expression ex = unaSemantic(exp, sc)) return ex; if (exp.ident == Id._mangleof) { // symbol.mangleof Dsymbol ds; switch (exp.e1.op) { case TOK.scope_: ds = (cast(ScopeExp)exp.e1).sds; goto L1; case TOK.variable: ds = (cast(VarExp)exp.e1).var; goto L1; case TOK.dotVariable: ds = (cast(DotVarExp)exp.e1).var; goto L1; case TOK.overloadSet: ds = (cast(OverExp)exp.e1).vars; goto L1; case TOK.template_: { TemplateExp te = cast(TemplateExp)exp.e1; ds = te.fd ? cast(Dsymbol)te.fd : te.td; } L1: { assert(ds); if (auto f = ds.isFuncDeclaration()) { if (f.checkForwardRef(exp.loc)) { return new ErrorExp(); } } OutBuffer buf; mangleToBuffer(ds, &buf); const s = buf.peekSlice(); Expression e = new StringExp(exp.loc, buf.extractString(), s.length); e = e.expressionSemantic(sc); return e; } default: break; } } if (exp.e1.op == TOK.variable && exp.e1.type.toBasetype().ty == Tsarray && exp.ident == Id.length) { // bypass checkPurity return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0); } if (exp.e1.op == TOK.dot) { } else { exp.e1 = resolvePropertiesX(sc, exp.e1); } if (exp.e1.op == TOK.tuple && exp.ident == Id.offsetof) { /* 'distribute' the .offsetof to each of the tuple elements. */ TupleExp te = cast(TupleExp)exp.e1; auto exps = new Expressions(te.exps.dim); for (size_t i = 0; i < exps.dim; i++) { Expression e = (*te.exps)[i]; e = e.expressionSemantic(sc); e = new DotIdExp(e.loc, e, Id.offsetof); (*exps)[i] = e; } // Don't evaluate te.e0 in runtime Expression e = new TupleExp(exp.loc, null, exps); e = e.expressionSemantic(sc); return e; } if (exp.e1.op == TOK.tuple && exp.ident == Id.length) { TupleExp te = cast(TupleExp)exp.e1; // Don't evaluate te.e0 in runtime Expression e = new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t); return e; } // https://issues.dlang.org/show_bug.cgi?id=14416 // Template has no built-in properties except for 'stringof'. if ((exp.e1.op == TOK.dotTemplateDeclaration || exp.e1.op == TOK.template_) && exp.ident != Id.stringof) { exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); return new ErrorExp(); } if (!exp.e1.type) { exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); return new ErrorExp(); } return exp; } // Resolve e1.ident without seeing UFCS. // If flag == 1, stop "not a property" error and return NULL. Expression semanticY(DotIdExp exp, Scope* sc, int flag) { //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } /* Special case: rewrite this.id and super.id * to be classtype.id and baseclasstype.id * if we have no this pointer. */ if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && !hasThis(sc)) { if (AggregateDeclaration ad = sc.getStructClassScope()) { if (exp.e1.op == TOK.this_) { exp.e1 = new TypeExp(exp.e1.loc, ad.type); } else { ClassDeclaration cd = ad.isClassDeclaration(); if (cd && cd.baseClass) exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type); } } } Expression e = semanticX(exp, sc); if (e != exp) return e; Expression eleft; Expression eright; if (exp.e1.op == TOK.dot) { DotExp de = cast(DotExp)exp.e1; eleft = de.e1; eright = de.e2; } else { eleft = null; eright = exp.e1; } Type t1b = exp.e1.type.toBasetype(); if (eright.op == TOK.scope_) // also used for template alias's { ScopeExp ie = cast(ScopeExp)eright; int flags = SearchLocalsOnly; /* Disable access to another module's private imports. * The check for 'is sds our current module' is because * the current module should have access to its own imports. */ if (ie.sds.isModule() && ie.sds != sc._module) flags |= IgnorePrivateImports; if (sc.flags & SCOPE.ignoresymbolvisibility) flags |= IgnoreSymbolVisibility; Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); /* Check for visibility before resolving aliases because public * aliases to private symbols are public. */ if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s)) { if (s.isDeclaration()) error(exp.loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), sc._module.toChars()); else deprecation(exp.loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), sc._module.toChars()); // s = null; } if (s) { if (auto p = s.isPackage()) checkAccess(exp.loc, sc, p); // if 's' is a tuple variable, the tuple is returned. s = s.toAlias(); exp.checkDeprecated(sc, s); exp.checkDisabled(sc, s); EnumMember em = s.isEnumMember(); if (em) { return em.getVarExp(exp.loc, sc); } VarDeclaration v = s.isVarDeclaration(); if (v) { //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); if (!v.type || !v.type.deco && v.inuse) { if (v.inuse) exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars()); else exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars()); return new ErrorExp(); } if (v.type.ty == Terror) return new ErrorExp(); if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym) { /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2(). * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably * be reverted. `wantsym` is the hack to work around the problem. */ if (v.inuse) { error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); return new ErrorExp(); } e = v.expandInitializer(exp.loc); v.inuse++; e = e.expressionSemantic(sc); v.inuse--; return e; } if (v.needThis()) { if (!eleft) eleft = new ThisExp(exp.loc); e = new DotVarExp(exp.loc, eleft, v); e = e.expressionSemantic(sc); } else { e = new VarExp(exp.loc, v); if (eleft) { e = new CommaExp(exp.loc, eleft, e); e.type = v.type; } } e = e.deref(); return e.expressionSemantic(sc); } FuncDeclaration f = s.isFuncDeclaration(); if (f) { //printf("it's a function\n"); if (!f.functionSemantic()) return new ErrorExp(); if (f.needThis()) { if (!eleft) eleft = new ThisExp(exp.loc); e = new DotVarExp(exp.loc, eleft, f, true); e = e.expressionSemantic(sc); } else { e = new VarExp(exp.loc, f, true); if (eleft) { e = new CommaExp(exp.loc, eleft, e); e.type = f.type; } } return e; } if (auto td = s.isTemplateDeclaration()) { if (eleft) e = new DotTemplateExp(exp.loc, eleft, td); else e = new TemplateExp(exp.loc, td); e = e.expressionSemantic(sc); return e; } if (OverDeclaration od = s.isOverDeclaration()) { e = new VarExp(exp.loc, od, true); if (eleft) { e = new CommaExp(exp.loc, eleft, e); e.type = Type.tvoid; // ambiguous type? } return e; } OverloadSet o = s.isOverloadSet(); if (o) { //printf("'%s' is an overload set\n", o.toChars()); return new OverExp(exp.loc, o); } if (auto t = s.getType()) { return (new TypeExp(exp.loc, t)).expressionSemantic(sc); } TupleDeclaration tup = s.isTupleDeclaration(); if (tup) { if (eleft) { e = new DotVarExp(exp.loc, eleft, tup); e = e.expressionSemantic(sc); return e; } e = new TupleExp(exp.loc, tup); e = e.expressionSemantic(sc); return e; } ScopeDsymbol sds = s.isScopeDsymbol(); if (sds) { //printf("it's a ScopeDsymbol %s\n", ident.toChars()); e = new ScopeExp(exp.loc, sds); e = e.expressionSemantic(sc); if (eleft) e = new DotExp(exp.loc, eleft, e); return e; } Import imp = s.isImport(); if (imp) { ie = new ScopeExp(exp.loc, imp.pkg); return ie.expressionSemantic(sc); } // BUG: handle other cases like in IdentifierExp::semantic() debug { printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind()); } assert(0); } else if (exp.ident == Id.stringof) { const p = ie.toString(); e = new StringExp(exp.loc, cast(char*)p.ptr, p.length); e = e.expressionSemantic(sc); return e; } if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) { flag = 0; } if (flag) return null; s = ie.sds.search_correct(exp.ident); if (s) exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars()); else exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); return new ErrorExp(); } else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof) { Type t1bn = t1b.nextOf(); if (flag) { AggregateDeclaration ad = isAggregate(t1bn); if (ad && !ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312 return null; } /* Rewrite: * p.ident * as: * (*p).ident */ if (flag && t1bn.ty == Tvoid) return null; e = new PtrExp(exp.loc, exp.e1); e = e.expressionSemantic(sc); return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); } else { if (exp.e1.op == TOK.type || exp.e1.op == TOK.template_) flag = 0; e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); if (e) e = e.expressionSemantic(sc); return e; } } // Resolve e1.ident!tiargs without seeing UFCS. // If flag == 1, stop "not a property" error and return NULL. Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) { static if (LOGSEMANTIC) { printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars()); } static Expression errorExp() { return new ErrorExp(); } auto die = new DotIdExp(exp.loc, exp.e1, exp.ti.name); Expression e = die.semanticX(sc); if (e == die) { exp.e1 = die.e1; // take back Type t1b = exp.e1.type.toBasetype(); if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) { /* No built-in type has templatized properties, so do shortcut. * It is necessary in: 1024.max!"a < b" */ if (flag) return null; } e = die.semanticY(sc, flag); if (flag) { if (!e || isDotOpDispatch(e)) { /* opDispatch!tiargs would be a function template that needs IFTI, * so it's not a template */ return null; } } } assert(e); if (e.op == TOK.error) return e; if (e.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)e; if (FuncDeclaration fd = dve.var.isFuncDeclaration()) { if (TemplateDeclaration td = fd.findTemplateDeclRoot()) { e = new DotTemplateExp(dve.loc, dve.e1, td); e = e.expressionSemantic(sc); } } else if (OverDeclaration od = dve.var.isOverDeclaration()) { exp.e1 = dve.e1; // pull semantic() result if (!exp.findTempDecl(sc)) goto Lerr; if (exp.ti.needsTypeInference(sc)) return exp; exp.ti.dsymbolSemantic(sc); if (!exp.ti.inst || exp.ti.errors) // if template failed to expand return errorExp(); if (Declaration v = exp.ti.toAlias().isDeclaration()) { if (v.type && !v.type.deco) v.type = v.type.typeSemantic(v.loc, sc); return new DotVarExp(exp.loc, exp.e1, v) .expressionSemantic(sc); } return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) .expressionSemantic(sc); } } else if (e.op == TOK.variable) { VarExp ve = cast(VarExp)e; if (FuncDeclaration fd = ve.var.isFuncDeclaration()) { if (TemplateDeclaration td = fd.findTemplateDeclRoot()) { e = new TemplateExp(ve.loc, td) .expressionSemantic(sc); } } else if (OverDeclaration od = ve.var.isOverDeclaration()) { exp.ti.tempdecl = od; return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); } } if (e.op == TOK.dotTemplateDeclaration) { DotTemplateExp dte = cast(DotTemplateExp)e; exp.e1 = dte.e1; // pull semantic() result exp.ti.tempdecl = dte.td; if (!exp.ti.semanticTiargs(sc)) return errorExp(); if (exp.ti.needsTypeInference(sc)) return exp; exp.ti.dsymbolSemantic(sc); if (!exp.ti.inst || exp.ti.errors) // if template failed to expand return errorExp(); if (Declaration v = exp.ti.toAlias().isDeclaration()) { if (v.isFuncDeclaration() || v.isVarDeclaration()) { return new DotVarExp(exp.loc, exp.e1, v) .expressionSemantic(sc); } } return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) .expressionSemantic(sc); } else if (e.op == TOK.template_) { exp.ti.tempdecl = (cast(TemplateExp)e).td; return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); } else if (e.op == TOK.dot) { DotExp de = cast(DotExp)e; if (de.e2.op == TOK.overloadSet) { if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) { return errorExp(); } if (exp.ti.needsTypeInference(sc)) return exp; exp.ti.dsymbolSemantic(sc); if (!exp.ti.inst || exp.ti.errors) // if template failed to expand return errorExp(); if (Declaration v = exp.ti.toAlias().isDeclaration()) { if (v.type && !v.type.deco) v.type = v.type.typeSemantic(v.loc, sc); return new DotVarExp(exp.loc, exp.e1, v) .expressionSemantic(sc); } return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) .expressionSemantic(sc); } } else if (e.op == TOK.overloadSet) { OverExp oe = cast(OverExp)e; exp.ti.tempdecl = oe.vars; return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); } Lerr: exp.error("`%s` isn't a template", e.toChars()); return errorExp(); } /**************************************************** * Determine if `exp`, which takes the address of `v`, can do so safely. * Params: * sc = context * exp = expression that takes the address of `v` * v = the variable getting its address taken * Returns: * `true` if ok, `false` for error */ private bool checkAddressVar(Scope* sc, UnaExp exp, VarDeclaration v) { //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); if (v) { if (!v.canTakeAddressOf()) { exp.error("cannot take address of `%s`", exp.e1.toChars()); return false; } if (sc.func && !sc.intypeof && !v.isDataseg()) { const(char)* p = v.isParameter() ? "parameter" : "local"; if (global.params.vsafe) { // Taking the address of v means it cannot be set to 'scope' later v.storage_class &= ~STC.maybescope; v.doNotInferScope = true; if (v.storage_class & STC.scope_ && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; } } else if (sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; } } } return true; } /******************************* * Checks the attributes of a function. * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) * and usage of `deprecated` and `@disabled`-ed symbols are checked. * * Params: * exp = expression to check attributes for * sc = scope of the function * f = function to be checked * Returns: `true` if error occur. */ private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f) { with(exp) { bool error = checkDisabled(sc, f); error |= checkDeprecated(sc, f); error |= checkPurity(sc, f); error |= checkSafety(sc, f); error |= checkNogc(sc, f); return error; } } ================================================ FILE: gcc/d/dmd/func.d ================================================ /*** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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.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 : int { unknown = -1, /// not known if this is a builtin no, /// this is not a builtin yes, /// this is a builtin } /* 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; if (fd.returnLabel) { /* Rewrite: * return exp; * as: * vresult = exp; goto Lresult; */ auto gs = new GotoStatement(s.loc, Id.returnLabel); gs.label = fd.returnLabel; Statement s1 = gs; if (s.exp) s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); replaceCurrent(s1); } } override void visit(TryFinallyStatement s) { DtorExpStatement des; if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && fd.nrvo_var == des.var) { if (!(global.params.useExceptions && ClassDeclaration.throwable)) { /* Don't need to call destructor at all, since it is nrvo */ replaceCurrent(s._body); s._body.accept(this); 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; */ Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var); Identifier id = Identifier.generateId("__o"); Statement handler = new PeelStatement(sexception); if (sexception.blockExit(fd, false) & BE.fallthru) { auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); ts.internalThrow = true; handler = new CompoundStatement(Loc.initial, handler, ts); } auto catches = new Catches(); auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); ctch.internalCatch = true; ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o' catches.push(ctch); Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); fd.eh_none = false; replaceCurrent(s2); s2.accept(this); } else 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 } /*********************************************************** * 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() { return Ensure(id, ensure.syntaxCopy()); } /***************************************** * Do syntax copy of an array of Ensure's. */ static Ensures* arraySyntaxCopy(Ensures* a) { Ensures* b = null; if (a) { b = a.copy(); foreach (i, e; *a) { (*b)[i] = e.syntaxCopy(); } } return b; } } /*********************************************************** */ extern (C++) class FuncDeclaration : Declaration { Types* fthrows; /// Array of Type's of exceptions (not used) 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 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) VarDeclaration v_arguments; /// '_arguments' parameter ObjcSelector* selector; /// Objective-C method selector (member function only) VarDeclaration v_argptr; /// '_argptr' variable VarDeclarations* parameters; /// Array of VarDeclaration's for parameters DsymbolTable labtab; /// statement label symbol table Dsymbol overnext; /// next in overload list FuncDeclaration overnext0; /// next in overload list (only used during IFTI) Loc endloc; /// location of closing curly bracket int vtblIndex = -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 ILS inlineStatusStmt = ILS.uninitialized; ILS inlineStatusExp = ILS.uninitialized; PINLINE inlining = PINLINE.default_; CompiledCtfeFunctionPimpl ctfeCode; /// Local data (i.e. CompileCtfeFunction*) for module dinterpret int inlineNest; /// !=0 if nested inline bool isArrayOp; /// true if array operation 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 VarDeclarations closureVars; /// Sibling nested functions which called this one FuncDeclarations siblingCallers; FuncDeclarations *inlinedNestedCallees; uint flags; /// FUNCFLAG.xxxxx extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type) { super(id); //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); //printf("storage_class = x%x\n", storage_class); this.storage_class = storage_class; this.type = type; if (type) { // Normalize storage_class, because function-type related attributes // are already set in the 'type' in parsing phase. this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); } this.loc = loc; this.endloc = endloc; /* The type given for "infer the return type" is a TypeFunction with * NULL for the return type. */ inferRetType = (type && type.nextOf() is null); } static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type) { return new FuncDeclaration(loc, endloc, id, storage_class, type); } override Dsymbol syntaxCopy(Dsymbol s) { //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null; f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null; f.fbody = fbody ? fbody.syntaxCopy() : null; assert(!fthrows); // deprecated 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() { if (!_scope) return !errors; if (!originalType) // semantic not yet run { TemplateInstance spec = isSpeculative(); uint olderrs = global.errors; uint oldgag = global.gag; if (global.gag && !spec) global.gag = 0; dsymbolSemantic(this, _scope); global.gag = oldgag; if (spec && global.errors != olderrs) spec.errors = (global.errors - olderrs != 0); if (olderrs != global.errors) // if errors compiling this function return false; } // if inferring return type, sematic3 needs to be run // - When the function body contains any errors, we cannot assume // the inferred return type is valid. // So, the body errors should become the function signature error. if (inferRetType && type && !type.nextOf()) return functionSemantic3(); TemplateInstance ti; if (isInstantiated() && !isVirtualMethod() && ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) { AggregateDeclaration ad = isMember2(); 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 return functionSemantic3() || !errors; } if (storage_class & STC.inference) return functionSemantic3() || !errors; return !errors; } /**************************************************** * Resolve forward reference of function body. * Returns false if any errors exist in the body. */ final bool functionSemantic3() { 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. */ TemplateInstance spec = isSpeculative(); uint olderrs = global.errors; uint oldgag = global.gag; if (global.gag && !spec) global.gag = 0; semantic3(this, _scope); global.gag = oldgag; // If it is a speculatively-instantiated template, and errors occur, // we need to mark the template as having errors. if (spec && global.errors != olderrs) spec.errors = (global.errors - olderrs != 0); if (olderrs != global.errors) // if errors compiling this function return false; } return !errors && !semantic3Errors; } /**************************************************** * Check that this function type is properly resolved. * If not, report "forward reference error" and return true. */ extern (D) final bool checkForwardRef(const ref Loc loc) { if (!functionSemantic()) return true; /* No deco means the functionSemantic() call could not resolve * forward referenes in the type of this function. */ if (!type.deco) { bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3); .error(loc, "forward reference to %s`%s`", (inSemantic3 ? "inferred return type of function " : "").ptr, toChars()); return true; } return false; } // called from semantic3 final VarDeclaration declareThis(Scope* sc, AggregateDeclaration ad) { if (ad) { //printf("declareThis() %s\n", toChars()); Type thandle = ad.handleType(); assert(thandle); thandle = thandle.addMod(type.mod); thandle = thandle.addStorageClass(storage_class); VarDeclaration v = new ThisDeclaration(loc, thandle); v.storage_class |= STC.parameter; if (thandle.ty == Tstruct) { v.storage_class |= STC.ref_; // if member function is marked 'inout', then 'this' is 'return ref' if (type.ty == Tfunction && (cast(TypeFunction)type).iswild & 2) v.storage_class |= STC.return_; } if (type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)type; if (tf.isreturn) v.storage_class |= STC.return_; if (tf.isscope) v.storage_class |= STC.scope_; } if (flags & FUNCFLAG.inferScope && !(v.storage_class & STC.scope_)) v.storage_class |= STC.maybescope; v.dsymbolSemantic(sc); if (!sc.insert(v)) assert(0); v.parent = this; return v; } if (isNested()) { /* The 'this' for a nested function is the link to the * enclosing function's stack frame. * Note that nested functions and member functions are disjoint. */ VarDeclaration v = new ThisDeclaration(loc, Type.tvoid.pointerTo()); v.storage_class |= STC.parameter; if (type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)type; if (tf.isreturn) v.storage_class |= STC.return_; if (tf.isscope) v.storage_class |= STC.scope_; } if (flags & FUNCFLAG.inferScope && !(v.storage_class & STC.scope_)) v.storage_class |= STC.maybescope; v.dsymbolSemantic(sc); if (!sc.insert(v)) assert(0); v.parent = this; return v; } return null; } override final bool equals(RootObject o) { if (this == o) return true; Dsymbol s = isDsymbol(o); if (s) { alias fd1 = this; auto fd2 = s.isFuncDeclaration(); if (!fd2) return false; auto fa1 = fd1.isFuncAliasDeclaration(); auto fa2 = fd2.isFuncAliasDeclaration(); if (fa1 && fa2) { return fa1.toAliasFunc().equals(fa2.toAliasFunc()) && fa1.hasOverloads == fa2.hasOverloads; } if (fa1 && (fd1 = fa1.toAliasFunc()).isUnique() && !fa1.hasOverloads) fa1 = null; if (fa2 && (fd2 = fa2.toAliasFunc()).isUnique() && !fa2.hasOverloads) fa2 = null; if ((fa1 !is null) != (fa2 !is null)) return false; return fd1.toParent().equals(fd2.toParent()) && fd1.ident.equals(fd2.ident) && fd1.type.equals(fd2.type); } return false; } /**************************************************** * Determine if 'this' overrides fd. * Return !=0 if it does. */ final int overrides(FuncDeclaration fd) { int result = 0; if (fd.ident == ident) { int cov = type.covariant(fd.type); if (cov) { ClassDeclaration cd1 = toParent().isClassDeclaration(); ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) result = 1; } } return result; } /************************************************* * Find index of function in vtbl[0..dim] that * this function overrides. * Prefer an exact match to a covariant one. * Params: * vtbl = vtable to use * dim = maximal vtable dimension * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349 * Returns: * -1 didn't find one * -2 can't determine because of forward references */ final int findVtblIndex(Dsymbols* vtbl, int dim, bool fix17349 = true) { //printf("findVtblIndex() %s\n", toChars()); FuncDeclaration mismatch = null; StorageClass mismatchstc = 0; int mismatchvi = -1; int exactvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); if (fdv && fdv.ident == ident) { if (type.equals(fdv.type)) // if exact match { if (fdv.parent.isClassDeclaration()) { if (fdv.isFuture()) { bestvi = vi; continue; // keep looking } return vi; // no need to look further } if (exactvi >= 0) { error("cannot determine overridden function"); return exactvi; } exactvi = vi; bestvi = vi; continue; } StorageClass stc = 0; int cov = type.covariant(fdv.type, &stc, fix17349); //printf("\tbaseclass cov = %d\n", cov); switch (cov) { case 0: // types are distinct break; case 1: bestvi = vi; // covariant, but not identical break; // keep looking for an exact match case 2: mismatchvi = vi; mismatchstc = stc; mismatch = fdv; // overrides, but is not covariant break; // keep looking for an exact match case 3: return -2; // forward references default: assert(0); } } } if (bestvi == -1 && mismatch) { //type.print(); //mismatch.type.print(); //printf("%s %s\n", type.deco, mismatch.type.deco); //printf("stc = %llx\n", mismatchstc); if (mismatchstc) { // Fix it by modifying the type to add the storage classes type = type.addStorageClass(mismatchstc); bestvi = mismatchvi; } } return bestvi; } /********************************* * If function a function in a base class, * return that base class. * Returns: * base class if overriding, null if not */ final BaseClass* overrideInterface() { if (ClassDeclaration cd = toParent2().isClassDeclaration()) { foreach (b; cd.interfaces) { auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); if (v >= 0) return b; } } return null; } /**************************************************** * Overload this FuncDeclaration with the new one f. * Return true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars()); assert(s != this); AliasDeclaration ad = s.isAliasDeclaration(); if (ad) { if (overnext) return overnext.overloadInsert(ad); if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof) { //printf("\tad = '%s'\n", ad.type.toChars()); return false; } overnext = ad; //printf("\ttrue: no conflict\n"); return true; } TemplateDeclaration td = s.isTemplateDeclaration(); if (td) { if (!td.funcroot) td.funcroot = this; if (overnext) return overnext.overloadInsert(td); overnext = td; return true; } FuncDeclaration fd = s.isFuncDeclaration(); if (!fd) return false; 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; } } if (overnext) { td = overnext.isTemplateDeclaration(); if (td) fd.overloadInsert(td); else return overnext.overloadInsert(fd); } overnext = fd; //printf("\ttrue: no conflict\n"); return true; } /******************************************** * Find function in overload list that exactly matches t. */ final FuncDeclaration overloadExactMatch(Type t) { FuncDeclaration fd; overloadApply(this, (Dsymbol s) { auto f = s.isFuncDeclaration(); if (!f) return 0; if (t.equals(f.type)) { fd = f; return 1; } /* Allow covariant matches, as long as the return type * is just a const conversion. * This allows things like pure functions to match with an impure function type. */ if (t.ty == Tfunction) { auto tf = cast(TypeFunction)f.type; if (tf.covariant(t) == 1 && tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) { fd = f; return 1; } } return 0; }); 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. */ final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads) { //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars()); Match m; m.last = MATCH.nomatch; overloadApply(this, (Dsymbol s) { auto f = s.isFuncDeclaration(); if (!f || f == m.lastf) // skip duplicates return 0; m.anyf = f; auto tf = f.type.toTypeFunction(); //printf("tf = %s\n", tf.toChars()); MATCH match; if (tthis) // non-static functions are preferred than static ones { if (f.needThis()) match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod); else match = MATCH.constant; // keep static function in overload candidates } else // static functions are preferred than non-static ones { if (f.needThis()) match = MATCH.convert; else match = MATCH.exact; } if (match == MATCH.nomatch) return 0; if (match > m.last) goto LcurrIsBetter; if (match < m.last) goto LlastIsBetter; // See if one of the matches overrides the other. if (m.lastf.overrides(f)) goto LlastIsBetter; if (f.overrides(m.lastf)) goto LcurrIsBetter; Lambiguous: //printf("\tambiguous\n"); m.nextf = f; m.count++; return 0; LlastIsBetter: //printf("\tlastbetter\n"); m.count++; // count up return 0; LcurrIsBetter: //printf("\tisbetter\n"); if (m.last <= MATCH.convert) { // clear last secondary matching m.nextf = null; m.count = 0; } m.last = match; m.lastf = f; m.count++; // count up return 0; }); if (m.count == 1) // exact match { hasOverloads = false; } else if (m.count > 1) // better or ambiguous match { hasOverloads = true; } else // no match { hasOverloads = true; auto tf = this.type.toTypeFunction(); assert(tthis); assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); .error(loc, "%smethod %s is not callable using a %sobject", funcBuf.peekString(), this.toPrettyChars(), thisBuf.peekString()); } } return m.lastf; } /******************************************** * find function template root in overload list */ final TemplateDeclaration findTemplateDeclRoot() { FuncDeclaration f = this; while (f && f.overnext) { //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars()); TemplateDeclaration td = f.overnext.isTemplateDeclaration(); if (td) return td; f = f.overnext.isFuncDeclaration(); } return null; } /******************************************** * Returns true if function was declared * directly or indirectly in a unittest block */ final bool inUnittest() { Dsymbol f = this; do { if (f.isUnitTestDeclaration()) return true; f = f.toParent(); } while (f); 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. */ TypeFunction tf = type.toTypeFunction(); TypeFunction tg = g.type.toTypeFunction(); size_t nfparams = Parameter.dim(tf.parameters); /* If both functions have a 'this' pointer, and the mods are not * the same and g's is not const, then this is less specialized. */ if (needThis() && g.needThis() && tf.mod != tg.mod) { if (isCtorDeclaration()) { if (!MODimplicitConv(tg.mod, tf.mod)) return MATCH.nomatch; } else { if (!MODimplicitConv(tf.mod, tg.mod)) return MATCH.nomatch; } } /* Create a dummy array of arguments out of the parameters to f() */ Expressions args = Expressions(nfparams); for (size_t u = 0; u < nfparams; u++) { Parameter p = Parameter.getNth(tf.parameters, u); Expression e; if (p.storageClass & (STC.ref_ | STC.out_)) { e = new IdentifierExp(Loc.initial, p.ident); e.type = p.type; } else e = p.type.defaultInitLiteral(Loc.initial); args[u] = e; } MATCH m = tg.callMatch(null, &args, 1); if (m > MATCH.nomatch) { /* A variadic parameter list is less specialized than a * non-variadic one. */ if (tf.varargs && !tg.varargs) goto L1; // less specialized static if (LOG_LEASTAS) { printf(" matches %d, so is least as specialized\n", m); } return m; } L1: static if (LOG_LEASTAS) { printf(" doesn't match, so is not as specialized\n"); } return MATCH.nomatch; } /******************************** * Labels are in a separate scope, one per function. */ final LabelDsymbol searchLabel(Identifier ident) { Dsymbol s; if (!labtab) labtab = new DsymbolTable(); // guess we need one s = labtab.lookup(ident); if (!s) { s = new LabelDsymbol(ident); labtab.insert(s); } return cast(LabelDsymbol)s; } /***************************************** * Determine lexical level difference from 'this' to nested function 'fd'. * Error if this cannot call fd. * Returns: * 0 same level * >0 decrease nesting by number * -1 increase nesting by 1 (fd is nested within 'this') * -2 error */ final int getLevel(const ref Loc loc, Scope* sc, FuncDeclaration fd) { int level; Dsymbol s; Dsymbol fdparent; //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars()); fdparent = fd.toParent2(); if (fdparent == this) return -1; s = this; level = 0; while (fd != s && fdparent != s.toParent2()) { //printf("\ts = %s, '%s'\n", s.kind(), s.toChars()); FuncDeclaration thisfd = s.isFuncDeclaration(); if (thisfd) { if (!thisfd.isNested() && !thisfd.vthis && !sc.intypeof) goto Lerr; } else { AggregateDeclaration thiscd = s.isAggregateDeclaration(); if (thiscd) { /* AggregateDeclaration::isNested returns true only when * it has a hidden pointer. * But, calling the function belongs unrelated lexical scope * is still allowed inside typeof. * * struct Map(alias fun) { * typeof({ return fun(); }) RetType; * // No member function makes Map struct 'not nested'. * } */ if (!thiscd.isNested() && !sc.intypeof) goto Lerr; } else goto Lerr; } s = s.toParent2(); assert(s); level++; } return level; Lerr: // Don't give error if in template constraint if (!(sc.flags & SCOPE.constraint)) { const(char)* xstatic = isStatic() ? "static " : ""; // better diagnostics for static functions .error(loc, "%s%s %s cannot access frame of function %s", xstatic, kind(), toPrettyChars(), fd.toPrettyChars()); return -2; } return 1; } override const(char)* toPrettyChars(bool QualifyTypes = false) { if (isMain()) return "D main"; else return Dsymbol.toPrettyChars(QualifyTypes); } /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ final const(char)* toFullSignature() { OutBuffer buf; functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars()); return buf.extractString(); } final bool isMain() const { return ident == Id.main && linkage != LINK.c && !isMember() && !isNested(); } final bool isCMain() const { 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 { return ident == Id.WinMain && linkage != LINK.c && !isMember(); } } final bool isDllMain() const { return ident == Id.DllMain && linkage != LINK.c && !isMember(); } final bool isRtInit() const { return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested(); } override final bool isExport() const { return protection.kind == Prot.Kind.export_; } override final bool isImportedSymbol() const { //printf("isImportedSymbol()\n"); //printf("protection = %d\n", protection); return (protection.kind == Prot.Kind.export_) && !fbody; } override final bool isCodeseg() const pure nothrow @nogc @safe { return true; // functions are always in the code segment } override final bool isOverloadable() { return true; // functions can be overloaded } /*********************************** * Override so it can work even if semantic() hasn't yet * been run. */ override final bool isAbstract() { if (storage_class & STC.abstract_) return true; if (semanticRun >= PASS.semanticdone) return false; if (_scope) { if (_scope.stc & STC.abstract_) return true; parent = _scope.parent; Dsymbol parent = toParent(); if (parent.isInterfaceDeclaration()) return true; } 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) { if (!fbody) return false; if (isVirtualMethod()) return false; // since they may be overridden if (sc.func && /********** this is for backwards compatibility for the moment ********/ (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated())) return true; if (isFuncLiteralDeclaration() || // externs are not possible with literals (storage_class & STC.inference) || // do attribute inference (inferRetType && !isCtorDeclaration())) return true; if (isInstantiated()) { auto ti = parent.isTemplateInstance(); if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident) return true; } return false; } /***************************************** * Initialize for inferring the attributes of this function. */ final void initInferAttributes() { //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars()); TypeFunction tf = type.toTypeFunction(); if (tf.purity == PURE.impure) // purity not specified flags |= FUNCFLAG.purityInprocess; if (tf.trust == TRUST.default_) flags |= FUNCFLAG.safetyInprocess; if (!tf.isnothrow) flags |= FUNCFLAG.nothrowInprocess; if (!tf.isnogc) flags |= FUNCFLAG.nogcInprocess; if (!isVirtual() || introducing) flags |= FUNCFLAG.returnInprocess; // Initialize for inferring STC.scope_ if (global.params.vsafe) flags |= FUNCFLAG.inferScope; } final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); TypeFunction tf = type.toTypeFunction(); if (flags & FUNCFLAG.purityInprocess) setImpure(); if (tf.purity == PURE.fwdref) tf.purityLevel(); PURE purity = tf.purity; if (purity > PURE.weak && isNested()) purity = PURE.weak; if (purity > PURE.weak && needThis()) { // The attribute of the 'this' reference affects purity strength if (type.mod & MODFlags.immutable_) { } else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_) purity = PURE.const_; else purity = PURE.weak; } tf.purity = purity; // ^ This rely on the current situation that every FuncDeclaration has a // unique TypeFunction. return purity; } final PURE isPureBypassingInference() { if (flags & FUNCFLAG.purityInprocess) return PURE.fwdref; else return isPure(); } /************************************** * The function is doing something impure, * so mark it as impure. * If there's a purity error, return true. */ final bool setImpure() { if (flags & FUNCFLAG.purityInprocess) { flags &= ~FUNCFLAG.purityInprocess; if (fes) fes.func.setImpure(); } else if (isPure()) return true; return false; } final bool isSafe() { if (flags & FUNCFLAG.safetyInprocess) setUnsafe(); return type.toTypeFunction().trust == TRUST.safe; } final bool isSafeBypassingInference() { return !(flags & FUNCFLAG.safetyInprocess) && isSafe(); } final bool isTrusted() { if (flags & FUNCFLAG.safetyInprocess) setUnsafe(); return type.toTypeFunction().trust == TRUST.trusted; } /************************************** * The function is doing something unsave, * so mark it as unsafe. * If there's a safe error, return true. */ final bool setUnsafe() { if (flags & FUNCFLAG.safetyInprocess) { flags &= ~FUNCFLAG.safetyInprocess; type.toTypeFunction().trust = TRUST.system; if (fes) fes.func.setUnsafe(); } else if (isSafe()) return true; return false; } final bool isNogc() { //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); if (flags & FUNCFLAG.nogcInprocess) setGC(); return type.toTypeFunction().isnogc; } final bool isNogcBypassingInference() { 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 */ final bool setGC() { //printf("setGC() %s\n", toChars()); if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope) { this.semantic2(_scope); this.semantic3(_scope); } if (flags & FUNCFLAG.nogcInprocess) { flags &= ~FUNCFLAG.nogcInprocess; type.toTypeFunction().isnogc = false; if (fes) fes.func.setGC(); } else if (isNogc()) return true; return false; } final void printGCUsage(const ref Loc loc, const(char)* warn) { if (!global.params.vgc) return; Module m = getModule(); if (m && m.isRoot() && !inUnittest()) { 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 */ final bool isReturnIsolated() { TypeFunction tf = type.toTypeFunction(); assert(tf.next); Type treti = tf.next; if (tf.isref) return isTypeIsolatedIndirect(treti); // check influence from parameters 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 */ final bool isTypeIsolated(Type t) { //printf("isTypeIsolated(t: %s)\n", t.toChars()); t = t.baseElemOf(); switch (t.ty) { case Tarray: case Tpointer: return isTypeIsolatedIndirect(t.nextOf()); // go down one level case Taarray: case Tclass: return isTypeIsolatedIndirect(t); case Tstruct: /* Drill down and check the struct's fields */ auto sym = t.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { Type tmi = v.type.addMod(t.mod); //printf("\tt = %s, tmi = %s\n", t.toChars(), tmi.toChars()); if (!isTypeIsolated(tmi)) return false; } return true; default: 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()); 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. */ if (!isPureBypassingInference() || isNested()) return false; TypeFunction tf = type.toTypeFunction(); //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars()); size_t dim = Parameter.dim(tf.parameters); for (size_t i = 0; i < dim; i++) { Parameter fparam = Parameter.getNth(tf.parameters, i); Type tp = fparam.type; if (!tp) continue; if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_)) { if (!traverseIndirections(tp, t)) 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) { tp = tp.baseElemOf(); switch (tp.ty) { case Tarray: case Tpointer: return traverseIndirections(tp.nextOf(), t); case Taarray: case Tclass: return traverseIndirections(tp, t); case Tstruct: /* Drill down and check the struct's fields */ auto sym = tp.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { Type tprmi = v.type.addMod(tp.mod); //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars()); if (!traverse(tprmi, t)) return false; } return true; default: return true; } } if (!traverse(tp, t)) return false; } // The 'this' reference is a parameter, too if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis()) { Type tthis = ad.getType().addMod(tf.mod); //printf("\ttthis = %s\n", tthis.toChars()); if (!traverseIndirections(tthis, t)) return false; } return true; } /**************************************** * Determine if function needs a static frame pointer. * Returns: * `true` if function is really nested within other function. * Contracts: * If isNested() returns true, isThis() should return false. */ bool isNested() const { auto f = toAliasFunc(); //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars()); return ((f.storage_class & STC.static_) == 0) && (f.linkage == LINK.d) && (f.toParent2().isFuncDeclaration() !is null); } /**************************************** * Determine if function is a non-static member function * that has an implicit 'this' expression. * Returns: * The aggregate it is a member of, or null. * Contracts: * If isThis() returns true, isNested() should return false. */ override inout(AggregateDeclaration) isThis() inout { //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); auto ad = (storage_class & STC.static_) ? objc.isThis(this) : isMember2(); //printf("-FuncDeclaration::isThis() %p\n", ad); return ad; } override final bool needThis() { //printf("FuncDeclaration::needThis() '%s'\n", toChars()); return toAliasFunc().isThis() !is null; } // Determine if a function is pedantically virtual final bool isVirtualMethod() { if (toAliasFunc() != this) return toAliasFunc().isVirtualMethod(); //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); if (!isVirtual()) return false; // If it's a final method, and does not override anything, then it is not virtual if (isFinalFunc() && foverrides.dim == 0) { return false; } return true; } // Determine if function goes into virtual function pointer table bool isVirtual() const { if (toAliasFunc() != this) return toAliasFunc().isVirtual(); auto p = toParent(); 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())); } return isMember() && !(isStatic() || protection.kind == Prot.Kind.private_ || protection.kind == Prot.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()); } final bool isFinalFunc() const { if (toAliasFunc() != this) 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()); }} if (!isMember()) return false; if (Declaration.isFinal()) return true; auto cd = toParent().isClassDeclaration(); return (cd !is null) && (cd.storage_class & STC.final_); } bool addPreInvariant() { auto ad = isThis(); ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); } bool addPostInvariant() { auto ad = isThis(); ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); } override const(char)* kind() const { return generated ? "generated function" : "function"; } /******************************************** * If there are no overloads of function f, return that function, * otherwise return NULL. */ final FuncDeclaration isUnique() { FuncDeclaration result = null; overloadApply(this, (Dsymbol s) { auto f = s.isFuncDeclaration(); if (!f) return 0; if (result) { result = null; return 1; // ambiguous, done } else { result = f; return 0; } }); 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()); if (auto fld = this.isFuncLiteralDeclaration()) { if (fld.tok == TOK.reserved) { fld.tok = TOK.function_; fld.vthis = null; } } if (!parent || parent == sc.parent) return false; if (ident == Id.require || ident == Id.ensure) return false; if (!isThis() && !isNested()) return false; // The current function FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); if (!fdthis) return false; // out of function scope Dsymbol p = toParent2(); // Function literals from fdthis to p must be delegates ensureStaticLinkTo(fdthis, p); if (isNested()) { // The function that this function is in FuncDeclaration fdv = p.isFuncDeclaration(); if (!fdv) return false; if (fdv == fdthis) return false; //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars()); //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars()); //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars()); // Add this function to the list of those which called us if (fdthis != this) { bool found = false; for (size_t i = 0; i < siblingCallers.dim; ++i) { if (siblingCallers[i] == fdthis) found = true; } if (!found) { //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); if (!sc.intypeof && !(sc.flags & SCOPE.compile)) siblingCallers.push(fdthis); } } int lv = fdthis.getLevel(loc, sc, fdv); if (lv == -2) return true; // error if (lv == -1) return false; // downlevel call if (lv == 0) return false; // same level call // Uplevel call } return false; } /******************************* * 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()); if (requiresClosure) goto Lyes; for (size_t i = 0; i < closureVars.dim; i++) { VarDeclaration v = closureVars[i]; //printf("\tv = %s\n", v.toChars()); for (size_t j = 0; j < v.nestedrefs.dim; j++) { FuncDeclaration f = v.nestedrefs[j]; assert(f != this); //printf("\t\tf = %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. */ for (Dsymbol s = f; s && s != this; s = s.parent) { FuncDeclaration fx = s.isFuncDeclaration(); if (!fx) continue; if (fx.isThis() || fx.tookAddressOf) { //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf); /* Mark as needing closure any functions between this and f */ markAsNeedingClosure((fx == f) ? fx.parent : fx, this); requiresClosure = true; } /* We also need to check if any sibling functions that * called us, have escaped. This is recursive: we need * to check the callers of our siblings. */ if (checkEscapingSiblings(fx, this)) requiresClosure = true; /* 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. */ } } } if (requiresClosure) goto Lyes; return false; Lyes: //printf("\tneeds closure\n"); return true; } /*********************************************** * Check that the function contains any closure. * If it's @nogc, report suitable errors. * This is mostly consistent with FuncDeclaration::needsClosure(). * * Returns: * true if any errors occur. */ extern (D) final bool checkClosure() { if (!needsClosure()) return false; if (setGC()) { error("is `@nogc` yet allocates closures with the GC"); if (global.gag) // need not report supplemental errors return true; } else { printGCUsage(loc, "using closure causes GC allocation"); return false; } FuncDeclarations a; foreach (v; closureVars) { foreach (f; v.nestedrefs) { assert(f !is this); LcheckAncestorsOfANestedRef: for (Dsymbol s = f; s && s !is this; s = s.parent) { auto fx = s.isFuncDeclaration(); if (!fx) continue; if (fx.isThis() || fx.tookAddressOf || checkEscapingSiblings(fx, this)) { foreach (f2; a) { if (f2 == f) break LcheckAncestorsOfANestedRef; } a.push(f); .errorSupplemental(f.loc, "%s closes over variable %s at %s", f.toPrettyChars(), v.toChars(), v.loc.toChars()); break LcheckAncestorsOfANestedRef; } } } } return true; } /*********************************************** * Determine if function's variables are referenced by a function * nested within it. */ final bool hasNestedFrameRefs() { if (closureVars.dim) return true; /* If a virtual function has contracts, assume its variables are referenced * by those contracts, even if they aren't. Because they might be referenced * by the overridden or overriding function's contracts. * This can happen because frequire and fensure are implemented as nested functions, * and they can be called directly by an overriding function and the overriding function's * context had better match, or * https://issues.dlang.org/show_bug.cgi?id=7335 will bite. */ if (fdrequire || fdensure) return true; if (foverrides.dim && isVirtualMethod()) { for (size_t i = 0; i < foverrides.dim; i++) { FuncDeclaration fdv = foverrides[i]; if (fdv.hasNestedFrameRefs()) return true; } } return false; } /**************************************************** * 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() { auto f = cast(TypeFunction)type; return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid; } /**************************************************** * Declare result variable lazily. */ final void buildResultVar(Scope* sc, Type tret) { if (!vresult) { Loc loc = fensure ? fensure.loc : this.loc; /* If inferRetType is true, tret may not be a correct return type yet. * So, in here it may be a temporary type for vresult, and after * fbody.dsymbolSemantic() running, vresult.type might be modified. */ vresult = new VarDeclaration(loc, tret, Id.result, null); vresult.storage_class |= STC.nodtor | STC.temp; if (!isVirtual()) vresult.storage_class |= STC.const_; vresult.storage_class |= STC.result; // set before the semantic() for checkNestedReference() vresult.parent = this; } if (sc && vresult.semanticRun == PASS.init) { TypeFunction tf = type.toTypeFunction(); if (tf.isref) vresult.storage_class |= STC.ref_; vresult.type = tret; vresult.dsymbolSemantic(sc); if (!sc.insert(vresult)) error("out result %s is already defined", vresult.toChars()); assert(vresult.parent == this); } } /**************************************************** * Merge into this function the 'in' contracts of all it overrides. * 'in's are OR'd together, i.e. only one of them needs to pass. */ final Statement mergeFrequire(Statement sf) { /* If a base function and its override both have an IN contract, then * only one of them needs to succeed. This is done by generating: * * void derived.in() { * try { * base.in(); * } * catch () { * ... body of derived.in() ... * } * } * * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid. * If base.in() throws, then derived.in()'s body is executed. */ /* Implementing this is done by having the overriding function call * nested functions (the fdrequire functions) nested inside the overridden * function. This requires that the stack layout of the calling function's * parameters and 'this' pointer be in the same place (as the nested * function refers to them). * This is easy for the parameters, as they are all on the stack in the same * place by definition, since it's an overriding function. The problem is * getting the 'this' pointer in the same place, since it is a local variable. * We did some hacks in the code generator to make this happen: * 1. always generate exception handler frame, or at least leave space for it * in the frame (Windows 32 SEH only) * 2. always generate an EBP style frame * 3. since 'this' is passed in a register that is subsequently copied into * a stack local, allocate that local immediately following the exception * handler block, so it is always at the same offset from EBP. */ 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 */ if (fdv.frequires && fdv.semanticRun != PASS.semantic3done) { assert(fdv._scope); Scope* sc = fdv._scope.push(); sc.stc &= ~STC.override_; fdv.semantic3(sc); sc.pop(); } sf = fdv.mergeFrequire(sf); if (sf && fdv.fdrequire) { //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); /* Make the call: * try { __require(); } * catch (Throwable) { frequire; } */ Expression eresult = null; Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), eresult); Statement s2 = new ExpStatement(loc, e); auto c = new Catch(loc, getThrowable(), null, sf); c.internalCatch = true; auto catches = new Catches(); catches.push(c); sf = new TryCatchStatement(loc, s2, catches); } else return null; } 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) { if (fd.fensures) return true; foreach (fdv; fd.foverrides) { if (needsFensure(fdv)) return true; } return false; } /**************************************************** * Rewrite contracts as statements. */ final void buildEnsureRequire() { if (frequires) { /* in { statements1... } * in { statements2... } * ... * becomes: * in { { statements1... } { statements2... } ... } */ assert(frequires.dim); auto loc = (*frequires)[0].loc; auto s = new Statements; foreach (r; *frequires) { s.push(new ScopeStatement(r.loc, r, r.loc)); } frequire = new CompoundStatement(loc, s); } if (fensures) { /* out(id1) { statements1... } * out(id2) { statements2... } * ... * becomes: * out(__result) { { ref id1 = __result; { statements1... } } * { ref id2 = __result; { statements2... } } ... } */ assert(fensures.dim); auto loc = (*fensures)[0].ensure.loc; auto s = new Statements; foreach (r; *fensures) { if (r.id && canBuildResultVar()) { auto rloc = r.ensure.loc; auto resultId = new IdentifierExp(rloc, Id.result); auto init = new ExpInitializer(rloc, resultId); auto stc = STC.ref_ | STC.temp | STC.result; auto decl = new VarDeclaration(rloc, null, r.id, init, stc); auto sdecl = new ExpStatement(rloc, decl); s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc)); } else { s.push(r.ensure); } } fensure = new CompoundStatement(loc, s); } if (!isVirtual()) return; /* Rewrite contracts as nested functions, then call them. Doing it as nested * functions means that overriding functions can call them. */ TypeFunction f = cast(TypeFunction) type; if (frequire) { /* in { ... } * becomes: * void __require() { ... } * __require(); */ Loc loc = frequire.loc; auto tf = new TypeFunction(null, Type.tvoid, 0, LINK.d); tf.isnothrow = f.isnothrow; tf.isnogc = f.isnogc; tf.purity = f.purity; tf.trust = f.trust; auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf); fd.fbody = frequire; Statement s1 = new ExpStatement(loc, fd); Expression e = new CallExp(loc, new VarExp(loc, fd, false), cast(Expressions*)null); Statement s2 = new ExpStatement(loc, e); frequire = new CompoundStatement(loc, s1, s2); fdrequire = fd; } if (fensure) { /* out (result) { ... } * becomes: * void __ensure(ref tret result) { ... } * __ensure(result); */ Loc loc = fensure.loc; auto fparams = new Parameters(); Parameter p = null; if (canBuildResultVar()) { p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null); fparams.push(p); } auto tf = new TypeFunction(fparams, Type.tvoid, 0, LINK.d); tf.isnothrow = f.isnothrow; tf.isnogc = f.isnogc; tf.purity = f.purity; tf.trust = f.trust; auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf); fd.fbody = fensure; Statement s1 = new ExpStatement(loc, fd); Expression eresult = null; if (canBuildResultVar()) eresult = new IdentifierExp(loc, Id.result); Expression e = new CallExp(loc, new VarExp(loc, fd, false), eresult); Statement s2 = new ExpStatement(loc, e); fensure = new CompoundStatement(loc, s1, s2); 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. */ final Statement mergeFensure(Statement sf, Identifier oid) { /* Same comments as for mergeFrequire(), except that we take care * of generating a consistent reference to the 'result' local by * explicitly passing 'result' to the nested function as a reference * argument. * This won't work for the 'this' parameter as it would require changing * the semantic code for the nested function so that it looks on the parameter * list for the 'this' pointer, something that would need an unknown amount * of tweaking of various parts of the compiler that I'd rather leave alone. */ 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 */ if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done) { assert(fdv._scope); Scope* sc = fdv._scope.push(); sc.stc &= ~STC.override_; fdv.semantic3(sc); sc.pop(); } sf = fdv.mergeFensure(sf, oid); if (fdv.fdensure) { //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); // Make the call: __ensure(result) Expression eresult = null; if (canBuildResultVar()) { eresult = new IdentifierExp(loc, oid); Type t1 = fdv.type.nextOf().toBasetype(); Type t2 = this.type.nextOf().toBasetype(); if (t1.isBaseOf(t2, null)) { /* Making temporary reference variable is necessary * in covariant return. * https://issues.dlang.org/show_bug.cgi?id=5204 * https://issues.dlang.org/show_bug.cgi?id=10479 */ auto ei = new ExpInitializer(Loc.initial, eresult); auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei); v.storage_class |= STC.temp; auto de = new DeclarationExp(Loc.initial, v); auto ve = new VarExp(Loc.initial, v); eresult = new CommaExp(Loc.initial, de, ve); } } Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), eresult); Statement s2 = new ExpStatement(loc, e); if (sf) { sf = new CompoundStatement(sf.loc, s2, sf); } else sf = s2; } } return sf; } /********************************************* * Return the function's parameter list, and whether * it is variadic or not. */ final Parameters* getParameters(int* pvarargs) { Parameters* fparameters = null; int fvarargs = 0; if (type) { TypeFunction fdtype = type.toTypeFunction(); fparameters = fdtype.parameters; fvarargs = fdtype.varargs; } if (pvarargs) *pvarargs = fvarargs; return fparameters; } /********************************** * Generate a FuncDeclaration for a runtime library function. */ static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) { return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc); } static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) { FuncDeclaration fd; TypeFunction tf; Dsymbol s; __gshared DsymbolTable st = null; //printf("genCfunc(name = '%s')\n", id.toChars()); //printf("treturn\n\t"); treturn.print(); // See if already in table if (!st) st = new DsymbolTable(); s = st.lookup(id); if (s) { fd = s.isFuncDeclaration(); assert(fd); assert(fd.type.nextOf().equals(treturn)); } else { tf = new TypeFunction(fparams, treturn, 0, LINK.c, stc); fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf); fd.protection = Prot(Prot.Kind.public_); fd.linkage = LINK.c; st.insert(fd); } return fd; } /****************** * Check parameters and return type of D main() function. * Issue error messages. */ extern (D) final void checkDmain() { TypeFunction tf = type.toTypeFunction(); const nparams = Parameter.dim(tf.parameters); bool argerr; if (nparams == 1) { auto fparam0 = Parameter.getNth(tf.parameters, 0); auto t = fparam0.type.toBasetype(); if (t.ty != Tarray || t.nextOf().ty != Tarray || t.nextOf().nextOf().ty != Tchar || fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_)) { argerr = true; } } if (!tf.nextOf()) error("must return `int` or `void`"); else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid) error("must return `int` or `void`, not `%s`", tf.nextOf().toChars()); else if (tf.varargs || nparams >= 2 || argerr) error("parameters must be `main()` or `main(string[] args)`"); } override final inout(FuncDeclaration) isFuncDeclaration() inout { return this; } inout(FuncDeclaration) toAliasFunc() inout { return this; } override void accept(Visitor v) { 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(const ref Loc loc, Scope* sc, AggregateDeclaration ad, VarDeclaration vthis) { Expression e = null; // Call invariant directly only if it exists FuncDeclaration inv = ad.inv; ClassDeclaration cd = ad.isClassDeclaration(); while (!inv && cd) { cd = cd.baseClass; if (!cd) break; inv = cd.inv; } if (inv) { version (all) { // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 // For the correct mangling, // run attribute inference on inv if needed. 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. */ e = new ThisExp(Loc.initial); e.type = vthis.type; e = new DotVarExp(Loc.initial, e, inv, false); e.type = inv.type; e = new CallExp(Loc.initial, e); e.type = Type.tvoid; } 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 = the initial scope from the calling context * * Returns: * ==0 continue * !=0 done */ extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null) { Dsymbol next; for (Dsymbol d = fstart; d; d = next) { import dmd.access : checkSymbolAccess; if (auto od = d.isOverDeclaration()) { 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. */ if (sc) { if (checkSymbolAccess(sc, od)) { if (int r = overloadApply(od.aliassym, dg, sc)) return r; } } else if (int r = overloadApply(od.aliassym, dg, sc)) return r; } else { if (int r = dg(od.aliassym)) return r; } next = od.overnext; } else if (auto fa = d.isFuncAliasDeclaration()) { if (fa.hasOverloads) { if (int r = overloadApply(fa.funcalias, dg, sc)) return r; } else if (auto fd = fa.toAliasFunc()) { if (int r = dg(fd)) return r; } else { d.error("is aliased to a function"); break; } next = fa.overnext; } else if (auto ad = d.isAliasDeclaration()) { if (sc) { if (checkSymbolAccess(sc, ad)) next = ad.toAlias(); } else next = ad.toAlias(); if (next == ad) break; if (next == fstart) break; } else if (auto td = d.isTemplateDeclaration()) { if (int r = dg(td)) return r; next = td.overnext; } else if (auto fd = d.isFuncDeclaration()) { if (int r = dg(fd)) return r; next = fd.overnext; } else { d.error("is aliased to a function"); break; // BUG: should print error message? } } 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; } Mismatches mismatches; bool bothMutable = ((lhsMod & rhsMod) == 0); bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0; bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_); if (lhsMod & MODFlags.shared_) buf.writestring("`shared` "); else if (sharedMismatch && !(lhsMod & MODFlags.immutable_)) { buf.writestring("non-shared "); mismatches.isNotShared = true; } if (bothMutable && sharedMismatchOnly) { } else if (lhsMod & MODFlags.immutable_) buf.writestring("`immutable` "); else if (lhsMod & MODFlags.const_) buf.writestring("`const` "); else if (lhsMod & MODFlags.wild) buf.writestring("`inout` "); else { buf.writestring("mutable "); mismatches.isMutable = true; } return mismatches; } /// unittest { OutBuffer buf; auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0); assert(buf.peekSlice == "`shared` "); assert(!mismatches.isNotShared); buf.reset; mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_); assert(buf.peekSlice == "non-shared "); assert(mismatches.isNotShared); buf.reset; mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0); assert(buf.peekSlice == "`const` "); assert(!mismatches.isMutable); buf.reset; mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_); assert(buf.peekSlice == "mutable "); assert(mismatches.isMutable); } private const(char)* prependSpace(const(char)* str) { if (!str || !*str) return ""; return (" " ~ str[0 .. strlen(str)] ~ "\0").ptr; } /******************************************* * 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 = 1: do not issue error message on no match, just return NULL * 2: overloadResolve only * 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, int flags = 0) { if (!s) 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(); } } } if (tiargs && arrayObjectIsError(tiargs) || fargs && arrayObjectIsError(cast(Objects*)fargs)) { return null; } Match m; m.last = MATCH.nomatch; functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, null); auto orig_s = s; if (m.last > MATCH.nomatch && m.lastf) { if (m.count == 1) // exactly one match { if (!(flags & 1)) m.lastf.functionSemantic(); return m.lastf; } if ((flags & 2) && !tthis && m.lastf.needThis()) { return m.lastf; } } /* Failed to find a best match. * Do nothing or print error. */ if (m.last <= MATCH.nomatch) { // error was caused on matched function if (m.count == 1) return m.lastf; // if do not print error messages if (flags & 1) return null; // no match } auto fd = s.isFuncDeclaration(); auto od = s.isOverDeclaration(); auto td = s.isTemplateDeclaration(); if (td && td.funcroot) s = fd = td.funcroot; OutBuffer tiargsBuf; arrayObjectsToBuffer(&tiargsBuf, tiargs); OutBuffer fargsBuf; fargsBuf.writeByte('('); argExpTypesToCBuffer(&fargsBuf, fargs); fargsBuf.writeByte(')'); if (tthis) tthis.modToBuffer(&fargsBuf); // max num of overloads to print (-v overrides this). enum int numOverloadsDisplay = 5; if (!m.lastf && !(flags & 1)) // no match { if (td && !fd) // all of overloads are templates { .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`, candidates are:", td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekString(), fargsBuf.peekString()); printCandidates(loc, td); } else if (od) { .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`", od.ident.toChars(), tiargsBuf.peekString(), fargsBuf.peekString()); } else { assert(fd); if (fd.checkDisabled(loc, sc)) return null; bool hasOverloads = fd.overnext !is null; auto tf = fd.type.toTypeFunction(); if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); if (hasOverloads) { .error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:", fd.ident.toChars(), thisBuf.peekString()); } else { auto fullFdPretty = fd.toPrettyChars(); .error(loc, "%smethod `%s` is not callable using a %sobject", funcBuf.peekString(), fullFdPretty, thisBuf.peekString()); if (mismatches.isNotShared) .errorSupplemental(loc, "Consider adding `shared` to %s", fullFdPretty); else if (mismatches.isMutable) .errorSupplemental(loc, "Consider adding `const` or `inout` to %s", fullFdPretty); } } else { //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco); if (hasOverloads) { .error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:", fd.toChars(), fargsBuf.peekString()); } else { .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs), tf.modToChars(), fargsBuf.peekString()); // re-resolve to check for supplemental message const(char)* failMessage; functionResolve(&m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); if (failMessage) errorSupplemental(loc, failMessage); } } if (hasOverloads) printCandidates(loc, fd); } } else if (m.nextf) { TypeFunction tf1 = m.lastf.type.toTypeFunction(); TypeFunction tf2 = m.nextf.type.toTypeFunction(); const(char)* lastprms = parametersTypeToChars(tf1.parameters, tf1.varargs); const(char)* nextprms = parametersTypeToChars(tf2.parameters, tf2.varargs); const(char)* mod1 = prependSpace(MODtoChars(tf1.mod)); const(char)* mod2 = prependSpace(MODtoChars(tf2.mod)); .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.peekString(), m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1, m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2); } return null; } /******************************************* * Prints template and function overload candidates as supplemental errors. * Params: * loc = instantiation location * declaration = the declaration to print overload candidates for */ private void printCandidates(Decl)(const ref Loc loc, Decl declaration) if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) { // max num of overloads to print (-v overrides this). int numToDisplay = 5; overloadApply(declaration, (Dsymbol s) { Dsymbol nextOverload; if (auto fd = s.isFuncDeclaration()) { if (fd.errors || fd.type.ty == Terror) return 0; auto tf = cast(TypeFunction) fd.type; .errorSupplemental(fd.loc, "`%s%s`", fd.toPrettyChars(), parametersTypeToChars(tf.parameters, tf.varargs)); nextOverload = fd.overnext; } else if (auto td = s.isTemplateDeclaration()) { .errorSupplemental(td.loc, "`%s`", td.toPrettyChars()); nextOverload = td.overnext; } if (global.params.verbose || --numToDisplay != 0) return 0; // Too many overloads to sensibly display. // Just show count of remaining overloads. int num = 0; overloadApply(nextOverload, (s) { ++num; return 0; }); if (num > 0) .errorSupplemental(loc, "... (%d more, -v to show) ...", num); return 1; // stop iterating }); } /************************************** * Returns an indirect type one step from t. */ Type getIndirection(Type t) { t = t.baseElemOf(); if (t.ty == Tarray || t.ty == Tpointer) return t.nextOf().toBasetype(); if (t.ty == Taarray || t.ty == Tclass) return t; if (t.ty == Tstruct) return t.hasPointers() ? t : null; // TODO // should consider TypeDelegate? return null; } /************************************** * 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()); ta = ta.baseElemOf(); 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) { 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 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)); } if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb)) { //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); return false; } if (ta.nextOf() && ta.nextOf() == tb.nextOf()) { //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); return true; } if (tb.ty == Tclass || tb.ty == Tstruct) { for (Ctxt* c = ctxt; c; c = c.prev) if (tb == c.type) return true; Ctxt c; c.prev = ctxt; c.type = tb; /* Traverse the type of each field of the aggregate */ AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); foreach (v; sym.fields) { Type tprmi = v.type.addMod(tb.mod); //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars()); if (!traverse(ta, tprmi, &c, reversePass)) return false; } } else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) { Type tind = tb.nextOf(); if (!traverse(ta, tind, ctxt, reversePass)) return false; } else if (tb.hasPointers()) { // BUG: consider the context pointer of delegate types return false; } // Still no match, so try breaking up ta if we have not done so yet. if (!reversePass) return traverse(tb, ta, ctxt, true); 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. const result = traverse(ta, tb, null, false); //printf(" returns %d\n", result); return result; } /* For all functions between outerFunc and f, mark them as needing * a closure. */ private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc) { for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.parent) { FuncDeclaration fy = sx.isFuncDeclaration(); if (fy && fy.closureVars.dim) { /* fy needs a closure if it has closureVars[], * because the frame pointer in the closure will be accessed. */ fy.requiresClosure = true; } } } /******** * Given a nested function f inside a function outerFunc, check * if any sibling callers of f have escaped. If so, mark * all the enclosing functions as needing closures. * 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; } PrevSibling ps; ps.p = cast(PrevSibling*)p; ps.f = f; //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars()); bool bAnyClosures = false; for (size_t i = 0; i < f.siblingCallers.dim; ++i) { FuncDeclaration g = f.siblingCallers[i]; if (g.isThis() || g.tookAddressOf) { markAsNeedingClosure(g, outerFunc); bAnyClosures = true; } PrevSibling* prev = cast(PrevSibling*)p; while (1) { if (!prev) { bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps); break; } if (prev.f == g) break; prev = prev.p; } } //printf("\t%d\n", bAnyClosures); return bAnyClosures; } /*********************************************************** * 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; extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true) { super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type); assert(funcalias != this); this.funcalias = funcalias; this.hasOverloads = hasOverloads; if (hasOverloads) { if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration()) this.hasOverloads = fad.hasOverloads; } else { // for internal use assert(!funcalias.isFuncAliasDeclaration()); this.hasOverloads = false; } userAttribDecl = funcalias.userAttribDecl; } override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return this; } override const(char)* kind() const { return "function alias"; } override inout(FuncDeclaration) toAliasFunc() inout { return funcalias.toAliasFunc(); } override void accept(Visitor v) { 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; extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) { super(loc, endloc, null, STC.undefined_, type); this.ident = id ? id : Id.empty; this.tok = tok; this.fes = fes; //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars()); } override Dsymbol syntaxCopy(Dsymbol s) { //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); assert(!s); auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); f.treq = treq; // don't need to copy return FuncDeclaration.syntaxCopy(f); } override bool isNested() const { //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); return (tok != TOK.function_) && !isThis(); } override inout(AggregateDeclaration) isThis() inout { return tok == TOK.delegate_ ? super.isThis() : null; } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return false; } /******************************* * Modify all expression type of return statements to tret. * * On function literals, return type may be modified based on the context type * after its semantic3 is done, in FuncExp::implicitCastTo. * * A function() dg = (){ return new B(); } // OK if is(B : A) == true * * If B to A conversion is convariant that requires offseet adjusting, * all return statements should be adjusted to return expressions typed A. */ void 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) { Expression exp = s.exp; if (exp && !exp.type.equals(tret)) { s.exp = exp.castTo(sc, tret); } } } if (semanticRun < PASS.semantic3done) return; if (fes) return; scope RetWalker w = new RetWalker(); w.sc = sc; w.tret = tret; w.fld = this; fbody.accept(w); // Also update the inferred function type to match the new return type. // This is required so the code generator does not try to cast the // modified returns back to the original type. if (inferRetType && type.nextOf() != tret) type.toTypeFunction().next = tret; } override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return this; } override const(char)* kind() const { // GCC requires the (char*) casts return (tok != TOK.function_) ? "delegate" : "function"; } override const(char)* toPrettyChars(bool QualifyTypes = false) { if (parent) { TemplateInstance ti = parent.isTemplateInstance(); if (ti) return ti.tempdecl.toPrettyChars(QualifyTypes); } return Dsymbol.toPrettyChars(QualifyTypes); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CtorDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type) { super(loc, endloc, Id.ctor, stc, type); //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy()); return FuncDeclaration.syntaxCopy(f); } override const(char)* kind() const { return "constructor"; } override const(char)* toChars() const { return "this"; } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return (isThis() && vthis && global.params.useInvariants); } override inout(CtorDeclaration) isCtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PostBlitDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) { super(loc, endloc, id, stc, null); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident); return FuncDeclaration.syntaxCopy(dd); } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return (isThis() && vthis && global.params.useInvariants); } override bool overloadInsert(Dsymbol s) { return false; // cannot overload postblits } override inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DtorDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc) { super(loc, endloc, Id.dtor, STC.undefined_, null); } extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) { super(loc, endloc, id, stc, null); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto dd = new DtorDeclaration(loc, endloc, storage_class, ident); return FuncDeclaration.syntaxCopy(dd); } override const(char)* kind() const { return "destructor"; } override const(char)* toChars() const { 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 return vtblIndex != -1; } override bool addPreInvariant() { return (isThis() && vthis && global.params.useInvariants); } override bool addPostInvariant() { return false; } override bool overloadInsert(Dsymbol s) { return false; // cannot overload destructors } override inout(DtorDeclaration) isDtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class StaticCtorDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null); } extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) { super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto scd = new StaticCtorDeclaration(loc, endloc, storage_class); return FuncDeclaration.syntaxCopy(scd); } override final inout(AggregateDeclaration) isThis() inout { return null; } override final bool isVirtual() const { return false; } override final bool addPreInvariant() { return false; } override final bool addPostInvariant() { return false; } override final bool hasStaticCtorOrDtor() { return true; } override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, "_sharedStaticCtor", stc); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class); return FuncDeclaration.syntaxCopy(scd); } override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class StaticDtorDeclaration : FuncDeclaration { VarDeclaration vgate; // 'gate' variable extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null); } extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) { super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class); return FuncDeclaration.syntaxCopy(sdd); } override final inout(AggregateDeclaration) isThis() inout { return null; } override final bool isVirtual() const { return false; } override final bool hasStaticCtorOrDtor() { return true; } override final bool addPreInvariant() { return false; } override final bool addPostInvariant() { return false; } override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, "_sharedStaticDtor", stc); } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class); return FuncDeclaration.syntaxCopy(sdd); } override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class InvariantDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) { super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); this.fbody = fbody; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null); return FuncDeclaration.syntaxCopy(id); } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return false; } override inout(InvariantDeclaration) isInvariantDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class UnitTestDeclaration : FuncDeclaration { char* codedoc; // for documented unittest // toObjFile() these nested functions after this one FuncDeclarations deferredNested; extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc) { super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null); this.codedoc = codedoc; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); return FuncDeclaration.syntaxCopy(utd); } override inout(AggregateDeclaration) isThis() inout { return null; } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return false; } override inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class NewDeclaration : FuncDeclaration { Parameters* parameters; int varargs; extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Parameters* fparams, int varargs) { super(loc, endloc, Id.classNew, STC.static_ | stc, null); this.parameters = fparams; this.varargs = varargs; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto f = new NewDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters), varargs); return FuncDeclaration.syntaxCopy(f); } override const(char)* kind() const { return "allocator"; } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return false; } override inout(NewDeclaration) isNewDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DeleteDeclaration : FuncDeclaration { Parameters* parameters; extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Parameters* fparams) { super(loc, endloc, Id.classDelete, STC.static_ | stc, null); this.parameters = fparams; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); auto f = new DeleteDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters)); return FuncDeclaration.syntaxCopy(f); } override const(char)* kind() const { return "deallocator"; } override bool isDelete() { return true; } override bool isVirtual() const { return false; } override bool addPreInvariant() { return false; } override bool addPostInvariant() { return false; } override inout(DeleteDeclaration) isDeleteDeclaration() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/globals.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/globals.d, _globals.d) * Documentation: https://dlang.org/phobos/dmd_globals.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/globals.d */ module dmd.globals; import core.stdc.stdint; import dmd.root.array; import dmd.root.filename; import dmd.root.outbuffer; import dmd.identifier; template xversion(string s) { enum xversion = mixin(`{ version (` ~ s ~ `) return true; else return false; }`)(); } enum TARGET : bool { Linux = xversion!`linux`, OSX = xversion!`OSX`, FreeBSD = xversion!`FreeBSD`, OpenBSD = xversion!`OpenBSD`, Solaris = xversion!`Solaris`, Windows = xversion!`Windows`, DragonFlyBSD = xversion!`DragonFlyBSD`, } enum Diagnostic : ubyte { error, // generate an error inform, // generate a warning off, // disable diagnostic } enum CHECKENABLE : ubyte { _default, // initial value off, // never do checking on, // always do checking safeonly, // do checking only in @safe functions } enum CHECKACTION : ubyte { D, // call D assert on failure C, // call C assert on failure halt, // cause program halt on failure } enum CPU { x87, mmx, sse, sse2, sse3, ssse3, sse4_1, sse4_2, avx, // AVX1 instruction set avx2, // AVX2 instruction set avx512, // AVX-512 instruction set // Special values that don't survive past the command line processing baseline, // (default) the minimum capability CPU native // the machine the compiler is being run on } /** Each flag represents a field that can be included in the JSON output. NOTE: set type to uint so its size matches C++ unsigned type */ enum JsonFieldFlags : uint { none = 0, compilerInfo = (1 << 0), buildInfo = (1 << 1), modules = (1 << 2), semantics = (1 << 3), } // Put command line switches in here struct Param { bool obj = true; // write object file bool link = true; // perform link bool dll; // generate shared dynamic library bool lib; // write library file instead of object file(s) bool multiobj; // break one object file into multiple ones bool oneobj; // write one object file instead of multiple ones bool trace; // insert profiling hooks bool tracegc; // instrument calls to 'new' bool verbose; // verbose compile bool vcg_ast; // write-out codegen-ast bool showColumns; // print character (column) numbers in diagnostics bool vtls; // identify thread local variables bool vgc; // identify gc usage bool vfield; // identify non-mutable field variables bool vcomplex; // identify complex/imaginary type usage ubyte symdebug; // insert debug symbolic information bool symdebugref; // insert debug information for all referenced types, too bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer bool map; // generate linker .map file bool is64bit = (size_t.sizeof == 8); // generate 64 bit code; true by default for 64 bit dmd bool isLP64; // generate code for LP64 bool isLinux; // generate code for linux bool isOSX; // generate code for Mac OSX bool isWindows; // generate code for Windows bool isFreeBSD; // generate code for FreeBSD bool isOpenBSD; // generate code for OpenBSD bool isDragonFlyBSD; // generate code for DragonFlyBSD bool isSolaris; // generate code for Solaris bool hasObjectiveC; // target supports Objective-C bool mscoff = false; // for Win32: write MsCoff object files instead of OMF Diagnostic useDeprecated = Diagnostic.inform; // how use of deprecated features are handled bool useInvariants = true; // generate class invariant checks bool useIn = true; // generate precondition checks bool useOut = true; // generate postcondition checks bool stackstomp; // add stack stomping code bool useUnitTests; // generate unittest code bool useInline = false; // inline expand functions bool useDIP25; // implement http://wiki.dlang.org/DIP25 bool release; // build release version bool preservePaths; // true means don't strip path from source file Diagnostic warnings = Diagnostic.off; // how compiler warnings are handled bool pic; // generate position-independent-code for shared libs bool color = true; // use ANSI colors in console output bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required bool nofloat; // code should not pull in floating point support bool ignoreUnsupportedPragmas; // rather than error on them bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations bool check10378; // check for issues transitioning to 10738 bool bug10378; // use pre- https://issues.dlang.org/show_bug.cgi?id=10378 search strategy bool fix16997; // fix integral promotions for unary + - ~ operators // https://issues.dlang.org/show_bug.cgi?id=16997 bool vsafe; // use enhanced @safe checking bool ehnogc; // use @nogc exception handling bool dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 /** The --transition=safe switch should only be used to show code with * silent semantics changes related to @safe improvements. It should not be * used to hide a feature that will have to go through deprecate-then-error * before becoming default. */ bool showGaggedErrors; // print gagged errors anyway bool manual; // open browser on compiler manual bool usage; // print usage and exit bool mcpuUsage; // print help on -mcpu switch bool transitionUsage; // print help on -transition switch bool logo; // print compiler logo CPU cpu = CPU.baseline; // CPU instruction set to target CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated uint errorLimit = 20; const(char)[] argv0; // program name Array!(const(char)*)* modFileAliasStrings; // array of char*'s of -I module filename alias strings Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules const(char)* objdir; // .obj/.lib file output directory const(char)* objname; // .obj file output name const(char)* libname; // .lib file output name bool doDocComments; // process embedded documentation comments const(char)* docdir; // write documentation file to docdir directory const(char)* docname; // write documentation file to docname Array!(const(char)*) ddocfiles; // macro include files for Ddoc bool doHdrGeneration; // process embedded documentation comments const(char)* hdrdir; // write 'header' file to docdir directory const(char)* hdrname; // write 'header' file to docname bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions bool doJsonGeneration; // write JSON file const(char)* jsonfilename; // write JSON file to jsonfilename JsonFieldFlags jsonFieldFlags; // JSON field flags to include uint debuglevel; // debug level Array!(const(char)*)* debugids; // debug identifiers uint versionlevel; // version level Array!(const(char)*)* versionids; // version identifiers const(char)* defaultlibname; // default library for non-debug builds const(char)* debuglibname; // default library for debug builds const(char)* mscrtlib; // MS C runtime library const(char)* moduleDepsFile; // filename for deps output OutBuffer* moduleDeps; // contents to be written to deps file // Hidden debug switches bool debugb; bool debugc; bool debugf; bool debugr; bool debugx; bool debugy; bool run; // run resulting executable Strings runargs; // arguments for executable // Linker stuff Array!(const(char)*) objfiles; Array!(const(char)*) linkswitches; Array!(const(char)*) libfiles; Array!(const(char)*) dllfiles; const(char)* deffile; const(char)* resfile; const(char)* exefile; const(char)* mapfile; } alias structalign_t = uint; // magic value means "match whatever the underlying C compiler does" // other values are all powers of 2 enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0); struct Global { const(char)* inifilename; const(char)* mars_ext = "d"; const(char)* obj_ext; const(char)* lib_ext; const(char)* dll_ext; const(char)* doc_ext = "html"; // for Ddoc generated files const(char)* ddoc_ext = "ddoc"; // for Ddoc macro include files const(char)* hdr_ext = "di"; // for D 'header' import files const(char)* json_ext = "json"; // for JSON files const(char)* map_ext = "map"; // for .map files bool run_noext; // allow -run sources without extensions. const(char)* copyright = "Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved"; const(char)* written = "written by Walter Bright"; const(char)* main_d = "__main.d"; // dummy filename for dummy main() Array!(const(char)*)* path; // Array of char*'s which form the import lookup path Array!(const(char)*)* filePath; // Array of char*'s which form the file import lookup path const(char)* _version; const(char)* vendor; // Compiler backend name Param params; uint errors; // number of errors reported so far uint warnings; // number of warnings reported so far uint gag; // !=0 means gag reporting of errors & warnings uint gaggedErrors; // number of errors reported while gagged uint gaggedWarnings; // number of warnings reported while gagged void* console; // opaque pointer to console for controlling text attributes Array!Identifier* versionids; // command line versions and predefined versions Array!Identifier* debugids; // command line debug versions and predefined versions /* Start gagging. Return the current number of gagged errors */ extern (C++) uint startGagging() { ++gag; gaggedWarnings = 0; return gaggedErrors; } /* End gagging, restoring the old gagged state. * Return true if errors occurred while gagged. */ extern (C++) bool endGagging(uint oldGagged) { bool anyErrs = (gaggedErrors != oldGagged); --gag; // Restore the original state of gagged errors; set total errors // to be original errors + new ungagged errors. errors -= (gaggedErrors - oldGagged); gaggedErrors = oldGagged; return anyErrs; } /* Increment the error count to record that an error * has occurred in the current context. An error message * may or may not have been printed. */ extern (C++) void increaseErrorCount() { if (gag) ++gaggedErrors; ++errors; } extern (C++) void _init(); /** Returns: the version as the number that would be returned for __VERSION__ */ extern(C++) uint versionNumber() { import core.stdc.ctype; __gshared uint cached = 0; if (cached == 0) { // // parse _version // uint major = 0; uint minor = 0; bool point = false; for (const(char)* p = _version + 1;; p++) { const c = *p; if (isdigit(cast(char)c)) { minor = minor * 10 + c - '0'; } else if (c == '.') { if (point) break; // ignore everything after second '.' point = true; major = minor; minor = 0; } else break; } cached = major * 1000 + minor; } return cached; } } // Because int64_t and friends may be any integral type of the // correct size, we have to explicitly ask for the correct // integer type to get the correct mangling with dmd // Be careful not to care about sign when using dinteger_t // use this instead of integer_t to // avoid conflicts with system #include's alias dinteger_t = ulong; // Signed and unsigned variants alias sinteger_t = long; alias uinteger_t = ulong; alias d_int8 = int8_t; alias d_uns8 = uint8_t; alias d_int16 = int16_t; alias d_uns16 = uint16_t; alias d_int32 = int32_t; alias d_uns32 = uint32_t; alias d_int64 = int64_t; alias d_uns64 = uint64_t; // file location struct Loc { const(char)* filename; // either absolute or relative to cwd uint linnum; uint charnum; static immutable Loc initial; /// use for default initialization of const ref Loc's nothrow: extern (D) this(const(char)* filename, uint linnum, uint charnum) pure { this.linnum = linnum; this.charnum = charnum; this.filename = filename; } extern (C++) const(char)* toChars() const; extern (C++) bool equals(ref const(Loc) loc) const { return (!global.params.showColumns || charnum == loc.charnum) && linnum == loc.linnum && FileName.equals(filename, loc.filename); } /****************** * Returns: * true if Loc has been set to other than the default initialization */ bool isValid() const pure { return filename !is null; } } enum LINK : int { default_, d, c, cpp, windows, pascal, objc, system, } enum CPPMANGLE : int { def, asStruct, asClass, } enum MATCH : int { nomatch, // no match convert, // match with conversions constant, // match with conversion to const exact, // exact match } enum PINLINE : int { default_, // as specified on the command line never, // never inline always, // always inline } alias StorageClass = uinteger_t; extern (C++) __gshared Global global; ================================================ FILE: gcc/d/dmd/globals.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/globals.h */ #pragma once #include "root/dcompat.h" #include "root/ctfloat.h" #include "root/outbuffer.h" #include "root/filename.h" #include "compiler.h" // Can't include arraytypes.h here, need to declare these directly. template struct Array; typedef unsigned char Diagnostic; enum { DIAGNOSTICerror, // generate an error DIAGNOSTICinform, // generate a warning DIAGNOSTICoff // disable diagnostic }; // The state of array bounds checking typedef unsigned char CHECKENABLE; enum { CHECKENABLEdefault, // initial value CHECKENABLEoff, // never do bounds checking CHECKENABLEon, // always do bounds checking CHECKENABLEsafeonly // do bounds checking only in @safe functions }; typedef unsigned char CHECKACTION; enum { CHECKACTION_D, // call D assert on failure CHECKACTION_C, // call C assert on failure CHECKACTION_halt // cause program halt on failure }; enum CPU { x87, mmx, sse, sse2, sse3, ssse3, sse4_1, sse4_2, avx, // AVX1 instruction set avx2, // AVX2 instruction set avx512, // AVX-512 instruction set // Special values that don't survive past the command line processing baseline, // (default) the minimum capability CPU native // the machine the compiler is being run on }; // Put command line switches in here struct Param { bool obj; // write object file bool link; // perform link bool dll; // generate shared dynamic library bool lib; // write library file instead of object file(s) bool multiobj; // break one object file into multiple ones bool oneobj; // write one object file instead of multiple ones bool trace; // insert profiling hooks bool tracegc; // instrument calls to 'new' bool verbose; // verbose compile bool vcg_ast; // write-out codegen-ast bool showColumns; // print character (column) numbers in diagnostics bool vtls; // identify thread local variables bool vgc; // identify gc usage bool vfield; // identify non-mutable field variables bool vcomplex; // identify complex/imaginary type usage char symdebug; // insert debug symbolic information bool symdebugref; // insert debug information for all referenced types, too bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer bool map; // generate linker .map file bool is64bit; // generate 64 bit code bool isLP64; // generate code for LP64 bool isLinux; // generate code for linux bool isOSX; // generate code for Mac OSX bool isWindows; // generate code for Windows bool isFreeBSD; // generate code for FreeBSD bool isOpenBSD; // generate code for OpenBSD bool isDragonFlyBSD;// generate code for DragonFlyBSD bool isSolaris; // generate code for Solaris bool hasObjectiveC; // target supports Objective-C bool mscoff; // for Win32: write COFF object files instead of OMF Diagnostic useDeprecated; bool useInvariants; // generate class invariant checks bool useIn; // generate precondition checks bool useOut; // generate postcondition checks bool stackstomp; // add stack stomping code bool useUnitTests; // generate unittest code bool useInline; // inline expand functions bool useDIP25; // implement http://wiki.dlang.org/DIP25 bool release; // build release version bool preservePaths; // true means don't strip path from source file Diagnostic warnings; bool pic; // generate position-independent-code for shared libs bool color; // use ANSI colors in console output bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required bool nofloat; // code should not pull in floating point support bool ignoreUnsupportedPragmas; // rather than error on them bool useModuleInfo; // generate runtime module information bool useTypeInfo; // generate runtime type information bool useExceptions; // support exception handling bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations bool check10378; // check for issues transitioning to 10738 bool bug10378; // use pre-bugzilla 10378 search strategy bool fix16997; // fix integral promotions for unary + - ~ operators // https://issues.dlang.org/show_bug.cgi?id=16997 bool vsafe; // use enhanced @safe checking bool ehnogc; // use @nogc exception handling bool dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 bool showGaggedErrors; // print gagged errors anyway bool manual; // open browser on compiler manual bool usage; // print usage and exit bool mcpuUsage; // print help on -mcpu switch bool transitionUsage; // print help on -transition switch bool logo; // print logo; CPU cpu; // CPU instruction set to target CHECKENABLE useArrayBounds; // when to generate code for array bounds checks CHECKENABLE useAssert; // when to generate code for assert()'s CHECKENABLE useSwitchError; // check for switches without a default CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated unsigned errorLimit; DArray argv0; // program name Array *modFileAliasStrings; // array of char*'s of -I module filename alias strings Array *imppath; // array of char*'s of where to look for import modules Array *fileImppath; // array of char*'s of where to look for file import modules const char *objdir; // .obj/.lib file output directory const char *objname; // .obj file output name const char *libname; // .lib file output name bool doDocComments; // process embedded documentation comments const char *docdir; // write documentation file to docdir directory const char *docname; // write documentation file to docname Array ddocfiles; // macro include files for Ddoc bool doHdrGeneration; // process embedded documentation comments const char *hdrdir; // write 'header' file to docdir directory const char *hdrname; // write 'header' file to docname bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions bool doJsonGeneration; // write JSON file const char *jsonfilename; // write JSON file to jsonfilename unsigned jsonFieldFlags; // JSON field flags to include unsigned debuglevel; // debug level Array *debugids; // debug identifiers unsigned versionlevel; // version level Array *versionids; // version identifiers const char *defaultlibname; // default library for non-debug builds const char *debuglibname; // default library for debug builds const char *mscrtlib; // MS C runtime library const char *moduleDepsFile; // filename for deps output OutBuffer *moduleDeps; // contents to be written to deps file // Hidden debug switches bool debugb; bool debugc; bool debugf; bool debugr; bool debugx; bool debugy; bool run; // run resulting executable Strings runargs; // arguments for executable // Linker stuff Array objfiles; Array linkswitches; Array libfiles; Array dllfiles; const char *deffile; const char *resfile; const char *exefile; const char *mapfile; }; typedef unsigned structalign_t; // magic value means "match whatever the underlying C compiler does" // other values are all powers of 2 #define STRUCTALIGN_DEFAULT ((structalign_t) ~0) struct Global { const char *inifilename; const char *mars_ext; const char *obj_ext; const char *lib_ext; const char *dll_ext; const char *doc_ext; // for Ddoc generated files const char *ddoc_ext; // for Ddoc macro include files const char *hdr_ext; // for D 'header' import files const char *json_ext; // for JSON files const char *map_ext; // for .map files bool run_noext; // allow -run sources without extensions. const char *copyright; const char *written; const char *main_d; // dummy filename for dummy main() Array *path; // Array of char*'s which form the import lookup path Array *filePath; // Array of char*'s which form the file import lookup path const char *version; // Compiler version string const char *vendor; // Compiler backend name Param params; unsigned errors; // number of errors reported so far unsigned warnings; // number of warnings reported so far unsigned gag; // !=0 means gag reporting of errors & warnings unsigned gaggedErrors; // number of errors reported while gagged unsigned gaggedWarnings; // number of warnings reported while gagged void* console; // opaque pointer to console for controlling text attributes Array* versionids; // command line versions and predefined versions Array* debugids; // command line debug versions and predefined versions /* Start gagging. Return the current number of gagged errors */ unsigned startGagging(); /* End gagging, restoring the old gagged state. * Return true if errors occurred while gagged. */ bool endGagging(unsigned oldGagged); /* Increment the error count to record that an error * has occurred in the current context. An error message * may or may not have been printed. */ void increaseErrorCount(); void _init(); /** Returns: the version as the number that would be returned for __VERSION__ */ unsigned versionNumber(); }; extern Global global; // Because int64_t and friends may be any integral type of the // correct size, we have to explicitly ask for the correct // integer type to get the correct mangling with dmd #if __LP64__ // Be careful not to care about sign when using dinteger_t // use this instead of integer_t to // avoid conflicts with system #include's typedef unsigned long dinteger_t; // Signed and unsigned variants typedef long sinteger_t; typedef unsigned long uinteger_t; #else typedef unsigned long long dinteger_t; typedef long long sinteger_t; typedef unsigned long long uinteger_t; #endif typedef int8_t d_int8; typedef uint8_t d_uns8; typedef int16_t d_int16; typedef uint16_t d_uns16; typedef int32_t d_int32; typedef uint32_t d_uns32; typedef int64_t d_int64; typedef uint64_t d_uns64; // file location struct Loc { const char *filename; // either absolute or relative to cwd unsigned linnum; unsigned charnum; Loc() { linnum = 0; charnum = 0; filename = NULL; } Loc(const char *filename, unsigned linnum, unsigned charnum); const char *toChars() const; bool equals(const Loc& loc) const; }; enum LINK { LINKdefault, LINKd, LINKc, LINKcpp, LINKwindows, LINKpascal, LINKobjc, LINKsystem }; enum CPPMANGLE { CPPMANGLEdefault, CPPMANGLEstruct, CPPMANGLEclass }; enum MATCH { MATCHnomatch, // no match MATCHconvert, // match with conversions MATCHconst, // match with conversion to const MATCHexact // exact match }; enum PINLINE { PINLINEdefault, // as specified on the command line PINLINEnever, // never inline PINLINEalways // always inline }; typedef uinteger_t StorageClass; ================================================ FILE: gcc/d/dmd/gluelayer.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/gluelayer.d, _gluelayer.d) * Documentation: https://dlang.org/phobos/dmd_gluelayer.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/gluelayer.d */ module dmd.gluelayer; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.mtype; import dmd.statement; import dmd.root.file; version (NoBackend) { import dmd.lib : Library; struct Symbol; struct code; struct block; struct Blockx; struct elem; struct TYPE; alias type = TYPE; extern (C++) { // glue void obj_write_deferred(Library library) {} void obj_start(const(char)* srcfile) {} void obj_end(Library library, File* objfile) {} void genObjFile(Module m, bool multiobj) {} // msc void backend_init() {} void backend_term() {} // iasm Statement asmSemantic(AsmStatement s, Scope* sc) { assert(0); } // toir void toObjFile(Dsymbol ds, bool multiobj) {} extern(C++) abstract class ObjcGlue { static void initialize() {} } } } else version (MARS) { import dmd.lib : Library; public import dmd.backend.cc : block, Blockx, Symbol; public import dmd.backend.type : type; public import dmd.backend.el : elem; public import dmd.backend.code_x86 : code; extern (C++) { void obj_write_deferred(Library library); void obj_start(const(char)* srcfile); void obj_end(Library library, File* objfile); void genObjFile(Module m, bool multiobj); void backend_init(); void backend_term(); Statement asmSemantic(AsmStatement s, Scope* sc); void toObjFile(Dsymbol ds, bool multiobj); extern(C++) abstract class ObjcGlue { static void initialize(); } } } else version (IN_GCC) { union tree_node; alias Symbol = tree_node; alias code = tree_node; alias type = tree_node; extern (C++) { Statement asmSemantic(AsmStatement s, Scope* sc); } // stubs extern(C++) abstract class ObjcGlue { static void initialize() {} } } else static assert(false, "Unsupported compiler backend"); ================================================ FILE: gcc/d/dmd/hdrgen.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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.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; } enum TEST_EMIT_ALL = 0; extern (C++) void genhdrfile(Module m) { OutBuffer buf; buf.doindent = 1; buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); buf.writenl(); HdrGenState hgs; hgs.hdrgen = true; toCBuffer(m, &buf, &hgs); // Transfer image to file m.hdrfile.setbuffer(buf.data, buf.offset); buf.extractData(); ensurePathToNameExists(Loc.initial, m.hdrfile.toChars()); writeFile(m.loc, m.hdrfile); } /** * Dumps the full contents of module `m` to `buf`. * Params: * buf = buffer to write to. * m = module to visit all members of. */ extern (C++) void moduleToBuffer(OutBuffer* buf, Module m) { HdrGenState hgs; hgs.fullDump = true; toCBuffer(m, buf, &hgs); } extern (C++) final class PrettyPrintVisitor : Visitor { alias visit = Visitor.visit; public: OutBuffer* buf; HdrGenState* hgs; bool declstring; // set while declaring alias for string,wstring or dstring EnumDeclaration inEnumDecl; extern (D) this(OutBuffer* buf, HdrGenState* hgs) { this.buf = buf; this.hgs = hgs; } override void visit(Statement s) { buf.writestring("Statement::toCBuffer()"); buf.writenl(); assert(0); } override void visit(ErrorStatement s) { buf.writestring("__error__"); buf.writenl(); } override void visit(ExpStatement s) { if (s.exp && s.exp.op == TOK.declaration) { // bypass visit(DeclarationExp) (cast(DeclarationExp)s.exp).declaration.accept(this); return; } if (s.exp) s.exp.accept(this); buf.writeByte(';'); if (!hgs.forStmtInit) buf.writenl(); } override void visit(CompileStatement s) { buf.writestring("mixin("); argsToBuffer(s.exps, null); buf.writestring(");"); if (!hgs.forStmtInit) buf.writenl(); } override void visit(CompoundStatement s) { foreach (sx; *s.statements) { if (sx) sx.accept(this); } } override void visit(CompoundDeclarationStatement s) { bool anywritten = false; foreach (sx; *s.statements) { auto ds = sx ? sx.isExpStatement() : null; if (ds && ds.exp.op == TOK.declaration) { auto d = (cast(DeclarationExp)ds.exp).declaration; assert(d.isDeclaration()); if (auto v = d.isVarDeclaration()) visitVarDecl(v, anywritten); else d.accept(this); anywritten = true; } } buf.writeByte(';'); if (!hgs.forStmtInit) buf.writenl(); } override void visit(UnrolledLoopStatement s) { buf.writestring("/*unrolled*/ {"); buf.writenl(); buf.level++; foreach (sx; *s.statements) { if (sx) sx.accept(this); } buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(ScopeStatement s) { buf.writeByte('{'); buf.writenl(); buf.level++; if (s.statement) s.statement.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(WhileStatement s) { buf.writestring("while ("); s.condition.accept(this); buf.writeByte(')'); buf.writenl(); if (s._body) s._body.accept(this); } override void visit(DoStatement s) { buf.writestring("do"); buf.writenl(); if (s._body) s._body.accept(this); buf.writestring("while ("); s.condition.accept(this); buf.writestring(");"); buf.writenl(); } override void visit(ForStatement s) { buf.writestring("for ("); if (s._init) { hgs.forStmtInit++; s._init.accept(this); hgs.forStmtInit--; } else buf.writeByte(';'); if (s.condition) { buf.writeByte(' '); s.condition.accept(this); } buf.writeByte(';'); if (s.increment) { buf.writeByte(' '); s.increment.accept(this); } buf.writeByte(')'); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; if (s._body) s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } private void visitWithoutBody(ForeachStatement s) { buf.writestring(Token.toString(s.op)); buf.writestring(" ("); foreach (i, p; *s.parameters) { if (i) buf.writestring(", "); if (stcToBuffer(buf, p.storageClass)) buf.writeByte(' '); if (p.type) typeToBuffer(p.type, p.ident); else buf.writestring(p.ident.toString()); } buf.writestring("; "); s.aggr.accept(this); buf.writeByte(')'); buf.writenl(); } override void visit(ForeachStatement s) { visitWithoutBody(s); buf.writeByte('{'); buf.writenl(); buf.level++; if (s._body) s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } private void visitWithoutBody(ForeachRangeStatement s) { buf.writestring(Token.toString(s.op)); buf.writestring(" ("); if (s.prm.type) typeToBuffer(s.prm.type, s.prm.ident); else buf.writestring(s.prm.ident.toString()); buf.writestring("; "); s.lwr.accept(this); buf.writestring(" .. "); s.upr.accept(this); buf.writeByte(')'); buf.writenl(); buf.writeByte('{'); buf.writenl(); } override void visit(ForeachRangeStatement s) { visitWithoutBody(s); buf.level++; if (s._body) s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(StaticForeachStatement s) { buf.writestring("static "); if (s.sfe.aggrfe) { visit(s.sfe.aggrfe); } else { assert(s.sfe.rangefe); visit(s.sfe.rangefe); } } override void visit(IfStatement s) { buf.writestring("if ("); if (Parameter p = s.prm) { StorageClass stc = p.storageClass; if (!p.type && !stc) stc = STC.auto_; if (stcToBuffer(buf, stc)) buf.writeByte(' '); if (p.type) typeToBuffer(p.type, p.ident); else buf.writestring(p.ident.toString()); buf.writestring(" = "); } s.condition.accept(this); buf.writeByte(')'); buf.writenl(); if (s.ifbody.isScopeStatement()) { s.ifbody.accept(this); } else { buf.level++; s.ifbody.accept(this); buf.level--; } if (s.elsebody) { buf.writestring("else"); if (!s.elsebody.isIfStatement()) { buf.writenl(); } else { buf.writeByte(' '); } if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) { s.elsebody.accept(this); } else { buf.level++; s.elsebody.accept(this); buf.level--; } } } override void visit(ConditionalStatement s) { s.condition.accept(this); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; if (s.ifbody) s.ifbody.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); if (s.elsebody) { buf.writestring("else"); buf.writenl(); buf.writeByte('{'); buf.level++; buf.writenl(); s.elsebody.accept(this); buf.level--; buf.writeByte('}'); } buf.writenl(); } override void visit(PragmaStatement s) { buf.writestring("pragma ("); buf.writestring(s.ident.toString()); if (s.args && s.args.dim) { buf.writestring(", "); argsToBuffer(s.args); } buf.writeByte(')'); if (s._body) { buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } else { buf.writeByte(';'); buf.writenl(); } } override void visit(StaticAssertStatement s) { s.sa.accept(this); } override void visit(SwitchStatement s) { buf.writestring(s.isFinal ? "final switch (" : "switch ("); s.condition.accept(this); buf.writeByte(')'); buf.writenl(); if (s._body) { if (!s._body.isScopeStatement()) { buf.writeByte('{'); buf.writenl(); buf.level++; s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } else { s._body.accept(this); } } } override void visit(CaseStatement s) { buf.writestring("case "); s.exp.accept(this); buf.writeByte(':'); buf.writenl(); s.statement.accept(this); } override void visit(CaseRangeStatement s) { buf.writestring("case "); s.first.accept(this); buf.writestring(": .. case "); s.last.accept(this); buf.writeByte(':'); buf.writenl(); s.statement.accept(this); } override void visit(DefaultStatement s) { buf.writestring("default:"); buf.writenl(); s.statement.accept(this); } override void visit(GotoDefaultStatement s) { buf.writestring("goto default;"); buf.writenl(); } override void visit(GotoCaseStatement s) { buf.writestring("goto case"); if (s.exp) { buf.writeByte(' '); s.exp.accept(this); } buf.writeByte(';'); buf.writenl(); } override void visit(SwitchErrorStatement s) { buf.writestring("SwitchErrorStatement::toCBuffer()"); buf.writenl(); } override void visit(ReturnStatement s) { buf.writestring("return "); if (s.exp) s.exp.accept(this); buf.writeByte(';'); buf.writenl(); } override void visit(BreakStatement s) { buf.writestring("break"); if (s.ident) { buf.writeByte(' '); buf.writestring(s.ident.toString()); } buf.writeByte(';'); buf.writenl(); } override void visit(ContinueStatement s) { buf.writestring("continue"); if (s.ident) { buf.writeByte(' '); buf.writestring(s.ident.toString()); } buf.writeByte(';'); buf.writenl(); } override void visit(SynchronizedStatement s) { buf.writestring("synchronized"); if (s.exp) { buf.writeByte('('); s.exp.accept(this); buf.writeByte(')'); } if (s._body) { buf.writeByte(' '); s._body.accept(this); } } override void visit(WithStatement s) { buf.writestring("with ("); s.exp.accept(this); buf.writestring(")"); buf.writenl(); if (s._body) s._body.accept(this); } override void visit(TryCatchStatement s) { buf.writestring("try"); buf.writenl(); if (s._body) { if (s._body.isScopeStatement()) { s._body.accept(this); } else { buf.level++; s._body.accept(this); buf.level--; } } foreach (c; *s.catches) { visit(c); } } override void visit(TryFinallyStatement s) { buf.writestring("try"); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; s._body.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); buf.writestring("finally"); buf.writenl(); if (s.finalbody.isScopeStatement()) { s.finalbody.accept(this); } else { buf.level++; s.finalbody.accept(this); buf.level--; } } override void visit(OnScopeStatement s) { buf.writestring(Token.toString(s.tok)); buf.writeByte(' '); s.statement.accept(this); } override void visit(ThrowStatement s) { buf.writestring("throw "); s.exp.accept(this); buf.writeByte(';'); buf.writenl(); } override void visit(DebugStatement s) { if (s.statement) { s.statement.accept(this); } } override void visit(GotoStatement s) { buf.writestring("goto "); buf.writestring(s.ident.toString()); buf.writeByte(';'); buf.writenl(); } override void visit(LabelStatement s) { buf.writestring(s.ident.toString()); buf.writeByte(':'); buf.writenl(); if (s.statement) s.statement.accept(this); } override void visit(AsmStatement s) { buf.writestring("asm { "); Token* t = s.tokens; buf.level++; while (t) { buf.writestring(t.toChars()); if (t.next && t.value != TOK.min && t.value != TOK.comma && t.next.value != TOK.comma && t.value != TOK.leftBracket && t.next.value != TOK.leftBracket && t.next.value != TOK.rightBracket && t.value != TOK.leftParentheses && t.next.value != TOK.leftParentheses && t.next.value != TOK.rightParentheses && t.value != TOK.dot && t.next.value != TOK.dot) { buf.writeByte(' '); } t = t.next; } buf.level--; buf.writestring("; }"); buf.writenl(); } override void visit(ImportStatement s) { foreach (imp; *s.imports) { imp.accept(this); } } void visit(Catch c) { buf.writestring("catch"); if (c.type) { buf.writeByte('('); typeToBuffer(c.type, c.ident); buf.writeByte(')'); } buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; if (c.handler) c.handler.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } //////////////////////////////////////////////////////////////////////////// /************************************************** * An entry point to pretty-print type. */ void typeToBuffer(Type t, Identifier ident) { if (t.ty == Tfunction) { visitFuncIdentWithPrefix(cast(TypeFunction)t, ident, null); return; } visitWithMask(t, 0); if (ident) { buf.writeByte(' '); buf.writestring(ident.toString()); } } void visitWithMask(Type t, ubyte modMask) { // Tuples and functions don't use the type constructor syntax if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) { t.accept(this); } else { ubyte m = t.mod & ~(t.mod & modMask); if (m & MODFlags.shared_) { MODtoBuffer(buf, MODFlags.shared_); buf.writeByte('('); } if (m & MODFlags.wild) { MODtoBuffer(buf, MODFlags.wild); buf.writeByte('('); } if (m & (MODFlags.const_ | MODFlags.immutable_)) { MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); buf.writeByte('('); } t.accept(this); if (m & (MODFlags.const_ | MODFlags.immutable_)) buf.writeByte(')'); if (m & MODFlags.wild) buf.writeByte(')'); if (m & MODFlags.shared_) buf.writeByte(')'); } } override void visit(Type t) { printf("t = %p, ty = %d\n", t, t.ty); assert(0); } override void visit(TypeError t) { buf.writestring("_error_"); } override void visit(TypeBasic t) { //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); buf.writestring(t.dstring); } override void visit(TypeVector t) { //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); buf.writestring("__vector("); visitWithMask(t.basetype, t.mod); buf.writestring(")"); } override void visit(TypeSArray t) { visitWithMask(t.next, t.mod); buf.writeByte('['); sizeToBuffer(t.dim); buf.writeByte(']'); } override void visit(TypeDArray t) { Type ut = t.castMod(0); if (declstring) goto L1; if (ut.equals(Type.tstring)) buf.writestring("string"); else if (ut.equals(Type.twstring)) buf.writestring("wstring"); else if (ut.equals(Type.tdstring)) buf.writestring("dstring"); else { L1: visitWithMask(t.next, t.mod); buf.writestring("[]"); } } override void visit(TypeAArray t) { visitWithMask(t.next, t.mod); buf.writeByte('['); visitWithMask(t.index, 0); buf.writeByte(']'); } override void visit(TypePointer t) { //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); if (t.next.ty == Tfunction) visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function"); else { visitWithMask(t.next, t.mod); buf.writeByte('*'); } } override void visit(TypeReference t) { visitWithMask(t.next, t.mod); buf.writeByte('&'); } override void visit(TypeFunction t) { //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref); visitFuncIdentWithPostfix(t, null); } // callback for TypeFunction::attributesApply struct PrePostAppendStrings { OutBuffer* buf; bool isPostfixStyle; bool isCtor; extern (D) static int fp(void* param, string str) { PrePostAppendStrings* p = cast(PrePostAppendStrings*)param; // don't write 'ref' for ctors if (p.isCtor && str == "ref") return 0; if (p.isPostfixStyle) p.buf.writeByte(' '); p.buf.writestring(str); if (!p.isPostfixStyle) p.buf.writeByte(' '); return 0; } } void visitFuncIdentWithPostfix(TypeFunction t, const(char)* ident) { if (t.inuse) { t.inuse = 2; // flag error to caller return; } t.inuse++; PrePostAppendStrings pas; pas.buf = buf; pas.isCtor = false; pas.isPostfixStyle = true; if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) { linkageToBuffer(buf, t.linkage); buf.writeByte(' '); } if (t.next) { typeToBuffer(t.next, null); if (ident) buf.writeByte(' '); } else if (hgs.ddoc) buf.writestring("auto "); if (ident) buf.writestring(ident); parametersToBuffer(t.parameters, t.varargs); /* Use postfix style for attributes */ if (t.mod) { buf.writeByte(' '); MODtoBuffer(buf, t.mod); } t.attributesApply(&pas, &PrePostAppendStrings.fp); t.inuse--; } void visitFuncIdentWithPrefix(TypeFunction t, Identifier ident, TemplateDeclaration td) { if (t.inuse) { t.inuse = 2; // flag error to caller return; } t.inuse++; PrePostAppendStrings pas; extern (D) static int ignoreReturn(void* param, string name) { if (name != "return") PrePostAppendStrings.fp(param, name); return 0; } pas.buf = buf; pas.isCtor = (ident == Id.ctor); pas.isPostfixStyle = false; /* Use 'storage class' (prefix) style for attributes */ if (t.mod) { MODtoBuffer(buf, t.mod); buf.writeByte(' '); } t.attributesApply(&pas, &ignoreReturn); if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) { linkageToBuffer(buf, t.linkage); buf.writeByte(' '); } if (ident && ident.toHChars2() != ident.toChars()) { // Don't print return type for ctor, dtor, unittest, etc } else if (t.next) { typeToBuffer(t.next, null); if (ident) buf.writeByte(' '); } else if (hgs.ddoc) buf.writestring("auto "); if (ident) buf.writestring(ident.toHChars2()); if (td) { buf.writeByte('('); foreach (i, p; *td.origParameters) { if (i) buf.writestring(", "); p.accept(this); } buf.writeByte(')'); } parametersToBuffer(t.parameters, t.varargs); if (t.isreturn) { PrePostAppendStrings.fp(&pas, " return"); pas.buf.offset -= 1; // remove final whitespace } t.inuse--; } override void visit(TypeDelegate t) { visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate"); } void visitTypeQualifiedHelper(TypeQualified t) { foreach (id; t.idents) { if (id.dyncast() == DYNCAST.dsymbol) { buf.writeByte('.'); TemplateInstance ti = cast(TemplateInstance)id; ti.accept(this); } else if (id.dyncast() == DYNCAST.expression) { buf.writeByte('['); (cast(Expression)id).accept(this); buf.writeByte(']'); } else if (id.dyncast() == DYNCAST.type) { buf.writeByte('['); (cast(Type)id).accept(this); buf.writeByte(']'); } else { buf.writeByte('.'); buf.writestring(id.toChars()); } } } override void visit(TypeIdentifier t) { buf.writestring(t.ident.toString()); visitTypeQualifiedHelper(t); } override void visit(TypeInstance t) { t.tempinst.accept(this); visitTypeQualifiedHelper(t); } override void visit(TypeTypeof t) { buf.writestring("typeof("); t.exp.accept(this); buf.writeByte(')'); visitTypeQualifiedHelper(t); } override void visit(TypeReturn t) { buf.writestring("typeof(return)"); visitTypeQualifiedHelper(t); } override void visit(TypeEnum t) { buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); } override void visit(TypeStruct t) { // https://issues.dlang.org/show_bug.cgi?id=13776 // Don't use ti.toAlias() to avoid forward reference error // while printing messages. TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; if (ti && ti.aliasdecl == t.sym) buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); else buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); } override void visit(TypeClass t) { // https://issues.dlang.org/show_bug.cgi?id=13776 // Don't use ti.toAlias() to avoid forward reference error // while printing messages. TemplateInstance ti = t.sym.parent.isTemplateInstance(); if (ti && ti.aliasdecl == t.sym) buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); else buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); } override void visit(TypeTuple t) { parametersToBuffer(t.arguments, 0); } override void visit(TypeSlice t) { visitWithMask(t.next, t.mod); buf.writeByte('['); sizeToBuffer(t.lwr); buf.writestring(" .. "); sizeToBuffer(t.upr); buf.writeByte(']'); } override void visit(TypeNull t) { buf.writestring("typeof(null)"); } //////////////////////////////////////////////////////////////////////////// override void visit(Dsymbol s) { buf.writestring(s.toChars()); } override void visit(StaticAssert s) { buf.writestring(s.kind()); buf.writeByte('('); s.exp.accept(this); if (s.msg) { buf.writestring(", "); s.msg.accept(this); } buf.writestring(");"); buf.writenl(); } override void visit(DebugSymbol s) { buf.writestring("debug = "); if (s.ident) buf.writestring(s.ident.toString()); else buf.print(s.level); buf.writeByte(';'); buf.writenl(); } override void visit(VersionSymbol s) { buf.writestring("version = "); if (s.ident) buf.writestring(s.ident.toString()); else buf.print(s.level); buf.writeByte(';'); buf.writenl(); } override void visit(EnumMember em) { if (em.type) typeToBuffer(em.type, em.ident); else buf.writestring(em.ident.toString()); if (em.value) { buf.writestring(" = "); em.value.accept(this); } } override void visit(Import imp) { if (hgs.hdrgen && imp.id == Id.object) return; // object is imported by default if (imp.isstatic) buf.writestring("static "); buf.writestring("import "); if (imp.aliasId) { buf.printf("%s = ", imp.aliasId.toChars()); } if (imp.packages && imp.packages.dim) { foreach (const pid; *imp.packages) { buf.printf("%s.", pid.toChars()); } } buf.writestring(imp.id.toChars()); if (imp.names.dim) { buf.writestring(" : "); foreach (const i, const name; imp.names) { if (i) buf.writestring(", "); const _alias = imp.aliases[i]; if (_alias) buf.printf("%s = %s", _alias.toChars(), name.toChars()); else buf.writestring(name.toChars()); } } buf.writeByte(';'); buf.writenl(); } override void visit(AliasThis d) { buf.writestring("alias "); buf.writestring(d.ident.toString()); buf.writestring(" this;\n"); } override void visit(AttribDeclaration d) { if (!d.decl) { buf.writeByte(';'); buf.writenl(); return; } if (d.decl.dim == 0) buf.writestring("{}"); else if (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()) { // hack for bugzilla 8081 buf.writestring("{}"); } else if (d.decl.dim == 1) { (*d.decl)[0].accept(this); return; } else { buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (de; *d.decl) de.accept(this); buf.level--; buf.writeByte('}'); } buf.writenl(); } override void visit(StorageClassDeclaration d) { if (stcToBuffer(buf, d.stc)) buf.writeByte(' '); visit(cast(AttribDeclaration)d); } override void visit(DeprecatedDeclaration d) { buf.writestring("deprecated("); d.msg.accept(this); buf.writestring(") "); visit(cast(AttribDeclaration)d); } override void visit(LinkDeclaration d) { const(char)* p; final switch (d.linkage) { case LINK.d: p = "D"; break; case LINK.c: p = "C"; break; case LINK.cpp: p = "C++"; break; case LINK.windows: p = "Windows"; break; case LINK.pascal: p = "Pascal"; break; case LINK.objc: p = "Objective-C"; break; case LINK.default_: case LINK.system: assert(0); } buf.writestring("extern ("); buf.writestring(p); buf.writestring(") "); visit(cast(AttribDeclaration)d); } override void visit(CPPMangleDeclaration d) { const(char)* p; final switch (d.cppmangle) { case CPPMANGLE.asClass: p = "class"; break; case CPPMANGLE.asStruct: p = "struct"; break; case CPPMANGLE.def: break; } buf.writestring("extern (C++, "); buf.writestring(p); buf.writestring(") "); visit(cast(AttribDeclaration)d); } override void visit(ProtDeclaration d) { protectionToBuffer(buf, d.protection); buf.writeByte(' '); AttribDeclaration ad = cast(AttribDeclaration)d; if (ad.decl.dim == 1 && (*ad.decl)[0].isProtDeclaration) visit(cast(AttribDeclaration)(*ad.decl)[0]); else visit(cast(AttribDeclaration)d); } override void visit(AlignDeclaration d) { if (!d.ealign) buf.writestring("align "); else buf.printf("align (%s) ", d.ealign.toChars()); visit(cast(AttribDeclaration)d); } override void visit(AnonDeclaration d) { buf.writestring(d.isunion ? "union" : "struct"); buf.writenl(); buf.writestring("{"); buf.writenl(); buf.level++; if (d.decl) { foreach (de; *d.decl) de.accept(this); } buf.level--; buf.writestring("}"); buf.writenl(); } override void visit(PragmaDeclaration d) { buf.writestring("pragma ("); buf.writestring(d.ident.toString()); if (d.args && d.args.dim) { buf.writestring(", "); argsToBuffer(d.args); } buf.writeByte(')'); visit(cast(AttribDeclaration)d); } override void visit(ConditionalDeclaration d) { d.condition.accept(this); if (d.decl || d.elsedecl) { buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; if (d.decl) { foreach (de; *d.decl) de.accept(this); } buf.level--; buf.writeByte('}'); if (d.elsedecl) { buf.writenl(); buf.writestring("else"); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (de; *d.elsedecl) de.accept(this); buf.level--; buf.writeByte('}'); } } else buf.writeByte(':'); buf.writenl(); } override void visit(StaticForeachDeclaration s) { buf.writestring("static "); if (s.sfe.aggrfe) { visitWithoutBody(s.sfe.aggrfe); } else { assert(s.sfe.rangefe); visitWithoutBody(s.sfe.rangefe); } buf.writeByte('{'); buf.writenl(); buf.level++; visit(cast(AttribDeclaration)s); buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(CompileDeclaration d) { buf.writestring("mixin("); argsToBuffer(d.exps, null); buf.writestring(");"); buf.writenl(); } override void visit(UserAttributeDeclaration d) { buf.writestring("@("); argsToBuffer(d.atts); buf.writeByte(')'); 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 "); } if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d)) return; if (hgs.ddoc) buf.writestring(d.kind()); else buf.writestring("template"); buf.writeByte(' '); buf.writestring(d.ident.toString()); buf.writeByte('('); visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); buf.writeByte(')'); visitTemplateConstraint(d.constraint); if (hgs.hdrgen || hgs.fullDump) { hgs.tpltMember++; buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (s; *d.members) s.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); hgs.tpltMember--; } } bool visitEponymousMember(TemplateDeclaration d) { if (!d.members || d.members.dim != 1) return false; Dsymbol onemember = (*d.members)[0]; if (onemember.ident != d.ident) return false; if (FuncDeclaration fd = onemember.isFuncDeclaration()) { assert(fd.type); if (stcToBuffer(buf, fd.storage_class)) buf.writeByte(' '); functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); visitTemplateConstraint(d.constraint); hgs.tpltMember++; bodyToBuffer(fd); hgs.tpltMember--; return true; } if (AggregateDeclaration ad = onemember.isAggregateDeclaration()) { buf.writestring(ad.kind()); buf.writeByte(' '); buf.writestring(ad.ident.toString()); buf.writeByte('('); visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); buf.writeByte(')'); visitTemplateConstraint(d.constraint); visitBaseClasses(ad.isClassDeclaration()); hgs.tpltMember++; if (ad.members) { buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (s; *ad.members) s.accept(this); buf.level--; buf.writeByte('}'); } else buf.writeByte(';'); buf.writenl(); hgs.tpltMember--; return true; } if (VarDeclaration vd = onemember.isVarDeclaration()) { if (d.constraint) return false; if (stcToBuffer(buf, vd.storage_class)) buf.writeByte(' '); if (vd.type) typeToBuffer(vd.type, vd.ident); else buf.writestring(vd.ident.toString()); buf.writeByte('('); visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); buf.writeByte(')'); if (vd._init) { buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) (cast(AssignExp)ie.exp).e2.accept(this); else vd._init.accept(this); } buf.writeByte(';'); buf.writenl(); return true; } return false; } void visitTemplateParameters(TemplateParameters* parameters) { if (!parameters || !parameters.dim) return; foreach (i, p; *parameters) { if (i) buf.writestring(", "); p.accept(this); } } void visitTemplateConstraint(Expression constraint) { if (!constraint) return; buf.writestring(" if ("); constraint.accept(this); buf.writeByte(')'); } override void visit(TemplateInstance ti) { buf.writestring(ti.name.toChars()); tiargsToBuffer(ti); if (hgs.fullDump) { buf.writenl(); dumpTemplateInstance(ti); } } override void visit(TemplateMixin tm) { buf.writestring("mixin "); typeToBuffer(tm.tqual, null); tiargsToBuffer(tm); if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) { buf.writeByte(' '); buf.writestring(tm.ident.toString()); } buf.writeByte(';'); buf.writenl(); if (hgs.fullDump) dumpTemplateInstance(tm); } void dumpTemplateInstance(TemplateInstance ti) { buf.writeByte('{'); buf.writenl(); buf.level++; if (ti.aliasdecl) { ti.aliasdecl.accept(this); buf.writenl(); } else if (ti.members) { foreach(m;*ti.members) m.accept(this); } buf.level--; buf.writeByte('}'); buf.writenl(); } void tiargsToBuffer(TemplateInstance ti) { buf.writeByte('!'); if (ti.nest) { buf.writestring("(...)"); return; } if (!ti.tiargs) { buf.writestring("()"); return; } if (ti.tiargs.dim == 1) { RootObject oarg = (*ti.tiargs)[0]; if (Type t = isType(oarg)) { if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.dim == 0)) { buf.writestring(t.toChars()); return; } } else if (Expression e = isExpression(oarg)) { if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_) { buf.writestring(e.toChars()); return; } } } buf.writeByte('('); ti.nest++; foreach (i, arg; *ti.tiargs) { if (i) buf.writestring(", "); objectToBuffer(arg); } ti.nest--; buf.writeByte(')'); } /**************************************** * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ void objectToBuffer(RootObject oarg) { //printf("objectToBuffer()\n"); /* The logic of this should match what genIdent() does. The _dynamic_cast() * function relies on all the pretty strings to be unique for different classes * See https://issues.dlang.org/show_bug.cgi?id=7375 * Perhaps it would be better to demangle what genIdent() does. */ if (auto t = isType(oarg)) { //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); typeToBuffer(t, null); } else if (auto e = isExpression(oarg)) { if (e.op == TOK.variable) e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 e.accept(this); } else if (Dsymbol s = isDsymbol(oarg)) { const p = s.ident ? s.ident.toChars() : s.toChars(); buf.writestring(p); } else if (auto v = isTuple(oarg)) { auto args = &v.objects; foreach (i, arg; *args) { if (i) buf.writestring(", "); objectToBuffer(arg); } } else if (!oarg) { buf.writestring("NULL"); } else { debug { printf("bad Object = %p\n", oarg); } assert(0); } } override void visit(EnumDeclaration d) { auto oldInEnumDecl = inEnumDecl; scope(exit) inEnumDecl = oldInEnumDecl; inEnumDecl = d; buf.writestring("enum "); if (d.ident) { buf.writestring(d.ident.toString()); buf.writeByte(' '); } if (d.memtype) { buf.writestring(": "); typeToBuffer(d.memtype, null); } if (!d.members) { buf.writeByte(';'); buf.writenl(); return; } buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (em; *d.members) { if (!em) continue; em.accept(this); buf.writeByte(','); buf.writenl(); } buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(Nspace d) { buf.writestring("extern (C++, "); buf.writestring(d.ident.toString()); buf.writeByte(')'); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (s; *d.members) s.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(StructDeclaration d) { buf.writestring(d.kind()); buf.writeByte(' '); if (!d.isAnonymous()) buf.writestring(d.toChars()); if (!d.members) { buf.writeByte(';'); buf.writenl(); return; } buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (s; *d.members) s.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); } override void visit(ClassDeclaration d) { if (!d.isAnonymous()) { buf.writestring(d.kind()); buf.writeByte(' '); buf.writestring(d.ident.toString()); } visitBaseClasses(d); if (d.members) { buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; foreach (s; *d.members) s.accept(this); buf.level--; buf.writeByte('}'); } else buf.writeByte(';'); buf.writenl(); } void visitBaseClasses(ClassDeclaration d) { if (!d || !d.baseclasses.dim) return; if (!d.isAnonymous()) buf.writestring(" : "); foreach (i, b; *d.baseclasses) { if (i) buf.writestring(", "); typeToBuffer(b.type, null); } } override void visit(AliasDeclaration d) { if (d.storage_class & STC.local) return; buf.writestring("alias "); if (d.aliassym) { buf.writestring(d.ident.toString()); buf.writestring(" = "); if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); d.aliassym.accept(this); } else if (d.type.ty == Tfunction) { if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); typeToBuffer(d.type, d.ident); } else { declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring); buf.writestring(d.ident.toString()); buf.writestring(" = "); if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); typeToBuffer(d.type, null); declstring = false; } buf.writeByte(';'); buf.writenl(); } override void visit(VarDeclaration d) { if (d.storage_class & STC.local) return; visitVarDecl(d, false); buf.writeByte(';'); buf.writenl(); } void visitVarDecl(VarDeclaration v, bool anywritten) { if (anywritten) { buf.writestring(", "); buf.writestring(v.ident.toString()); } else { if (stcToBuffer(buf, v.storage_class)) buf.writeByte(' '); if (v.type) typeToBuffer(v.type, v.ident); else buf.writestring(v.ident.toString()); } if (v._init) { buf.writestring(" = "); auto ie = v._init.isExpInitializer(); if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) (cast(AssignExp)ie.exp).e2.accept(this); else v._init.accept(this); } } override void visit(FuncDeclaration f) { //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); if (stcToBuffer(buf, f.storage_class)) buf.writeByte(' '); auto tf = cast(TypeFunction)f.type; typeToBuffer(tf, f.ident); if (hgs.hdrgen) { // if the return type is missing (e.g. ref functions or auto) if (!tf.next || f.storage_class & STC.auto_) { hgs.autoMember++; bodyToBuffer(f); hgs.autoMember--; } else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions) { buf.writeByte(';'); buf.writenl(); } else bodyToBuffer(f); } else bodyToBuffer(f); } void bodyToBuffer(FuncDeclaration f) { if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember)) { buf.writeByte(';'); buf.writenl(); return; } int savetlpt = hgs.tpltMember; int saveauto = hgs.autoMember; hgs.tpltMember = 0; hgs.autoMember = 0; buf.writenl(); bool requireDo = false; // in{} if (f.frequires) { foreach (frequire; *f.frequires) { buf.writestring("in"); if (auto es = frequire.isExpStatement()) { assert(es.exp && es.exp.op == TOK.assert_); buf.writestring(" ("); (cast(AssertExp)es.exp).e1.accept(this); buf.writeByte(')'); buf.writenl(); requireDo = false; } else { buf.writenl(); frequire.accept(this); requireDo = true; } } } // out{} if (f.fensures) { foreach (fensure; *f.fensures) { buf.writestring("out"); if (auto es = fensure.ensure.isExpStatement()) { assert(es.exp && es.exp.op == TOK.assert_); buf.writestring(" ("); if (fensure.id) { buf.writestring(fensure.id.toChars()); } buf.writestring("; "); (cast(AssertExp)es.exp).e1.accept(this); buf.writeByte(')'); buf.writenl(); requireDo = false; } else { if (fensure.id) { buf.writeByte('('); buf.writestring(fensure.id.toChars()); buf.writeByte(')'); } buf.writenl(); fensure.ensure.accept(this); requireDo = true; } } } if (requireDo) { buf.writestring("do"); buf.writenl(); } buf.writeByte('{'); buf.writenl(); buf.level++; f.fbody.accept(this); buf.level--; buf.writeByte('}'); buf.writenl(); hgs.tpltMember = savetlpt; hgs.autoMember = saveauto; } override void visit(FuncLiteralDeclaration f) { if (f.type.ty == Terror) { buf.writestring("__error"); return; } if (f.tok != TOK.reserved) { buf.writestring(f.kind()); buf.writeByte(' '); } TypeFunction tf = cast(TypeFunction)f.type; // Don't print tf.mod, tf.trust, and tf.linkage if (!f.inferRetType && tf.next) typeToBuffer(tf.next, null); parametersToBuffer(tf.parameters, tf.varargs); CompoundStatement cs = f.fbody.isCompoundStatement(); Statement s1; if (f.semanticRun >= PASS.semantic3done && cs) { s1 = (*cs.statements)[cs.statements.dim - 1]; } else s1 = !cs ? f.fbody : null; ReturnStatement rs = s1 ? s1.isReturnStatement() : null; if (rs && rs.exp) { buf.writestring(" => "); rs.exp.accept(this); } else { hgs.tpltMember++; bodyToBuffer(f); hgs.tpltMember--; } } override void visit(PostBlitDeclaration d) { if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); buf.writestring("this(this)"); bodyToBuffer(d); } override void visit(DtorDeclaration d) { if (d.storage_class & STC.trusted) buf.writestring("@trusted "); if (d.storage_class & STC.safe) buf.writestring("@safe "); if (d.storage_class & STC.nogc) buf.writestring("@nogc "); if (d.storage_class & STC.disable) buf.writestring("@disable "); buf.writestring("~this()"); bodyToBuffer(d); } override void visit(StaticCtorDeclaration d) { if (stcToBuffer(buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); if (d.isSharedStaticCtorDeclaration()) buf.writestring("shared "); buf.writestring("static this()"); if (hgs.hdrgen && !hgs.tpltMember) { buf.writeByte(';'); buf.writenl(); } else bodyToBuffer(d); } override void visit(StaticDtorDeclaration d) { if (stcToBuffer(buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); if (d.isSharedStaticDtorDeclaration()) buf.writestring("shared "); buf.writestring("static ~this()"); if (hgs.hdrgen && !hgs.tpltMember) { buf.writeByte(';'); buf.writenl(); } else bodyToBuffer(d); } override void visit(InvariantDeclaration d) { if (hgs.hdrgen) return; if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); buf.writestring("invariant"); if(auto es = d.fbody.isExpStatement()) { assert(es.exp && es.exp.op == TOK.assert_); buf.writestring(" ("); (cast(AssertExp)es.exp).e1.accept(this); buf.writestring(");"); buf.writenl(); } else { bodyToBuffer(d); } } override void visit(UnitTestDeclaration d) { if (hgs.hdrgen) return; if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); buf.writestring("unittest"); bodyToBuffer(d); } override void visit(NewDeclaration d) { if (stcToBuffer(buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); buf.writestring("new"); parametersToBuffer(d.parameters, d.varargs); bodyToBuffer(d); } override void visit(DeleteDeclaration d) { if (stcToBuffer(buf, d.storage_class & ~STC.static_)) buf.writeByte(' '); buf.writestring("delete"); parametersToBuffer(d.parameters, 0); bodyToBuffer(d); } //////////////////////////////////////////////////////////////////////////// override void visit(ErrorInitializer iz) { buf.writestring("__error__"); } override void visit(VoidInitializer iz) { buf.writestring("void"); } override void visit(StructInitializer si) { //printf("StructInitializer::toCBuffer()\n"); buf.writeByte('{'); foreach (i, const id; si.field) { if (i) buf.writestring(", "); if (id) { buf.writestring(id.toChars()); buf.writeByte(':'); } if (auto iz = si.value[i]) iz.accept(this); } buf.writeByte('}'); } override void visit(ArrayInitializer ai) { buf.writeByte('['); foreach (i, ex; ai.index) { if (i) buf.writestring(", "); if (ex) { ex.accept(this); buf.writeByte(':'); } if (auto iz = ai.value[i]) iz.accept(this); } buf.writeByte(']'); } override void visit(ExpInitializer ei) { ei.exp.accept(this); } //////////////////////////////////////////////////////////////////////////// /************************************************** * Write out argument list to buf. */ void argsToBuffer(Expressions* expressions, Expression basis = null) { if (!expressions || !expressions.dim) return; version (all) { foreach (i, el; *expressions) { if (i) buf.writestring(", "); if (!el) el = basis; if (el) expToBuffer(el, PREC.assign); } } 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); } foreach (i, el; *expressions) { if (el) { if (basis) { buf.writestring(", "); buf.print(i); buf.writestring(": "); } else if (i) buf.writestring(", "); expToBuffer(el, PREC.assign); } } } } void sizeToBuffer(Expression e) { if (e.type == Type.tsize_t) { Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e); ex = ex.optimize(WANTvalue); dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1; if (cast(sinteger_t)uval >= 0) { dinteger_t sizemax; if (Target.ptrsize == 4) sizemax = 0xFFFFFFFFU; else if (Target.ptrsize == 8) sizemax = 0xFFFFFFFFFFFFFFFFUL; else assert(0); if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) { buf.print(uval); return; } } } expToBuffer(e, PREC.assign); } /************************************************** * Write expression out to buf, but wrap it * in ( ) if its precedence is less than pr. */ void expToBuffer(Expression e, PREC pr) { debug { if (precedence[e.op] == PREC.zero) printf("precedence not defined for token '%s'\n", Token.toChars(e.op)); } assert(precedence[e.op] != PREC.zero); assert(pr != PREC.zero); /* Despite precedence, we don't allow a= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) { buf.writeByte('('); e.accept(this); buf.writeByte(')'); } else e.accept(this); } override void visit(Expression e) { buf.writestring(Token.toString(e.op)); } override void visit(IntegerExp e) { dinteger_t v = e.toInteger(); if (e.type) { Type t = e.type; L1: switch (t.ty) { case Tenum: { TypeEnum te = cast(TypeEnum)t; if (hgs.fullDump) { auto sym = te.sym; if (inEnumDecl != sym) foreach(i;0 .. sym.members.dim) { EnumMember em = cast(EnumMember) (*sym.members)[i]; if (em.value.toInteger == v) { buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); return ; } } //assert(0, "We could not find the EmumMember");// for some reason it won't append char* ~ e.toChars() ~ " in " ~ sym.toChars() ); } buf.printf("cast(%s)", te.sym.toChars()); t = te.sym.memtype; goto L1; } case Twchar: // BUG: need to cast(wchar) case Tdchar: // BUG: need to cast(dchar) if (cast(uinteger_t)v > 0xFF) { buf.printf("'\\U%08x'", v); break; } goto case; case Tchar: { size_t o = buf.offset; if (v == '\'') buf.writestring("'\\''"); else if (isprint(cast(int)v) && v != '\\') buf.printf("'%c'", cast(int)v); else buf.printf("'\\x%02x'", cast(int)v); if (hgs.ddoc) escapeDdocString(buf, o); break; } case Tint8: buf.writestring("cast(byte)"); goto L2; case Tint16: buf.writestring("cast(short)"); goto L2; case Tint32: L2: buf.printf("%d", cast(int)v); break; case Tuns8: buf.writestring("cast(ubyte)"); goto L3; case Tuns16: buf.writestring("cast(ushort)"); goto L3; case Tuns32: L3: buf.printf("%uu", cast(uint)v); break; case Tint64: buf.printf("%lldL", v); break; case Tuns64: L4: buf.printf("%lluLU", v); break; case Tbool: buf.writestring(v ? "true" : "false"); break; case Tpointer: buf.writestring("cast("); buf.writestring(t.toChars()); buf.writeByte(')'); if (Target.ptrsize == 4) goto L3; else if (Target.ptrsize == 8) goto L4; else assert(0); default: /* This can happen if errors, such as * the type is painted on like in fromConstInitializer(). */ if (!global.errors) { assert(0); } break; } } else if (v & 0x8000000000000000L) buf.printf("0x%llx", v); else buf.print(v); } override void visit(ErrorExp e) { buf.writestring("__error"); } override void visit(VoidInitExp e) { 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. */ const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; char[BUFFER_LEN] buffer; CTFloat.sprint(buffer.ptr, 'g', value); assert(strlen(buffer.ptr) < BUFFER_LEN); if (hgs.hdrgen) { real_t r = CTFloat.parse(buffer.ptr); if (r != value) // if exact duplication CTFloat.sprint(buffer.ptr, 'a', value); } buf.writestring(buffer.ptr); if (type) { Type t = type.toBasetype(); switch (t.ty) { case Tfloat32: case Timaginary32: case Tcomplex32: buf.writeByte('F'); break; case Tfloat80: case Timaginary80: case Tcomplex80: buf.writeByte('L'); break; default: break; } if (t.isimaginary()) buf.writeByte('i'); } } override void visit(RealExp e) { floatToBuffer(e.type, e.value); } override void visit(ComplexExp e) { /* Print as: * (re+imi) */ buf.writeByte('('); floatToBuffer(e.type, creall(e.value)); buf.writeByte('+'); floatToBuffer(e.type, cimagl(e.value)); buf.writestring("i)"); } override void visit(IdentifierExp e) { if (hgs.hdrgen || hgs.ddoc) buf.writestring(e.ident.toHChars2()); else buf.writestring(e.ident.toString()); } override void visit(DsymbolExp e) { buf.writestring(e.s.toChars()); } override void visit(ThisExp e) { buf.writestring("this"); } override void visit(SuperExp e) { buf.writestring("super"); } override void visit(NullExp e) { buf.writestring("null"); } override void visit(StringExp e) { buf.writeByte('"'); size_t o = buf.offset; for (size_t i = 0; i < e.len; i++) { uint c = e.charAt(i); switch (c) { case '"': case '\\': buf.writeByte('\\'); goto default; default: if (c <= 0xFF) { if (c <= 0x7F && isprint(c)) buf.writeByte(c); else buf.printf("\\x%02x", c); } else if (c <= 0xFFFF) buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); else buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); break; } } if (hgs.ddoc) escapeDdocString(buf, o); buf.writeByte('"'); if (e.postfix) buf.writeByte(e.postfix); } override void visit(ArrayLiteralExp e) { buf.writeByte('['); argsToBuffer(e.elements, e.basis); buf.writeByte(']'); } override void visit(AssocArrayLiteralExp e) { buf.writeByte('['); foreach (i, key; *e.keys) { if (i) buf.writestring(", "); expToBuffer(key, PREC.assign); buf.writeByte(':'); auto value = (*e.values)[i]; expToBuffer(value, PREC.assign); } buf.writeByte(']'); } override void visit(StructLiteralExp e) { buf.writestring(e.sd.toChars()); buf.writeByte('('); // CTFE can generate struct literals that contain an AddrExp pointing // to themselves, need to avoid infinite recursion: // struct S { this(int){ this.s = &this; } S* s; } // const foo = new S(0); if (e.stageflags & stageToCBuffer) buf.writestring(""); else { int old = e.stageflags; e.stageflags |= stageToCBuffer; argsToBuffer(e.elements); e.stageflags = old; } buf.writeByte(')'); } override void visit(TypeExp e) { typeToBuffer(e.type, null); } override void visit(ScopeExp e) { if (e.sds.isTemplateInstance()) { e.sds.accept(this); } else if (hgs !is null && hgs.ddoc) { // fixes bug 6491 Module m = e.sds.isModule(); if (m) buf.writestring(m.md.toChars()); else buf.writestring(e.sds.toChars()); } else { buf.writestring(e.sds.kind()); buf.writeByte(' '); buf.writestring(e.sds.toChars()); } } override void visit(TemplateExp e) { buf.writestring(e.td.toChars()); } override void visit(NewExp e) { if (e.thisexp) { expToBuffer(e.thisexp, PREC.primary); buf.writeByte('.'); } buf.writestring("new "); if (e.newargs && e.newargs.dim) { buf.writeByte('('); argsToBuffer(e.newargs); buf.writeByte(')'); } typeToBuffer(e.newtype, null); if (e.arguments && e.arguments.dim) { buf.writeByte('('); argsToBuffer(e.arguments); buf.writeByte(')'); } } override void visit(NewAnonClassExp e) { if (e.thisexp) { expToBuffer(e.thisexp, PREC.primary); buf.writeByte('.'); } buf.writestring("new"); if (e.newargs && e.newargs.dim) { buf.writeByte('('); argsToBuffer(e.newargs); buf.writeByte(')'); } buf.writestring(" class "); if (e.arguments && e.arguments.dim) { buf.writeByte('('); argsToBuffer(e.arguments); buf.writeByte(')'); } if (e.cd) e.cd.accept(this); } override void visit(SymOffExp e) { if (e.offset) buf.printf("(& %s+%u)", e.var.toChars(), e.offset); else if (e.var.isTypeInfoDeclaration()) buf.writestring(e.var.toChars()); else buf.printf("& %s", e.var.toChars()); } override void visit(VarExp e) { buf.writestring(e.var.toChars()); } override void visit(OverExp e) { buf.writestring(e.vars.ident.toString()); } override void visit(TupleExp e) { if (e.e0) { buf.writeByte('('); e.e0.accept(this); buf.writestring(", tuple("); argsToBuffer(e.exps); buf.writestring("))"); } else { buf.writestring("tuple("); argsToBuffer(e.exps); buf.writeByte(')'); } } override void visit(FuncExp e) { e.fd.accept(this); //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. */ if (auto v = e.declaration.isVarDeclaration()) { // For debugging use: // - Avoid printing newline. // - Intentionally use the format (Type var;) // which isn't correct as regular D code. buf.writeByte('('); visitVarDecl(v, false); buf.writeByte(';'); buf.writeByte(')'); } else e.declaration.accept(this); } override void visit(TypeidExp e) { buf.writestring("typeid("); objectToBuffer(e.obj); buf.writeByte(')'); } override void visit(TraitsExp e) { buf.writestring("__traits("); buf.writestring(e.ident.toString()); if (e.args) { foreach (arg; *e.args) { buf.writestring(", "); objectToBuffer(arg); } } buf.writeByte(')'); } override void visit(HaltExp e) { buf.writestring("halt"); } override void visit(IsExp e) { buf.writestring("is("); typeToBuffer(e.targ, e.id); if (e.tok2 != TOK.reserved) { buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); } else if (e.tspec) { if (e.tok == TOK.colon) buf.writestring(" : "); else buf.writestring(" == "); typeToBuffer(e.tspec, null); } if (e.parameters && e.parameters.dim) { buf.writestring(", "); visitTemplateParameters(e.parameters); } buf.writeByte(')'); } override void visit(UnaExp e) { buf.writestring(Token.toString(e.op)); expToBuffer(e.e1, precedence[e.op]); } override void visit(BinExp e) { expToBuffer(e.e1, precedence[e.op]); buf.writeByte(' '); buf.writestring(Token.toString(e.op)); buf.writeByte(' '); expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1)); } override void visit(CompileExp e) { buf.writestring("mixin("); argsToBuffer(e.exps, null); buf.writeByte(')'); } override void visit(ImportExp e) { buf.writestring("import("); expToBuffer(e.e1, PREC.assign); buf.writeByte(')'); } override void visit(AssertExp e) { buf.writestring("assert("); expToBuffer(e.e1, PREC.assign); if (e.msg) { buf.writestring(", "); expToBuffer(e.msg, PREC.assign); } buf.writeByte(')'); } override void visit(DotIdExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); buf.writestring(e.ident.toString()); } override void visit(DotTemplateExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); buf.writestring(e.td.toChars()); } override void visit(DotVarExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); buf.writestring(e.var.toChars()); } override void visit(DotTemplateInstanceExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); e.ti.accept(this); } override void visit(DelegateExp e) { buf.writeByte('&'); if (!e.func.isNested()) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); } buf.writestring(e.func.toChars()); } override void visit(DotTypeExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); buf.writestring(e.sym.toChars()); } override void visit(CallExp e) { 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 */ e.e1.accept(this); } else expToBuffer(e.e1, precedence[e.op]); buf.writeByte('('); argsToBuffer(e.arguments); buf.writeByte(')'); } override void visit(PtrExp e) { buf.writeByte('*'); expToBuffer(e.e1, precedence[e.op]); } override void visit(DeleteExp e) { buf.writestring("delete "); expToBuffer(e.e1, precedence[e.op]); } override void visit(CastExp e) { buf.writestring("cast("); if (e.to) typeToBuffer(e.to, null); else { MODtoBuffer(buf, e.mod); } buf.writeByte(')'); expToBuffer(e.e1, precedence[e.op]); } override void visit(VectorExp e) { buf.writestring("cast("); typeToBuffer(e.to, null); buf.writeByte(')'); expToBuffer(e.e1, precedence[e.op]); } override void visit(SliceExp e) { expToBuffer(e.e1, precedence[e.op]); buf.writeByte('['); if (e.upr || e.lwr) { if (e.lwr) sizeToBuffer(e.lwr); else buf.writeByte('0'); buf.writestring(".."); if (e.upr) sizeToBuffer(e.upr); else buf.writeByte('$'); } buf.writeByte(']'); } override void visit(ArrayLengthExp e) { expToBuffer(e.e1, PREC.primary); buf.writestring(".length"); } override void visit(IntervalExp e) { expToBuffer(e.lwr, PREC.assign); buf.writestring(".."); expToBuffer(e.upr, PREC.assign); } override void visit(DelegatePtrExp e) { expToBuffer(e.e1, PREC.primary); buf.writestring(".ptr"); } override void visit(DelegateFuncptrExp e) { expToBuffer(e.e1, PREC.primary); buf.writestring(".funcptr"); } override void visit(ArrayExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('['); argsToBuffer(e.arguments); buf.writeByte(']'); } override void visit(DotExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('.'); expToBuffer(e.e2, PREC.primary); } override void visit(IndexExp e) { expToBuffer(e.e1, PREC.primary); buf.writeByte('['); sizeToBuffer(e.e2); buf.writeByte(']'); } override void visit(PostExp e) { expToBuffer(e.e1, precedence[e.op]); buf.writestring(Token.toString(e.op)); } override void visit(PreExp e) { buf.writestring(Token.toString(e.op)); expToBuffer(e.e1, precedence[e.op]); } override void visit(RemoveExp e) { expToBuffer(e.e1, PREC.primary); buf.writestring(".remove("); expToBuffer(e.e2, PREC.assign); buf.writeByte(')'); } override void visit(CondExp e) { expToBuffer(e.econd, PREC.oror); buf.writestring(" ? "); expToBuffer(e.e1, PREC.expr); buf.writestring(" : "); expToBuffer(e.e2, PREC.cond); } override void visit(DefaultInitExp e) { buf.writestring(Token.toString(e.subop)); } override void visit(ClassReferenceExp e) { buf.writestring(e.value.toChars()); } //////////////////////////////////////////////////////////////////////////// override void visit(TemplateTypeParameter tp) { buf.writestring(tp.ident.toString()); if (tp.specType) { buf.writestring(" : "); typeToBuffer(tp.specType, null); } if (tp.defaultType) { buf.writestring(" = "); typeToBuffer(tp.defaultType, null); } } override void visit(TemplateThisParameter tp) { buf.writestring("this "); visit(cast(TemplateTypeParameter)tp); } override void visit(TemplateAliasParameter tp) { buf.writestring("alias "); if (tp.specType) typeToBuffer(tp.specType, tp.ident); else buf.writestring(tp.ident.toString()); if (tp.specAlias) { buf.writestring(" : "); objectToBuffer(tp.specAlias); } if (tp.defaultAlias) { buf.writestring(" = "); objectToBuffer(tp.defaultAlias); } } override void visit(TemplateValueParameter tp) { typeToBuffer(tp.valType, tp.ident); if (tp.specValue) { buf.writestring(" : "); tp.specValue.accept(this); } if (tp.defaultValue) { buf.writestring(" = "); tp.defaultValue.accept(this); } } override void visit(TemplateTupleParameter tp) { buf.writestring(tp.ident.toString()); buf.writestring("..."); } //////////////////////////////////////////////////////////////////////////// override void visit(DebugCondition c) { buf.writestring("debug ("); if (c.ident) buf.writestring(c.ident.toString()); else buf.print(c.level); buf.writeByte(')'); } override void visit(VersionCondition c) { buf.writestring("version ("); if (c.ident) buf.writestring(c.ident.toString()); else buf.print(c.level); buf.writeByte(')'); } override void visit(StaticIfCondition c) { buf.writestring("static if ("); c.exp.accept(this); buf.writeByte(')'); } //////////////////////////////////////////////////////////////////////////// override void visit(Parameter p) { if (p.userAttribDecl) { buf.writestring("@"); scope(exit) buf.writestring(" "); bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call; if (isAnonymous) buf.writestring("("); argsToBuffer(p.userAttribDecl.atts); if (isAnonymous) buf.writestring(")"); } if (p.storageClass & STC.auto_) buf.writestring("auto "); if (p.storageClass & STC.return_) buf.writestring("return "); if (p.storageClass & STC.out_) buf.writestring("out "); else if (p.storageClass & STC.ref_) buf.writestring("ref "); else if (p.storageClass & STC.in_) buf.writestring("in "); else if (p.storageClass & STC.lazy_) buf.writestring("lazy "); else if (p.storageClass & STC.alias_) buf.writestring("alias "); StorageClass stc = p.storageClass; if (p.type && p.type.mod & MODFlags.shared_) stc &= ~STC.shared_; if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.scope_ | STC.scopeinferred))) buf.writeByte(' '); if (p.storageClass & STC.alias_) { if (p.ident) buf.writestring(p.ident.toString()); } else if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident.toString().length > 3 && strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) { // print parameter name, instead of undetermined type parameter buf.writestring(p.ident.toString()); } else typeToBuffer(p.type, p.ident); if (p.defaultArg) { buf.writestring(" = "); p.defaultArg.accept(this); } } void parametersToBuffer(Parameters* parameters, int varargs) { buf.writeByte('('); if (parameters) { size_t dim = Parameter.dim(parameters); foreach (i; 0 .. dim) { if (i) buf.writestring(", "); Parameter fparam = Parameter.getNth(parameters, i); fparam.accept(this); } if (varargs) { if (parameters.dim && varargs == 1) buf.writestring(", "); buf.writestring("..."); } } buf.writeByte(')'); } override void visit(Module m) { if (m.md) { if (m.userAttribDecl) { buf.writestring("@("); argsToBuffer(m.userAttribDecl.atts); buf.writeByte(')'); buf.writenl(); } if (m.md.isdeprecated) { if (m.md.msg) { buf.writestring("deprecated("); m.md.msg.accept(this); buf.writestring(") "); } else buf.writestring("deprecated "); } buf.writestring("module "); buf.writestring(m.md.toChars()); buf.writeByte(';'); buf.writenl(); } foreach (s; *m.members) { s.accept(this); } } } void toCBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); s.accept(v); } void toCBuffer(Type t, OutBuffer* buf, Identifier ident, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); v.typeToBuffer(t, ident); } void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); s.accept(v); } // used from TemplateInstance::toChars() and TemplateMixin::toChars() void toCBufferInstance(TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false) { HdrGenState hgs; hgs.fullQual = qualifyTypes; scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs); v.visit(ti); } void toCBuffer(Initializer iz, OutBuffer* buf, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); iz.accept(v); } bool stcToBuffer(OutBuffer* buf, StorageClass stc) { bool result = false; if ((stc & (STC.return_ | STC.scope_)) == (STC.return_ | STC.scope_)) stc &= ~STC.scope_; if (stc & STC.scopeinferred) stc &= ~(STC.scope_ | STC.scopeinferred); while (stc) { const(char)* p = stcToChars(stc); if (!p) // there's no visible storage classes break; if (!result) result = true; else buf.writeByte(' '); buf.writestring(p); } return result; } /************************************************* * Pick off one of the storage classes from stc, * and return a pointer to a string representation of it. * stc is reduced by the one picked. */ extern (C++) const(char)* stcToChars(ref StorageClass stc) { struct SCstring { StorageClass stc; TOK tok; const(char)* id; } __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) ]; for (int i = 0; table[i].stc; i++) { StorageClass tbl = table[i].stc; assert(tbl & STCStorageClass); if (stc & tbl) { stc &= ~tbl; if (tbl == STC.tls) // TOKtls was removed return "__thread"; TOK tok = table[i].tok; if (tok == TOK.at) return table[i].id; else return Token.toChars(tok); } } //printf("stc = %llx\n", stc); return null; } /** * Returns: * a human readable representation of `stc` */ extern (D) const(char)[] stcToString(ref StorageClass stc) { return stcToChars(stc).toDString; } extern (C++) void trustToBuffer(OutBuffer* buf, TRUST trust) { const(char)* p = trustToChars(trust); if (p) buf.writestring(p); } /** * Returns: * a human readable representation of `trust`, * which is the token `trust` corresponds to */ extern (C++) const(char)* trustToChars(TRUST trust) { /// Works because we return a literal return trustToString(trust).ptr; } /// Ditto extern (D) string trustToString(TRUST trust) { final switch (trust) { case TRUST.default_: return null; case TRUST.system: return "@system"; case TRUST.trusted: return "@trusted"; case TRUST.safe: return "@safe"; } } private void linkageToBuffer(OutBuffer* buf, LINK linkage) { const(char)* p = linkageToChars(linkage); if (p) { buf.writestring("extern ("); buf.writestring(p); buf.writeByte(')'); } } extern (C++) const(char)* linkageToChars(LINK linkage) { final switch (linkage) { case LINK.default_: return null; case LINK.d: return "D"; case LINK.c: return "C"; case LINK.cpp: return "C++"; case LINK.windows: return "Windows"; case LINK.pascal: return "Pascal"; case LINK.objc: return "Objective-C"; case LINK.system: return "System"; } } extern (C++) void protectionToBuffer(OutBuffer* buf, Prot prot) { const(char)* p = protectionToChars(prot.kind); if (p) buf.writestring(p); if (prot.kind == Prot.Kind.package_ && prot.pkg) { buf.writeByte('('); buf.writestring(prot.pkg.toPrettyChars(true)); buf.writeByte(')'); } } /** * Returns: * a human readable representation of `kind` */ extern (C++) const(char)* protectionToChars(Prot.Kind kind) { // Null terminated because we return a literal return protectionToString(kind).ptr; } /// Ditto extern (D) string protectionToString(Prot.Kind kind) { final switch (kind) { case Prot.Kind.undefined: return null; case Prot.Kind.none: return "none"; case Prot.Kind.private_: return "private"; case Prot.Kind.package_: return "package"; case Prot.Kind.protected_: return "protected"; case Prot.Kind.public_: return "public"; case Prot.Kind.export_: return "export"; } } // Print the full function signature with correct ident, attributes and template args void functionToBufferFull(TypeFunction tf, OutBuffer* buf, Identifier ident, HdrGenState* hgs, TemplateDeclaration td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); v.visitFuncIdentWithPrefix(tf, ident, td); } // ident is inserted before the argument list and will be "function" or "delegate" for a type void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident) { HdrGenState hgs; scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs); v.visitFuncIdentWithPostfix(tf, ident); } void toCBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); e.accept(v); } /************************************************** * Write out argument types to buf. */ void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) { if (!arguments || !arguments.dim) return; HdrGenState hgs; scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs); foreach (i, arg; *arguments) { if (i) buf.writestring(", "); v.typeToBuffer(arg.type, null); } } void toCBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) { scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); tp.accept(v); } void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) { if (!objects || !objects.dim) return; HdrGenState hgs; scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, &hgs); foreach (i, o; *objects) { if (i) buf.writestring(", "); v.objectToBuffer(o); } } /************************************************************* * Pretty print function parameters. * Params: * parameters = parameters to print, such as TypeFunction.parameters. * varargs = kind of varargs, see TypeFunction.varargs. * Returns: Null-terminated string representing parameters. */ extern (C++) const(char)* parametersTypeToChars(Parameters* parameters, int varargs) { OutBuffer buf; HdrGenState hgs; scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); v.parametersToBuffer(parameters, varargs); return buf.extractString(); } /************************************************************* * 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) { OutBuffer buf; HdrGenState hgs; hgs.fullQual = fullQual; scope PrettyPrintVisitor v = new PrettyPrintVisitor(&buf, &hgs); parameter.accept(v); if (tf.varargs == 2 && parameter == Parameter.getNth(tf.parameters, tf.parameters.dim - 1)) { buf.writestring("..."); } return buf.extractString(); } ================================================ FILE: gcc/d/dmd/hdrgen.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Dave Fladebo * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.h */ #pragma once #include "globals.h" #include "dsymbol.h" #include "mtype.h" class Module; void genhdrfile(Module *m); void moduleToBuffer(OutBuffer *buf, Module *m); const char *parametersTypeToChars(Parameters *parameters, int varargs); const char *stcToChars(StorageClass& stc); void trustToBuffer(OutBuffer *buf, TRUST trust); const char *trustToChars(TRUST trust); const char *linkageToChars(LINK linkage); void protectionToBuffer(OutBuffer *buf, Prot prot); const char *protectionToChars(Prot::Kind kind); ================================================ FILE: gcc/d/dmd/iasm.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright (C) 2018 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/iasm.d, _iasm.d) * Documentation: https://dlang.org/phobos/dmd_iasm.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasm.d */ /* Inline assembler for the D programming language compiler */ module dmd.iasm; import dmd.dscope; import dmd.func; import dmd.statement; version (MARS) { import dmd.iasmdmd; } else version (IN_GCC) { import dmd.iasmgcc; } /************************ AsmStatement ***************************************/ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc) { //printf("AsmStatement.semantic()\n"); FuncDeclaration fd = sc.parent.isFuncDeclaration(); assert(fd); if (!s.tokens) return null; // Assume assembler code takes care of setting the return value sc.func.hasReturnExp |= 8; version (MARS) { auto ias = new InlineAsmStatement(s.loc, s.tokens); return inlineAsmSemantic(ias, sc); } else version (IN_GCC) { auto eas = new GccAsmStatement(s.loc, s.tokens); return gccAsmSemantic(eas, sc); } else { s.error("D inline assembler statements are not supported"); return new ErrorStatement(); } } ================================================ FILE: gcc/d/dmd/iasmgcc.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright (C) 2018 by The D Language Foundation, All Rights Reserved * Authors: Iain Buclaw * 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/iasmgcc.d, _iasmgcc.d) * Documentation: https://dlang.org/phobos/dmd_iasmgcc.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasmgcc.d */ /* Inline assembler for the GCC D compiler. */ module dmd.iasmgcc; import core.stdc.string; import dmd.arraytypes; import dmd.astcodegen; import dmd.dscope; import dmd.expression; import dmd.expressionsem; import dmd.identifier; import dmd.globals; import dmd.parse; import dmd.tokens; import dmd.statement; import dmd.statementsem; private: /*********************************** * Parse list of extended asm input or output operands. * Grammar: * | Operands: * | SymbolicName(opt) StringLiteral AssignExpression * | SymbolicName(opt) StringLiteral AssignExpression , Operands * | * | SymbolicName: * | [ Identifier ] * Params: * p = parser state * s = asm statement to parse * Returns: * number of operands added to the gcc asm statement */ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) { int numargs = 0; while (1) { Expression arg; Identifier name; Expression constraint; switch (p.token.value) { case TOK.semicolon: case TOK.colon: case TOK.endOfFile: return numargs; case TOK.leftBracket: if (p.peekNext() == TOK.identifier) { p.nextToken(); name = p.token.ident; p.nextToken(); } else { p.error(s.loc, "expected identifier after `[`"); goto Lerror; } p.check(TOK.rightBracket); goto case; case TOK.string_: constraint = p.parsePrimaryExp(); arg = p.parseAssignExp(); if (!s.args) { s.names = new Identifiers(); s.constraints = new Expressions(); s.args = new Expressions(); } s.names.push(name); s.args.push(arg); s.constraints.push(constraint); numargs++; if (p.token.value == TOK.comma) p.nextToken(); break; default: p.error("expected constant string constraint for operand, not `%s`", p.token.toChars()); goto Lerror; } } Lerror: while (p.token.value != TOK.rightCurly && p.token.value != TOK.semicolon && p.token.value != TOK.endOfFile) p.nextToken(); return numargs; } /*********************************** * Parse list of extended asm clobbers. * Grammar: * | Clobbers: * | StringLiteral * | StringLiteral , Clobbers * Params: * p = parser state * Returns: * array of parsed clobber expressions */ Expressions *parseExtAsmClobbers(Parser)(Parser p) { Expressions *clobbers; while (1) { Expression clobber; switch (p.token.value) { case TOK.semicolon: case TOK.colon: case TOK.endOfFile: return clobbers; case TOK.string_: clobber = p.parsePrimaryExp(); if (!clobbers) clobbers = new Expressions(); clobbers.push(clobber); if (p.token.value == TOK.comma) p.nextToken(); break; default: p.error("expected constant string constraint for clobber name, not `%s`", p.token.toChars()); goto Lerror; } } Lerror: while (p.token.value != TOK.rightCurly && p.token.value != TOK.semicolon && p.token.value != TOK.endOfFile) p.nextToken(); return clobbers; } /*********************************** * Parse list of extended asm goto labels. * Grammar: * | GotoLabels: * | Identifier * | Identifier , GotoLabels * Params: * p = parser state * Returns: * array of parsed goto labels */ Identifiers *parseExtAsmGotoLabels(Parser)(Parser p) { Identifiers *labels; while (1) { switch (p.token.value) { case TOK.semicolon: case TOK.endOfFile: return labels; case TOK.identifier: if (!labels) labels = new Identifiers(); labels.push(p.token.ident); if (p.nextToken() == TOK.comma) p.nextToken(); break; default: p.error("expected identifier for goto label name, not `%s`", p.token.toChars()); goto Lerror; } } Lerror: while (p.token.value != TOK.rightCurly && p.token.value != TOK.semicolon && p.token.value != TOK.endOfFile) p.nextToken(); return labels; } /*********************************** * Parse a gcc asm statement. * There are three forms of inline asm statements, basic, extended, and goto. * Grammar: * | AsmInstruction: * | BasicAsmInstruction * | ExtAsmInstruction * | GotoAsmInstruction * | * | BasicAsmInstruction: * | Expression * | * | ExtAsmInstruction: * | Expression : Operands(opt) : Operands(opt) : Clobbers(opt) * | * | GotoAsmInstruction: * | Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt) * Params: * p = parser state * s = asm statement to parse * Returns: * the parsed gcc asm statement */ GccAsmStatement parseGccAsm(Parser)(Parser p, GccAsmStatement s) { s.insn = p.parseExpression(); if (p.token.value == TOK.semicolon) goto Ldone; // No semicolon followed after instruction template, treat as extended asm. foreach (section; 0 .. 4) { p.check(TOK.colon); final switch (section) { case 0: s.outputargs = p.parseExtAsmOperands(s); break; case 1: p.parseExtAsmOperands(s); break; case 2: s.clobbers = p.parseExtAsmClobbers(); break; case 3: s.labels = p.parseExtAsmGotoLabels(); break; } if (p.token.value == TOK.semicolon) goto Ldone; } Ldone: p.check(TOK.semicolon); return s; } /*********************************** * Parse and run semantic analysis on a GccAsmStatement. * Params: * s = gcc asm statement being parsed * sc = the scope where the asm statement is located * Returns: * the completed gcc asm statement, or null if errors occurred */ public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { //printf("GccAsmStatement.semantic()\n"); scope p = new Parser!ASTCodegen(sc._module, ";", false); // Make a safe copy of the token list before parsing. Token *toklist = null; Token **ptoklist = &toklist; for (Token *token = s.tokens; token; token = token.next) { *ptoklist = Token.alloc(); memcpy(*ptoklist, token, Token.sizeof); ptoklist = &(*ptoklist).next; *ptoklist = null; } p.token = *toklist; // Parse the gcc asm statement. s = p.parseGccAsm(s); if (p.errors) return null; s.stc = sc.stc; // Fold the instruction template string. s.insn = semanticString(sc, s.insn, "asm instruction template"); if (s.labels && s.outputargs) s.error("extended asm statements with labels cannot have output constraints"); // Analyse all input and output operands. if (s.args) { foreach (i; 0 .. s.args.dim) { Expression e = (*s.args)[i]; e = e.expressionSemantic(sc); // Check argument is a valid lvalue/rvalue. if (i < s.outputargs) e = e.modifiableLvalue(sc, null); else if (e.checkValue()) e = new ErrorExp(); (*s.args)[i] = e; e = (*s.constraints)[i]; e = e.expressionSemantic(sc); assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1); (*s.constraints)[i] = e; } } // Analyse all clobbers. if (s.clobbers) { foreach (i; 0 .. s.clobbers.dim) { Expression e = (*s.clobbers)[i]; e = e.expressionSemantic(sc); assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1); (*s.clobbers)[i] = e; } } // Analyse all goto labels. if (s.labels) { foreach (i; 0 .. s.labels.dim) { Identifier ident = (*s.labels)[i]; GotoStatement gs = new GotoStatement(s.loc, ident); if (!s.gotos) s.gotos = new GotoStatements(); s.gotos.push(gs); gs.statementSemantic(sc); } } return s; } unittest { uint errors = global.startGagging(); // Immitates asmSemantic if version = IN_GCC. static int semanticAsm(Token* tokens) { scope gas = new GccAsmStatement(Loc.initial, tokens); scope p = new Parser!ASTCodegen(null, ";", false); p.token = *tokens; p.parseGccAsm(gas); return p.errors; } // Immitates parseStatement for asm statements. static void parseAsm(string input, bool expectError) { // Generate tokens from input test. scope p = new Parser!ASTCodegen(null, input, false); p.nextToken(); Token* toklist = null; Token** ptoklist = &toklist; p.check(TOK.asm_); p.check(TOK.leftCurly); while (1) { if (p.token.value == TOK.rightCurly || p.token.value == TOK.endOfFile) break; *ptoklist = Token.alloc(); memcpy(*ptoklist, &p.token, Token.sizeof); ptoklist = &(*ptoklist).next; *ptoklist = null; p.nextToken(); } p.check(TOK.rightCurly); auto res = semanticAsm(toklist); assert(res == 0 || expectError); } /// Assembly Tests, all should pass. /// Note: Frontend is not initialized, use only strings and identifiers. immutable string[] passAsmTests = [ // Basic asm statement q{ asm { "nop"; } }, // Extended asm statement q{ asm { "cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" input; } }, // Assembly with symbolic names q{ asm { "bts %[base], %[offset]" : [base] "+rm" *ptr, : [offset] "Ir" bitnum; } }, // Assembly with clobbers q{ asm { "cpuid" : "=a" a : "a" input : "ebx", "ecx", "edx"; } }, // Goto asm statement q{ asm { "jmp %l0" : : : : Ljmplabel; } }, // Any CTFE-able string allowed as instruction template. q{ asm { generateAsm(); } }, // Likewise mixins, permissible so long as the result is a string. q{ asm { mixin(`"repne"`, `~ "scasb"`); } }, ]; foreach (test; passAsmTests) parseAsm(test, false); global.endGagging(errors); } ================================================ FILE: gcc/d/dmd/id.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * This module contains the `Id` struct with a list of predefined symbols the * compiler knows about. * * Copyright: Copyright (C) 1999-2018 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. */ 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)); } } 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" }, { "_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" }, { "cpp_type_info_ptr", "__cpp_type_info_ptr" }, { "_assert", "assert" }, { "_unittest", "unittest" }, { "_body", "body" }, { "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" }, { "Class" }, { "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" }, { "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" }, { "__ArrayEq" }, { "__ArrayPostblit" }, { "__ArrayDtor" }, { "_d_delThrowable" }, { "dup" }, // 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" }, { "tls_get_addr", "___tls_get_addr" }, { "entrypoint", "__entrypoint" }, { "rt_init" }, { "__cmp" }, { "__equals"}, { "__switch"}, { "__switch_error"}, // varargs implementation { "va_start" }, // Builtin functions { "std" }, { "core" }, { "etc" }, { "attribute" }, { "math" }, { "sin" }, { "cos" }, { "tan" }, { "_sqrt", "sqrt" }, { "_pow", "pow" }, { "atan2" }, { "rndtol" }, { "expm1" }, { "exp2" }, { "yl2x" }, { "yl2xp1" }, { "fabs" }, { "bitop" }, { "bsf" }, { "bsr" }, { "bswap" }, // Traits { "isAbstractClass" }, { "isArithmetic" }, { "isAssociativeArray" }, { "isFinalClass" }, { "isTemplate" }, { "isPOD" }, { "isDeprecated" }, { "isDisabled" }, { "isFuture" }, { "isNested" }, { "isFloating" }, { "isIntegral" }, { "isScalar" }, { "isStaticArray" }, { "isUnsigned" }, { "isVirtualFunction" }, { "isVirtualMethod" }, { "isAbstractFunction" }, { "isFinalFunction" }, { "isOverrideFunction" }, { "isStaticFunction" }, { "isRef" }, { "isOut" }, { "isLazy" }, { "hasMember" }, { "identifier" }, { "getProtection" }, { "parent" }, { "getMember" }, { "getOverloads" }, { "getVirtualFunctions" }, { "getVirtualMethods" }, { "classInstanceSize" }, { "allMembers" }, { "derivedMembers" }, { "isSame" }, { "compiles" }, { "parameters" }, { "getAliasThis" }, { "getAttributes" }, { "getFunctionAttributes" }, { "getFunctionVariadicStyle" }, { "getParameterStorageClasses" }, { "getLinkage" }, { "getUnitTests" }, { "getVirtualIndex" }, { "getPointerBitmap" }, { "isReturnOnStack" }, { "isZeroInit" }, { "getTargetInfo" }, // For C++ mangling { "allocator" }, { "basic_string" }, { "basic_istream" }, { "basic_ostream" }, { "basic_iostream" }, { "char_traits" }, // Compiler recognized UDA's { "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() { 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) { string code; foreach (i, m ; msgtable) { if (i != 0) code ~= '\n'; code ~= dg(m); } return code; } // Used to generate the code for each identifier. string identifier(Msgtable m) { return "Identifier " ~ m.ident ~ ";"; } // Used to generate the code for each initializer. string initializer(Msgtable m) { return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`; } ================================================ FILE: gcc/d/dmd/id.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 2017-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/id.h */ #pragma once struct Id { static void initialize(); }; ================================================ FILE: gcc/d/dmd/identifier.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/identifier.d, _identifier.d) * Documentation: https://dlang.org/phobos/dmd_identifier.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/identifier.d */ module dmd.identifier; import core.stdc.ctype; import core.stdc.stdio; import core.stdc.string; import dmd.globals; import dmd.id; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.root.stringtable; import dmd.tokens; import dmd.utf; import dmd.utils; /*********************************************************** */ extern (C++) final class Identifier : RootObject { private: const int value; const char[] name; public: /** Construct an identifier from a D slice Note: Since `name` needs to be `\0` terminated for `toChars`, no slice overload is provided yet. Params: name = the identifier name There must be `'\0'` at `name[length]`. length = the length of `name`, excluding the terminating `'\0'` value = Identifier value (e.g. `Id.unitTest`) or `TOK.identifier` */ extern (D) this(const(char)* name, size_t length, int value) nothrow { //printf("Identifier('%s', %d)\n", name, value); this.name = name[0 .. length]; this.value = value; } extern (D) this(const(char)* name) nothrow { //printf("Identifier('%s', %d)\n", name, value); this(name, strlen(name), TOK.identifier); } static Identifier create(const(char)* name) nothrow { return new Identifier(name); } override bool equals(RootObject o) const { return this == o || name == o.toString(); } override int compare(RootObject o) const { return strncmp(name.ptr, o.toChars(), name.length + 1); } nothrow: override const(char)* toChars() const pure { return name.ptr; } extern (D) override const(char)[] toString() const pure { return name; } int getValue() const pure { return value; } const(char)* toHChars2() const { const(char)* p = null; if (this == Id.ctor) p = "this"; else if (this == Id.dtor) p = "~this"; else if (this == Id.unitTest) p = "unittest"; else if (this == Id.dollar) p = "$"; else if (this == Id.withSym) p = "with"; else if (this == Id.result) p = "result"; else if (this == Id.returnLabel) p = "return"; else { p = toChars(); if (*p == '_') { if (strncmp(p, "_staticCtor", 11) == 0) p = "static this"; else if (strncmp(p, "_staticDtor", 11) == 0) p = "static ~this"; else if (strncmp(p, "__invariant", 11) == 0) p = "invariant"; } } return p; } override DYNCAST dyncast() const { return DYNCAST.identifier; } private extern (D) __gshared StringTable stringtable; /** A secondary string table is used to guarantee that we generate unique identifiers per module. See generateIdWithLoc and issues https://issues.dlang.org/show_bug.cgi?id=16995 https://issues.dlang.org/show_bug.cgi?id=18097 https://issues.dlang.org/show_bug.cgi?id=18111 https://issues.dlang.org/show_bug.cgi?id=18880 https://issues.dlang.org/show_bug.cgi?id=18868 https://issues.dlang.org/show_bug.cgi?id=19058. */ private extern (D) __gshared StringTable fullPathStringTable; static Identifier generateId(const(char)* prefix) { __gshared size_t i; return generateId(prefix, ++i); } static Identifier generateId(const(char)* prefix, size_t i) { OutBuffer buf; buf.writestring(prefix); buf.print(i); return idPool(buf.peekSlice()); } /*************************************** * Generate deterministic named identifier based on a source location, * such that the name is consistent across multiple compilations. * A new unique name is generated. If the prefix+location is already in * the stringtable, an extra suffix is added (starting the count at "_1"). * * Params: * prefix = first part of the identifier name. * loc = source location to use in the identifier name. * Returns: * Identifier (inside Identifier.idPool) with deterministic name based * on the source location. */ extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc) { import dmd.root.filename: absPathThen; // see below for why we use absPathThen return loc.filename.toDString().absPathThen!((absPath) { // this block generates the "regular" identifier, i.e. if there are no collisions OutBuffer idBuf; idBuf.writestring(prefix); idBuf.writestring("_L"); idBuf.print(loc.linnum); idBuf.writestring("_C"); idBuf.print(loc.charnum); // This block generates an identifier that is prefixed by the absolute path of the file // being compiled. The reason this is necessary is that we want unique identifiers per // module, but the identifiers are generated before the module information is available. // To guarantee that each generated identifier is unique without modules, we make them // unique to each absolute file path. This also makes it consistent even if the files // are compiled separately. See issues: // https://issues.dlang.org/show_bug.cgi?id=16995 // https://issues.dlang.org/show_bug.cgi?id=18097 // https://issues.dlang.org/show_bug.cgi?id=18111 // https://issues.dlang.org/show_bug.cgi?id=18880 // https://issues.dlang.org/show_bug.cgi?id=18868 // https://issues.dlang.org/show_bug.cgi?id=19058. OutBuffer fullPathIdBuf; if (absPath) { // replace characters that demangle can't handle foreach (ref c; absPath) { // see dmd.dmangle.isValidMangling // Unfortunately importing it leads to either build failures or cyclic dependencies // between modules. if (c == '/' || c == '\\' || c == '.' || c == '?' || c == ':') c = '_'; } fullPathIdBuf.writestring(absPath); fullPathIdBuf.writestring("_"); } fullPathIdBuf.writestring(idBuf.peekSlice()); const fullPathIdLength = fullPathIdBuf.peekSlice().length; uint counter = 1; // loop until we can't find the absolute path ~ identifier, adding a counter suffix each time while (fullPathStringTable.lookup(fullPathIdBuf.peekSlice()) !is null) { // Strip the counter suffix if any fullPathIdBuf.setsize(fullPathIdLength); // Add new counter suffix fullPathIdBuf.writestring("_"); fullPathIdBuf.print(counter++); } // `idStartIndex` is the start of the "true" identifier. We don't actually use the absolute // file path in the generated identifier since the module system makes sure that the fully // qualified name is unique. const idStartIndex = fullPathIdLength - idBuf.peekSlice().length; // Remember the full path identifier to avoid possible future collisions fullPathStringTable.insert(fullPathIdBuf.peekSlice(), null); return idPool(fullPathIdBuf.peekSlice()[idStartIndex .. $]); }); } /******************************************** * Create an identifier in the string table. */ extern (D) static Identifier idPool(const(char)[] s) { return idPool(s.ptr, cast(uint)s.length); } static Identifier idPool(const(char)* s, uint len) { StringValue* sv = stringtable.update(s, len); Identifier id = cast(Identifier)sv.ptrvalue; if (!id) { id = new Identifier(sv.toDchars(), len, TOK.identifier); sv.ptrvalue = cast(char*)id; } return id; } extern (D) static Identifier idPool(const(char)* s, size_t len, int value) { auto sv = stringtable.insert(s, len, null); assert(sv); auto id = new Identifier(sv.toDchars(), len, value); sv.ptrvalue = cast(char*)id; return id; } /********************************** * Determine if string is a valid Identifier. * Returns: * 0 invalid */ static bool isValidIdentifier(const(char)* p) { if (!p || !*p) return false; return isValidIdentifier(p.toDString); } /********************************** * ditto */ extern (D) static bool isValidIdentifier(const(char)[] str) { const(char)* p = str.ptr; size_t len = str.length; size_t idx = 0; if (!p || len == 0) goto Linvalid; if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars goto Linvalid; while (idx < len) { dchar dc; const q = utf_decodeChar(p, len, idx, dc); if (q) goto Linvalid; if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) goto Linvalid; } return true; Linvalid: return false; } extern (D) static Identifier lookup(const(char)* s, size_t len) { auto sv = stringtable.lookup(s, len); if (!sv) return null; return cast(Identifier)sv.ptrvalue; } extern (D) static void initTable() { enum size = 28_000; stringtable._init(size); fullPathStringTable._init(size); } } ================================================ FILE: gcc/d/dmd/identifier.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/identifier.h */ #pragma once #include "root/dcompat.h" #include "root/root.h" class Identifier : public RootObject { private: int value; DArray string; public: static Identifier* create(const char *string); bool equals(RootObject *o); int compare(RootObject *o); const char *toChars(); int getValue() const; const char *toHChars2(); int dyncast() const; static Identifier *generateId(const char *prefix); static Identifier *generateId(const char *prefix, size_t i); static Identifier *idPool(const char *s, unsigned len); static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); } static bool isValidIdentifier(const char *p); }; ================================================ FILE: gcc/d/dmd/impcnvtab.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/impcnvtab.d, _impcnvtab.d) * Documentation: https://dlang.org/phobos/dmd_impcnvtab.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/impcnvtab.d */ module dmd.impcnvtab; import dmd.mtype; immutable ENUMTY[TMAX][TMAX] impcnvResult = impCnvTab.impcnvResultTab; immutable ENUMTY[TMAX][TMAX] impcnvType1 = impCnvTab.impcnvType1Tab; immutable ENUMTY[TMAX][TMAX] impcnvType2 = impCnvTab.impcnvType2Tab; private: struct ImpCnvTab { ENUMTY[TMAX][TMAX] impcnvResultTab; ENUMTY[TMAX][TMAX] impcnvType1Tab; ENUMTY[TMAX][TMAX] impcnvType2Tab; } enum ImpCnvTab impCnvTab = generateImpCnvTab(); ImpCnvTab generateImpCnvTab() { ImpCnvTab impCnvTab; // Set conversion tables foreach (i; 0 .. cast(size_t)TMAX) { foreach (j; 0 .. cast(size_t)TMAX) { impCnvTab.impcnvResultTab[i][j] = Terror; impCnvTab.impcnvType1Tab[i][j] = Terror; impCnvTab.impcnvType2Tab[i][j] = Terror; } } void X(ENUMTY t1, ENUMTY t2, ENUMTY nt1, ENUMTY nt2, ENUMTY rt) { impCnvTab.impcnvResultTab[t1][t2] = rt; impCnvTab.impcnvType1Tab[t1][t2] = nt1; impCnvTab.impcnvType2Tab[t1][t2] = nt2; } /* ======================= */ X(Tbool,Tbool, Tbool,Tbool, Tbool); X(Tbool,Tint8, Tint32,Tint32, Tint32); X(Tbool,Tuns8, Tint32,Tint32, Tint32); X(Tbool,Tint16, Tint32,Tint32, Tint32); X(Tbool,Tuns16, Tint32,Tint32, Tint32); X(Tbool,Tint32, Tint32,Tint32, Tint32); X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32); X(Tbool,Tint64, Tint64,Tint64, Tint64); X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64); X(Tbool,Tint128, Tint128,Tint128, Tint128); X(Tbool,Tuns128, Tuns128,Tuns128, Tuns128); X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tint8,Tint8, Tint32,Tint32, Tint32); X(Tint8,Tuns8, Tint32,Tint32, Tint32); X(Tint8,Tint16, Tint32,Tint32, Tint32); X(Tint8,Tuns16, Tint32,Tint32, Tint32); X(Tint8,Tint32, Tint32,Tint32, Tint32); X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32); X(Tint8,Tint64, Tint64,Tint64, Tint64); X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64); X(Tint8,Tint128, Tint128,Tint128, Tint128); X(Tint8,Tuns128, Tuns128,Tuns128, Tuns128); X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tuns8,Tuns8, Tint32,Tint32, Tint32); X(Tuns8,Tint16, Tint32,Tint32, Tint32); X(Tuns8,Tuns16, Tint32,Tint32, Tint32); X(Tuns8,Tint32, Tint32,Tint32, Tint32); X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32); X(Tuns8,Tint64, Tint64,Tint64, Tint64); X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64); X(Tuns8,Tint128, Tint128,Tint128, Tint128); X(Tuns8,Tuns128, Tuns128,Tuns128, Tuns128); X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tint16,Tint16, Tint32,Tint32, Tint32); X(Tint16,Tuns16, Tint32,Tint32, Tint32); X(Tint16,Tint32, Tint32,Tint32, Tint32); X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32); X(Tint16,Tint64, Tint64,Tint64, Tint64); X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64); X(Tint16,Tint128, Tint128,Tint128, Tint128); X(Tint16,Tuns128, Tuns128,Tuns128, Tuns128); X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tuns16,Tuns16, Tint32,Tint32, Tint32); X(Tuns16,Tint32, Tint32,Tint32, Tint32); X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32); X(Tuns16,Tint64, Tint64,Tint64, Tint64); X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64); X(Tuns16,Tint128, Tint128,Tint128, Tint128); X(Tuns16,Tuns128, Tuns128,Tuns128, Tuns128); X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tint32,Tint32, Tint32,Tint32, Tint32); X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32); X(Tint32,Tint64, Tint64,Tint64, Tint64); X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64); X(Tint32,Tint128, Tint128,Tint128, Tint128); X(Tint32,Tuns128, Tuns128,Tuns128, Tuns128); X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32); X(Tuns32,Tint64, Tint64,Tint64, Tint64); X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64); X(Tuns32,Tint128, Tint128,Tint128, Tint128); X(Tuns32,Tuns128, Tuns128,Tuns128, Tuns128); X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tint64,Tint64, Tint64,Tint64, Tint64); X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64); X(Tint64,Tint128, Tint128,Tint128, Tint128); X(Tint64,Tuns128, Tuns128,Tuns128, Tuns128); X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64); X(Tuns64,Tint128, Tint128,Tint128, Tint128); X(Tuns64,Tuns128, Tuns128,Tuns128, Tuns128); X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tint128,Tint128, Tint128,Tint128, Tint128); X(Tint128,Tuns128, Tuns128,Tuns128, Tuns128); X(Tint128,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tint128,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tint128,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tint128,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tint128,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tint128,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tint128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tint128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tint128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tuns128,Tuns128, Tuns128,Tuns128, Tuns128); X(Tuns128,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tuns128,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tuns128,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tuns128,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tuns128,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tuns128,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tuns128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tuns128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tuns128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32); X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32); X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32); X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64); X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64); X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64); X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64); X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64); X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80); X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80); X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80); X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80); X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80); X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80); X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80); /* ======================= */ X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32); X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64); X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80); X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32); X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64); X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80); /* ======================= */ X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64); X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80); X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64); X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64); X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80); /* ======================= */ X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80); X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80); X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80); X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32); X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64); X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64); X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); /* ======================= */ X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); foreach (i; 0 .. cast(size_t)TMAX) { foreach (j; 0 .. cast(size_t)TMAX) { if (impCnvTab.impcnvResultTab[i][j] == Terror) { impCnvTab.impcnvResultTab[i][j] = impCnvTab.impcnvResultTab[j][i]; impCnvTab.impcnvType1Tab[i][j] = impCnvTab.impcnvType2Tab[j][i]; impCnvTab.impcnvType2Tab[i][j] = impCnvTab.impcnvType1Tab[j][i]; } } } return impCnvTab; } ================================================ FILE: gcc/d/dmd/imphint.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/imphint.d, _imphint.d) * Documentation: https://dlang.org/phobos/dmd_imphint.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/imphint.d */ module dmd.imphint; import dmd.utils; /****************************************** * Looks for undefined identifier s to see * if it might be undefined because an import * was not specified. * Not meant to be a comprehensive list of names in each module, * just the most common ones. */ const(char)[] importHint(const(char)[] s) { if (auto entry = s in hints) return *entry; return null; } private immutable string[string] hints; shared static this() { // in alphabetic order hints = [ "calloc": "core.stdc.stdlib", "cos": "std.math", "fabs": "std.math", "free": "core.stdc.stdlib", "malloc": "core.stdc.stdlib", "printf": "core.stdc.stdio", "realloc": "core.stdc.stdlib", "sin": "std.math", "sqrt": "std.math", "writefln": "std.stdio", "writeln": "std.stdio", "__va_argsave_t": "core.vararg", ]; } unittest { assert(importHint("printf") !is null); assert(importHint("fabs") !is null); assert(importHint("xxxxx") is null); } ================================================ FILE: gcc/d/dmd/import.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/import.h */ #pragma once #include "dsymbol.h" class Identifier; struct Scope; class Module; class Package; class Import : public Dsymbol { public: /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; */ Identifiers *packages; // array of Identifier's representing packages Identifier *id; // module Identifier Identifier *aliasId; int isstatic; // !=0 if static import Prot protection; // Pairs of alias=name to bind into current namespace Identifiers names; Identifiers aliases; Module *mod; Package *pkg; // leftmost package/module AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs void addAlias(Identifier *name, Identifier *alias); const char *kind() const; Prot prot(); Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees void load(Scope *sc); void importAll(Scope *sc); Dsymbol *toAlias(); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope* sc); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); bool overloadInsert(Dsymbol *s); Import *isImport() { return this; } void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/init.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/init.d, _init.d) * Documentation: https://dlang.org/phobos/dmd_init.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d */ module dmd.init; import core.stdc.stdio; import core.checkedint; import dmd.arraytypes; import dmd.dsymbol; import dmd.expression; import dmd.globals; import dmd.hdrgen; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.tokens; import dmd.visitor; enum NeedInterpret : int { INITnointerpret, INITinterpret, } alias INITnointerpret = NeedInterpret.INITnointerpret; alias INITinterpret = NeedInterpret.INITinterpret; /************* * Discriminant for which kind of initializer */ enum InitKind : ubyte { void_, error, struct_, array, exp, } /*********************************************************** */ extern (C++) class Initializer : RootObject { Loc loc; InitKind kind; extern (D) this(const ref Loc loc, InitKind kind) { this.loc = loc; this.kind = kind; } override final const(char)* toChars() { OutBuffer buf; HdrGenState hgs; .toCBuffer(this, &buf, &hgs); return buf.extractString(); } final inout(ErrorInitializer) isErrorInitializer() inout pure { // Use void* cast to skip dynamic casting call return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null; } final inout(VoidInitializer) isVoidInitializer() inout pure { return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; } final inout(StructInitializer) isStructInitializer() inout pure { return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; } final inout(ArrayInitializer) isArrayInitializer() inout pure { return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null; } final inout(ExpInitializer) isExpInitializer() inout pure { return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null; } void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class VoidInitializer : Initializer { Type type; // type that this will initialize to extern (D) this(const ref Loc loc) { super(loc, InitKind.void_); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ErrorInitializer : Initializer { extern (D) this() { super(Loc.initial, InitKind.error); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class StructInitializer : Initializer { Identifiers field; // of Identifier *'s Initializers value; // parallel array of Initializer *'s extern (D) this(const ref Loc loc) { super(loc, InitKind.struct_); } void addInit(Identifier field, Initializer value) { //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); this.field.push(field); this.value.push(value); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ArrayInitializer : Initializer { Expressions index; // indices Initializers value; // of Initializer *'s uint dim; // length of array being initialized Type type; // type that array will be used to initialize bool sem; // true if semantic() is run extern (D) this(const ref Loc loc) { super(loc, InitKind.array); } void addInit(Expression index, Initializer value) { this.index.push(index); this.value.push(value); dim = 0; type = null; } bool isAssociativeArray() { for (size_t i = 0; i < value.dim; i++) { if (index[i]) return true; } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ExpInitializer : Initializer { bool expandTuples; Expression exp; extern (D) this(const ref Loc loc, Expression exp) { super(loc, InitKind.exp); this.exp = exp; } override void accept(Visitor v) { v.visit(this); } } version (all) { extern (C++) bool hasNonConstPointers(Expression e) { static bool checkArray(Expressions* elems) { foreach (e; *elems) { if (e && hasNonConstPointers(e)) return true; } return false; } if (e.type.ty == Terror) return false; if (e.op == TOK.null_) return false; if (e.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)e; return checkArray(se.elements); } if (e.op == TOK.arrayLiteral) { if (!e.type.nextOf().hasPointers()) return false; ArrayLiteralExp ae = cast(ArrayLiteralExp)e; return checkArray(ae.elements); } if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; if (ae.type.nextOf().hasPointers() && checkArray(ae.values)) return true; if ((cast(TypeAArray)ae.type).index.hasPointers()) return checkArray(ae.keys); return false; } if (e.op == TOK.address) { AddrExp ae = cast(AddrExp)e; if (ae.e1.op == TOK.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)ae.e1; if (!(se.stageflags & stageSearchPointers)) { int old = se.stageflags; se.stageflags |= stageSearchPointers; bool ret = checkArray(se.elements); se.stageflags = old; return ret; } else { return false; } } return true; } if (e.type.ty == Tpointer && e.type.nextOf().ty != Tfunction) { if (e.op == TOK.symbolOffset) // address of a global is OK return false; if (e.op == TOK.int64) // cast(void *)int is OK return false; if (e.op == TOK.string_) // "abc".ptr is OK return false; return true; } return false; } } /**************************************** * Copy the AST for Initializer. * Params: * inx = Initializer AST to copy * Returns: * the copy */ Initializer syntaxCopy(Initializer inx) { static Initializer copyStruct(StructInitializer vi) { auto si = new StructInitializer(vi.loc); assert(vi.field.dim == vi.value.dim); si.field.setDim(vi.field.dim); si.value.setDim(vi.value.dim); foreach (const i; 0 .. vi.field.dim) { si.field[i] = vi.field[i]; si.value[i] = vi.value[i].syntaxCopy(); } return si; } static Initializer copyArray(ArrayInitializer vi) { auto ai = new ArrayInitializer(vi.loc); assert(vi.index.dim == vi.value.dim); ai.index.setDim(vi.index.dim); ai.value.setDim(vi.value.dim); foreach (const i; 0 .. vi.value.dim) { ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null; ai.value[i] = vi.value[i].syntaxCopy(); } return ai; } final switch (inx.kind) { case InitKind.void_: return new VoidInitializer(inx.loc); case InitKind.error: return inx; case InitKind.struct_: return copyStruct(cast(StructInitializer)inx); case InitKind.array: return copyArray(cast(ArrayInitializer)inx); case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy()); } } ================================================ FILE: gcc/d/dmd/init.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/init.h */ #pragma once #include "globals.h" #include "arraytypes.h" #include "visitor.h" class Identifier; class Expression; class Type; class ErrorInitializer; class VoidInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; enum NeedInterpret { INITnointerpret, INITinterpret }; class Initializer : public RootObject { public: Loc loc; unsigned char kind; const char *toChars(); ErrorInitializer *isErrorInitializer(); VoidInitializer *isVoidInitializer(); StructInitializer *isStructInitializer(); ArrayInitializer *isArrayInitializer(); ExpInitializer *isExpInitializer(); virtual void accept(Visitor *v) { v->visit(this); } }; class VoidInitializer : public Initializer { public: Type *type; // type that this will initialize to void accept(Visitor *v) { v->visit(this); } }; class ErrorInitializer : public Initializer { public: void accept(Visitor *v) { v->visit(this); } }; class StructInitializer : public Initializer { public: Identifiers field; // of Identifier *'s Initializers value; // parallel array of Initializer *'s void addInit(Identifier *field, Initializer *value); void accept(Visitor *v) { v->visit(this); } }; class ArrayInitializer : public Initializer { public: Expressions index; // indices Initializers value; // of Initializer *'s unsigned dim; // length of array being initialized Type *type; // type that array will be used to initialize bool sem; // true if semantic() is run void addInit(Expression *index, Initializer *value); bool isAssociativeArray(); Expression *toAssocArrayLiteral(); void accept(Visitor *v) { v->visit(this); } }; class ExpInitializer : public Initializer { public: bool expandTuples; Expression *exp; void accept(Visitor *v) { v->visit(this); } }; Expression *initializerToExpression(Initializer *init, Type *t = NULL); Initializer *syntaxCopy(Initializer *inx); ================================================ FILE: gcc/d/dmd/initsem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/initsem.d, _initsem.d) * Documentation: https://dlang.org/phobos/dmd_initsem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/initsem.d */ module dmd.initsem; import core.stdc.stdio; import core.checkedint; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.dcast; import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.statement; import dmd.target; import dmd.tokens; import dmd.typesem; /******************************** * If possible, convert array initializer to associative array initializer. * * Params: * ai = array initializer to be converted * * Returns: * The converted associative array initializer or ErrorExp if `ai` * is not an associative array initializer. */ Expression toAssocArrayLiteral(ArrayInitializer ai) { Expression e; //printf("ArrayInitializer::toAssocArrayInitializer()\n"); //static int i; if (++i == 2) assert(0); const dim = ai.value.dim; auto keys = new Expressions(dim); auto values = new Expressions(dim); for (size_t i = 0; i < dim; i++) { e = ai.index[i]; if (!e) goto Lno; (*keys)[i] = e; Initializer iz = ai.value[i]; if (!iz) goto Lno; e = iz.initializerToExpression(); if (!e) goto Lno; (*values)[i] = e; } e = new AssocArrayLiteralExp(ai.loc, keys, values); return e; Lno: error(ai.loc, "not an associative array initializer"); return new ErrorExp(); } /****************************************** * Perform semantic analysis on init. * Params: * init = Initializer AST node * sc = context * t = type that the initializer needs to become * needInterpret = if CTFE needs to be run on this, * such as if it is the initializer for a const declaration * Returns: * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors * were encountered */ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, Type t, NeedInterpret needInterpret) { Initializer visitVoid(VoidInitializer i) { i.type = t; return i; } Initializer visitError(ErrorInitializer i) { return i; } Initializer visitStruct(StructInitializer i) { //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), toChars()); t = t.toBasetype(); if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct) t = t.nextOf().toBasetype(); if (t.ty == Tstruct) { StructDeclaration sd = (cast(TypeStruct)t).sym; if (sd.ctor) { error(i.loc, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd.kind(), sd.toChars(), sd.toChars()); return new ErrorInitializer(); } sd.size(i.loc); if (sd.sizeok != Sizeok.done) { return new ErrorInitializer(); } size_t nfields = sd.fields.dim - sd.isNested(); //expandTuples for non-identity arguments? auto elements = new Expressions(nfields); for (size_t j = 0; j < elements.dim; j++) (*elements)[j] = null; // Run semantic for explicitly given initializers // TODO: this part is slightly different from StructLiteralExp::semantic. bool errors = false; for (size_t fieldi = 0, j = 0; j < i.field.dim; j++) { if (Identifier id = i.field[j]) { Dsymbol s = sd.search(i.loc, id); if (!s) { s = sd.search_correct(id); Loc initLoc = i.value[j].loc; if (s) error(initLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars()); else error(initLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); return new ErrorInitializer(); } s = s.toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) { if (fieldi >= nfields) { error(i.loc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars()); return new ErrorInitializer(); } if (s == sd.fields[fieldi]) break; } } else if (fieldi >= nfields) { error(i.loc, "too many initializers for `%s`", sd.toChars()); return new ErrorInitializer(); } VarDeclaration vd = sd.fields[fieldi]; if ((*elements)[fieldi]) { error(i.loc, "duplicate initializer for field `%s`", vd.toChars()); errors = true; continue; } if (vd.type.hasPointers) { if ((t.alignment() < Target.ptrsize || (vd.offset & (Target.ptrsize - 1))) && sc.func && sc.func.setUnsafe()) { error(i.loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd.toChars(), vd.toChars()); errors = true; } } for (size_t k = 0; k < nfields; k++) { VarDeclaration v2 = sd.fields[k]; if (vd.isOverlappedWith(v2) && (*elements)[k]) { error(i.loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; continue; } } assert(sc); Initializer iz = i.value[j]; iz = iz.initializerSemantic(sc, vd.type.addMod(t.mod), needInterpret); Expression ex = iz.initializerToExpression(); if (ex.op == TOK.error) { errors = true; continue; } i.value[j] = iz; (*elements)[fieldi] = doCopyOrMove(sc, ex); ++fieldi; } if (errors) { return new ErrorInitializer(); } auto sle = new StructLiteralExp(i.loc, sd, elements, t); if (!sd.fill(i.loc, elements, false)) { return new ErrorInitializer(); } sle.type = t; auto ie = new ExpInitializer(i.loc, sle); return ie.initializerSemantic(sc, t, needInterpret); } else if ((t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction) && i.value.dim == 0) { TOK tok = (t.ty == Tdelegate) ? TOK.delegate_ : TOK.function_; /* Rewrite as empty delegate literal { } */ auto parameters = new Parameters(); Type tf = new TypeFunction(parameters, null, 0, LINK.d); auto fd = new FuncLiteralDeclaration(i.loc, Loc.initial, tf, tok, null); fd.fbody = new CompoundStatement(i.loc, new Statements()); fd.endloc = i.loc; Expression e = new FuncExp(i.loc, fd); auto ie = new ExpInitializer(i.loc, e); return ie.initializerSemantic(sc, t, needInterpret); } error(i.loc, "a struct is not a valid initializer for a `%s`", t.toChars()); return new ErrorInitializer(); } Initializer visitArray(ArrayInitializer i) { uint length; const(uint) amax = 0x80000000; bool errors = false; //printf("ArrayInitializer::semantic(%s)\n", t.toChars()); if (i.sem) // if semantic() already run { return i; } i.sem = true; t = t.toBasetype(); switch (t.ty) { case Tsarray: case Tarray: break; case Tvector: t = (cast(TypeVector)t).basetype; break; case Taarray: case Tstruct: // consider implicit constructor call { Expression e; // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int]) if (t.ty == Taarray || i.isAssociativeArray()) e = i.toAssocArrayLiteral(); else e = i.initializerToExpression(); // Bugzilla 13987 if (!e) { error(i.loc, "cannot use array to initialize `%s`", t.toChars()); goto Lerr; } auto ei = new ExpInitializer(e.loc, e); return ei.initializerSemantic(sc, t, needInterpret); } case Tpointer: if (t.nextOf().ty != Tfunction) break; goto default; default: error(i.loc, "cannot use array to initialize `%s`", t.toChars()); goto Lerr; } i.type = t; length = 0; for (size_t j = 0; j < i.index.dim; j++) { Expression idx = i.index[j]; if (idx) { sc = sc.startCTFE(); idx = idx.expressionSemantic(sc); sc = sc.endCTFE(); idx = idx.ctfeInterpret(); i.index[j] = idx; const uinteger_t idxvalue = idx.toInteger(); if (idxvalue >= amax) { error(i.loc, "array index %llu overflow", ulong(idxvalue)); errors = true; } length = cast(uint)idxvalue; if (idx.op == TOK.error) errors = true; } Initializer val = i.value[j]; ExpInitializer ei = val.isExpInitializer(); if (ei && !idx) ei.expandTuples = true; val = val.initializerSemantic(sc, t.nextOf(), needInterpret); if (val.isErrorInitializer()) errors = true; ei = val.isExpInitializer(); // found a tuple, expand it if (ei && ei.exp.op == TOK.tuple) { TupleExp te = cast(TupleExp)ei.exp; i.index.remove(j); i.value.remove(j); for (size_t k = 0; k < te.exps.dim; ++k) { Expression e = (*te.exps)[k]; i.index.insert(j + k, cast(Expression)null); i.value.insert(j + k, new ExpInitializer(e.loc, e)); } j--; continue; } else { i.value[j] = val; } length++; if (length == 0) { error(i.loc, "array dimension overflow"); goto Lerr; } if (length > i.dim) i.dim = length; } if (t.ty == Tsarray) { uinteger_t edim = (cast(TypeSArray)t).dim.toInteger(); if (i.dim > edim) { error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); goto Lerr; } } if (errors) goto Lerr; { const sz = t.nextOf().size(); bool overflow; const max = mulu(i.dim, sz, overflow); if (overflow || max >= amax) { error(i.loc, "array dimension %llu exceeds max of %llu", ulong(i.dim), ulong(amax / sz)); goto Lerr; } return i; } Lerr: return new ErrorInitializer(); } Initializer visitExp(ExpInitializer i) { //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars()); if (needInterpret) sc = sc.startCTFE(); i.exp = i.exp.expressionSemantic(sc); i.exp = resolveProperties(sc, i.exp); if (needInterpret) sc = sc.endCTFE(); if (i.exp.op == TOK.error) { return new ErrorInitializer(); } uint olderrors = global.errors; if (needInterpret) { // If the result will be implicitly cast, move the cast into CTFE // to avoid premature truncation of polysemous types. // eg real [] x = [1.1, 2.2]; should use real precision. if (i.exp.implicitConvTo(t)) { i.exp = i.exp.implicitCastTo(sc, t); } if (!global.gag && olderrors != global.errors) { return i; } i.exp = i.exp.ctfeInterpret(); } else { i.exp = i.exp.optimize(WANTvalue); } if (!global.gag && olderrors != global.errors) { return i; // Failed, suppress duplicate error messages } if (i.exp.type.ty == Ttuple && (cast(TypeTuple)i.exp.type).arguments.dim == 0) { Type et = i.exp.type; i.exp = new TupleExp(i.exp.loc, new Expressions()); i.exp.type = et; } if (i.exp.op == TOK.type) { i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars()); return new ErrorInitializer(); } // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(i.exp)) { i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", i.exp.toChars()); return new ErrorInitializer(); } Type tb = t.toBasetype(); Type ti = i.exp.type.toBasetype(); if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t)) { return new ExpInitializer(i.loc, i.exp); } /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; * Allow this by doing an explicit cast, which will lengthen the string * literal. */ if (i.exp.op == TOK.string_ && tb.ty == Tsarray) { StringExp se = cast(StringExp)i.exp; Type typeb = se.type.toBasetype(); TY tynto = tb.nextOf().ty; if (!se.committed && (typeb.ty == Tarray || typeb.ty == Tsarray) && (tynto == Tchar || tynto == Twchar || tynto == Tdchar) && se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) { i.exp = se.castTo(sc, t); goto L1; } } // Look for implicit constructor call if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t)) { StructDeclaration sd = (cast(TypeStruct)tb).sym; if (sd.ctor) { // Rewrite as S().ctor(exp) Expression e; e = new StructLiteralExp(i.loc, sd, null); e = new DotIdExp(i.loc, e, Id.ctor); e = new CallExp(i.loc, e, i.exp); e = e.expressionSemantic(sc); if (needInterpret) i.exp = e.ctfeInterpret(); else i.exp = e.optimize(WANTvalue); } } // Look for the case of statically initializing an array // with a single member. if (tb.ty == Tsarray && !tb.nextOf().equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tb.nextOf())) { /* If the variable is not actually used in compile time, array creation is * redundant. So delay it until invocation of toExpression() or toDt(). */ t = tb.nextOf(); } if (i.exp.implicitConvTo(t)) { i.exp = i.exp.implicitCastTo(sc, t); } else { // Look for mismatch of compile-time known length to emit // better diagnostic message, as same as AssignExp::semantic. if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch) { uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger(); uinteger_t dim2 = dim1; if (i.exp.op == TOK.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp; dim2 = ale.elements ? ale.elements.dim : 0; } else if (i.exp.op == TOK.slice) { Type tx = toStaticArrayType(cast(SliceExp)i.exp); if (tx) dim2 = (cast(TypeSArray)tx).dim.toInteger(); } if (dim1 != dim2) { i.exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); i.exp = new ErrorExp(); } } i.exp = i.exp.implicitCastTo(sc, t); } L1: if (i.exp.op == TOK.error) { return i; } if (needInterpret) i.exp = i.exp.ctfeInterpret(); else i.exp = i.exp.optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); i.exp.print(); return i; } final switch (init.kind) { case InitKind.void_: return visitVoid (cast( VoidInitializer)init); case InitKind.error: return visitError (cast( ErrorInitializer)init); case InitKind.struct_: return visitStruct(cast(StructInitializer)init); case InitKind.array: return visitArray (cast( ArrayInitializer)init); case InitKind.exp: return visitExp (cast( ExpInitializer)init); } } /*********************** * Translate init to an `Expression` in order to infer the type. * Params: * init = `Initializer` AST node * sc = context * Returns: * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated */ Initializer inferType(Initializer init, Scope* sc) { Initializer visitVoid(VoidInitializer i) { error(i.loc, "cannot infer type from void initializer"); return new ErrorInitializer(); } Initializer visitError(ErrorInitializer i) { return i; } Initializer visitStruct(StructInitializer i) { error(i.loc, "cannot infer type from struct initializer"); return new ErrorInitializer(); } Initializer visitArray(ArrayInitializer init) { //printf("ArrayInitializer::inferType() %s\n", toChars()); Expressions* keys = null; Expressions* values; if (init.isAssociativeArray()) { keys = new Expressions(init.value.dim); values = new Expressions(init.value.dim); for (size_t i = 0; i < init.value.dim; i++) { Expression e = init.index[i]; if (!e) goto Lno; (*keys)[i] = e; Initializer iz = init.value[i]; if (!iz) goto Lno; iz = iz.inferType(sc); if (iz.isErrorInitializer()) { return iz; } assert(iz.isExpInitializer()); (*values)[i] = (cast(ExpInitializer)iz).exp; assert((*values)[i].op != TOK.error); } Expression e = new AssocArrayLiteralExp(init.loc, keys, values); auto ei = new ExpInitializer(init.loc, e); return ei.inferType(sc); } else { auto elements = new Expressions(init.value.dim); elements.zero(); for (size_t i = 0; i < init.value.dim; i++) { assert(!init.index[i]); // already asserted by isAssociativeArray() Initializer iz = init.value[i]; if (!iz) goto Lno; iz = iz.inferType(sc); if (iz.isErrorInitializer()) { return iz; } assert(iz.isExpInitializer()); (*elements)[i] = (cast(ExpInitializer)iz).exp; assert((*elements)[i].op != TOK.error); } Expression e = new ArrayLiteralExp(init.loc, null, elements); auto ei = new ExpInitializer(init.loc, e); return ei.inferType(sc); } Lno: if (keys) { error(init.loc, "not an associative array initializer"); } else { error(init.loc, "cannot infer type from array initializer"); } return new ErrorInitializer(); } Initializer visitExp(ExpInitializer init) { //printf("ExpInitializer::inferType() %s\n", toChars()); init.exp = init.exp.expressionSemantic(sc); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (init.exp.op == TOK.type) init.exp = resolveAliasThis(sc, init.exp); init.exp = resolveProperties(sc, init.exp); if (init.exp.op == TOK.scope_) { ScopeExp se = cast(ScopeExp)init.exp; TemplateInstance ti = se.sds.isTemplateInstance(); if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl) se.error("cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars()); else se.error("cannot infer type from %s `%s`", se.sds.kind(), se.toChars()); return new ErrorInitializer(); } // Give error for overloaded function addresses bool hasOverloads; if (auto f = isFuncAddress(init.exp, &hasOverloads)) { if (f.checkForwardRef(init.loc)) { return new ErrorInitializer(); } if (hasOverloads && !f.isUnique()) { init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); return new ErrorInitializer(); } } if (init.exp.op == TOK.address) { AddrExp ae = cast(AddrExp)init.exp; if (ae.e1.op == TOK.overloadSet) { init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); return new ErrorInitializer(); } } if (init.exp.op == TOK.error) { return new ErrorInitializer(); } if (!init.exp.type) { return new ErrorInitializer(); } return init; } final switch (init.kind) { case InitKind.void_: return visitVoid (cast( VoidInitializer)init); case InitKind.error: return visitError (cast( ErrorInitializer)init); case InitKind.struct_: return visitStruct(cast(StructInitializer)init); case InitKind.array: return visitArray (cast( ArrayInitializer)init); case InitKind.exp: return visitExp (cast( ExpInitializer)init); } } /*********************** * Translate init to an `Expression`. * Params: * init = `Initializer` AST node * itype = if not `null`, type to coerce expression to * Returns: * `Expression` created, `null` if cannot, `ErrorExp` for other errors */ extern (C++) Expression initializerToExpression(Initializer init, Type itype = null) { Expression visitVoid(VoidInitializer) { return null; } Expression visitError(ErrorInitializer) { return new ErrorExp(); } /*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the * same thing. */ Expression visitStruct(StructInitializer) { // cannot convert to an expression without target 'ad' return null; } /******************************** * If possible, convert array initializer to array literal. * Otherwise return NULL. */ Expression visitArray(ArrayInitializer init) { //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); //static int i; if (++i == 2) assert(0); Expressions* elements; uint edim; const(uint) amax = 0x80000000; Type t = null; if (init.type) { if (init.type == Type.terror) { return new ErrorExp(); } t = init.type.toBasetype(); switch (t.ty) { case Tvector: t = (cast(TypeVector)t).basetype; goto case Tsarray; case Tsarray: uinteger_t adim = (cast(TypeSArray)t).dim.toInteger(); if (adim >= amax) goto Lno; edim = cast(uint)adim; break; case Tpointer: case Tarray: edim = init.dim; break; default: assert(0); } } else { edim = cast(uint)init.value.dim; for (size_t i = 0, j = 0; i < init.value.dim; i++, j++) { if (init.index[i]) { if (init.index[i].op == TOK.int64) { const uinteger_t idxval = init.index[i].toInteger(); if (idxval >= amax) goto Lno; j = cast(size_t)idxval; } else goto Lno; } if (j >= edim) edim = cast(uint)(j + 1); } } elements = new Expressions(edim); elements.zero(); for (size_t i = 0, j = 0; i < init.value.dim; i++, j++) { if (init.index[i]) j = cast(size_t)init.index[i].toInteger(); assert(j < edim); Initializer iz = init.value[i]; if (!iz) goto Lno; Expression ex = iz.initializerToExpression(); if (!ex) { goto Lno; } (*elements)[j] = ex; } { /* Fill in any missing elements with the default initializer */ Expression _init = null; for (size_t i = 0; i < edim; i++) { if (!(*elements)[i]) { if (!init.type) goto Lno; if (!_init) _init = (cast(TypeNext)t).next.defaultInit(Loc.initial); (*elements)[i] = _init; } } /* Expand any static array initializers that are a single expression * into an array of them */ if (t) { Type tn = t.nextOf().toBasetype(); if (tn.ty == Tsarray) { const dim = cast(size_t)(cast(TypeSArray)tn).dim.toInteger(); Type te = tn.nextOf().toBasetype(); foreach (ref e; *elements) { if (te.equals(e.type)) { auto elements2 = new Expressions(dim); foreach (ref e2; *elements2) e2 = e; e = new ArrayLiteralExp(e.loc, tn, elements2); } } } } /* If any elements are errors, then the whole thing is an error */ for (size_t i = 0; i < edim; i++) { Expression e = (*elements)[i]; if (e.op == TOK.error) { return e; } } Expression e = new ArrayLiteralExp(init.loc, init.type, elements); return e; } Lno: return null; } Expression visitExp(ExpInitializer i) { if (itype) { //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars()); Type tb = itype.toBasetype(); Expression e = (i.exp.op == TOK.construct || i.exp.op == TOK.blit) ? (cast(AssignExp)i.exp).e2 : i.exp; if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf())) { TypeSArray tsa = cast(TypeSArray)tb; size_t d = cast(size_t)tsa.dim.toInteger(); auto elements = new Expressions(d); for (size_t j = 0; j < d; j++) (*elements)[j] = e; auto ae = new ArrayLiteralExp(e.loc, itype, elements); return ae; } } return i.exp; } final switch (init.kind) { case InitKind.void_: return visitVoid (cast( VoidInitializer)init); case InitKind.error: return visitError (cast( ErrorInitializer)init); case InitKind.struct_: return visitStruct(cast(StructInitializer)init); case InitKind.array: return visitArray (cast( ArrayInitializer)init); case InitKind.exp: return visitExp (cast( ExpInitializer)init); } } ================================================ FILE: gcc/d/dmd/inline.d ================================================ /* inline.d -- Inline interface for the D front end. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.inline; import dmd.dscope; import dmd.expression; /*********************************************************** * Perform the "inline copying" of a default argument for a function parameter. */ public Expression inlineCopy(Expression e, Scope* sc) { return e.copy(); } ================================================ FILE: gcc/d/dmd/intrange.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/intrange.d, _intrange.d) * Documentation: https://dlang.org/phobos/dmd_intrange.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/intrange.d */ module dmd.intrange; import core.stdc.stdio; import dmd.mtype; import dmd.expression; import dmd.globals; private uinteger_t copySign(uinteger_t x, bool sign) { // return sign ? -x : x; return (x - cast(uinteger_t)sign) ^ -cast(uinteger_t)sign; } struct SignExtendedNumber { uinteger_t value; bool negative; static SignExtendedNumber fromInteger(uinteger_t value_) { return SignExtendedNumber(value_, value_ >> 63); } static SignExtendedNumber extreme(bool minimum) { return SignExtendedNumber(minimum - 1, minimum); } static SignExtendedNumber max() { return SignExtendedNumber(ulong.max, false); } static SignExtendedNumber min() { return SignExtendedNumber(0, true); } bool isMinimum() const { return negative && value == 0; } bool opEquals(const ref SignExtendedNumber a) const { return value == a.value && negative == a.negative; } int opCmp(const ref SignExtendedNumber a) const { if (negative != a.negative) { if (negative) return -1; else return 1; } if (value < a.value) return -1; else if (value > a.value) return 1; else return 0; } SignExtendedNumber opUnary(string op : "++")() { if (value != ulong.max) ++value; else if (negative) { value = 0; negative = false; } return this; } SignExtendedNumber opUnary(string op : "~")() const { if (~value == 0) return SignExtendedNumber(~value); else return SignExtendedNumber(~value, !negative); } SignExtendedNumber opUnary(string op : "-")() const { if (value == 0) return SignExtendedNumber(-cast(ulong)negative); else return SignExtendedNumber(-value, !negative); } SignExtendedNumber opBinary(string op : "&")(SignExtendedNumber rhs) const { return SignExtendedNumber(value & rhs.value); } SignExtendedNumber opBinary(string op : "|")(SignExtendedNumber rhs) { return SignExtendedNumber(value | rhs.value); } SignExtendedNumber opBinary(string op : "^")(SignExtendedNumber rhs) { return SignExtendedNumber(value ^ rhs.value); } SignExtendedNumber opBinary(string op : "+")(SignExtendedNumber rhs) { uinteger_t sum = value + rhs.value; bool carry = sum < value && sum < rhs.value; if (negative != rhs.negative) return SignExtendedNumber(sum, !carry); else if (negative) return SignExtendedNumber(carry ? sum : 0, true); else return SignExtendedNumber(carry ? ulong.max : sum, false); } SignExtendedNumber opBinary(string op : "-")(SignExtendedNumber rhs) { if (rhs.isMinimum()) return negative ? SignExtendedNumber(value, false) : max(); else return this + (-rhs); } SignExtendedNumber opBinary(string op : "*")(SignExtendedNumber rhs) { // perform *saturated* multiplication, otherwise we may get bogus ranges // like 0x10 * 0x10 == 0x100 == 0. /* Special handling for zeros: INT65_MIN * 0 = 0 INT65_MIN * + = INT65_MIN INT65_MIN * - = INT65_MAX 0 * anything = 0 */ if (value == 0) { if (!negative) return this; else if (rhs.negative) return max(); else return rhs.value == 0 ? rhs : this; } else if (rhs.value == 0) return rhs * this; // don't duplicate the symmetric case. SignExtendedNumber rv; // these are != 0 now surely. uinteger_t tAbs = copySign(value, negative); uinteger_t aAbs = copySign(rhs.value, rhs.negative); rv.negative = negative != rhs.negative; if (ulong.max / tAbs < aAbs) rv.value = rv.negative - 1; else rv.value = copySign(tAbs * aAbs, rv.negative); return rv; } SignExtendedNumber opBinary(string op : "/")(SignExtendedNumber rhs) { /* special handling for zeros: INT65_MIN / INT65_MIN = 1 anything / INT65_MIN = 0 + / 0 = INT65_MAX (eh?) - / 0 = INT65_MIN (eh?) */ if (rhs.value == 0) { if (rhs.negative) return SignExtendedNumber(value == 0 && negative); else return extreme(negative); } uinteger_t aAbs = copySign(rhs.value, rhs.negative); uinteger_t rvVal; if (!isMinimum()) rvVal = copySign(value, negative) / aAbs; // Special handling for INT65_MIN // if the denominator is not a power of 2, it is same as ulong.max / x. else if (aAbs & (aAbs - 1)) rvVal = ulong.max / aAbs; // otherwise, it's the same as reversing the bits of x. else { if (aAbs == 1) return extreme(!rhs.negative); rvVal = 1UL << 63; aAbs >>= 1; if (aAbs & 0xAAAAAAAAAAAAAAAAUL) rvVal >>= 1; if (aAbs & 0xCCCCCCCCCCCCCCCCUL) rvVal >>= 2; if (aAbs & 0xF0F0F0F0F0F0F0F0UL) rvVal >>= 4; if (aAbs & 0xFF00FF00FF00FF00UL) rvVal >>= 8; if (aAbs & 0xFFFF0000FFFF0000UL) rvVal >>= 16; if (aAbs & 0xFFFFFFFF00000000UL) rvVal >>= 32; } bool rvNeg = negative != rhs.negative; rvVal = copySign(rvVal, rvNeg); return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg); } SignExtendedNumber opBinary(string op : "%")(SignExtendedNumber rhs) { if (rhs.value == 0) return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : this; uinteger_t aAbs = copySign(rhs.value, rhs.negative); uinteger_t rvVal; // a % b == sgn(a) * abs(a) % abs(b). if (!isMinimum()) rvVal = copySign(value, negative) % aAbs; // Special handling for INT65_MIN // if the denominator is not a power of 2, it is same as ulong.max % x + 1. else if (aAbs & (aAbs - 1)) rvVal = ulong.max % aAbs + 1; // otherwise, the modulus is trivially zero. else rvVal = 0; rvVal = copySign(rvVal, negative); return SignExtendedNumber(rvVal, rvVal != 0 && negative); } SignExtendedNumber opBinary(string op : "<<")(SignExtendedNumber rhs) { // assume left-shift the shift-amount is always unsigned. Thus negative // shifts will give huge result. if (value == 0) return this; else if (rhs.negative) return extreme(negative); uinteger_t v = copySign(value, negative); // compute base-2 log of 'v' to determine the maximum allowed bits to shift. // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog // Why is this a size_t? Looks like a bug. size_t r, s; r = (v > 0xFFFFFFFFUL) << 5; v >>= r; s = (v > 0xFFFFUL ) << 4; v >>= s; r |= s; s = (v > 0xFFUL ) << 3; v >>= s; r |= s; s = (v > 0xFUL ) << 2; v >>= s; r |= s; s = (v > 0x3UL ) << 1; v >>= s; r |= s; r |= (v >> 1); uinteger_t allowableShift = 63 - r; if (rhs.value > allowableShift) return extreme(negative); else return SignExtendedNumber(value << rhs.value, negative); } SignExtendedNumber opBinary(string op : ">>")(SignExtendedNumber rhs) { if (rhs.negative || rhs.value > 64) return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0); else if (isMinimum()) return rhs.value == 0 ? this : SignExtendedNumber(-1UL << (64 - rhs.value), true); uinteger_t x = value ^ -cast(int)negative; x >>= rhs.value; return SignExtendedNumber(x ^ -cast(int)negative, negative); } SignExtendedNumber opBinary(string op : "^^")(SignExtendedNumber rhs) { // Not yet implemented assert(0); } } struct IntRange { SignExtendedNumber imin, imax; this(IntRange another) { imin = another.imin; imax = another.imax; } this(SignExtendedNumber a) { imin = a; imax = a; } this(SignExtendedNumber lower, SignExtendedNumber upper) { imin = lower; imax = upper; } static IntRange fromType(Type type) { return fromType(type, type.isunsigned()); } static IntRange fromType(Type type, bool isUnsigned) { if (!type.isintegral()) return widest(); uinteger_t mask = type.sizemask(); auto lower = SignExtendedNumber(0); auto upper = SignExtendedNumber(mask); if (type.toBasetype().ty == Tdchar) upper.value = 0x10FFFFUL; else if (!isUnsigned) { lower.value = ~(mask >> 1); lower.negative = true; upper.value = (mask >> 1); } return IntRange(lower, upper); } static IntRange fromNumbers2(SignExtendedNumber* numbers) { if (numbers[0] < numbers[1]) return IntRange(numbers[0], numbers[1]); else return IntRange(numbers[1], numbers[0]); } static IntRange fromNumbers4(SignExtendedNumber* numbers) { IntRange ab = fromNumbers2(numbers); IntRange cd = fromNumbers2(numbers + 2); if (cd.imin < ab.imin) ab.imin = cd.imin; if (cd.imax > ab.imax) ab.imax = cd.imax; return ab; } static IntRange widest() { return IntRange(SignExtendedNumber.min(), SignExtendedNumber.max()); } IntRange castSigned(uinteger_t mask) { // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 .... // // regular signed type. We use a technique similar to the unsigned version, // but the chunk has to be offset by 1/2 of the range. uinteger_t halfChunkMask = mask >> 1; uinteger_t minHalfChunk = imin.value & ~halfChunkMask; uinteger_t maxHalfChunk = imax.value & ~halfChunkMask; int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max int maxHalfChunkNegativity = imax.negative; if (minHalfChunk & mask) { minHalfChunk += halfChunkMask + 1; if (minHalfChunk == 0) --minHalfChunkNegativity; } if (maxHalfChunk & mask) { maxHalfChunk += halfChunkMask + 1; if (maxHalfChunk == 0) --maxHalfChunkNegativity; } if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity) { imin.value &= mask; imax.value &= mask; // sign extend if necessary. imin.negative = (imin.value & ~halfChunkMask) != 0; imax.negative = (imax.value & ~halfChunkMask) != 0; halfChunkMask += 1; imin.value = (imin.value ^ halfChunkMask) - halfChunkMask; imax.value = (imax.value ^ halfChunkMask) - halfChunkMask; } else { imin = SignExtendedNumber(~halfChunkMask, true); imax = SignExtendedNumber(halfChunkMask, false); } return this; } IntRange castUnsigned(uinteger_t mask) { // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 .... // // regular unsigned type. We just need to see if ir steps across the // boundary of validRange. If yes, ir will represent the whole validRange, // otherwise, we just take the modulus. // e.g. [0x105, 0x107] & 0xff == [5, 7] // [0x105, 0x207] & 0xff == [0, 0xff] uinteger_t minChunk = imin.value & ~mask; uinteger_t maxChunk = imax.value & ~mask; if (minChunk == maxChunk && imin.negative == imax.negative) { imin.value &= mask; imax.value &= mask; } else { imin.value = 0; imax.value = mask; } imin.negative = imax.negative = false; return this; } IntRange castDchar() { // special case for dchar. Casting to dchar means "I'll ignore all // invalid characters." castUnsigned(0xFFFFFFFFUL); if (imin.value > 0x10FFFFUL) // ?? imin.value = 0x10FFFFUL; // ?? if (imax.value > 0x10FFFFUL) imax.value = 0x10FFFFUL; return this; } IntRange _cast(Type type) { if (!type.isintegral()) return this; else if (!type.isunsigned()) return castSigned(type.sizemask()); else if (type.toBasetype().ty == Tdchar) return castDchar(); else return castUnsigned(type.sizemask()); } IntRange castUnsigned(Type type) { if (!type.isintegral()) return castUnsigned(ulong.max); else if (type.toBasetype().ty == Tdchar) return castDchar(); else return castUnsigned(type.sizemask()); } bool contains(IntRange a) { return imin <= a.imin && imax >= a.imax; } bool containsZero() const { return (imin.negative && !imax.negative) || (!imin.negative && imin.value == 0); } IntRange absNeg() const { if (imax.negative) return this; else if (!imin.negative) return IntRange(-imax, -imin); else { SignExtendedNumber imaxAbsNeg = -imax; return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin, SignExtendedNumber(0)); } } IntRange unionWith(const ref IntRange other) const { return IntRange(imin < other.imin ? imin : other.imin, imax > other.imax ? imax : other.imax); } void unionOrAssign(IntRange other, ref bool union_) { if (!union_ || imin > other.imin) imin = other.imin; if (!union_ || imax < other.imax) imax = other.imax; union_ = true; } ref const(IntRange) dump(const(char)* funcName, Expression e) const { printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n", imin.negative?'-':'+', cast(ulong)imin.value, imax.negative?'-':'+', cast(ulong)imax.value, funcName, e.toChars()); return this; } void splitBySign(ref IntRange negRange, ref bool hasNegRange, ref IntRange nonNegRange, ref bool hasNonNegRange) const { hasNegRange = imin.negative; if (hasNegRange) { negRange.imin = imin; negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true); } hasNonNegRange = !imax.negative; if (hasNonNegRange) { nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin; nonNegRange.imax = imax; } } IntRange opUnary(string op:"~")() const { return IntRange(~imax, ~imin); } IntRange opUnary(string op : "-")() { return IntRange(-imax, -imin); } // Credits to Timon Gehr for the algorithms for &, | // https://github.com/tgehr/d-compiler/blob/master/vrange.d IntRange opBinary(string op : "&")(IntRange rhs) const { // unsigned or identical sign bits if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1) { return IntRange(minAnd(this, rhs), maxAnd(this, rhs)); } IntRange l = IntRange(this); IntRange r = IntRange(rhs); // both intervals span [-1,0] if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1) { // cannot be larger than either l.max or r.max, set the other one to -1 SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax; // only negative numbers for minimum l.imax.value = -1; l.imax.negative = true; r.imax.value = -1; r.imax.negative = true; return IntRange(minAnd(l, r), max); } else { // only one interval spans [-1,0] if ((l.imin.negative ^ l.imax.negative) == 1) { swap(l, r); // r spans [-1,0] } auto minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1))); auto minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax)); auto maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1))); auto maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax)); auto min = minAndNeg < minAndPos ? minAndNeg : minAndPos; auto max = maxAndNeg > maxAndNeg ? maxAndNeg : maxAndPos; auto range = IntRange(min, max); return range; } } // Credits to Timon Gehr for the algorithms for &, | // https://github.com/tgehr/d-compiler/blob/master/vrange.d IntRange opBinary(string op : "|")(IntRange rhs) const { // unsigned or identical sign bits: if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0) { return IntRange(minOr(this, rhs), maxOr(this, rhs)); } IntRange l = IntRange(this); IntRange r = IntRange(rhs); // both intervals span [-1,0] if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1) { // cannot be smaller than either l.min or r.min, set the other one to 0 SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin; // only negative numbers for minimum l.imin.value = 0; l.imin.negative = false; r.imin.value = 0; r.imin.negative = false; return IntRange(min, maxOr(l, r)); } else { // only one interval spans [-1,0] if ((imin.negative ^ imax.negative) == 1) { swap(l, r); // r spans [-1,0] } auto minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1))); auto minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax)); auto maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1))); auto maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax)); auto min = minOrNeg.value < minOrPos.value ? minOrNeg : minOrPos; auto max = maxOrNeg.value > maxOrNeg.value ? maxOrNeg : maxOrPos; auto range = IntRange(min, max); return range; } } IntRange opBinary(string op : "^")(IntRange rhs) const { return this & ~rhs | ~this & rhs; } IntRange opBinary(string op : "+")(IntRange rhs) { return IntRange(imin + rhs.imin, imax + rhs.imax); } IntRange opBinary(string op : "-")(IntRange rhs) { return IntRange(imin - rhs.imax, imax - rhs.imin); } IntRange opBinary(string op : "*")(IntRange rhs) { // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)] SignExtendedNumber[4] bdy; bdy[0] = imin * rhs.imin; bdy[1] = imin * rhs.imax; bdy[2] = imax * rhs.imin; bdy[3] = imax * rhs.imax; return IntRange.fromNumbers4(bdy.ptr); } IntRange opBinary(string op : "/")(IntRange rhs) { // Handle divide by 0 if (rhs.imax.value == 0 && rhs.imin.value == 0) return widest(); // Don't treat the whole range as divide by 0 if only one end of a range is 0. // Issue 15289 if (rhs.imax.value == 0) { rhs.imax.value--; } else if(rhs.imin.value == 0) { rhs.imin.value++; } if (!imin.negative && !imax.negative && !rhs.imin.negative && !rhs.imax.negative) { return IntRange(imin / rhs.imax, imax / rhs.imin); } else { // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)] SignExtendedNumber[4] bdy; bdy[0] = imin / rhs.imin; bdy[1] = imin / rhs.imax; bdy[2] = imax / rhs.imin; bdy[3] = imax / rhs.imax; return IntRange.fromNumbers4(bdy.ptr); } } IntRange opBinary(string op : "%")(IntRange rhs) { IntRange irNum = this; IntRange irDen = rhs.absNeg(); /* due to the rules of D (C)'s % operator, we need to consider the cases separately in different range of signs. case 1. [500, 1700] % [7, 23] (numerator is always positive) = [0, 22] case 2. [-500, 1700] % [7, 23] (numerator can be negative) = [-22, 22] case 3. [-1700, -500] % [7, 23] (numerator is always negative) = [-22, 0] the number 22 is the maximum absolute value in the denomator's range. We don't care about divide by zero. */ irDen.imin = irDen.imin + SignExtendedNumber(1); irDen.imax = -irDen.imin; if (!irNum.imin.negative) { irNum.imin.value = 0; } else if (irNum.imin < irDen.imin) { irNum.imin = irDen.imin; } if (irNum.imax.negative) { irNum.imax.negative = false; irNum.imax.value = 0; } else if (irNum.imax > irDen.imax) { irNum.imax = irDen.imax; } return irNum; } IntRange opBinary(string op : "<<")(IntRange rhs) { if (rhs.imin.negative) { rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); } SignExtendedNumber lower = imin << (imin.negative ? rhs.imax : rhs.imin); SignExtendedNumber upper = imax << (imax.negative ? rhs.imin : rhs.imax); return IntRange(lower, upper); } IntRange opBinary(string op : ">>")(IntRange rhs) { if (rhs.imin.negative) { rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); } SignExtendedNumber lower = imin >> (imin.negative ? rhs.imin : rhs.imax); SignExtendedNumber upper = imax >> (imax.negative ? rhs.imax : rhs.imin); return IntRange(lower, upper); } IntRange opBinary(string op : ">>>")(IntRange rhs) { if (rhs.imin.negative) { rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); } return IntRange(imin >> rhs.imax, imax >> rhs.imin); } IntRange opBinary(string op : "^^")(IntRange rhs) { // Not yet implemented assert(0); } private: // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd // https://github.com/tgehr/d-compiler/blob/master/vrange.d static SignExtendedNumber maxOr(const IntRange lhs, const IntRange rhs) { uinteger_t x = 0; auto sign = false; auto xor = lhs.imax.value ^ rhs.imax.value; auto and = lhs.imax.value & rhs.imax.value; auto lhsc = IntRange(lhs); auto rhsc = IntRange(rhs); // Sign bit not part of the .value so we need an extra iteration if (lhsc.imax.negative ^ rhsc.imax.negative) { sign = true; if (lhsc.imax.negative) { if (!lhsc.imin.negative) { lhsc.imin.value = 0; } if (!rhsc.imin.negative) { rhsc.imin.value = 0; } } } else if (lhsc.imin.negative & rhsc.imin.negative) { sign = true; } else if (lhsc.imax.negative & rhsc.imax.negative) { return SignExtendedNumber(-1, false); } for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1) { if (xor & d) { x |= d; if (lhsc.imax.value & d) { if (~lhsc.imin.value & d) { lhsc.imin.value = 0; } } else { if (~rhsc.imin.value & d) { rhsc.imin.value = 0; } } } else if (lhsc.imin.value & rhsc.imin.value & d) { x |= d; } else if (and & d) { x |= (d << 1) - 1; break; } } auto range = SignExtendedNumber(x, sign); return range; } // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd // https://github.com/tgehr/d-compiler/blob/master/vrange.d static SignExtendedNumber minOr(const IntRange lhs, const IntRange rhs) { return ~maxAnd(~lhs, ~rhs); } // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd // https://github.com/tgehr/d-compiler/blob/master/vrange.d static SignExtendedNumber maxAnd(const IntRange lhs, const IntRange rhs) { uinteger_t x = 0; bool sign = false; auto lhsc = IntRange(lhs); auto rhsc = IntRange(rhs); if (lhsc.imax.negative & rhsc.imax.negative) { sign = true; } for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1) { if (lhsc.imax.value & rhsc.imax.value & d) { x |= d; if (~lhsc.imin.value & d) { lhsc.imin.value = 0; } if (~rhsc.imin.value & d) { rhsc.imin.value = 0; } } else if (~lhsc.imin.value & d && lhsc.imax.value & d) { lhsc.imax.value |= d - 1; } else if (~rhsc.imin.value & d && rhsc.imax.value & d) { rhsc.imax.value |= d - 1; } } auto range = SignExtendedNumber(x, sign); return range; } // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd // https://github.com/tgehr/d-compiler/blob/master/vrange.d static SignExtendedNumber minAnd(const IntRange lhs, const IntRange rhs) { return ~maxOr(~lhs, ~rhs); } static swap(ref IntRange a, ref IntRange b) { auto aux = a; a = b; b = aux; } } ================================================ FILE: gcc/d/dmd/json.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/json.d, _json.d) * Documentation: https://dlang.org/phobos/dmd_json.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d */ module dmd.json; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.attrib; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dmodule; import dmd.dsymbol; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.utils; import dmd.visitor; version(Windows) { extern (C) char* getcwd(char* buffer, size_t maxlen); } else { import core.sys.posix.unistd : getcwd; } private extern (C++) final class ToJsonVisitor : Visitor { alias visit = Visitor.visit; public: OutBuffer* buf; int indentLevel; const(char)[] filename; extern (D) this(OutBuffer* buf) { this.buf = buf; } void indent() { if (buf.offset >= 1 && buf.data[buf.offset - 1] == '\n') for (int i = 0; i < indentLevel; i++) buf.writeByte(' '); } void removeComma() { if (buf.offset >= 2 && buf.data[buf.offset - 2] == ',' && (buf.data[buf.offset - 1] == '\n' || buf.data[buf.offset - 1] == ' ')) buf.offset -= 2; } void comma() { if (indentLevel > 0) buf.writestring(",\n"); } void stringStart() { buf.writeByte('\"'); } void stringEnd() { buf.writeByte('\"'); } extern(D) void stringPart(const(char)[] s) { foreach (char c; s) { switch (c) { case '\n': buf.writestring("\\n"); break; case '\r': buf.writestring("\\r"); break; case '\t': buf.writestring("\\t"); break; case '\"': buf.writestring("\\\""); break; case '\\': buf.writestring("\\\\"); break; case '\b': buf.writestring("\\b"); break; case '\f': buf.writestring("\\f"); break; default: if (c < 0x20) buf.printf("\\u%04x", c); else { // Note that UTF-8 chars pass through here just fine buf.writeByte(c); } break; } } } // Json value functions /********************************* * Encode string into buf, and wrap it in double quotes. */ extern(D) void value(const(char)[] s) { stringStart(); stringPart(s); stringEnd(); } void value(int value) { if (value < 0) { buf.writeByte('-'); value = -value; } buf.print(value); } void valueBool(bool value) { buf.writestring(value ? "true" : "false"); } /********************************* * Item is an intented value and a comma, for use in arrays */ extern(D) void item(const(char)[] s) { indent(); value(s); comma(); } void item(int i) { indent(); value(i); comma(); } void itemBool(const bool b) { indent(); valueBool(b); comma(); } // Json array functions void arrayStart() { indent(); buf.writestring("[\n"); indentLevel++; } void arrayEnd() { indentLevel--; removeComma(); if (buf.offset >= 2 && buf.data[buf.offset - 2] == '[' && buf.data[buf.offset - 1] == '\n') buf.offset -= 1; else if (!(buf.offset >= 1 && buf.data[buf.offset - 1] == '[')) { buf.writestring("\n"); indent(); } buf.writestring("]"); comma(); } // Json object functions void objectStart() { indent(); buf.writestring("{\n"); indentLevel++; } void objectEnd() { indentLevel--; removeComma(); if (buf.offset >= 2 && buf.data[buf.offset - 2] == '{' && buf.data[buf.offset - 1] == '\n') buf.offset -= 1; else { buf.writestring("\n"); indent(); } buf.writestring("}"); comma(); } // Json object property functions extern(D) void propertyStart(const(char)[] name) { indent(); value(name); buf.writestring(" : "); } /** Write the given string object property only if `s` is not null. Params: name = the name of the object property s = the string value of the object property */ extern(D) void property(const(char)[] name, const(char)[] s) { if (s is null) return; propertyStart(name); value(s); comma(); } /** Write the given string object property. Params: name = the name of the object property s = the string value of the object property */ extern(D) void requiredProperty(const(char)[] name, const(char)[] s) { propertyStart(name); if (s is null) buf.writestring("null"); else value(s); comma(); } extern(D) void property(const(char)[] name, int i) { propertyStart(name); value(i); comma(); } extern(D) void propertyBool(const(char)[] name, const bool b) { propertyStart(name); valueBool(b); comma(); } extern(D) void property(const(char)[] name, TRUST trust) { final switch (trust) { case TRUST.default_: // Should not be printed //property(name, "default"); break; case TRUST.system: property(name, "system"); break; case TRUST.trusted: property(name, "trusted"); break; case TRUST.safe: property(name, "safe"); break; } } extern(D) void property(const(char)[] name, PURE purity) { final switch (purity) { case PURE.impure: // Should not be printed //property(name, "impure"); break; case PURE.weak: property(name, "weak"); break; case PURE.const_: property(name, "const"); break; case PURE.strong: property(name, "strong"); break; case PURE.fwdref: property(name, "fwdref"); break; } } extern(D) void property(const(char)[] name, const LINK linkage) { final switch (linkage) { case LINK.default_: // Should not be printed //property(name, "default"); break; case LINK.d: // Should not be printed //property(name, "d"); break; case LINK.system: // Should not be printed //property(name, "system"); break; case LINK.c: property(name, "c"); break; case LINK.cpp: property(name, "cpp"); break; case LINK.windows: property(name, "windows"); break; case LINK.pascal: property(name, "pascal"); break; case LINK.objc: property(name, "objc"); break; } } extern(D) void propertyStorageClass(const(char)[] name, StorageClass stc) { stc &= STCStorageClass; if (stc) { propertyStart(name); arrayStart(); while (stc) { auto p = stcToString(stc); assert(p.length); item(p); } arrayEnd(); } } extern(D) void property(const(char)[] linename, const(char)[] charname, Loc* loc) { if (loc) { if (auto filename = loc.filename.toDString) { if (filename != this.filename) { this.filename = filename; property("file", filename); } } if (loc.linnum) { property(linename, loc.linnum); if (loc.charnum) property(charname, loc.charnum); } } } extern(D) void property(const(char)[] name, Type type) { if (type) { property(name, type.toString()); } } extern(D) void property(const(char)[] name, const(char)[] deconame, Type type) { if (type) { if (type.deco) property(deconame, type.deco.toDString); else property(name, type.toString()); } } extern(D) void property(const(char)[] name, Parameters* parameters) { if (parameters is null || parameters.dim == 0) return; propertyStart(name); arrayStart(); if (parameters) { for (size_t i = 0; i < parameters.dim; i++) { Parameter p = (*parameters)[i]; objectStart(); if (p.ident) property("name", p.ident.toString()); property("type", "deco", p.type); propertyStorageClass("storageClass", p.storageClass); if (p.defaultArg) property("default", p.defaultArg.toString()); objectEnd(); } } arrayEnd(); } /* ========================================================================== */ void jsonProperties(Dsymbol s) { if (s.isModule()) return; if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes { property("name", s.toString()); property("kind", s.kind.toDString); } if (s.prot().kind != Prot.Kind.public_) // TODO: How about package(names)? property("protection", protectionToString(s.prot().kind)); if (EnumMember em = s.isEnumMember()) { if (em.origValue) property("value", em.origValue.toString()); } property("comment", s.comment.toDString); property("line", "char", &s.loc); } void jsonProperties(Declaration d) { if (d.storage_class & STC.local) return; jsonProperties(cast(Dsymbol)d); propertyStorageClass("storageClass", d.storage_class); property("linkage", d.linkage); property("type", "deco", d.type); // Emit originalType if it differs from type if (d.type != d.originalType && d.originalType) { auto ostr = d.originalType.toString(); if (d.type) { auto tstr = d.type.toString(); if (ostr != tstr) { //printf("tstr = %s, ostr = %s\n", tstr, ostr); property("originalType", ostr); } } else property("originalType", ostr); } } void jsonProperties(TemplateDeclaration td) { jsonProperties(cast(Dsymbol)td); if (td.onemember && td.onemember.isCtorDeclaration()) property("name", "this"); // __ctor -> this else property("name", td.ident.toString()); // Foo(T) -> Foo } /* ========================================================================== */ override void visit(Dsymbol s) { } override void visit(Module s) { objectStart(); if (s.md) property("name", s.md.toString()); property("kind", s.kind.toDString); filename = s.srcfile.toString(); property("file", filename); property("comment", s.comment.toDString); propertyStart("members"); arrayStart(); for (size_t i = 0; i < s.members.dim; i++) { (*s.members)[i].accept(this); } arrayEnd(); objectEnd(); } override void visit(Import s) { if (s.id == Id.object) return; objectStart(); propertyStart("name"); stringStart(); if (s.packages && s.packages.dim) { for (size_t i = 0; i < s.packages.dim; i++) { Identifier pid = (*s.packages)[i]; stringPart(pid.toString()); buf.writeByte('.'); } } stringPart(s.id.toString()); stringEnd(); comma(); property("kind", s.kind.toDString); property("comment", s.comment.toDString); property("line", "char", &s.loc); if (s.prot().kind != Prot.Kind.public_) property("protection", protectionToString(s.prot().kind)); if (s.aliasId) property("alias", s.aliasId.toString()); bool hasRenamed = false; bool hasSelective = false; for (size_t i = 0; i < s.aliases.dim; i++) { // avoid empty "renamed" and "selective" sections if (hasRenamed && hasSelective) break; else if (s.aliases[i]) hasRenamed = true; else hasSelective = true; } if (hasRenamed) { // import foo : alias1 = target1; propertyStart("renamed"); objectStart(); for (size_t i = 0; i < s.aliases.dim; i++) { Identifier name = s.names[i]; Identifier _alias = s.aliases[i]; if (_alias) property(_alias.toString(), name.toString()); } objectEnd(); } if (hasSelective) { // import foo : target1; propertyStart("selective"); arrayStart(); foreach (i, name; s.names) { if (!s.aliases[i]) item(name.toString()); } arrayEnd(); } objectEnd(); } override void visit(AttribDeclaration d) { Dsymbols* ds = d.include(null); if (ds) { for (size_t i = 0; i < ds.dim; i++) { Dsymbol s = (*ds)[i]; s.accept(this); } } } override void visit(ConditionalDeclaration d) { if (d.condition.inc) { visit(cast(AttribDeclaration)d); } Dsymbols* ds = d.decl ? d.decl : d.elsedecl; for (size_t i = 0; i < ds.dim; i++) { Dsymbol s = (*ds)[i]; s.accept(this); } } override void visit(TypeInfoDeclaration d) { } override void visit(PostBlitDeclaration d) { } override void visit(Declaration d) { objectStart(); //property("unknown", "declaration"); jsonProperties(d); objectEnd(); } override void visit(AggregateDeclaration d) { objectStart(); jsonProperties(d); ClassDeclaration cd = d.isClassDeclaration(); if (cd) { if (cd.baseClass && cd.baseClass.ident != Id.Object) { property("base", cd.baseClass.toPrettyChars(true).toDString); } if (cd.interfaces.length) { propertyStart("interfaces"); arrayStart(); foreach (b; cd.interfaces) { item(b.sym.toPrettyChars(true).toDString); } arrayEnd(); } } if (d.members) { propertyStart("members"); arrayStart(); for (size_t i = 0; i < d.members.dim; i++) { Dsymbol s = (*d.members)[i]; s.accept(this); } arrayEnd(); } objectEnd(); } override void visit(FuncDeclaration d) { objectStart(); jsonProperties(d); TypeFunction tf = cast(TypeFunction)d.type; if (tf && tf.ty == Tfunction) property("parameters", tf.parameters); property("endline", "endchar", &d.endloc); if (d.foverrides.dim) { propertyStart("overrides"); arrayStart(); for (size_t i = 0; i < d.foverrides.dim; i++) { FuncDeclaration fd = d.foverrides[i]; item(fd.toPrettyChars().toDString); } arrayEnd(); } if (d.fdrequire) { propertyStart("in"); d.fdrequire.accept(this); } if (d.fdensure) { propertyStart("out"); d.fdensure.accept(this); } objectEnd(); } override void visit(TemplateDeclaration d) { objectStart(); // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one property("kind", "template"); jsonProperties(d); propertyStart("parameters"); arrayStart(); for (size_t i = 0; i < d.parameters.dim; i++) { TemplateParameter s = (*d.parameters)[i]; objectStart(); property("name", s.ident.toString()); TemplateTypeParameter type = s.isTemplateTypeParameter(); if (type) { if (s.isTemplateThisParameter()) property("kind", "this"); else property("kind", "type"); property("type", "deco", type.specType); property("default", "defaultDeco", type.defaultType); } TemplateValueParameter value = s.isTemplateValueParameter(); if (value) { property("kind", "value"); property("type", "deco", value.valType); if (value.specValue) property("specValue", value.specValue.toString()); if (value.defaultValue) property("defaultValue", value.defaultValue.toString()); } TemplateAliasParameter _alias = s.isTemplateAliasParameter(); if (_alias) { property("kind", "alias"); property("type", "deco", _alias.specType); if (_alias.specAlias) property("specAlias", _alias.specAlias.toString()); if (_alias.defaultAlias) property("defaultAlias", _alias.defaultAlias.toString()); } TemplateTupleParameter tuple = s.isTemplateTupleParameter(); if (tuple) { property("kind", "tuple"); } objectEnd(); } arrayEnd(); Expression expression = d.constraint; if (expression) { property("constraint", expression.toString()); } propertyStart("members"); arrayStart(); for (size_t i = 0; i < d.members.dim; i++) { Dsymbol s = (*d.members)[i]; s.accept(this); } arrayEnd(); objectEnd(); } override void visit(EnumDeclaration d) { if (d.isAnonymous()) { if (d.members) { for (size_t i = 0; i < d.members.dim; i++) { Dsymbol s = (*d.members)[i]; s.accept(this); } } return; } objectStart(); jsonProperties(d); property("base", "baseDeco", d.memtype); if (d.members) { propertyStart("members"); arrayStart(); for (size_t i = 0; i < d.members.dim; i++) { Dsymbol s = (*d.members)[i]; s.accept(this); } arrayEnd(); } objectEnd(); } override void visit(EnumMember s) { objectStart(); jsonProperties(cast(Dsymbol)s); property("type", "deco", s.origType); objectEnd(); } override void visit(VarDeclaration d) { if (d.storage_class & STC.local) return; objectStart(); jsonProperties(d); if (d._init) property("init", d._init.toString()); if (d.isField()) property("offset", d.offset); if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT) property("align", d.alignment); objectEnd(); } override void visit(TemplateMixin d) { objectStart(); jsonProperties(d); objectEnd(); } /** Generate an array of module objects that represent the syntax of each "root module". Params: modules = array of the "root modules" */ private void generateModules(Modules* modules) { arrayStart(); if (modules) { foreach (m; *modules) { if (global.params.verbose) message("json gen %s", m.toChars()); m.accept(this); } } arrayEnd(); } /** Generate the "compilerInfo" object which contains information about the compiler such as the filename, version, supported features, etc. */ private void generateCompilerInfo() { objectStart(); requiredProperty("vendor", global.vendor.toDString); requiredProperty("version", global._version.toDString); property("__VERSION__", global.versionNumber()); requiredProperty("interface", determineCompilerInterface()); property("size_t", size_t.sizeof); propertyStart("platforms"); arrayStart(); if (global.params.isWindows) { item("windows"); } else { item("posix"); if (global.params.isLinux) item("linux"); else if (global.params.isOSX) item("osx"); else if (global.params.isFreeBSD) { item("freebsd"); item("bsd"); } else if (global.params.isOpenBSD) { item("openbsd"); item("bsd"); } else if (global.params.isSolaris) { item("solaris"); item("bsd"); } } arrayEnd(); propertyStart("architectures"); arrayStart(); if (global.params.is64bit) item("x86_64"); else version(X86) item("x86"); arrayEnd(); propertyStart("predefinedVersions"); arrayStart(); if (global.versionids) { foreach (const versionid; *global.versionids) { item(versionid.toString()); } } arrayEnd(); propertyStart("supportedFeatures"); { objectStart(); scope(exit) objectEnd(); propertyBool("includeImports", true); } objectEnd(); } /** Generate the "buildInfo" object which contains information specific to the current build such as CWD, importPaths, configFile, etc. */ private void generateBuildInfo() { objectStart(); requiredProperty("cwd", getcwd(null, 0).toDString); requiredProperty("argv0", global.params.argv0); requiredProperty("config", global.inifilename.toDString); requiredProperty("libName", global.params.libname.toDString); propertyStart("importPaths"); arrayStart(); if (global.params.imppath) { foreach (importPath; *global.params.imppath) { item(importPath.toDString); } } arrayEnd(); propertyStart("objectFiles"); arrayStart(); foreach (objfile; global.params.objfiles) { item(objfile.toDString); } arrayEnd(); propertyStart("libraryFiles"); arrayStart(); foreach (lib; global.params.libfiles) { item(lib.toDString); } arrayEnd(); propertyStart("ddocFiles"); arrayStart(); foreach (ddocFile; global.params.ddocfiles) { item(ddocFile.toDString); } arrayEnd(); requiredProperty("mapFile", global.params.mapfile.toDString); requiredProperty("resourceFile", global.params.resfile.toDString); requiredProperty("defFile", global.params.deffile.toDString); objectEnd(); } /** Generate the "semantics" object which contains a 'modules' field representing semantic information about all the modules used in the compilation such as module name, isRoot, contentImportedFiles, etc. */ private void generateSemantics() { objectStart(); propertyStart("modules"); arrayStart(); foreach (m; Module.amodules) { objectStart(); requiredProperty("name", m.md ? m.md.toString() : null); requiredProperty("file", m.srcfile.toString()); propertyBool("isRoot", m.isRoot()); if(m.contentImportedFiles.dim > 0) { propertyStart("contentImports"); arrayStart(); foreach (file; m.contentImportedFiles) { item(file.toDString); } arrayEnd(); } objectEnd(); } arrayEnd(); objectEnd(); } } extern (C++) void json_generate(OutBuffer* buf, Modules* modules) { scope ToJsonVisitor json = new ToJsonVisitor(buf); // write trailing newline scope(exit) buf.writeByte('\n'); if (global.params.jsonFieldFlags == 0) { // Generate the original format, which is just an array // of modules representing their syntax. json.generateModules(modules); json.removeComma(); } else { // Generate the new format which is an object where each // output option is its own field. json.objectStart(); if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo) { json.propertyStart("compilerInfo"); json.generateCompilerInfo(); } if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo) { json.propertyStart("buildInfo"); json.generateBuildInfo(); } if (global.params.jsonFieldFlags & JsonFieldFlags.modules) { json.propertyStart("modules"); json.generateModules(modules); } if (global.params.jsonFieldFlags & JsonFieldFlags.semantics) { json.propertyStart("semantics"); json.generateSemantics(); } json.objectEnd(); } } /** A string listing the name of each JSON field. Useful for errors messages. */ enum jsonFieldNames = () { string s; string prefix = ""; foreach (idx, enumName; __traits(allMembers, JsonFieldFlags)) { static if (idx > 0) { s ~= prefix ~ "`" ~ enumName ~ "`"; prefix = ", "; } } return s; }(); /** Parse the given `fieldName` and return its corresponding JsonFieldFlags value. Params: fieldName = the field name to parse Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value corresponding to the given fieldName. */ JsonFieldFlags tryParseJsonField(const(char)* fieldName) { auto fieldNameString = fieldName[0 .. strlen(fieldName)]; foreach (idx, enumName; __traits(allMembers, JsonFieldFlags)) { static if (idx > 0) { if (fieldNameString == enumName) return __traits(getMember, JsonFieldFlags, enumName); } } return JsonFieldFlags.none; } /** Determines and returns the compiler interface which is one of `dmd`, `ldc`, `gdc` or `sdc`. Returns `null` if no interface can be determined. */ private extern(D) string determineCompilerInterface() { if (!strcmp(global.vendor, "Digital Mars D")) return "dmd"; if (!strcmp(global.vendor, "LDC")) return "ldc"; if (!strcmp(global.vendor, "GNU")) return "gdc"; if (!strcmp(global.vendor, "SDC")) return "sdc"; return null; } ================================================ FILE: gcc/d/dmd/json.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/json.h */ #pragma once #include "arraytypes.h" struct OutBuffer; void json_generate(OutBuffer *, Modules *); ================================================ FILE: gcc/d/dmd/lambdacomp.d ================================================ /*** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * This modules implements the serialization of a lambda function. The serialization * is computed by visiting the abstract syntax subtree of the given lambda function. * The serialization is a string which contains the type of the parameters and the * string represantation of the lambda expression. * * Copyright: Copyright (C) 1999-2018 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/lamdbacomp.d, _lambdacomp.d) * Documentation: https://dlang.org/phobos/dmd_lambdacomp.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lambdacomp.d */ module dmd.lambdacomp; import core.stdc.stdio; import core.stdc.string; import dmd.declaration; import dmd.denum; import dmd.dsymbol; import dmd.dtemplate; import dmd.expression; import dmd.func; import dmd.dmangle; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.stringtable; import dmd.dscope; import dmd.statement; import dmd.tokens; import dmd.visitor; enum LOG = false; /** * The type of the visited expression. */ private enum ExpType { None, EnumDecl, Arg } /** * Compares 2 lambda functions described by their serialization. * * Params: * l1 = first lambda to be compared * l2 = second lambda to be compared * sc = the scope where the lambdas are compared * * Returns: * `true` if the 2 lambda functions are equal, `false` otherwise */ bool isSameFuncLiteral(FuncLiteralDeclaration l1, FuncLiteralDeclaration l2, Scope* sc) { if (auto ser1 = getSerialization(l1, sc)) { //printf("l1 serialization: %s\n", &ser1[0]); if (auto ser2 = getSerialization(l2, sc)) { //printf("l2 serialization: %s\n", &ser2[0]); if (ser1 == ser2) return true; } } return false; } /** * Computes the string representation of a * lambda function described by the subtree starting from a * $(REF dmd, func, FuncLiteralDeclaration). * * Limitations: only IntegerExps, Enums and function * arguments are supported in the lambda function body. The * arguments may be of any type (basic types, user defined types), * except template instantiations. If a function call, a local * variable or a template instance is encountered, the * serialization is dropped and the function is considered * uncomparable. * * Params: * fld = the starting AST node for the lambda function * sc = the scope in which the lambda function is located * * Returns: * The serielization of `fld`. */ private string getSerialization(FuncLiteralDeclaration fld, Scope* sc) { scope serVisitor = new SerializeVisitor(sc); fld.accept(serVisitor); const len = serVisitor.buf.offset; if (len == 0) return null; return cast(string)serVisitor.buf.extractString()[0 .. len]; } private extern (C++) class SerializeVisitor : SemanticTimeTransitiveVisitor { private: StringTable arg_hash; Scope* sc; ExpType et; Dsymbol d; public: OutBuffer buf; alias visit = SemanticTimeTransitiveVisitor.visit; this(Scope* sc) { this.sc = sc; } /** * Entrypoint of the SerializeVisitor. * * Params: * fld = the lambda function for which the serialization is computed */ override void visit(FuncLiteralDeclaration fld) { assert(fld.type.ty != Terror); static if (LOG) printf("FuncLiteralDeclaration: %s\n", fld.toChars()); TypeFunction tf = cast(TypeFunction)fld.type; uint dim = cast(uint)Parameter.dim(tf.parameters); // Start the serialization by printing the number of // arguments the lambda has. buf.printf("%d:", dim); arg_hash._init(dim + 1); // For each argument foreach (i; 0 .. dim) { auto fparam = Parameter.getNth(tf.parameters, i); if (fparam.ident !is null) { // the variable name is introduced into a hashtable // where the key is the user defined name and the // value is the cannonically name (arg0, arg1 ...) auto key = fparam.ident.toString(); OutBuffer value; value.writestring("arg"); value.print(i); arg_hash.insert(&key[0], key.length, value.extractString); // and the type of the variable is serialized. fparam.accept(this); } } // Now the function body can be serialized. ReturnStatement rs = fld.fbody.isReturnStatement(); if (rs && rs.exp) { rs.exp.accept(this); } else { buf.offset = 0; } } override void visit(DotIdExp exp) { static if (LOG) printf("DotIdExp: %s\n", exp.toChars()); if (buf.offset == 0) return; // First we need to see what kind of expression e1 is. // It might an enum member (enum.value) or the field of // an argument (argX.value) if the argument is an aggregate // type. This is reported through the et variable. exp.e1.accept(this); if (buf.offset == 0) return; if (et == ExpType.EnumDecl) { Dsymbol s = d.search(exp.loc, exp.ident); if (s) { if (auto em = s.isEnumMember()) { em.value.accept(this); } et = ExpType.None; d = null; } } else if (et == ExpType.Arg) { buf.setsize(buf.offset -1); buf.writeByte('.'); buf.writestring(exp.ident.toString()); buf.writeByte('_'); } } bool checkArgument(const(char)* id) { // The identifier may be an argument auto stringtable_value = arg_hash.lookup(id, strlen(id)); if (stringtable_value) { // In which case we need to update the serialization accordingly const(char)* gen_id = cast(const(char)*)stringtable_value.ptrvalue; buf.writestring(gen_id); buf.writeByte('_'); et = ExpType.Arg; return true; } return false; } override void visit(IdentifierExp exp) { static if (LOG) printf("IdentifierExp: %s\n", exp.toChars()); if (buf.offset == 0) return; auto id = exp.ident.toChars(); // If it's not an argument if (!checkArgument(id)) { // we must check what the identifier expression is. Dsymbol scopesym; Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); if (s) { auto v = s.isVarDeclaration(); // If it's a VarDeclaration, it must be a manifest constant if (v && (v.storage_class & STC.manifest)) { v.getConstInitializer.accept(this); } else if (auto em = s.isEnumDeclaration()) { d = em; et = ExpType.EnumDecl; } else if (auto fd = s.isFuncDeclaration()) { writeMangledName(fd); } // For anything else, the function is deemed uncomparable else { buf.reset(); } } } } override void visit(DotVarExp exp) { static if (LOG) printf("DotVarExp: %s, var: %s, e1: %s\n", exp.toChars(), exp.var.toChars(), exp.e1.toChars()); exp.e1.accept(this); if (buf.offset == 0) return; buf.setsize(buf.offset -1); buf.writeByte('.'); buf.writestring(exp.var.toChars()); buf.writeByte('_'); } override void visit(VarExp exp) { static if (LOG) printf("VarExp: %s, var: %s\n", exp.toChars(), exp.var.toChars()); if (buf.offset == 0) return; auto id = exp.var.ident.toChars(); if (!checkArgument(id)) { buf.offset = 0; } } // serialize function calls override void visit(CallExp exp) { static if (LOG) printf("CallExp: %s\n", exp.toChars()); if (buf.offset == 0) return; if (!exp.f) { exp.e1.accept(this); } else { writeMangledName(exp.f); } buf.writeByte('('); foreach (arg; *(exp.arguments)) { arg.accept(this); } buf.writeByte(')'); } override void visit(UnaExp exp) { if (buf.offset == 0) return; buf.writeByte('('); buf.writestring(Token.toString(exp.op)); exp.e1.accept(this); if (buf.offset != 0) buf.writestring(")_"); } override void visit(IntegerExp exp) { if (buf.offset == 0) return; buf.print(exp.toInteger()); buf.writeByte('_'); } override void visit(RealExp exp) { if (buf.offset == 0) return; buf.writestring(exp.toChars()); buf.writeByte('_'); } override void visit(BinExp exp) { static if (LOG) printf("BinExp: %s\n", exp.toChars()); if (buf.offset == 0) return; buf.writeByte('('); buf.writestring(Token.toChars(exp.op)); exp.e1.accept(this); if (buf.offset == 0) return; exp.e2.accept(this); if (buf.offset == 0) return; buf.writeByte(')'); } override void visit(TypeBasic t) { buf.writestring(t.dstring); buf.writeByte('_'); } void writeMangledName(Dsymbol s) { if (s) { OutBuffer mangledName; mangleToBuffer(s, &mangledName); buf.writestring(mangledName.peekSlice); buf.writeByte('_'); } else buf.reset(); } private bool checkTemplateInstance(T)(T t) if (is(T == TypeStruct) || is(T == TypeClass)) { if (t.sym.parent && t.sym.parent.isTemplateInstance()) { buf.reset(); return true; } return false; } override void visit(TypeStruct t) { static if (LOG) printf("TypeStruct: %s\n", t.toChars); if (!checkTemplateInstance!TypeStruct(t)) writeMangledName(t.sym); } override void visit(TypeClass t) { static if (LOG) printf("TypeClass: %s\n", t.toChars()); if (!checkTemplateInstance!TypeClass(t)) writeMangledName(t.sym); } override void visit(Parameter p) { if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident.toString().length > 3 && strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) { buf.writestring("none_"); } else visitType(p.type); } } ================================================ FILE: gcc/d/dmd/lexer.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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.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.tokens; import dmd.utf; enum LS = 0x2028; // UTF line separator enum PS = 0x2029; // UTF paragraph separator /******************************************** * Do our own char maps */ 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; }(); enum CMoctal = 0x1; enum CMhex = 0x2; enum CMidchar = 0x4; enum CMzerosecond = 0x8; enum CMdigitsecond = 0x10; enum CMsinglechar = 0x20; bool isoctal(const char c) { return (cmtable[c] & CMoctal) != 0; } bool ishex(const char c) { return (cmtable[c] & CMhex) != 0; } bool isidchar(const char c) { return (cmtable[c] & CMidchar) != 0; } bool isZeroSecond(const char c) { return (cmtable[c] & CMzerosecond) != 0; } bool isDigitSecond(const char c) { return (cmtable[c] & CMdigitsecond) != 0; } bool issinglechar(const char c) { return (cmtable[c] & CMsinglechar) != 0; } private bool c_isxdigit(const int c) { return (( c >= '0' && c <= '9') || ( c >= 'a' && c <= 'f') || ( c >= 'A' && c <= 'F')); } private bool c_isalnum(const int c) { return (( c >= '0' && c <= '9') || ( c >= 'a' && c <= 'z') || ( 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); } } /** Handles error messages */ class ErrorHandler { /** Report an error message. Params: format = format string for error ... = format string arguments */ abstract void error(const(char)* format, ...); /** Report an error message. Params: loc = Location of error format = format string for error ... = format string arguments */ abstract void error(Loc loc, const(char)* format, ...); } /*********************************************************** */ class Lexer : ErrorHandler { __gshared OutBuffer stringbuffer; Loc scanloc; // for error messages Loc prevloc; // location of token before current const(char)* base; // pointer to start of buffer const(char)* end; // pointer to last element of buffer const(char)* p; // current character const(char)* line; // start of current line Token token; bool doDocComment; // collect doc comment information bool anyToken; // seen at least one token bool commentToken; // comments are TOK.comment's int lastDocLine; // last line of previous doc comment bool errors; // errors occurred during lexing or parsing /********************* * 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 */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken) { scanloc = Loc(filename, 1, 1); //printf("Lexer::Lexer(%p,%d)\n",base,length); //printf("lexer.filename = %s\n", filename); token = Token.init; this.base = base; this.end = base + endoffset; p = base + begoffset; line = p; this.doDocComment = doDocComment; this.commentToken = commentToken; this.lastDocLine = 0; //initKeywords(); /* If first line starts with '#!', ignore the line */ if (p && p[0] == '#' && p[1] == '!') { p += 2; while (1) { char c = *p++; switch (c) { case 0: case 0x1A: p--; goto case; case '\n': break; default: continue; } break; } endOfLine(); } } final TOK nextToken() { prevloc = token.loc; if (token.next) { Token* t = token.next; memcpy(&token, t, Token.sizeof); t.free(); } else { scan(&token); } //printf(token.toChars()); return token.value; } /*********************** * Look ahead at next token's value. */ final TOK peekNext() { return peek(&token).value; } /*********************** * Look 2 tokens ahead at value. */ final TOK peekNext2() { Token* t = peek(&token); return peek(t).value; } /**************************** * Turn next token in buffer into a token. */ final void scan(Token* t) { const lastLine = scanloc.linnum; Loc startLoc; t.blockComment = null; t.lineComment = null; while (1) { t.ptr = p; //printf("p = %p, *p = '%c'\n",p,*p); t.loc = loc(); switch (*p) { case 0: case 0x1A: t.value = TOK.endOfFile; // end of file // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile. return; case ' ': case '\t': case '\v': case '\f': p++; continue; // skip white space case '\r': p++; if (*p != '\n') // if CR stands by itself endOfLine(); continue; // skip white space case '\n': p++; endOfLine(); continue; // skip white space case '0': if (!isZeroSecond(p[1])) // if numeric literal does not continue { ++p; t.unsvalue = 0; t.value = TOK.int32Literal; return; } goto Lnumber; case '1': .. case '9': if (!isDigitSecond(p[1])) // if numeric literal does not continue { t.unsvalue = *p - '0'; ++p; t.value = TOK.int32Literal; return; } Lnumber: t.value = number(t); return; case '\'': if (issinglechar(p[1]) && p[2] == '\'') { t.unsvalue = p[1]; // simple one character literal t.value = TOK.charLiteral; p += 3; } else t.value = charConstant(t); return; case 'r': if (p[1] != '"') goto case_ident; p++; goto case '`'; case '`': wysiwygStringConstant(t); return; case 'x': if (p[1] != '"') goto case_ident; p++; t.value = hexStringConstant(t); deprecation("Built-in hex string literals are deprecated, use `std.conv.hexString` instead."); return; case 'q': if (p[1] == '"') { p++; delimitedStringConstant(t); return; } else if (p[1] == '{') { p++; tokenStringConstant(t); return; } else goto case_ident; case '"': escapeStringConstant(t); return; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': /*case 'q': case 'r':*/ case 's': case 't': case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case_ident: { while (1) { const c = *++p; if (isidchar(c)) continue; else if (c & 0x80) { const s = p; const u = decodeUTF(); if (isUniAlpha(u)) continue; error("char 0x%04x not allowed in identifier", u); p = s; } break; } Identifier id = Identifier.idPool(cast(char*)t.ptr, cast(uint)(p - t.ptr)); t.ident = id; t.value = cast(TOK)id.getValue(); anyToken = 1; if (*t.ptr == '_') // if special identifier token { __gshared bool initdone = false; __gshared char[11 + 1] date; __gshared char[8 + 1] time; __gshared char[24 + 1] timestamp; if (!initdone) // lazy evaluation { initdone = true; time_t ct; .time(&ct); const p = ctime(&ct); assert(p); sprintf(&date[0], "%.6s %.4s", p + 4, p + 20); sprintf(&time[0], "%.8s", p + 11); sprintf(×tamp[0], "%.24s", p); } if (id == Id.DATE) { t.ustring = date.ptr; goto Lstr; } else if (id == Id.TIME) { t.ustring = time.ptr; goto Lstr; } else if (id == Id.VENDOR) { t.ustring = global.vendor; goto Lstr; } else if (id == Id.TIMESTAMP) { t.ustring = timestamp.ptr; Lstr: t.value = TOK.string_; t.postfix = 0; t.len = cast(uint)strlen(t.ustring); } else if (id == Id.VERSIONX) { t.value = TOK.int64Literal; t.unsvalue = global.versionNumber(); } else if (id == Id.EOFX) { t.value = TOK.endOfFile; // Advance scanner to end of file while (!(*p == 0 || *p == 0x1A)) p++; } } //printf("t.value = %d\n",t.value); return; } case '/': p++; switch (*p) { case '=': p++; t.value = TOK.divAssign; return; case '*': p++; startLoc = loc(); while (1) { while (1) { const c = *p; switch (c) { case '/': break; case '\n': endOfLine(); p++; continue; case '\r': p++; if (*p != '\n') endOfLine(); continue; case 0: case 0x1A: error("unterminated /* */ comment"); p = end; t.loc = loc(); t.value = TOK.endOfFile; return; default: if (c & 0x80) { const u = decodeUTF(); if (u == PS || u == LS) endOfLine(); } p++; continue; } break; } p++; if (p[-2] == '*' && p - 3 != t.ptr) break; } if (commentToken) { t.loc = startLoc; t.value = TOK.comment; return; } else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr) { // if /** but not /**/ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); lastDocLine = scanloc.linnum; } continue; case '/': // do // style comments startLoc = loc(); while (1) { const c = *++p; switch (c) { case '\n': break; case '\r': if (p[1] == '\n') p++; break; case 0: case 0x1A: if (commentToken) { p = end; t.loc = startLoc; t.value = TOK.comment; return; } if (doDocComment && t.ptr[2] == '/') { getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); lastDocLine = scanloc.linnum; } p = end; t.loc = loc(); t.value = TOK.endOfFile; return; default: if (c & 0x80) { const u = decodeUTF(); if (u == PS || u == LS) break; } continue; } break; } if (commentToken) { p++; endOfLine(); t.loc = startLoc; t.value = TOK.comment; return; } if (doDocComment && t.ptr[2] == '/') { getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); lastDocLine = scanloc.linnum; } p++; endOfLine(); continue; case '+': { int nest; startLoc = loc(); p++; nest = 1; while (1) { char c = *p; switch (c) { case '/': p++; if (*p == '+') { p++; nest++; } continue; case '+': p++; if (*p == '/') { p++; if (--nest == 0) break; } continue; case '\r': p++; if (*p != '\n') endOfLine(); continue; case '\n': endOfLine(); p++; continue; case 0: case 0x1A: error("unterminated /+ +/ comment"); p = end; t.loc = loc(); t.value = TOK.endOfFile; return; default: if (c & 0x80) { uint u = decodeUTF(); if (u == PS || u == LS) endOfLine(); } p++; continue; } break; } if (commentToken) { t.loc = startLoc; t.value = TOK.comment; return; } if (doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr) { // if /++ but not /++/ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); lastDocLine = scanloc.linnum; } continue; } default: break; } t.value = TOK.div; return; case '.': p++; if (isdigit(*p)) { /* Note that we don't allow ._1 and ._ as being * valid floating point numbers. */ p--; t.value = inreal(t); } else if (p[0] == '.') { if (p[1] == '.') { p += 2; t.value = TOK.dotDotDot; } else { p++; t.value = TOK.slice; } } else t.value = TOK.dot; return; case '&': p++; if (*p == '=') { p++; t.value = TOK.andAssign; } else if (*p == '&') { p++; t.value = TOK.andAnd; } else t.value = TOK.and; return; case '|': p++; if (*p == '=') { p++; t.value = TOK.orAssign; } else if (*p == '|') { p++; t.value = TOK.orOr; } else t.value = TOK.or; return; case '-': p++; if (*p == '=') { p++; t.value = TOK.minAssign; } else if (*p == '-') { p++; t.value = TOK.minusMinus; } else t.value = TOK.min; return; case '+': p++; if (*p == '=') { p++; t.value = TOK.addAssign; } else if (*p == '+') { p++; t.value = TOK.plusPlus; } else t.value = TOK.add; return; case '<': p++; if (*p == '=') { p++; t.value = TOK.lessOrEqual; // <= } else if (*p == '<') { p++; if (*p == '=') { p++; t.value = TOK.leftShiftAssign; // <<= } else t.value = TOK.leftShift; // << } else t.value = TOK.lessThan; // < return; case '>': p++; if (*p == '=') { p++; t.value = TOK.greaterOrEqual; // >= } else if (*p == '>') { p++; if (*p == '=') { p++; t.value = TOK.rightShiftAssign; // >>= } else if (*p == '>') { p++; if (*p == '=') { p++; t.value = TOK.unsignedRightShiftAssign; // >>>= } else t.value = TOK.unsignedRightShift; // >>> } else t.value = TOK.rightShift; // >> } else t.value = TOK.greaterThan; // > return; case '!': p++; if (*p == '=') { p++; t.value = TOK.notEqual; // != } else t.value = TOK.not; // ! return; case '=': p++; if (*p == '=') { p++; t.value = TOK.equal; // == } else if (*p == '>') { p++; t.value = TOK.goesTo; // => } else t.value = TOK.assign; // = return; case '~': p++; if (*p == '=') { p++; t.value = TOK.concatenateAssign; // ~= } else t.value = TOK.tilde; // ~ return; case '^': p++; if (*p == '^') { p++; if (*p == '=') { p++; t.value = TOK.powAssign; // ^^= } else t.value = TOK.pow; // ^^ } else if (*p == '=') { p++; t.value = TOK.xorAssign; // ^= } else t.value = TOK.xor; // ^ return; case '(': p++; t.value = TOK.leftParentheses; return; case ')': p++; t.value = TOK.rightParentheses; return; case '[': p++; t.value = TOK.leftBracket; return; case ']': p++; t.value = TOK.rightBracket; return; case '{': p++; t.value = TOK.leftCurly; return; case '}': p++; t.value = TOK.rightCurly; return; case '?': p++; t.value = TOK.question; return; case ',': p++; t.value = TOK.comma; return; case ';': p++; t.value = TOK.semicolon; return; case ':': p++; t.value = TOK.colon; return; case '$': p++; t.value = TOK.dollar; return; case '@': p++; t.value = TOK.at; return; case '*': p++; if (*p == '=') { p++; t.value = TOK.mulAssign; } else t.value = TOK.mul; return; case '%': p++; if (*p == '=') { p++; t.value = TOK.modAssign; } else t.value = TOK.mod; return; case '#': { p++; Token n; scan(&n); if (n.value == TOK.identifier) { if (n.ident == Id.line) { poundLine(); continue; } else { const locx = loc(); warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); } } else if (n.value == TOK.if_) { error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); } t.value = TOK.pound; return; } default: { dchar c = *p; if (c & 0x80) { c = decodeUTF(); // Check for start of unicode identifier if (isUniAlpha(c)) goto case_ident; if (c == PS || c == LS) { endOfLine(); p++; continue; } } if (c < 0x80 && isprint(c)) error("character '%c' is not a valid token", c); else error("character 0x%02x is not a valid token", c); p++; continue; } } } } final Token* peek(Token* ct) { Token* t; if (ct.next) t = ct.next; else { t = Token.alloc(); scan(t); ct.next = t; } 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"); int parens = 1; int curlynest = 0; while (1) { tk = peek(tk); //tk.print(); switch (tk.value) { case TOK.leftParentheses: parens++; continue; case TOK.rightParentheses: --parens; if (parens) continue; tk = peek(tk); break; case TOK.leftCurly: curlynest++; continue; case TOK.rightCurly: if (--curlynest >= 0) continue; break; case TOK.semicolon: if (curlynest) continue; break; case TOK.endOfFile: break; default: continue; } return tk; } } /******************************************* * Parse escape sequence. */ final uint escapeSequence() { return Lexer.escapeSequence(this, p); } /** Parse the given string literal escape sequence into a single character. Params: handler = the error handler object 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 */ static dchar escapeSequence(ErrorHandler handler, ref const(char)* sequence) { const(char)* p = sequence; // cache sequence reference on stack scope(exit) sequence = p; uint c = *p; int ndigits; switch (c) { case '\'': case '"': case '?': case '\\': Lconsume: p++; break; case 'a': c = 7; goto Lconsume; case 'b': c = 8; goto Lconsume; case 'f': c = 12; goto Lconsume; case 'n': c = 10; goto Lconsume; case 'r': c = 13; goto Lconsume; case 't': c = 9; goto Lconsume; case 'v': c = 11; goto Lconsume; case 'u': ndigits = 4; goto Lhex; case 'U': ndigits = 8; goto Lhex; case 'x': ndigits = 2; Lhex: p++; c = *p; if (ishex(cast(char)c)) { uint v = 0; int n = 0; while (1) { if (isdigit(cast(char)c)) c -= '0'; else if (islower(c)) c -= 'a' - 10; else c -= 'A' - 10; v = v * 16 + c; c = *++p; if (++n == ndigits) break; if (!ishex(cast(char)c)) { handler.error("escape hex sequence has %d hex digits instead of %d", n, ndigits); break; } } if (ndigits != 2 && !utf_isValidDchar(v)) { handler.error("invalid UTF character \\U%08x", v); v = '?'; // recover with valid UTF character } c = v; } else { handler.error("undefined escape hex sequence \\%c%c", sequence[0], c); p++; } break; case '&': // named character entity for (const idstart = ++p; 1; p++) { switch (*p) { case ';': c = HtmlNamedEntity(idstart, p - idstart); if (c == ~0) { handler.error("unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); c = '?'; } p++; break; default: if (isalpha(*p) || (p != idstart && isdigit(*p))) continue; handler.error("unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); c = '?'; break; } break; } break; case 0: case 0x1A: // end of file c = '\\'; break; default: if (isoctal(cast(char)c)) { uint v = 0; int n = 0; do { v = v * 8 + (c - '0'); c = *++p; } while (++n < 3 && isoctal(cast(char)c)); c = v; if (c > 0xFF) handler.error("escape octal sequence \\%03o is larger than \\377", c); } else { handler.error("undefined escape sequence \\%c", c); p++; } break; } 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 */ final void wysiwygStringConstant(Token* result) { result.value = TOK.string_; Loc start = loc(); auto terminator = p[0]; p++; stringbuffer.reset(); while (1) { dchar c = p[0]; p++; switch (c) { case '\n': endOfLine(); break; case '\r': if (p[0] == '\n') continue; // ignore c = '\n'; // treat EndOfLine as \n character endOfLine(); break; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); result.setString(); // rewind `p` so it points to the EOF character p--; return; default: if (c == terminator) { result.setString(stringbuffer); stringPostfix(result); return; } else if (c & 0x80) { p--; const u = decodeUTF(); p++; if (u == PS || u == LS) endOfLine(); stringbuffer.writeUTF8(u); continue; } break; } stringbuffer.writeByte(c); } } /************************************** * Lex hex strings: * x"0A ae 34FE BD" */ final TOK hexStringConstant(Token* t) { Loc start = loc(); uint n = 0; uint v = ~0; // dead assignment, needed to suppress warning p++; stringbuffer.reset(); while (1) { dchar c = *p++; switch (c) { case ' ': case '\t': case '\v': case '\f': continue; // skip white space case '\r': if (*p == '\n') continue; // ignore '\r' if followed by '\n' // Treat isolated '\r' as if it were a '\n' goto case '\n'; case '\n': endOfLine(); continue; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); t.setString(); // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). p--; return TOK.hexadecimalString; case '"': if (n & 1) { error("odd number (%d) of hex characters in hex string", n); stringbuffer.writeByte(v); } t.setString(stringbuffer); stringPostfix(t); return TOK.hexadecimalString; default: if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c -= 'a' - 10; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; else if (c & 0x80) { p--; const u = decodeUTF(); p++; if (u == PS || u == LS) endOfLine(); else error("non-hex character \\u%04x in hex string", u); } else error("non-hex character '%c' in hex string", c); if (n & 1) { v = (v << 4) | c; stringbuffer.writeByte(v); } else v = c; n++; break; } } 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 */ final void delimitedStringConstant(Token* result) { result.value = TOK.string_; Loc start = loc(); dchar delimleft = 0; dchar delimright = 0; uint nest = 1; uint nestcount = ~0; // dead assignment, needed to suppress warning Identifier hereid = null; uint blankrol = 0; uint startline = 0; p++; stringbuffer.reset(); while (1) { dchar c = *p++; //printf("c = '%c'\n", c); switch (c) { case '\n': Lnextline: endOfLine(); startline = 1; if (blankrol) { blankrol = 0; continue; } if (hereid) { stringbuffer.writeUTF8(c); continue; } break; case '\r': if (*p == '\n') continue; // ignore c = '\n'; // treat EndOfLine as \n character goto Lnextline; case 0: case 0x1A: error("unterminated delimited string constant starting at %s", start.toChars()); result.setString(); // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). p--; return; default: if (c & 0x80) { p--; c = decodeUTF(); p++; if (c == PS || c == LS) goto Lnextline; } break; } if (delimleft == 0) { delimleft = c; nest = 1; nestcount = 1; if (c == '(') delimright = ')'; else if (c == '{') delimright = '}'; else if (c == '[') delimright = ']'; else if (c == '<') delimright = '>'; else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) { // Start of identifier; must be a heredoc Token tok; p--; scan(&tok); // read in heredoc identifier if (tok.value != TOK.identifier) { error("identifier expected for heredoc, not %s", tok.toChars()); delimright = c; } else { hereid = tok.ident; //printf("hereid = '%s'\n", hereid.toChars()); blankrol = 1; } nest = 0; } else { delimright = c; nest = 0; if (isspace(c)) error("delimiter cannot be whitespace"); } } else { if (blankrol) { error("heredoc rest of line should be blank"); blankrol = 0; continue; } if (nest == 1) { if (c == delimleft) nestcount++; else if (c == delimright) { nestcount--; if (nestcount == 0) goto Ldone; } } else if (c == delimright) goto Ldone; if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) && hereid) { Token tok; auto psave = p; p--; scan(&tok); // read in possible heredoc identifier //printf("endid = '%s'\n", tok.ident.toChars()); if (tok.value == TOK.identifier && tok.ident.equals(hereid)) { /* should check that rest of line is blank */ goto Ldone; } p = psave; } stringbuffer.writeUTF8(c); startline = 0; } } Ldone: if (*p == '"') p++; else if (hereid) error("delimited string must end in %s\"", hereid.toChars()); else error("delimited string must end in %c\"", delimright); result.setString(stringbuffer); 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 */ final void tokenStringConstant(Token* result) { result.value = TOK.string_; uint nest = 1; const start = loc(); const pstart = ++p; while (1) { Token tok; scan(&tok); switch (tok.value) { case TOK.leftCurly: nest++; continue; case TOK.rightCurly: if (--nest == 0) { result.setString(pstart, p - 1 - pstart); stringPostfix(result); return; } continue; case TOK.endOfFile: error("unterminated token string constant starting at %s", start.toChars()); result.setString(); return; default: 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 */ final void escapeStringConstant(Token* t) { t.value = TOK.string_; const start = loc(); p++; stringbuffer.reset(); while (1) { dchar c = *p++; switch (c) { case '\\': switch (*p) { case 'u': case 'U': case '&': c = escapeSequence(); stringbuffer.writeUTF8(c); continue; default: c = escapeSequence(); break; } break; case '\n': endOfLine(); break; case '\r': if (*p == '\n') continue; // ignore c = '\n'; // treat EndOfLine as \n character endOfLine(); break; case '"': t.setString(stringbuffer); stringPostfix(t); return; case 0: case 0x1A: // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). p--; error("unterminated string constant starting at %s", start.toChars()); t.setString(); return; default: if (c & 0x80) { p--; c = decodeUTF(); if (c == LS || c == PS) { c = '\n'; endOfLine(); } p++; stringbuffer.writeUTF8(c); continue; } break; } stringbuffer.writeByte(c); } } /************************************** */ final TOK charConstant(Token* t) { TOK tk = TOK.charLiteral; //printf("Lexer::charConstant\n"); p++; dchar c = *p++; switch (c) { case '\\': switch (*p) { case 'u': t.unsvalue = escapeSequence(); tk = TOK.wcharLiteral; break; case 'U': case '&': t.unsvalue = escapeSequence(); tk = TOK.dcharLiteral; break; default: t.unsvalue = escapeSequence(); break; } break; case '\n': L1: endOfLine(); goto case; case '\r': goto case '\''; case 0: case 0x1A: // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). p--; goto case; case '\'': error("unterminated character constant"); t.unsvalue = '?'; return tk; default: if (c & 0x80) { p--; c = decodeUTF(); p++; if (c == LS || c == PS) goto L1; if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) tk = TOK.wcharLiteral; else tk = TOK.dcharLiteral; } t.unsvalue = c; break; } if (*p != '\'') { error("unterminated character constant"); t.unsvalue = '?'; return tk; } p++; return tk; } /*************************************** * Get postfix of string literal. */ final void stringPostfix(Token* t) { switch (*p) { case 'c': case 'w': case 'd': t.postfix = *p; p++; break; default: t.postfix = 0; break; } } /************************************** * Read in a number. * If it's an integer, store it in tok.TKutok.Vlong. * integers can be decimal, octal or hex * Handle the suffixes U, UL, LU, L, etc. * If it's double, store it in tok.TKutok.Vdouble. * Returns: * TKnum * TKdouble,... */ final TOK number(Token* t) { int base = 10; const start = p; uinteger_t n = 0; // unsigned >=64 bit integer type int d; bool err = false; bool overflow = false; bool anyBinaryDigitsUS = false; bool anyHexDigitsNoSingleUS = false; dchar c = *p; if (c == '0') { ++p; c = *p; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': base = 8; break; case 'x': case 'X': ++p; base = 16; break; case 'b': case 'B': ++p; base = 2; break; case '.': if (p[1] == '.') goto Ldone; // if ".." if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80) goto Ldone; // if ".identifier" or ".unicode" goto Lreal; // '.' is part of current token case 'i': case 'f': case 'F': goto Lreal; case '_': ++p; base = 8; break; case 'L': if (p[1] == 'i') goto Lreal; break; default: break; } } while (1) { c = *p; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ++p; d = c - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ++p; if (base != 16) { if (c == 'e' || c == 'E' || c == 'f' || c == 'F') goto Lreal; } if (c >= 'a') d = c + 10 - 'a'; else d = c + 10 - 'A'; break; case 'L': if (p[1] == 'i') goto Lreal; goto Ldone; case '.': if (p[1] == '.') goto Ldone; // if ".." if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)) goto Ldone; // if ".identifier" or ".unicode" goto Lreal; // otherwise as part of a floating point literal case 'p': case 'P': case 'i': Lreal: p = start; return inreal(t); case '_': anyBinaryDigitsUS = true; ++p; continue; default: goto Ldone; } // got a digit here, set any necessary flags, check for errors anyHexDigitsNoSingleUS = true; anyBinaryDigitsUS = true; if (!err && d >= base) { error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : base == 8 ? "octal".ptr : "decimal".ptr, c); err = true; } // Avoid expensive overflow check if we aren't at risk of overflow if (n <= 0x0FFF_FFFF_FFFF_FFFFUL) n = n * base + d; else { import core.checkedint : mulu, addu; n = mulu(n, base, overflow); n = addu(n, d, overflow); } } Ldone: if (overflow && !err) { error("integer overflow"); err = true; } // Deprecated in 2018-06. // Change to error in 2019-06. // @@@DEPRECATED_2019-06@@@ if ((base == 2 && !anyBinaryDigitsUS) || (base == 16 && !anyHexDigitsNoSingleUS)) deprecation("`%.*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 } FLAGS flags = (base == 10) ? FLAGS.decimal : FLAGS.none; // Parse trailing 'u', 'U', 'l' or 'L' in any combination const psuffix = p; while (1) { FLAGS f; switch (*p) { case 'U': case 'u': f = FLAGS.unsigned; goto L1; case 'l': f = FLAGS.long_; error("lower case integer suffix 'l' is not allowed. Please use 'L' instead"); goto L1; case 'L': f = FLAGS.long_; L1: p++; if ((flags & f) && !err) { error("unrecognized token"); err = true; } flags = cast(FLAGS)(flags | f); continue; default: break; } break; } if (base == 8 && n >= 8) { if (err) // can't translate invalid octal value, just show a generic message error("octal literals larger than 7 are no longer supported"); else error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead", n, p - psuffix, psuffix, n, p - psuffix, psuffix); } TOK result; switch (flags) { case FLAGS.none: /* Octal or Hexadecimal constant. * First that fits: int, uint, long, ulong */ if (n & 0x8000000000000000L) result = TOK.uns64Literal; else if (n & 0xFFFFFFFF00000000L) result = TOK.int64Literal; else if (n & 0x80000000) result = TOK.uns32Literal; else result = TOK.int32Literal; break; case FLAGS.decimal: /* First that fits: int, long, long long */ if (n & 0x8000000000000000L) { if (!err) { error("signed integer overflow"); err = true; } result = TOK.uns64Literal; } else if (n & 0xFFFFFFFF80000000L) result = TOK.int64Literal; else result = TOK.int32Literal; break; case FLAGS.unsigned: case FLAGS.decimal | FLAGS.unsigned: /* First that fits: uint, ulong */ if (n & 0xFFFFFFFF00000000L) result = TOK.uns64Literal; else result = TOK.uns32Literal; break; case FLAGS.decimal | FLAGS.long_: if (n & 0x8000000000000000L) { if (!err) { error("signed integer overflow"); err = true; } result = TOK.uns64Literal; } else result = TOK.int64Literal; break; case FLAGS.long_: if (n & 0x8000000000000000L) result = TOK.uns64Literal; else result = TOK.int64Literal; break; case FLAGS.unsigned | FLAGS.long_: case FLAGS.decimal | FLAGS.unsigned | FLAGS.long_: result = TOK.uns64Literal; break; default: debug { printf("%x\n", flags); } assert(0); } t.unsvalue = n; return result; } /************************************** * Read in characters, converting them to real. * Bugs: * Exponent overflow not detected. * Too much requested precision is not detected. */ final TOK inreal(Token* t) { //printf("Lexer::inreal()\n"); debug { assert(*p == '.' || isdigit(*p)); } bool isWellformedString = true; stringbuffer.reset(); auto pstart = p; bool hex = false; dchar c = *p++; // Leading '0x' if (c == '0') { c = *p++; if (c == 'x' || c == 'X') { hex = true; c = *p++; } } // Digits to left of '.' while (1) { if (c == '.') { c = *p++; break; } if (isdigit(c) || (hex && isxdigit(c)) || c == '_') { c = *p++; continue; } break; } // Digits to right of '.' while (1) { if (isdigit(c) || (hex && isxdigit(c)) || c == '_') { c = *p++; continue; } break; } if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P'))) { c = *p++; if (c == '-' || c == '+') { c = *p++; } bool anyexp = false; while (1) { if (isdigit(c)) { anyexp = true; c = *p++; continue; } if (c == '_') { c = *p++; continue; } if (!anyexp) { error("missing exponent"); isWellformedString = false; } break; } } else if (hex) { error("exponent required for hex float"); isWellformedString = false; } --p; while (pstart < p) { if (*pstart != '_') stringbuffer.writeByte(*pstart); ++pstart; } stringbuffer.writeByte(0); auto sbufptr = cast(const(char)*)stringbuffer.data; TOK result; bool isOutOfRange = false; t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, &isOutOfRange) : CTFloat.zero); switch (*p) { case 'F': case 'f': if (isWellformedString && !isOutOfRange) isOutOfRange = Port.isFloat32LiteralOutOfRange(sbufptr); result = TOK.float32Literal; p++; break; default: if (isWellformedString && !isOutOfRange) isOutOfRange = Port.isFloat64LiteralOutOfRange(sbufptr); result = TOK.float64Literal; break; case 'l': error("use 'L' suffix instead of 'l'"); goto case 'L'; case 'L': result = TOK.float80Literal; p++; break; } if (*p == 'i' || *p == 'I') { if (*p == 'I') error("use 'i' suffix instead of 'I'"); p++; switch (result) { case TOK.float32Literal: result = TOK.imaginary32Literal; break; case TOK.float64Literal: result = TOK.imaginary64Literal; break; case TOK.float80Literal: result = TOK.imaginary80Literal; break; default: break; } } const isLong = (result == TOK.float80Literal || result == TOK.imaginary80Literal); if (isOutOfRange && !isLong) { const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : ""; error(scanloc, "number `%s%s` is not representable", sbufptr, suffix); } debug { switch (result) { case TOK.float32Literal: case TOK.float64Literal: case TOK.float80Literal: case TOK.imaginary32Literal: case TOK.imaginary64Literal: case TOK.imaginary80Literal: break; default: assert(0); } } return result; } final Loc loc() { scanloc.charnum = cast(uint)(1 + p - line); return scanloc; } final override void error(const(char)* format, ...) { va_list ap; va_start(ap, format); .verror(token.loc, format, ap); va_end(ap); errors = true; } final override void error(Loc loc, const(char)* format, ...) { va_list ap; va_start(ap, format); .verror(loc, format, ap); va_end(ap); errors = true; } final void deprecation(const(char)* format, ...) { va_list ap; va_start(ap, format); .vdeprecation(token.loc, format, ap); va_end(ap); if (global.params.useDeprecated == Diagnostic.error) errors = true; } /********************************************* * parse: * #line linnum [filespec] * also allow __LINE__ for linnum, and __FILE__ for filespec */ final void poundLine() { auto linnum = this.scanloc.linnum; const(char)* filespec = null; const loc = this.loc(); Token tok; scan(&tok); if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal) { const lin = cast(int)(tok.unsvalue - 1); if (lin != tok.unsvalue - 1) error("line number `%lld` out of range", cast(ulong)tok.unsvalue); else linnum = lin; } else if (tok.value == TOK.line) { } else goto Lerr; while (1) { switch (*p) { case 0: case 0x1A: case '\n': Lnewline: this.scanloc.linnum = linnum; if (filespec) this.scanloc.filename = filespec; return; case '\r': p++; if (*p != '\n') { p--; goto Lnewline; } continue; case ' ': case '\t': case '\v': case '\f': p++; continue; // skip white space case '_': if (memcmp(p, "__FILE__".ptr, 8) == 0) { p += 8; filespec = mem.xstrdup(scanloc.filename); continue; } goto Lerr; case '"': if (filespec) goto Lerr; stringbuffer.reset(); p++; while (1) { uint c; c = *p; switch (c) { case '\n': case '\r': case 0: case 0x1A: goto Lerr; case '"': stringbuffer.writeByte(0); filespec = mem.xstrdup(cast(const(char)*)stringbuffer.data); p++; break; default: if (c & 0x80) { uint u = decodeUTF(); if (u == PS || u == LS) goto Lerr; } stringbuffer.writeByte(c); p++; continue; } break; } continue; default: if (*p & 0x80) { uint u = decodeUTF(); if (u == PS || u == LS) goto Lnewline; } goto Lerr; } } Lerr: error(loc, "#line integer [\"filespec\"]\\n expected"); } /******************************************** * Decode UTF character. * Issue error messages for invalid sequences. * Return decoded character, advance p to last character in UTF sequence. */ final uint decodeUTF() { const s = p; assert(*s & 0x80); // Check length of remaining string up to 6 UTF-8 characters size_t len; for (len = 1; len < 6 && s[len]; len++) { } size_t idx = 0; dchar u; const msg = utf_decodeChar(s, len, idx, u); p += idx - 1; if (msg) { error("%s", msg); } return u; } /*************************************************** * Parse doc comment embedded between t.ptr and p. * Remove trailing blanks and tabs from lines. * Replace all newlines with \n. * Remove leading comment character from each line. * Decide if it's a lineComment or a blockComment. * Append to previous one for this token. * * If newParagraph is true, an extra newline will be * added between adjoining doc comments. */ final void getDocComment(Token* t, uint lineComment, bool newParagraph) { /* ct tells us which kind of comment it is: '/', '*', or '+' */ const ct = t.ptr[2]; /* Start of comment text skips over / * *, / + +, or / / / */ const(char)* q = t.ptr + 3; // start of comment text const(char)* qend = p; if (ct == '*' || ct == '+') qend -= 2; /* Scan over initial row of ****'s or ++++'s or ////'s */ for (; q < qend; q++) { if (*q != ct) break; } /* Remove leading spaces until start of the comment */ int linestart = 0; if (ct == '/') { while (q < qend && (*q == ' ' || *q == '\t')) ++q; } else if (q < qend) { if (*q == '\r') { ++q; if (q < qend && *q == '\n') ++q; linestart = 1; } else if (*q == '\n') { ++q; linestart = 1; } } /* Remove trailing row of ****'s or ++++'s */ if (ct != '/') { for (; q < qend; qend--) { if (qend[-1] != ct) break; } } /* Comment is now [q .. qend]. * Canonicalize it into buf[]. */ OutBuffer buf; void trimTrailingWhitespace() { const s = buf.peekSlice(); auto len = s.length; while (len && (s[len - 1] == ' ' || s[len - 1] == '\t')) --len; buf.setsize(len); } for (; q < qend; q++) { char c = *q; switch (c) { case '*': case '+': if (linestart && c == ct) { linestart = 0; /* Trim preceding whitespace up to preceding \n */ trimTrailingWhitespace(); continue; } break; case ' ': case '\t': break; case '\r': if (q[1] == '\n') continue; // skip the \r goto Lnewline; default: if (c == 226) { // If LS or PS if (q[1] == 128 && (q[2] == 168 || q[2] == 169)) { q += 2; goto Lnewline; } } linestart = 0; break; Lnewline: c = '\n'; // replace all newlines with \n goto case; case '\n': linestart = 1; /* Trim trailing whitespace */ trimTrailingWhitespace(); break; } buf.writeByte(c); } /* Trim trailing whitespace (if the last line does not have newline) */ trimTrailingWhitespace(); // Always end with a newline const s = buf.peekSlice(); if (s.length == 0 || s[$ - 1] != '\n') buf.writeByte('\n'); // It's a line comment if the start of the doc comment comes // after other non-whitespace on the same line. auto dc = (lineComment && anyToken) ? &t.lineComment : &t.blockComment; // Combine with previous doc comment, if any if (*dc) *dc = combineComments(*dc, buf.peekString(), newParagraph); else *dc = buf.extractString(); } /******************************************** * 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) { //printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph); auto c = c2; const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n' if (c1) { c = c1; if (c2) { size_t len1 = strlen(c1); size_t len2 = strlen(c2); int insertNewLine = 0; if (len1 && c1[len1 - 1] != '\n') { ++len1; insertNewLine = 1; } auto p = cast(char*)mem.xmalloc(len1 + newParagraphSize + len2 + 1); memcpy(p, c1, len1 - insertNewLine); if (insertNewLine) p[len1 - 1] = '\n'; if (newParagraph) p[len1] = '\n'; memcpy(p + len1 + newParagraphSize, c2, len2); p[len1 + newParagraphSize + len2] = 0; c = p; } } return c; } private: void endOfLine() { scanloc.linnum++; line = p; } } unittest { static class AssertErrorHandler : ErrorHandler { override final void error(const(char)* format, ...) { assert(0); } override final void error(Loc loc, const(char)* format, ...) { assert(0); } } static void test(T)(string sequence, T expected) { scope assertOnError = new AssertErrorHandler(); auto p = cast(const(char)*)sequence.ptr; assert(expected == Lexer.escapeSequence(assertOnError, 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(`>`, '>'); } unittest { static class ExpectErrorHandler : ErrorHandler { string expected; bool gotError; this(string expected) { this.expected = expected; } override final void error(const(char)* format, ...) { gotError = true; char[100] buffer; va_list ap; va_start(ap, format); auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)]; va_end(ap); assert(expected == actual); } override final void error(Loc loc, const(char)* format, ...) { assert(0); } } static void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength) { scope handler = new ExpectErrorHandler(expectedError); auto p = cast(const(char)*)sequence.ptr; auto actualReturnValue = Lexer.escapeSequence(handler, p); assert(handler.gotError); assert(expectedReturnValue == actualReturnValue); auto actualScanLength = p - sequence.ptr; assert(expectedScanLength == actualScanLength); } 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); } ================================================ FILE: gcc/d/dmd/mangle.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/mangle.h */ #pragma once class Dsymbol; class Expression; class FuncDeclaration; class TemplateInstance; class Type; struct OutBuffer; // In cppmangle.d const char *toCppMangleItanium(Dsymbol *s); const char *cppTypeInfoMangleItanium(Dsymbol *s); // In cppmanglewin.d const char *toCppMangleMSVC(Dsymbol *s); const char *cppTypeInfoMangleMSVC(Dsymbol *s); // In dmangle.d const char *mangleExact(FuncDeclaration *fd); void mangleToBuffer(Type *s, OutBuffer *buf); void mangleToBuffer(Expression *s, OutBuffer *buf); void mangleToBuffer(Dsymbol *s, OutBuffer *buf); void mangleToBuffer(TemplateInstance *s, OutBuffer *buf); ================================================ FILE: gcc/d/dmd/mars.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/mars.h */ #pragma once /* It is very important to use version control macros correctly - the idea is that host and target are independent. If these are done correctly, cross compilers can be built. The host compiler and host operating system are also different, and are predefined by the host compiler. The ones used in dmd are: Macros defined by the compiler, not the code: Compiler: __DMC__ Digital Mars compiler _MSC_VER Microsoft compiler __GNUC__ Gnu compiler __clang__ Clang compiler Host operating system: _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, Windows 2000, Win XP, Vista _WIN64 Windows for AMD64 __linux__ Linux __APPLE__ Mac OSX __FreeBSD__ FreeBSD __OpenBSD__ OpenBSD __DragonFly__ DragonFlyBSD __sun Solaris, OpenSolaris, SunOS, OpenIndiana, etc For the target systems, there are the target operating system and the target object file format: Target operating system: TARGET_WINDOS Covers 32 bit windows and 64 bit windows TARGET_LINUX Covers 32 and 64 bit linux TARGET_OSX Covers 32 and 64 bit Mac OSX TARGET_FREEBSD Covers 32 and 64 bit FreeBSD TARGET_OPENBSD Covers 32 and 64 bit OpenBSD TARGET_DRAGONFLYBSD Covers 64 bit DragonFlyBSD TARGET_SOLARIS Covers 32 and 64 bit Solaris It is expected that the compiler for each platform will be able to generate 32 and 64 bit code from the same compiler binary. There are currently no macros for byte endianness order. */ #include #include #include #ifdef __DMC__ #ifdef DEBUG #undef assert #define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) #endif #endif void unittests(); struct OutBuffer; #include "globals.h" #include "root/ctfloat.h" #include "complex_t.h" #include "errors.h" class Dsymbol; class Library; struct File; void obj_start(const char *srcfile); void obj_end(Library *library, File *objfile); void obj_append(Dsymbol *s); void obj_write_deferred(Library *library); /// Utility functions used by both main and frontend. void readFile(Loc loc, File *f); void writeFile(Loc loc, File *f); void ensurePathToNameExists(Loc loc, const char *name); /// Little helper function for writing out deps. void escapePath(OutBuffer *buf, const char *fname); ================================================ FILE: gcc/d/dmd/module.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/module.h */ #pragma once #include "dsymbol.h" struct ModuleDeclaration; struct Macro; struct Escape; enum PKG { PKGunknown, // not yet determined whether it's a package.d or not PKGmodule, // already determined that's an actual package.d PKGpackage // already determined that's an actual package }; class Package : public ScopeDsymbol { public: PKG isPkgMod; unsigned tag; // auto incremented tag, used to mask package tree in scopes Module *mod; // != NULL if isPkgMod == PKGmodule const char *kind() const; Package *isPackage() { return this; } bool isAncestorPackageOf(const Package * const pkg) const; Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); void accept(Visitor *v) { v->visit(this); } Module *isPackageMod(); }; class Module : public Package { public: static Module *rootModule; static DsymbolTable *modules; // symbol table of all modules static Modules amodules; // array of all modules static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them static unsigned dprogress; // progress resolving the deferred list static void _init(); static AggregateDeclaration *moduleinfo; const char *arg; // original argument name ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration File *srcfile; // input source file File *objfile; // output .obj file File *hdrfile; // 'header' file File *docfile; // output documentation file unsigned errors; // if any errors in file unsigned numlines; // number of lines in source file int isDocFile; // if it is a documentation input file, not D source bool isPackageFile; // if it is a package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does bool selfImports(); // returns true if module imports itself int rootimports; // 0: don't know, 1: does not, 2: does bool rootImports(); // returns true if module imports root module int insearch; Identifier *searchCacheIdent; Dsymbol *searchCacheSymbol; // cached value of search int searchCacheFlags; // cached flags // module from command line we're imported from, // i.e. a module that will be taken all the // way to an object file Module *importedFrom; Dsymbols *decldefs; // top level declarations for this Module Modules aimports; // all imported modules unsigned debuglevel; // debug level Strings *debugids; // debug identifiers Strings *debugidsNot; // forward referenced debug identifiers unsigned versionlevel; // version level Strings *versionids; // version identifiers Strings *versionidsNot; // forward referenced version identifiers Macro *macrotable; // document comment macros Escape *escapetable; // document comment escapes size_t nameoffset; // offset of module name from start of ModuleInfo size_t namelen; // length of module name in characters static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen); static Module *load(Loc loc, Identifiers *packages, Identifier *ident); const char *kind() const; File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext); void setDocfile(); bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. Module *parse(); // syntactic parse void importAll(Scope *sc); int needModuleInfo(); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); bool isPackageAccessible(Package *p, Prot protection, int flags = 0); Dsymbol *symtabInsert(Dsymbol *s); void deleteObjFile(); static void addDeferredSemantic(Dsymbol *s); static void addDeferredSemantic2(Dsymbol *s); static void addDeferredSemantic3(Dsymbol *s); static void runDeferredSemantic(); static void runDeferredSemantic2(); static void runDeferredSemantic3(); static void clearCache(); int imports(Module *m); bool isRoot() { return this->importedFrom == this; } // true if the module source file is directly // listed in command line. bool isCoreModule(Identifier *ident); // Back end int doppelganger; // sub-module Symbol *cov; // private uint[] __coverage; unsigned *covb; // bit array of valid code line numbers Symbol *sictor; // module order independent constructor Symbol *sctor; // module constructor Symbol *sdtor; // module destructor Symbol *ssharedctor; // module shared constructor Symbol *sshareddtor; // module shared destructor Symbol *stest; // module unit test Symbol *sfilename; // symbol for filename Module *isModule() { return this; } void accept(Visitor *v) { v->visit(this); } }; struct ModuleDeclaration { Loc loc; Identifier *id; Identifiers *packages; // array of Identifier's representing packages bool isdeprecated; // if it is a deprecated module Expression *msg; const char *toChars() const; }; ================================================ FILE: gcc/d/dmd/mtype.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/mtype.d, _mtype.d) * Documentation: https://dlang.org/phobos/dmd_mtype.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d */ module dmd.mtype; import core.checkedint; import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.attrib; import dmd.gluelayer; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dmangle; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.init; import dmd.opover; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.root.stringtable; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; enum LOGDOTEXP = 0; // log ::dotExp() enum LOGDEFAULTINIT = 0; // log ::defaultInit() extern (C++) __gshared int Tsize_t = Tuns32; extern (C++) __gshared int Tptrdiff_t = Tint32; enum SIZE_INVALID = (~cast(d_uns64)0); // error return from size() functions /*************************** * Return !=0 if modfrom can be implicitly converted to modto */ bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe { if (modfrom == modto) return true; //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); auto X(T, U)(T m, U n) { return ((m << 4) | n); } switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_)) { case X(0, MODFlags.const_): case X(MODFlags.wild, MODFlags.const_): case X(MODFlags.wild, MODFlags.wildconst): case X(MODFlags.wildconst, MODFlags.const_): return (modfrom & MODFlags.shared_) == (modto & MODFlags.shared_); case X(MODFlags.immutable_, MODFlags.const_): case X(MODFlags.immutable_, MODFlags.wildconst): return true; default: return false; } } /*************************** * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'. */ MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe { if (modfrom == modto) return MATCH.exact; if (MODimplicitConv(modfrom, modto)) return MATCH.constant; auto X(T, U)(T m, U n) { return ((m << 4) | n); } switch (X(modfrom, modto)) { case X(0, MODFlags.wild): case X(MODFlags.immutable_, MODFlags.wild): case X(MODFlags.const_, MODFlags.wild): case X(MODFlags.wildconst, MODFlags.wild): case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild): return MATCH.constant; default: return MATCH.nomatch; } } /*************************** * Merge mod bits to form common mod. */ MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe { if (mod1 == mod2) return mod1; //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2); MOD result = 0; if ((mod1 | mod2) & MODFlags.shared_) { // If either type is shared, the result will be shared result |= MODFlags.shared_; mod1 &= ~MODFlags.shared_; mod2 &= ~MODFlags.shared_; } if (mod1 == 0 || mod1 == MODFlags.mutable || mod1 == MODFlags.const_ || mod2 == 0 || mod2 == MODFlags.mutable || mod2 == MODFlags.const_) { // If either type is mutable or const, the result will be const. result |= MODFlags.const_; } else { // MODFlags.immutable_ vs MODFlags.wild // MODFlags.immutable_ vs MODFlags.wildconst // MODFlags.wild vs MODFlags.wildconst assert(mod1 & MODFlags.wild || mod2 & MODFlags.wild); result |= MODFlags.wildconst; } return result; } /********************************* * Store modifier name into buf. */ void MODtoBuffer(OutBuffer* buf, MOD mod) nothrow { buf.writestring(MODtoString(mod)); } /********************************* * Returns: * a human readable representation of `mod`, * which is the token `mod` corresponds to */ const(char)* MODtoChars(MOD mod) nothrow { /// Works because we return a literal return MODtoString(mod).ptr; } /// Ditto string MODtoString(MOD mod) nothrow { final switch (mod) { case 0: return ""; case MODFlags.immutable_: return "immutable"; case MODFlags.shared_: return "shared"; case MODFlags.shared_ | MODFlags.const_: return "shared const"; case MODFlags.const_: return "const"; case MODFlags.shared_ | MODFlags.wild: return "shared inout"; case MODFlags.wild: return "inout"; case MODFlags.shared_ | MODFlags.wildconst: return "shared inout const"; case MODFlags.wildconst: return "inout const"; } } /************************************ * Convert MODxxxx to STCxxx */ StorageClass ModToStc(uint mod) pure nothrow @nogc @safe { StorageClass stc = 0; if (mod & MODFlags.immutable_) stc |= STC.immutable_; if (mod & MODFlags.const_) stc |= STC.const_; if (mod & MODFlags.wild) stc |= STC.wild; if (mod & MODFlags.shared_) stc |= STC.shared_; return stc; } private enum TFlags { integral = 1, floating = 2, unsigned = 4, real_ = 8, imaginary = 0x10, complex = 0x20, } enum ENUMTY : int { Tarray, // slice array, aka T[] Tsarray, // static array, aka T[dimension] Taarray, // associative array, aka T[type] Tpointer, Treference, Tfunction, Tident, Tclass, Tstruct, Tenum, Tdelegate, Tnone, Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, Tfloat32, Tfloat64, Tfloat80, Timaginary32, Timaginary64, Timaginary80, Tcomplex32, Tcomplex64, Tcomplex80, Tbool, Tchar, Twchar, Tdchar, Terror, Tinstance, Ttypeof, Ttuple, Tslice, Treturn, Tnull, Tvector, Tint128, Tuns128, TMAX, } alias Tarray = ENUMTY.Tarray; alias Tsarray = ENUMTY.Tsarray; alias Taarray = ENUMTY.Taarray; alias Tpointer = ENUMTY.Tpointer; alias Treference = ENUMTY.Treference; alias Tfunction = ENUMTY.Tfunction; alias Tident = ENUMTY.Tident; alias Tclass = ENUMTY.Tclass; alias Tstruct = ENUMTY.Tstruct; alias Tenum = ENUMTY.Tenum; alias Tdelegate = ENUMTY.Tdelegate; alias Tnone = ENUMTY.Tnone; alias Tvoid = ENUMTY.Tvoid; alias Tint8 = ENUMTY.Tint8; alias Tuns8 = ENUMTY.Tuns8; alias Tint16 = ENUMTY.Tint16; alias Tuns16 = ENUMTY.Tuns16; alias Tint32 = ENUMTY.Tint32; alias Tuns32 = ENUMTY.Tuns32; alias Tint64 = ENUMTY.Tint64; alias Tuns64 = ENUMTY.Tuns64; alias Tfloat32 = ENUMTY.Tfloat32; alias Tfloat64 = ENUMTY.Tfloat64; alias Tfloat80 = ENUMTY.Tfloat80; alias Timaginary32 = ENUMTY.Timaginary32; alias Timaginary64 = ENUMTY.Timaginary64; alias Timaginary80 = ENUMTY.Timaginary80; alias Tcomplex32 = ENUMTY.Tcomplex32; alias Tcomplex64 = ENUMTY.Tcomplex64; alias Tcomplex80 = ENUMTY.Tcomplex80; alias Tbool = ENUMTY.Tbool; alias Tchar = ENUMTY.Tchar; alias Twchar = ENUMTY.Twchar; alias Tdchar = ENUMTY.Tdchar; alias Terror = ENUMTY.Terror; alias Tinstance = ENUMTY.Tinstance; alias Ttypeof = ENUMTY.Ttypeof; alias Ttuple = ENUMTY.Ttuple; alias Tslice = ENUMTY.Tslice; alias Treturn = ENUMTY.Treturn; alias Tnull = ENUMTY.Tnull; alias Tvector = ENUMTY.Tvector; alias Tint128 = ENUMTY.Tint128; alias Tuns128 = ENUMTY.Tuns128; alias TMAX = ENUMTY.TMAX; alias TY = ubyte; enum MODFlags : int { const_ = 1, // type is const immutable_ = 4, // type is immutable shared_ = 2, // type is shared wild = 8, // type is wild wildconst = (MODFlags.wild | MODFlags.const_), // type is wild const mutable = 0x10, // type is mutable (only used in wildcard matching) } alias MOD = ubyte; /**************** * dotExp() bit flags */ enum DotExpFlag { gag = 1, // don't report "not a property" error and just return null noDeref = 2, // the use of the expression will not attempt a dereference } /*********************************************************** */ extern (C++) abstract class Type : RootObject { TY ty; MOD mod; // modifiers MODxxxx char* deco; /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc. * They should not be referenced by anybody but mtype.c. * They can be NULL if not lazily evaluated yet. * Note that there is no "shared immutable", because that is just immutable * Naked == no MOD bits */ Type cto; // MODFlags.const_ ? naked version of this type : const version Type ito; // MODFlags.immutable_ ? naked version of this type : immutable version Type sto; // MODFlags.shared_ ? naked version of this type : shared mutable version Type scto; // MODFlags.shared_ | MODFlags.const_ ? naked version of this type : shared const version Type wto; // MODFlags.wild ? naked version of this type : wild version Type wcto; // MODFlags.wildconst ? naked version of this type : wild const version Type swto; // MODFlags.shared_ | MODFlags.wild ? naked version of this type : shared wild version Type swcto; // MODFlags.shared_ | MODFlags.wildconst ? naked version of this type : shared wild const version Type pto; // merged pointer to this type Type rto; // reference to this type Type arrayof; // array of this type TypeInfoDeclaration vtinfo; // TypeInfo object for this Type type* ctype; // for back end extern (C++) __gshared Type tvoid; extern (C++) __gshared Type tint8; extern (C++) __gshared Type tuns8; extern (C++) __gshared Type tint16; extern (C++) __gshared Type tuns16; extern (C++) __gshared Type tint32; extern (C++) __gshared Type tuns32; extern (C++) __gshared Type tint64; extern (C++) __gshared Type tuns64; extern (C++) __gshared Type tint128; extern (C++) __gshared Type tuns128; extern (C++) __gshared Type tfloat32; extern (C++) __gshared Type tfloat64; extern (C++) __gshared Type tfloat80; extern (C++) __gshared Type timaginary32; extern (C++) __gshared Type timaginary64; extern (C++) __gshared Type timaginary80; extern (C++) __gshared Type tcomplex32; extern (C++) __gshared Type tcomplex64; extern (C++) __gshared Type tcomplex80; extern (C++) __gshared Type tbool; extern (C++) __gshared Type tchar; extern (C++) __gshared Type twchar; extern (C++) __gshared Type tdchar; // Some special types extern (C++) __gshared Type tshiftcnt; extern (C++) __gshared Type tvoidptr; // void* extern (C++) __gshared Type tstring; // immutable(char)[] extern (C++) __gshared Type twstring; // immutable(wchar)[] extern (C++) __gshared Type tdstring; // immutable(dchar)[] extern (C++) __gshared Type tvalist; // va_list alias extern (C++) __gshared Type terror; // for error recovery extern (C++) __gshared Type tnull; // for null type extern (C++) __gshared Type tsize_t; // matches size_t alias extern (C++) __gshared Type tptrdiff_t; // matches ptrdiff_t alias extern (C++) __gshared Type thash_t; // matches hash_t alias extern (C++) __gshared ClassDeclaration dtypeinfo; extern (C++) __gshared ClassDeclaration typeinfoclass; extern (C++) __gshared ClassDeclaration typeinfointerface; extern (C++) __gshared ClassDeclaration typeinfostruct; extern (C++) __gshared ClassDeclaration typeinfopointer; extern (C++) __gshared ClassDeclaration typeinfoarray; extern (C++) __gshared ClassDeclaration typeinfostaticarray; extern (C++) __gshared ClassDeclaration typeinfoassociativearray; extern (C++) __gshared ClassDeclaration typeinfovector; extern (C++) __gshared ClassDeclaration typeinfoenum; extern (C++) __gshared ClassDeclaration typeinfofunction; extern (C++) __gshared ClassDeclaration typeinfodelegate; extern (C++) __gshared ClassDeclaration typeinfotypelist; extern (C++) __gshared ClassDeclaration typeinfoconst; extern (C++) __gshared ClassDeclaration typeinfoinvariant; extern (C++) __gshared ClassDeclaration typeinfoshared; extern (C++) __gshared ClassDeclaration typeinfowild; extern (C++) __gshared TemplateDeclaration rtinfo; extern (C++) __gshared Type[TMAX] basic; extern (D) __gshared StringTable stringtable; extern (D) private __gshared ubyte[TMAX] sizeTy = () { ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic); sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray); sizeTy[Tarray] = __traits(classInstanceSize, TypeDArray); sizeTy[Taarray] = __traits(classInstanceSize, TypeAArray); sizeTy[Tpointer] = __traits(classInstanceSize, TypePointer); sizeTy[Treference] = __traits(classInstanceSize, TypeReference); sizeTy[Tfunction] = __traits(classInstanceSize, TypeFunction); sizeTy[Tdelegate] = __traits(classInstanceSize, TypeDelegate); sizeTy[Tident] = __traits(classInstanceSize, TypeIdentifier); sizeTy[Tinstance] = __traits(classInstanceSize, TypeInstance); sizeTy[Ttypeof] = __traits(classInstanceSize, TypeTypeof); sizeTy[Tenum] = __traits(classInstanceSize, TypeEnum); sizeTy[Tstruct] = __traits(classInstanceSize, TypeStruct); sizeTy[Tclass] = __traits(classInstanceSize, TypeClass); sizeTy[Ttuple] = __traits(classInstanceSize, TypeTuple); sizeTy[Tslice] = __traits(classInstanceSize, TypeSlice); sizeTy[Treturn] = __traits(classInstanceSize, TypeReturn); sizeTy[Terror] = __traits(classInstanceSize, TypeError); sizeTy[Tnull] = __traits(classInstanceSize, TypeNull); sizeTy[Tvector] = __traits(classInstanceSize, TypeVector); return sizeTy; }(); final extern (D) this(TY ty) { this.ty = ty; } const(char)* kind() const nothrow pure @nogc @safe { assert(false); // should be overridden } final Type copy() nothrow { Type t = cast(Type)mem.xmalloc(sizeTy[ty]); memcpy(cast(void*)t, cast(void*)this, sizeTy[ty]); return t; } Type syntaxCopy() { fprintf(stderr, "this = %s, ty = %d\n", toChars(), ty); assert(0); } override bool equals(RootObject o) const { Type t = cast(Type)o; //printf("Type::equals(%s, %s)\n", toChars(), t.toChars()); // deco strings are unique // and semantic() has been run if (this == o || ((t && deco == t.deco) && deco !is null)) { //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); return true; } //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco); return false; } final bool equivalent(Type t) { return immutableOf().equals(t.immutableOf()); } // kludge for template.isType() override final DYNCAST dyncast() const { return DYNCAST.type; } /******************************* * Covariant means that 'this' can substitute for 't', * i.e. a pure function is a match for an impure type. * Params: * t = type 'this' is covariant with * pstc = if not null, store STCxxxx which would make it covariant * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349 * Returns: * 0 types are distinct * 1 this is covariant with t * 2 arguments match as far as overloading goes, * but types are not covariant * 3 cannot determine covariance because of forward references * *pstc STCxxxx which would make it covariant */ final int covariant(Type t, StorageClass* pstc = null, bool fix17349 = true) { version (none) { printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); printf("deco = %p, %p\n", deco, t.deco); // printf("ty = %d\n", next.ty); printf("mod = %x, %x\n", mod, t.mod); } if (pstc) *pstc = 0; StorageClass stc = 0; bool notcovariant = false; TypeFunction t1; TypeFunction t2; if (equals(t)) return 1; // covariant if (ty != Tfunction || t.ty != Tfunction) goto Ldistinct; t1 = cast(TypeFunction)this; t2 = cast(TypeFunction)t; if (t1.varargs != t2.varargs) goto Ldistinct; if (t1.parameters && t2.parameters) { size_t dim = Parameter.dim(t1.parameters); if (dim != Parameter.dim(t2.parameters)) goto Ldistinct; for (size_t i = 0; i < dim; i++) { Parameter fparam1 = Parameter.getNth(t1.parameters, i); Parameter fparam2 = Parameter.getNth(t2.parameters, i); if (!fparam1.type.equals(fparam2.type)) { if (!fix17349) goto Ldistinct; Type tp1 = fparam1.type; Type tp2 = fparam2.type; if (tp1.ty == tp2.ty) { if (tp1.ty == Tclass) { if ((cast(TypeClass)tp1).sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) goto Lcov; } else if (tp1.ty == Tstruct) { if ((cast(TypeStruct)tp1).sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) goto Lcov; } else if (tp1.ty == Tpointer) { if (tp2.implicitConvTo(tp1)) goto Lcov; } else if (tp1.ty == Tarray) { if (tp2.implicitConvTo(tp1)) goto Lcov; } else if (tp1.ty == Tdelegate) { if (tp1.implicitConvTo(tp2)) goto Lcov; } } goto Ldistinct; } Lcov: notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); } } else if (t1.parameters != t2.parameters) { size_t dim1 = !t1.parameters ? 0 : t1.parameters.dim; size_t dim2 = !t2.parameters ? 0 : t2.parameters.dim; if (dim1 || dim2) goto Ldistinct; } // The argument lists match if (notcovariant) goto Lnotcovariant; if (t1.linkage != t2.linkage) goto Lnotcovariant; { // Return types Type t1n = t1.next; Type t2n = t2.next; if (!t1n || !t2n) // happens with return type inference goto Lnotcovariant; if (t1n.equals(t2n)) goto Lcovariant; if (t1n.ty == Tclass && t2n.ty == Tclass) { /* If same class type, but t2n is const, then it's * covariant. Do this test first because it can work on * forward references. */ if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) goto Lcovariant; // If t1n is forward referenced: ClassDeclaration cd = (cast(TypeClass)t1n).sym; if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) cd.dsymbolSemantic(null); if (!cd.isBaseInfoComplete()) { return 3; // forward references } } if (t1n.ty == Tstruct && t2n.ty == Tstruct) { if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) goto Lcovariant; } else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) goto Lcovariant; else if (t1n.ty == Tnull && t1n.implicitConvTo(t2n) && t1n.size() == t2n.size()) goto Lcovariant; } goto Lnotcovariant; Lcovariant: if (t1.isref != t2.isref) goto Lnotcovariant; if (!t1.isref && (t1.isscope || t2.isscope)) { StorageClass stc1 = t1.isscope ? STC.scope_ : 0; StorageClass stc2 = t2.isscope ? STC.scope_ : 0; if (t1.isreturn) { stc1 |= STC.return_; if (!t1.isscope) stc1 |= STC.ref_; } if (t2.isreturn) { stc2 |= STC.return_; if (!t2.isscope) stc2 |= STC.ref_; } if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) goto Lnotcovariant; } // We can subtract 'return ref' from 'this', but cannot add it else if (t1.isreturn && !t2.isreturn) goto Lnotcovariant; /* Can convert mutable to const */ if (!MODimplicitConv(t2.mod, t1.mod)) { version (none) { //stop attribute inference with const // If adding 'const' will make it covariant if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) stc |= STC.const_; else goto Lnotcovariant; } else { goto Ldistinct; } } /* Can convert pure to impure, nothrow to throw, and nogc to gc */ if (!t1.purity && t2.purity) stc |= STC.pure_; if (!t1.isnothrow && t2.isnothrow) stc |= STC.nothrow_; if (!t1.isnogc && t2.isnogc) stc |= STC.nogc; /* Can convert safe/trusted to system */ if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) { // Should we infer trusted or safe? Go with safe. stc |= STC.safe; } if (stc) { if (pstc) *pstc = stc; goto Lnotcovariant; } //printf("\tcovaraint: 1\n"); return 1; Ldistinct: //printf("\tcovaraint: 0\n"); return 0; Lnotcovariant: //printf("\tcovaraint: 2\n"); return 2; } /******************************** * For pretty-printing a type. */ final override const(char)* toChars() { OutBuffer buf; buf.reserve(16); HdrGenState hgs; hgs.fullQual = (ty == Tclass && !mod); .toCBuffer(this, &buf, null, &hgs); return buf.extractString(); } /// ditto final char* toPrettyChars(bool QualifyTypes = false) { OutBuffer buf; buf.reserve(16); HdrGenState hgs; hgs.fullQual = QualifyTypes; .toCBuffer(this, &buf, null, &hgs); return buf.extractString(); } static void _init() { stringtable._init(14000); // Set basic types __gshared TY* basetab = [ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, Tint128, Tuns128, Tfloat32, Tfloat64, Tfloat80, Timaginary32, Timaginary64, Timaginary80, Tcomplex32, Tcomplex64, Tcomplex80, Tbool, Tchar, Twchar, Tdchar, Terror ]; for (size_t i = 0; basetab[i] != Terror; i++) { Type t = new TypeBasic(basetab[i]); t = t.merge(); basic[basetab[i]] = t; } basic[Terror] = new TypeError(); tvoid = basic[Tvoid]; tint8 = basic[Tint8]; tuns8 = basic[Tuns8]; tint16 = basic[Tint16]; tuns16 = basic[Tuns16]; tint32 = basic[Tint32]; tuns32 = basic[Tuns32]; tint64 = basic[Tint64]; tuns64 = basic[Tuns64]; tint128 = basic[Tint128]; tuns128 = basic[Tuns128]; tfloat32 = basic[Tfloat32]; tfloat64 = basic[Tfloat64]; tfloat80 = basic[Tfloat80]; timaginary32 = basic[Timaginary32]; timaginary64 = basic[Timaginary64]; timaginary80 = basic[Timaginary80]; tcomplex32 = basic[Tcomplex32]; tcomplex64 = basic[Tcomplex64]; tcomplex80 = basic[Tcomplex80]; tbool = basic[Tbool]; tchar = basic[Tchar]; twchar = basic[Twchar]; tdchar = basic[Tdchar]; tshiftcnt = tint32; terror = basic[Terror]; tnull = basic[Tnull]; tnull = new TypeNull(); tnull.deco = tnull.merge().deco; tvoidptr = tvoid.pointerTo(); tstring = tchar.immutableOf().arrayOf(); twstring = twchar.immutableOf().arrayOf(); tdstring = tdchar.immutableOf().arrayOf(); tvalist = Target.va_listType(); if (global.params.isLP64) { Tsize_t = Tuns64; Tptrdiff_t = Tint64; } else { Tsize_t = Tuns32; Tptrdiff_t = Tint32; } tsize_t = basic[Tsize_t]; tptrdiff_t = basic[Tptrdiff_t]; thash_t = tsize_t; } final d_uns64 size() { return size(Loc.initial); } d_uns64 size(const ref Loc loc) { error(loc, "no size for type `%s`", toChars()); return SIZE_INVALID; } uint alignsize() { return cast(uint)size(Loc.initial); } final Type trySemantic(const ref Loc loc, Scope* sc) { //printf("+trySemantic(%s) %d\n", toChars(), global.errors); // Needed to display any deprecations that were gagged auto tcopy = this.syntaxCopy(); uint errors = global.startGagging(); Type t = typeSemantic(this, loc, sc); if (global.endGagging(errors) || t.ty == Terror) // if any errors happened { t = null; } else { // If `typeSemantic` succeeded, there may have been deprecations that // were gagged due the the `startGagging` above. Run again to display // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 if (global.gaggedWarnings > 0) typeSemantic(tcopy, loc, sc); } //printf("-trySemantic(%s) %d\n", toChars(), global.errors); return t; } /************************************* * This version does a merge even if the deco is already computed. * Necessary for types that have a deco, but are not merged. */ final Type merge2() { //printf("merge2(%s)\n", toChars()); Type t = this; assert(t); if (!t.deco) return t.merge(); StringValue* sv = stringtable.lookup(t.deco, strlen(t.deco)); if (sv && sv.ptrvalue) { t = cast(Type)sv.ptrvalue; assert(t.deco); } else assert(0); return t; } /********************************* * Store this type's modifier name into buf. */ final void modToBuffer(OutBuffer* buf) nothrow { if (mod) { buf.writeByte(' '); MODtoBuffer(buf, mod); } } /********************************* * Return this type's modifier name. */ final char* modToChars() nothrow { OutBuffer buf; buf.reserve(16); modToBuffer(&buf); return buf.extractString(); } bool isintegral() { return false; } // real, imaginary, or complex bool isfloating() { return false; } bool isreal() { return false; } bool isimaginary() { return false; } bool iscomplex() { return false; } bool isscalar() { return false; } bool isunsigned() { return false; } bool isscope() { return false; } bool isString() { return false; } /************************** * When T is mutable, * Given: * T a, b; * Can we bitwise assign: * a = b; * ? */ bool isAssignable() { return true; } /************************** * Returns true if T can be converted to boolean value. */ bool isBoolean() { return isscalar(); } /********************************* * Check type to see if it is based on a deprecated symbol. */ void checkDeprecated(const ref Loc loc, Scope* sc) { if (Dsymbol s = toDsymbol(sc)) { s.checkDeprecated(loc, sc); } } final bool isConst() const nothrow pure @nogc @safe { return (mod & MODFlags.const_) != 0; } final bool isImmutable() const nothrow pure @nogc @safe { return (mod & MODFlags.immutable_) != 0; } final bool isMutable() const nothrow pure @nogc @safe { return (mod & (MODFlags.const_ | MODFlags.immutable_ | MODFlags.wild)) == 0; } final bool isShared() const nothrow pure @nogc @safe { return (mod & MODFlags.shared_) != 0; } final bool isSharedConst() const nothrow pure @nogc @safe { return (mod & (MODFlags.shared_ | MODFlags.const_)) == (MODFlags.shared_ | MODFlags.const_); } final bool isWild() const nothrow pure @nogc @safe { return (mod & MODFlags.wild) != 0; } final bool isWildConst() const nothrow pure @nogc @safe { return (mod & MODFlags.wildconst) == MODFlags.wildconst; } final bool isSharedWild() const nothrow pure @nogc @safe { return (mod & (MODFlags.shared_ | MODFlags.wild)) == (MODFlags.shared_ | MODFlags.wild); } final bool isNaked() const nothrow pure @nogc @safe { return mod == 0; } /******************************** * Return a copy of this type with all attributes null-initialized. * Useful for creating a type with different modifiers. */ final Type nullAttributes() nothrow { uint sz = sizeTy[ty]; Type t = cast(Type)mem.xmalloc(sz); memcpy(cast(void*)t, cast(void*)this, sz); // t.mod = NULL; // leave mod unchanged t.deco = null; t.arrayof = null; t.pto = null; t.rto = null; t.cto = null; t.ito = null; t.sto = null; t.scto = null; t.wto = null; t.wcto = null; t.swto = null; t.swcto = null; t.vtinfo = null; t.ctype = null; if (t.ty == Tstruct) (cast(TypeStruct)t).att = AliasThisRec.fwdref; if (t.ty == Tclass) (cast(TypeClass)t).att = AliasThisRec.fwdref; return t; } /******************************** * Convert to 'const'. */ final Type constOf() { //printf("Type::constOf() %p %s\n", this, toChars()); if (mod == MODFlags.const_) return this; if (cto) { assert(cto.mod == MODFlags.const_); return cto; } Type t = makeConst(); t = t.merge(); t.fixTo(this); //printf("-Type::constOf() %p %s\n", t, t.toChars()); return t; } /******************************** * Convert to 'immutable'. */ final Type immutableOf() { //printf("Type::immutableOf() %p %s\n", this, toChars()); if (isImmutable()) return this; if (ito) { assert(ito.isImmutable()); return ito; } Type t = makeImmutable(); t = t.merge(); t.fixTo(this); //printf("\t%p\n", t); return t; } /******************************** * Make type mutable. */ final Type mutableOf() { //printf("Type::mutableOf() %p, %s\n", this, toChars()); Type t = this; if (isImmutable()) { t = ito; // immutable => naked assert(!t || (t.isMutable() && !t.isShared())); } else if (isConst()) { if (isShared()) { if (isWild()) t = swcto; // shared wild const -> shared else t = sto; // shared const => shared } else { if (isWild()) t = wcto; // wild const -> naked else t = cto; // const => naked } assert(!t || t.isMutable()); } else if (isWild()) { if (isShared()) t = sto; // shared wild => shared else t = wto; // wild => naked assert(!t || t.isMutable()); } if (!t) { t = makeMutable(); t = t.merge(); t.fixTo(this); } else t = t.merge(); assert(t.isMutable()); return t; } final Type sharedOf() { //printf("Type::sharedOf() %p, %s\n", this, toChars()); if (mod == MODFlags.shared_) return this; if (sto) { assert(sto.mod == MODFlags.shared_); return sto; } Type t = makeShared(); t = t.merge(); t.fixTo(this); //printf("\t%p\n", t); return t; } final Type sharedConstOf() { //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); if (mod == (MODFlags.shared_ | MODFlags.const_)) return this; if (scto) { assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); return scto; } Type t = makeSharedConst(); t = t.merge(); t.fixTo(this); //printf("\t%p\n", t); return t; } /******************************** * Make type unshared. * 0 => 0 * const => const * immutable => immutable * shared => 0 * shared const => const * wild => wild * wild const => wild const * shared wild => wild * shared wild const => wild const */ final Type unSharedOf() { //printf("Type::unSharedOf() %p, %s\n", this, toChars()); Type t = this; if (isShared()) { if (isWild()) { if (isConst()) t = wcto; // shared wild const => wild const else t = wto; // shared wild => wild } else { if (isConst()) t = cto; // shared const => const else t = sto; // shared => naked } assert(!t || !t.isShared()); } if (!t) { t = this.nullAttributes(); t.mod = mod & ~MODFlags.shared_; t.ctype = ctype; t = t.merge(); t.fixTo(this); } else t = t.merge(); assert(!t.isShared()); return t; } /******************************** * Convert to 'wild'. */ final Type wildOf() { //printf("Type::wildOf() %p %s\n", this, toChars()); if (mod == MODFlags.wild) return this; if (wto) { assert(wto.mod == MODFlags.wild); return wto; } Type t = makeWild(); t = t.merge(); t.fixTo(this); //printf("\t%p %s\n", t, t.toChars()); return t; } final Type wildConstOf() { //printf("Type::wildConstOf() %p %s\n", this, toChars()); if (mod == MODFlags.wildconst) return this; if (wcto) { assert(wcto.mod == MODFlags.wildconst); return wcto; } Type t = makeWildConst(); t = t.merge(); t.fixTo(this); //printf("\t%p %s\n", t, t.toChars()); return t; } final Type sharedWildOf() { //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); if (mod == (MODFlags.shared_ | MODFlags.wild)) return this; if (swto) { assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); return swto; } Type t = makeSharedWild(); t = t.merge(); t.fixTo(this); //printf("\t%p %s\n", t, t.toChars()); return t; } final Type sharedWildConstOf() { //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars()); if (mod == (MODFlags.shared_ | MODFlags.wildconst)) return this; if (swcto) { assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); return swcto; } Type t = makeSharedWildConst(); t = t.merge(); t.fixTo(this); //printf("\t%p %s\n", t, t.toChars()); return t; } /********************************** * For our new type 'this', which is type-constructed from t, * fill in the cto, ito, sto, scto, wto shortcuts. */ final void fixTo(Type t) { // If fixing this: immutable(T*) by t: immutable(T)*, // cache t to this.xto won't break transitivity. Type mto = null; Type tn = nextOf(); if (!tn || ty != Tsarray && tn.mod == t.nextOf().mod) { switch (t.mod) { case 0: mto = t; break; case MODFlags.const_: cto = t; break; case MODFlags.wild: wto = t; break; case MODFlags.wildconst: wcto = t; break; case MODFlags.shared_: sto = t; break; case MODFlags.shared_ | MODFlags.const_: scto = t; break; case MODFlags.shared_ | MODFlags.wild: swto = t; break; case MODFlags.shared_ | MODFlags.wildconst: swcto = t; break; case MODFlags.immutable_: ito = t; break; default: break; } } assert(mod != t.mod); auto X(T, U)(T m, U n) { return ((m << 4) | n); } switch (mod) { case 0: break; case MODFlags.const_: cto = mto; t.cto = this; break; case MODFlags.wild: wto = mto; t.wto = this; break; case MODFlags.wildconst: wcto = mto; t.wcto = this; break; case MODFlags.shared_: sto = mto; t.sto = this; break; case MODFlags.shared_ | MODFlags.const_: scto = mto; t.scto = this; break; case MODFlags.shared_ | MODFlags.wild: swto = mto; t.swto = this; break; case MODFlags.shared_ | MODFlags.wildconst: swcto = mto; t.swcto = this; break; case MODFlags.immutable_: t.ito = this; if (t.cto) t.cto.ito = this; if (t.sto) t.sto.ito = this; if (t.scto) t.scto.ito = this; if (t.wto) t.wto.ito = this; if (t.wcto) t.wcto.ito = this; if (t.swto) t.swto.ito = this; if (t.swcto) t.swcto.ito = this; break; default: assert(0); } check(); t.check(); //printf("fixTo: %s, %s\n", toChars(), t.toChars()); } /*************************** * Look for bugs in constructing types. */ final void check() { switch (mod) { case 0: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.const_: if (cto) assert(cto.mod == 0); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.wild: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == 0); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.wildconst: assert(!cto || cto.mod == MODFlags.const_); assert(!ito || ito.mod == MODFlags.immutable_); assert(!sto || sto.mod == MODFlags.shared_); assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); assert(!wto || wto.mod == MODFlags.wild); assert(!wcto || wcto.mod == 0); assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); assert(!swcto || swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.shared_: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == 0); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.shared_ | MODFlags.const_: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == 0); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.shared_ | MODFlags.wild: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == MODFlags.immutable_); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == 0); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; case MODFlags.shared_ | MODFlags.wildconst: assert(!cto || cto.mod == MODFlags.const_); assert(!ito || ito.mod == MODFlags.immutable_); assert(!sto || sto.mod == MODFlags.shared_); assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_)); assert(!wto || wto.mod == MODFlags.wild); assert(!wcto || wcto.mod == MODFlags.wildconst); assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild)); assert(!swcto || swcto.mod == 0); break; case MODFlags.immutable_: if (cto) assert(cto.mod == MODFlags.const_); if (ito) assert(ito.mod == 0); if (sto) assert(sto.mod == MODFlags.shared_); if (scto) assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); if (wto) assert(wto.mod == MODFlags.wild); if (wcto) assert(wcto.mod == MODFlags.wildconst); if (swto) assert(swto.mod == (MODFlags.shared_ | MODFlags.wild)); if (swcto) assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); break; default: assert(0); } Type tn = nextOf(); if (tn && ty != Tfunction && tn.ty != Tfunction && ty != Tenum) { // Verify transitivity switch (mod) { case 0: case MODFlags.const_: case MODFlags.wild: case MODFlags.wildconst: case MODFlags.shared_: case MODFlags.shared_ | MODFlags.const_: case MODFlags.shared_ | MODFlags.wild: case MODFlags.shared_ | MODFlags.wildconst: case MODFlags.immutable_: assert(tn.mod == MODFlags.immutable_ || (tn.mod & mod) == mod); break; default: assert(0); } tn.check(); } } /************************************* * Apply STCxxxx bits to existing type. * Use *before* semantic analysis is run. */ final Type addSTC(StorageClass stc) { Type t = this; if (t.isImmutable()) { } else if (stc & STC.immutable_) { t = t.makeImmutable(); } else { if ((stc & STC.shared_) && !t.isShared()) { if (t.isWild()) { if (t.isConst()) t = t.makeSharedWildConst(); else t = t.makeSharedWild(); } else { if (t.isConst()) t = t.makeSharedConst(); else t = t.makeShared(); } } if ((stc & STC.const_) && !t.isConst()) { if (t.isShared()) { if (t.isWild()) t = t.makeSharedWildConst(); else t = t.makeSharedConst(); } else { if (t.isWild()) t = t.makeWildConst(); else t = t.makeConst(); } } if ((stc & STC.wild) && !t.isWild()) { if (t.isShared()) { if (t.isConst()) t = t.makeSharedWildConst(); else t = t.makeSharedWild(); } else { if (t.isConst()) t = t.makeWildConst(); else t = t.makeWild(); } } } return t; } /************************************ * Apply MODxxxx bits to existing type. */ final Type castMod(MOD mod) { Type t; switch (mod) { case 0: t = unSharedOf().mutableOf(); break; case MODFlags.const_: t = unSharedOf().constOf(); break; case MODFlags.wild: t = unSharedOf().wildOf(); break; case MODFlags.wildconst: t = unSharedOf().wildConstOf(); break; case MODFlags.shared_: t = mutableOf().sharedOf(); break; case MODFlags.shared_ | MODFlags.const_: t = sharedConstOf(); break; case MODFlags.shared_ | MODFlags.wild: t = sharedWildOf(); break; case MODFlags.shared_ | MODFlags.wildconst: t = sharedWildConstOf(); break; case MODFlags.immutable_: t = immutableOf(); break; default: assert(0); } return t; } /************************************ * Add MODxxxx bits to existing type. * We're adding, not replacing, so adding const to * a shared type => "shared const" */ final Type addMod(MOD mod) { /* Add anything to immutable, and it remains immutable */ Type t = this; if (!t.isImmutable()) { //printf("addMod(%x) %s\n", mod, toChars()); switch (mod) { case 0: break; case MODFlags.const_: if (isShared()) { if (isWild()) t = sharedWildConstOf(); else t = sharedConstOf(); } else { if (isWild()) t = wildConstOf(); else t = constOf(); } break; case MODFlags.wild: if (isShared()) { if (isConst()) t = sharedWildConstOf(); else t = sharedWildOf(); } else { if (isConst()) t = wildConstOf(); else t = wildOf(); } break; case MODFlags.wildconst: if (isShared()) t = sharedWildConstOf(); else t = wildConstOf(); break; case MODFlags.shared_: if (isWild()) { if (isConst()) t = sharedWildConstOf(); else t = sharedWildOf(); } else { if (isConst()) t = sharedConstOf(); else t = sharedOf(); } break; case MODFlags.shared_ | MODFlags.const_: if (isWild()) t = sharedWildConstOf(); else t = sharedConstOf(); break; case MODFlags.shared_ | MODFlags.wild: if (isConst()) t = sharedWildConstOf(); else t = sharedWildOf(); break; case MODFlags.shared_ | MODFlags.wildconst: t = sharedWildConstOf(); break; case MODFlags.immutable_: t = immutableOf(); break; default: assert(0); } } return t; } /************************************ * Add storage class modifiers to type. */ Type addStorageClass(StorageClass stc) { /* Just translate to MOD bits and let addMod() do the work */ MOD mod = 0; if (stc & STC.immutable_) mod = MODFlags.immutable_; else { if (stc & (STC.const_ | STC.in_)) mod |= MODFlags.const_; if (stc & STC.wild) mod |= MODFlags.wild; if (stc & STC.shared_) mod |= MODFlags.shared_; } return addMod(mod); } final Type pointerTo() { if (ty == Terror) return this; if (!pto) { Type t = new TypePointer(this); if (ty == Tfunction) { t.deco = t.merge().deco; pto = t; } else pto = t.merge(); } return pto; } final Type referenceTo() { if (ty == Terror) return this; if (!rto) { Type t = new TypeReference(this); rto = t.merge(); } return rto; } final Type arrayOf() { if (ty == Terror) return this; if (!arrayof) { Type t = new TypeDArray(this); arrayof = t.merge(); } return arrayof; } // Make corresponding static array type without semantic final Type sarrayOf(dinteger_t dim) { assert(deco); Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t)); // according to TypeSArray::semantic() t = t.addMod(mod); t = t.merge(); return t; } final Type aliasthisOf() { auto ad = isAggregate(this); if (!ad || !ad.aliasthis) return null; auto s = ad.aliasthis; if (s.isAliasDeclaration()) s = s.toAlias(); if (s.isTupleDeclaration()) return null; if (auto vd = s.isVarDeclaration()) { auto t = vd.type; if (vd.needThis()) t = t.addMod(this.mod); return t; } if (auto fd = s.isFuncDeclaration()) { fd = resolveFuncCall(Loc.initial, null, fd, null, this, null, 1); if (!fd || fd.errors || !fd.functionSemantic()) return Type.terror; auto t = fd.type.nextOf(); if (!t) // issue 14185 return Type.terror; t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); return t; } if (auto d = s.isDeclaration()) { assert(d.type); return d.type; } if (auto ed = s.isEnumDeclaration()) { return ed.type; } if (auto td = s.isTemplateDeclaration()) { assert(td._scope); auto fd = resolveFuncCall(Loc.initial, null, td, null, this, null, 1); if (!fd || fd.errors || !fd.functionSemantic()) return Type.terror; auto t = fd.type.nextOf(); if (!t) return Type.terror; t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); return t; } //printf("%s\n", s.kind()); return null; } extern (D) final bool checkAliasThisRec() { Type tb = toBasetype(); AliasThisRec* pflag; if (tb.ty == Tstruct) pflag = &(cast(TypeStruct)tb).att; else if (tb.ty == Tclass) pflag = &(cast(TypeClass)tb).att; else return false; AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask); if (flag == AliasThisRec.fwdref) { Type att = aliasthisOf(); flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no; } *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask)); return flag == AliasThisRec.yes; } Type makeConst() { //printf("Type::makeConst() %p, %s\n", this, toChars()); if (cto) return cto; Type t = this.nullAttributes(); t.mod = MODFlags.const_; //printf("-Type::makeConst() %p, %s\n", t, toChars()); return t; } Type makeImmutable() { if (ito) return ito; Type t = this.nullAttributes(); t.mod = MODFlags.immutable_; return t; } Type makeShared() { if (sto) return sto; Type t = this.nullAttributes(); t.mod = MODFlags.shared_; return t; } Type makeSharedConst() { if (scto) return scto; Type t = this.nullAttributes(); t.mod = MODFlags.shared_ | MODFlags.const_; return t; } Type makeWild() { if (wto) return wto; Type t = this.nullAttributes(); t.mod = MODFlags.wild; return t; } Type makeWildConst() { if (wcto) return wcto; Type t = this.nullAttributes(); t.mod = MODFlags.wildconst; return t; } Type makeSharedWild() { if (swto) return swto; Type t = this.nullAttributes(); t.mod = MODFlags.shared_ | MODFlags.wild; return t; } Type makeSharedWildConst() { if (swcto) return swcto; Type t = this.nullAttributes(); t.mod = MODFlags.shared_ | MODFlags.wildconst; return t; } Type makeMutable() { Type t = this.nullAttributes(); t.mod = mod & MODFlags.shared_; return t; } Dsymbol toDsymbol(Scope* sc) { return null; } /******************************* * If this is a shell around another type, * get that other type. */ Type toBasetype() { return this; } bool isBaseOf(Type t, int* poffset) { return 0; // assume not } /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. * Returns: * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact */ MATCH implicitConvTo(Type to) { //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to.toChars()); if (this.equals(to)) return MATCH.exact; return MATCH.nomatch; } /******************************* * Determine if converting 'this' to 'to' is an identity operation, * a conversion to const operation, or the types aren't the same. * Returns: * MATCH.exact 'this' == 'to' * MATCH.constant 'to' is const * MATCH.nomatch conversion to mutable or invariant */ MATCH constConv(Type to) { //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars()); if (equals(to)) return MATCH.exact; if (ty == to.ty && MODimplicitConv(mod, to.mod)) return MATCH.constant; return MATCH.nomatch; } /*************************************** * Compute MOD bits matching `this` argument type to wild parameter type. * Params: * t = corresponding parameter type * isRef = parameter is `ref` or `out` * Returns: * MOD bits */ MOD deduceWild(Type t, bool isRef) { //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars()); if (t.isWild()) { if (isImmutable()) return MODFlags.immutable_; else if (isWildConst()) { if (t.isWildConst()) return MODFlags.wild; else return MODFlags.wildconst; } else if (isWild()) return MODFlags.wild; else if (isConst()) return MODFlags.const_; else if (isMutable()) return MODFlags.mutable; else assert(0); } return 0; } Type substWildTo(uint mod) { //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); Type t; if (Type tn = nextOf()) { // substitution has no effect on function pointer type. if (ty == Tpointer && tn.ty == Tfunction) { t = this; goto L1; } t = tn.substWildTo(mod); if (t == tn) t = this; else { if (ty == Tpointer) t = t.pointerTo(); else if (ty == Tarray) t = t.arrayOf(); else if (ty == Tsarray) t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy()); else if (ty == Taarray) { t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy()); (cast(TypeAArray)t).sc = (cast(TypeAArray)this).sc; // duplicate scope } else if (ty == Tdelegate) { t = new TypeDelegate(t); } else assert(0); t = t.merge(); } } else t = this; L1: if (isWild()) { if (mod == MODFlags.immutable_) { t = t.immutableOf(); } else if (mod == MODFlags.wildconst) { t = t.wildConstOf(); } else if (mod == MODFlags.wild) { if (isWildConst()) t = t.wildConstOf(); else t = t.wildOf(); } else if (mod == MODFlags.const_) { t = t.constOf(); } else { if (isWildConst()) t = t.constOf(); else t = t.mutableOf(); } } if (isConst()) t = t.addMod(MODFlags.const_); if (isShared()) t = t.addMod(MODFlags.shared_); //printf("-Type::substWildTo t = %s\n", t.toChars()); return t; } final Type unqualify(uint m) { Type t = mutableOf().unSharedOf(); Type tn = ty == Tenum ? null : nextOf(); if (tn && tn.ty != Tfunction) { Type utn = tn.unqualify(m); if (utn != tn) { if (ty == Tpointer) t = utn.pointerTo(); else if (ty == Tarray) t = utn.arrayOf(); else if (ty == Tsarray) t = new TypeSArray(utn, (cast(TypeSArray)this).dim); else if (ty == Taarray) { t = new TypeAArray(utn, (cast(TypeAArray)this).index); (cast(TypeAArray)t).sc = (cast(TypeAArray)this).sc; // duplicate scope } else assert(0); t = t.merge(); } } t = t.addMod(mod & ~m); return t; } /************************** * Return type with the top level of it being mutable. */ Type toHeadMutable() { if (!mod) return this; return mutableOf(); } inout(ClassDeclaration) isClassHandle() inout { return null; } /************************************ * Return alignment to use for this type. */ structalign_t alignment() { return STRUCTALIGN_DEFAULT; } /*************************************** * Use when we prefer the default initializer to be a literal, * rather than a global immutable variable. */ Expression defaultInitLiteral(const ref Loc loc) { static if (LOGDEFAULTINIT) { printf("Type::defaultInitLiteral() '%s'\n", toChars()); } return defaultInit(this, loc); } // if initializer is 0 bool isZeroInit(const ref Loc loc) { return false; // assume not } final Identifier getTypeInfoIdent() { // _init_10TypeInfo_%s OutBuffer buf; buf.reserve(32); mangleToBuffer(this, &buf); const slice = buf.peekSlice(); // Allocate buffer on stack, fail over to using malloc() char[128] namebuf; const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)malloc(namelen); assert(name); const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); assert(0 < length && length < namelen); // don't overflow the buffer auto id = Identifier.idPool(name, length); if (name != namebuf.ptr) free(name); return id; } /*************************************** * Normalize `e` as the result of Type.resolve() process. */ final void resolveExp(Expression e, Type *pt, Expression *pe, Dsymbol* ps) { *pt = null; *pe = null; *ps = null; Dsymbol s; switch (e.op) { case TOK.error: *pt = Type.terror; return; case TOK.type: *pt = e.type; return; case TOK.variable: s = (cast(VarExp)e).var; if (s.isVarDeclaration()) goto default; //if (s.isOverDeclaration()) // todo; break; case TOK.template_: // TemplateDeclaration s = (cast(TemplateExp)e).td; break; case TOK.scope_: s = (cast(ScopeExp)e).sds; // TemplateDeclaration, TemplateInstance, Import, Package, Module break; case TOK.function_: s = getDsymbol(e); break; case TOK.dotTemplateDeclaration: s = (cast(DotTemplateExp)e).td; break; //case TOK.this_: //case TOK.super_: //case TOK.tuple: //case TOK.overloadSet: //case TOK.dotVariable: //case TOK.dotTemplateInstance: //case TOK.dotType: //case TOK.dotIdentifier: default: *pe = e; return; } *ps = s; } /*************************************** * Return !=0 if the type or any of its subtypes is wild. */ int hasWild() const { return mod & MODFlags.wild; } /*************************************** * Return !=0 if type has pointers that need to * be scanned by the GC during a collection cycle. */ bool hasPointers() { //printf("Type::hasPointers() %s, %d\n", toChars(), ty); return false; } /************************************* * Detect if type has pointer fields that are initialized to void. * Local stack variables with such void fields can remain uninitialized, * leading to pointer bugs. * Returns: * true if so */ bool hasVoidInitPointers() { return false; } /************************************* * If this is a type of something, return that something. */ Type nextOf() { return null; } /************************************* * If this is a type of static array, return its base element type. */ final Type baseElemOf() { Type t = toBasetype(); while (t.ty == Tsarray) t = (cast(TypeSArray)t).next.toBasetype(); return t; } /******************************************* * Compute number of elements for a (possibly multidimensional) static array, * or 1 for other types. * Params: * loc = for error message * Returns: * number of elements, uint.max on overflow */ final uint numberOfElems(const ref Loc loc) { //printf("Type::numberOfElems()\n"); uinteger_t n = 1; Type tb = this; while ((tb = tb.toBasetype()).ty == Tsarray) { bool overflow = false; n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow); if (overflow || n >= uint.max) { error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n); return uint.max; } tb = (cast(TypeSArray)tb).next; } return cast(uint)n; } /**************************************** * Return the mask that an integral type will * fit into. */ final uinteger_t sizemask() { uinteger_t m; switch (toBasetype().ty) { case Tbool: m = 1; break; case Tchar: case Tint8: case Tuns8: m = 0xFF; break; case Twchar: case Tint16: case Tuns16: m = 0xFFFFU; break; case Tdchar: case Tint32: case Tuns32: m = 0xFFFFFFFFU; break; case Tint64: case Tuns64: m = 0xFFFFFFFFFFFFFFFFUL; break; default: assert(0); } return m; } /******************************** * true if when type goes out of scope, it needs a destructor applied. * Only applies to value types, not ref types. */ bool needsDestruction() { return false; } /********************************* * */ bool needsNested() { return false; } /************************************* * https://issues.dlang.org/show_bug.cgi?id=14488 * Check if the inner most base type is complex or imaginary. * Should only give alerts when set to emit transitional messages. * Params: * loc = The source location. * sc = scope of the type */ extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) { if (sc.isDeprecated()) return false; Type t = baseElemOf(); while (t.ty == Tpointer || t.ty == Tarray) t = t.nextOf().baseElemOf(); // Basetype is an opaque enum, nothing to check. if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) return false; if (t.isimaginary() || t.iscomplex()) { Type rt; switch (t.ty) { case Tcomplex32: case Timaginary32: rt = Type.tfloat32; break; case Tcomplex64: case Timaginary64: rt = Type.tfloat64; break; case Tcomplex80: case Timaginary80: rt = Type.tfloat80; break; default: assert(0); } if (t.iscomplex()) { deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", toChars(), rt.toChars()); return true; } else { deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", toChars(), rt.toChars()); return true; } } return false; } // For eliminating dynamic_cast TypeBasic isTypeBasic() { return null; } void accept(Visitor v) { v.visit(this); } final TypeFunction toTypeFunction() { if (ty != Tfunction) assert(0); return cast(TypeFunction)this; } } /*********************************************************** */ extern (C++) final class TypeError : Type { extern (D) this() { super(Terror); } override Type syntaxCopy() { // No semantic analysis done, no need to copy return this; } override d_uns64 size(const ref Loc loc) { return SIZE_INVALID; } override Expression defaultInitLiteral(const ref Loc loc) { return new ErrorExp(); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) abstract class TypeNext : Type { Type next; final extern (D) this(TY ty, Type next) { super(ty); this.next = next; } override final void checkDeprecated(const ref Loc loc, Scope* sc) { Type.checkDeprecated(loc, sc); if (next) // next can be NULL if TypeFunction and auto return type next.checkDeprecated(loc, sc); } override final int hasWild() const { if (ty == Tfunction) return 0; if (ty == Tdelegate) return Type.hasWild(); return mod & MODFlags.wild || (next && next.hasWild()); } /******************************* * For TypeFunction, nextOf() can return NULL if the function return * type is meant to be inferred, and semantic() hasn't yet ben run * on the function. After semantic(), it must no longer be NULL. */ override final Type nextOf() { return next; } override final Type makeConst() { //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); if (cto) { assert(cto.mod == MODFlags.const_); return cto; } TypeNext t = cast(TypeNext)Type.makeConst(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isShared()) { if (next.isWild()) t.next = next.sharedWildConstOf(); else t.next = next.sharedConstOf(); } else { if (next.isWild()) t.next = next.wildConstOf(); else t.next = next.constOf(); } } //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeImmutable() { //printf("TypeNext::makeImmutable() %s\n", toChars()); if (ito) { assert(ito.isImmutable()); return ito; } TypeNext t = cast(TypeNext)Type.makeImmutable(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { t.next = next.immutableOf(); } return t; } override final Type makeShared() { //printf("TypeNext::makeShared() %s\n", toChars()); if (sto) { assert(sto.mod == MODFlags.shared_); return sto; } TypeNext t = cast(TypeNext)Type.makeShared(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isWild()) { if (next.isConst()) t.next = next.sharedWildConstOf(); else t.next = next.sharedWildOf(); } else { if (next.isConst()) t.next = next.sharedConstOf(); else t.next = next.sharedOf(); } } //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeSharedConst() { //printf("TypeNext::makeSharedConst() %s\n", toChars()); if (scto) { assert(scto.mod == (MODFlags.shared_ | MODFlags.const_)); return scto; } TypeNext t = cast(TypeNext)Type.makeSharedConst(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isWild()) t.next = next.sharedWildConstOf(); else t.next = next.sharedConstOf(); } //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeWild() { //printf("TypeNext::makeWild() %s\n", toChars()); if (wto) { assert(wto.mod == MODFlags.wild); return wto; } TypeNext t = cast(TypeNext)Type.makeWild(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isShared()) { if (next.isConst()) t.next = next.sharedWildConstOf(); else t.next = next.sharedWildOf(); } else { if (next.isConst()) t.next = next.wildConstOf(); else t.next = next.wildOf(); } } //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeWildConst() { //printf("TypeNext::makeWildConst() %s\n", toChars()); if (wcto) { assert(wcto.mod == MODFlags.wildconst); return wcto; } TypeNext t = cast(TypeNext)Type.makeWildConst(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isShared()) t.next = next.sharedWildConstOf(); else t.next = next.wildConstOf(); } //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeSharedWild() { //printf("TypeNext::makeSharedWild() %s\n", toChars()); if (swto) { assert(swto.isSharedWild()); return swto; } TypeNext t = cast(TypeNext)Type.makeSharedWild(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { if (next.isConst()) t.next = next.sharedWildConstOf(); else t.next = next.sharedWildOf(); } //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeSharedWildConst() { //printf("TypeNext::makeSharedWildConst() %s\n", toChars()); if (swcto) { assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); return swcto; } TypeNext t = cast(TypeNext)Type.makeSharedWildConst(); if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable()) { t.next = next.sharedWildConstOf(); } //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars()); return t; } override final Type makeMutable() { //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); TypeNext t = cast(TypeNext)Type.makeMutable(); if (ty == Tsarray) { t.next = next.mutableOf(); } //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars()); return t; } override MATCH constConv(Type to) { //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars()); if (equals(to)) return MATCH.exact; if (!(ty == to.ty && MODimplicitConv(mod, to.mod))) return MATCH.nomatch; Type tn = to.nextOf(); if (!(tn && next.ty == tn.ty)) return MATCH.nomatch; MATCH m; if (to.isConst()) // whole tail const conversion { // Recursive shared level check m = next.constConv(tn); if (m == MATCH.exact) m = MATCH.constant; } else { //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars()); m = next.equals(tn) ? MATCH.constant : MATCH.nomatch; } return m; } override final MOD deduceWild(Type t, bool isRef) { if (ty == Tfunction) return 0; ubyte wm; Type tn = t.nextOf(); if (!isRef && (ty == Tarray || ty == Tpointer) && tn) { wm = next.deduceWild(tn, true); if (!wm) wm = Type.deduceWild(t, true); } else { wm = Type.deduceWild(t, isRef); if (!wm && tn) wm = next.deduceWild(tn, true); } return wm; } final void transitive() { /* Invoke transitivity of type attributes */ next = next.addMod(mod); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeBasic : Type { const(char)* dstring; uint flags; extern (D) this(TY ty) { super(ty); const(char)* d; uint flags = 0; switch (ty) { case Tvoid: d = Token.toChars(TOK.void_); break; case Tint8: d = Token.toChars(TOK.int8); flags |= TFlags.integral; break; case Tuns8: d = Token.toChars(TOK.uns8); flags |= TFlags.integral | TFlags.unsigned; break; case Tint16: d = Token.toChars(TOK.int16); flags |= TFlags.integral; break; case Tuns16: d = Token.toChars(TOK.uns16); flags |= TFlags.integral | TFlags.unsigned; break; case Tint32: d = Token.toChars(TOK.int32); flags |= TFlags.integral; break; case Tuns32: d = Token.toChars(TOK.uns32); flags |= TFlags.integral | TFlags.unsigned; break; case Tfloat32: d = Token.toChars(TOK.float32); flags |= TFlags.floating | TFlags.real_; break; case Tint64: d = Token.toChars(TOK.int64); flags |= TFlags.integral; break; case Tuns64: d = Token.toChars(TOK.uns64); flags |= TFlags.integral | TFlags.unsigned; break; case Tint128: d = Token.toChars(TOK.int128); flags |= TFlags.integral; break; case Tuns128: d = Token.toChars(TOK.uns128); flags |= TFlags.integral | TFlags.unsigned; break; case Tfloat64: d = Token.toChars(TOK.float64); flags |= TFlags.floating | TFlags.real_; break; case Tfloat80: d = Token.toChars(TOK.float80); flags |= TFlags.floating | TFlags.real_; break; case Timaginary32: d = Token.toChars(TOK.imaginary32); flags |= TFlags.floating | TFlags.imaginary; break; case Timaginary64: d = Token.toChars(TOK.imaginary64); flags |= TFlags.floating | TFlags.imaginary; break; case Timaginary80: d = Token.toChars(TOK.imaginary80); flags |= TFlags.floating | TFlags.imaginary; break; case Tcomplex32: d = Token.toChars(TOK.complex32); flags |= TFlags.floating | TFlags.complex; break; case Tcomplex64: d = Token.toChars(TOK.complex64); flags |= TFlags.floating | TFlags.complex; break; case Tcomplex80: d = Token.toChars(TOK.complex80); flags |= TFlags.floating | TFlags.complex; break; case Tbool: d = "bool"; flags |= TFlags.integral | TFlags.unsigned; break; case Tchar: d = Token.toChars(TOK.char_); flags |= TFlags.integral | TFlags.unsigned; break; case Twchar: d = Token.toChars(TOK.wchar_); flags |= TFlags.integral | TFlags.unsigned; break; case Tdchar: d = Token.toChars(TOK.dchar_); flags |= TFlags.integral | TFlags.unsigned; break; default: assert(0); } this.dstring = d; this.flags = flags; merge(this); } override const(char)* kind() const { return dstring; } override Type syntaxCopy() { // No semantic analysis done on basic types, no need to copy return this; } override d_uns64 size(const ref Loc loc) const { uint size; //printf("TypeBasic::size()\n"); switch (ty) { case Tint8: case Tuns8: size = 1; break; case Tint16: case Tuns16: size = 2; break; case Tint32: case Tuns32: case Tfloat32: case Timaginary32: size = 4; break; case Tint64: case Tuns64: case Tfloat64: case Timaginary64: size = 8; break; case Tfloat80: case Timaginary80: size = Target.realsize; break; case Tcomplex32: size = 8; break; case Tcomplex64: case Tint128: case Tuns128: size = 16; break; case Tcomplex80: size = Target.realsize * 2; break; case Tvoid: //size = Type::size(); // error message size = 1; break; case Tbool: size = 1; break; case Tchar: size = 1; break; case Twchar: size = 2; break; case Tdchar: size = 4; break; default: assert(0); } //printf("TypeBasic::size() = %d\n", size); return size; } override uint alignsize() { return Target.alignsize(this); } override bool isintegral() { //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags); return (flags & TFlags.integral) != 0; } override bool isfloating() const { return (flags & TFlags.floating) != 0; } override bool isreal() const { return (flags & TFlags.real_) != 0; } override bool isimaginary() const { return (flags & TFlags.imaginary) != 0; } override bool iscomplex() const { return (flags & TFlags.complex) != 0; } override bool isscalar() const { return (flags & (TFlags.integral | TFlags.floating)) != 0; } override bool isunsigned() const { return (flags & TFlags.unsigned) != 0; } override MATCH implicitConvTo(Type to) { //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); if (this == to) return MATCH.exact; if (ty == to.ty) { if (mod == to.mod) return MATCH.exact; else if (MODimplicitConv(mod, to.mod)) return MATCH.constant; else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching return MATCH.constant; else return MATCH.convert; } if (ty == Tvoid || to.ty == Tvoid) return MATCH.nomatch; if (to.ty == Tbool) return MATCH.nomatch; TypeBasic tob; if (to.ty == Tvector && to.deco) { TypeVector tv = cast(TypeVector)to; tob = tv.elementType(); } else if (to.ty == Tenum) { EnumDeclaration ed = (cast(TypeEnum)to).sym; if (ed.isSpecial()) { /* Special enums that allow implicit conversions to them. */ tob = to.toBasetype().isTypeBasic(); if (tob) return implicitConvTo(tob); } else return MATCH.nomatch; } else tob = to.isTypeBasic(); if (!tob) return MATCH.nomatch; if (flags & TFlags.integral) { // Disallow implicit conversion of integers to imaginary or complex if (tob.flags & (TFlags.imaginary | TFlags.complex)) return MATCH.nomatch; // If converting from integral to integral if (tob.flags & TFlags.integral) { d_uns64 sz = size(Loc.initial); d_uns64 tosz = tob.size(Loc.initial); /* Can't convert to smaller size */ if (sz > tosz) return MATCH.nomatch; /* Can't change sign if same size */ //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned) // return MATCH.nomatch; } } else if (flags & TFlags.floating) { // Disallow implicit conversion of floating point to integer if (tob.flags & TFlags.integral) return MATCH.nomatch; assert(tob.flags & TFlags.floating || to.ty == Tvector); // Disallow implicit conversion from complex to non-complex if (flags & TFlags.complex && !(tob.flags & TFlags.complex)) return MATCH.nomatch; // Disallow implicit conversion of real or imaginary to complex if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex) return MATCH.nomatch; // Disallow implicit conversion to-from real and imaginary if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary))) return MATCH.nomatch; } return MATCH.convert; } override bool isZeroInit(const ref Loc loc) const { switch (ty) { case Tchar: case Twchar: case Tdchar: case Timaginary32: case Timaginary64: case Timaginary80: case Tfloat32: case Tfloat64: case Tfloat80: case Tcomplex32: case Tcomplex64: case Tcomplex80: return false; // no default: return true; // yes } } // For eliminating dynamic_cast override TypeBasic isTypeBasic() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * The basetype must be one of: * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] * For AVX: * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4] */ extern (C++) final class TypeVector : Type { Type basetype; extern (D) this(Type basetype) { super(Tvector); this.basetype = basetype; } static TypeVector create(Type basetype) { return new TypeVector(basetype); } override const(char)* kind() const { return "vector"; } override Type syntaxCopy() { return new TypeVector(basetype.syntaxCopy()); } override d_uns64 size(const ref Loc loc) { return basetype.size(); } override uint alignsize() { return cast(uint)basetype.size(); } override bool isintegral() { //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags); return basetype.nextOf().isintegral(); } override bool isfloating() { return basetype.nextOf().isfloating(); } override bool isscalar() { return basetype.nextOf().isscalar(); } override bool isunsigned() { return basetype.nextOf().isunsigned(); } override bool isBoolean() const { return false; } override MATCH implicitConvTo(Type to) { //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); if (this == to) return MATCH.exact; if (to.ty == Tvector) { TypeVector tv = cast(TypeVector)to; assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray); // Can't convert to a vector which has different size. if (basetype.size() != tv.basetype.size()) return MATCH.nomatch; // Allow conversion to void[] if (tv.basetype.nextOf().ty == Tvoid) return MATCH.convert; // Otherwise implicitly convertible only if basetypes are. return basetype.implicitConvTo(tv.basetype); } return MATCH.nomatch; } override Expression defaultInitLiteral(const ref Loc loc) { //printf("TypeVector::defaultInitLiteral()\n"); assert(basetype.ty == Tsarray); Expression e = basetype.defaultInitLiteral(loc); auto ve = new VectorExp(loc, e, this); ve.type = this; ve.dim = cast(int)(basetype.size(loc) / elementType().size(loc)); return ve; } TypeBasic elementType() { assert(basetype.ty == Tsarray); TypeSArray t = cast(TypeSArray)basetype; TypeBasic tb = t.nextOf().isTypeBasic(); assert(tb); return tb; } override bool isZeroInit(const ref Loc loc) { return basetype.isZeroInit(loc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class TypeArray : TypeNext { final extern (D) this(TY ty, Type next) { super(ty, next); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Static array, one with a fixed dimension */ extern (C++) final class TypeSArray : TypeArray { Expression dim; extern (D) this(Type t, Expression dim) { super(Tsarray, t); //printf("TypeSArray(%s)\n", dim.toChars()); this.dim = dim; } override const(char)* kind() const { return "sarray"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); Expression e = dim.syntaxCopy(); t = new TypeSArray(t, e); t.mod = mod; return t; } override d_uns64 size(const ref Loc loc) { //printf("TypeSArray::size()\n"); const n = numberOfElems(loc); const elemsize = baseElemOf().size(loc); bool overflow = false; const sz = mulu(n, elemsize, overflow); if (overflow || sz >= uint.max) { if (elemsize != SIZE_INVALID && n != uint.max) error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz); return SIZE_INVALID; } return sz; } override uint alignsize() { return next.alignsize(); } override bool isString() { TY nty = next.toBasetype().ty; return nty == Tchar || nty == Twchar || nty == Tdchar; } override bool isZeroInit(const ref Loc loc) { return next.isZeroInit(loc); } override structalign_t alignment() { return next.alignment(); } override MATCH constConv(Type to) { if (to.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)to; if (!dim.equals(tsa.dim)) return MATCH.nomatch; } return TypeNext.constConv(to); } override MATCH implicitConvTo(Type to) { //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); if (to.ty == Tarray) { TypeDArray ta = cast(TypeDArray)to; if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCH.nomatch; /* Allow conversion to void[] */ if (ta.next.ty == Tvoid) { return MATCH.convert; } MATCH m = next.constConv(ta.next); if (m > MATCH.nomatch) { return MATCH.convert; } return MATCH.nomatch; } if (to.ty == Tsarray) { if (this == to) return MATCH.exact; TypeSArray tsa = cast(TypeSArray)to; if (dim.equals(tsa.dim)) { /* Since static arrays are value types, allow * conversions from const elements to non-const * ones, just like we allow conversion from const int * to int. */ MATCH m = next.implicitConvTo(tsa.next); if (m >= MATCH.constant) { if (mod != to.mod) m = MATCH.constant; return m; } } } return MATCH.nomatch; } override Expression defaultInitLiteral(const ref Loc loc) { static if (LOGDEFAULTINIT) { printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); } size_t d = cast(size_t)dim.toInteger(); Expression elementinit; if (next.ty == Tvoid) elementinit = tuns8.defaultInitLiteral(loc); else elementinit = next.defaultInitLiteral(loc); auto elements = new Expressions(d); for (size_t i = 0; i < d; i++) (*elements)[i] = null; auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements); return ae; } override bool hasPointers() { /* Don't want to do this, because: * struct S { T* array[0]; } * may be a variable length struct. */ //if (dim.toInteger() == 0) // return false; if (next.ty == Tvoid) { // Arrays of void contain arbitrary data, which may include pointers return true; } else return next.hasPointers(); } override bool needsDestruction() { return next.needsDestruction(); } /********************************* * */ override bool needsNested() { return next.needsNested(); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Dynamic array, no dimension */ extern (C++) final class TypeDArray : TypeArray { extern (D) this(Type t) { super(Tarray, t); //printf("TypeDArray(t = %p)\n", t); } override const(char)* kind() const { return "darray"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); if (t == next) t = this; else { t = new TypeDArray(t); t.mod = mod; } return t; } override d_uns64 size(const ref Loc loc) const { //printf("TypeDArray::size()\n"); return Target.ptrsize * 2; } override uint alignsize() const { // A DArray consists of two ptr-sized values, so align it on pointer size // boundary return Target.ptrsize; } override bool isString() { TY nty = next.toBasetype().ty; return nty == Tchar || nty == Twchar || nty == Tdchar; } override bool isZeroInit(const ref Loc loc) const { return true; } override bool isBoolean() const { return true; } override MATCH implicitConvTo(Type to) { //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); if (equals(to)) return MATCH.exact; if (to.ty == Tarray) { TypeDArray ta = cast(TypeDArray)to; if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCH.nomatch; // not const-compatible /* Allow conversion to void[] */ if (next.ty != Tvoid && ta.next.ty == Tvoid) { return MATCH.convert; } MATCH m = next.constConv(ta.next); if (m > MATCH.nomatch) { if (m == MATCH.exact && mod != to.mod) m = MATCH.constant; return m; } } return Type.implicitConvTo(to); } override bool hasPointers() const { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeAArray : TypeArray { Type index; // key type Loc loc; Scope* sc; extern (D) this(Type t, Type index) { super(Taarray, t); this.index = index; } static TypeAArray create(Type t, Type index) { return new TypeAArray(t, index); } override const(char)* kind() const { return "aarray"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); Type ti = index.syntaxCopy(); if (t == next && ti == index) t = this; else { t = new TypeAArray(t, ti); t.mod = mod; } return t; } override d_uns64 size(const ref Loc loc) { return Target.ptrsize; } override bool isZeroInit(const ref Loc loc) const { return true; } override bool isBoolean() const { return true; } override bool hasPointers() const { return true; } override MATCH implicitConvTo(Type to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); if (equals(to)) return MATCH.exact; if (to.ty == Taarray) { TypeAArray ta = cast(TypeAArray)to; if (!MODimplicitConv(next.mod, ta.next.mod)) return MATCH.nomatch; // not const-compatible if (!MODimplicitConv(index.mod, ta.index.mod)) return MATCH.nomatch; // not const-compatible MATCH m = next.constConv(ta.next); MATCH mi = index.constConv(ta.index); if (m > MATCH.nomatch && mi > MATCH.nomatch) { return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch; } } return Type.implicitConvTo(to); } override MATCH constConv(Type to) { if (to.ty == Taarray) { TypeAArray taa = cast(TypeAArray)to; MATCH mindex = index.constConv(taa.index); MATCH mkey = next.constConv(taa.next); // Pick the worst match return mkey < mindex ? mkey : mindex; } return Type.constConv(to); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypePointer : TypeNext { extern (D) this(Type t) { super(Tpointer, t); } static TypePointer create(Type t) { return new TypePointer(t); } override const(char)* kind() const { return "pointer"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); if (t == next) t = this; else { t = new TypePointer(t); t.mod = mod; } return t; } override d_uns64 size(const ref Loc loc) const { return Target.ptrsize; } override MATCH implicitConvTo(Type to) { //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars()); if (equals(to)) return MATCH.exact; if (next.ty == Tfunction) { if (to.ty == Tpointer) { TypePointer tp = cast(TypePointer)to; if (tp.next.ty == Tfunction) { if (next.equals(tp.next)) return MATCH.constant; if (next.covariant(tp.next) == 1) { Type tret = this.next.nextOf(); Type toret = tp.next.nextOf(); if (tret.ty == Tclass && toret.ty == Tclass) { /* https://issues.dlang.org/show_bug.cgi?id=10219 * Check covariant interface return with offset tweaking. * interface I {} * class C : Object, I {} * I function() dg = function C() {} // should be error */ int offset = 0; if (toret.isBaseOf(tret, &offset) && offset != 0) return MATCH.nomatch; } return MATCH.convert; } } else if (tp.next.ty == Tvoid) { // Allow conversions to void* return MATCH.convert; } } return MATCH.nomatch; } else if (to.ty == Tpointer) { TypePointer tp = cast(TypePointer)to; assert(tp.next); if (!MODimplicitConv(next.mod, tp.next.mod)) return MATCH.nomatch; // not const-compatible /* Alloc conversion to void* */ if (next.ty != Tvoid && tp.next.ty == Tvoid) { return MATCH.convert; } MATCH m = next.constConv(tp.next); if (m > MATCH.nomatch) { if (m == MATCH.exact && mod != to.mod) m = MATCH.constant; return m; } } return MATCH.nomatch; } override MATCH constConv(Type to) { if (next.ty == Tfunction) { if (to.nextOf() && next.equals((cast(TypeNext)to).next)) return Type.constConv(to); else return MATCH.nomatch; } return TypeNext.constConv(to); } override bool isscalar() const { return true; } override bool isZeroInit(const ref Loc loc) const { return true; } override bool hasPointers() const { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeReference : TypeNext { extern (D) this(Type t) { super(Treference, t); // BUG: what about references to static arrays? } override const(char)* kind() const { return "reference"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); if (t == next) t = this; else { t = new TypeReference(t); t.mod = mod; } return t; } override d_uns64 size(const ref Loc loc) const { return Target.ptrsize; } override bool isZeroInit(const ref Loc loc) const { return true; } override void accept(Visitor v) { v.visit(this); } } enum RET : int { regs = 1, // returned in registers stack = 2, // returned on stack } enum TRUST : int { default_ = 0, system = 1, // @system (same as TRUST.default) trusted = 2, // @trusted safe = 3, // @safe } enum TRUSTformat : int { TRUSTformatDefault, // do not emit @system when trust == TRUST.default_ TRUSTformatSystem, // emit @system when trust == TRUST.default_ } alias TRUSTformatDefault = TRUSTformat.TRUSTformatDefault; alias TRUSTformatSystem = TRUSTformat.TRUSTformatSystem; enum PURE : int { impure = 0, // not pure at all fwdref = 1, // it's pure, but not known which level yet weak = 2, // no mutable globals are read or written const_ = 3, // parameters are values or const strong = 4, // parameters are values or immutable } /*********************************************************** */ extern (C++) final class TypeFunction : TypeNext { // .next is the return type Parameters* parameters; // function parameters int varargs; // 1: T t, ...) style for variable number of arguments // 2: T t ...) style for variable number of arguments bool isnothrow; // true: nothrow bool isnogc; // true: is @nogc bool isproperty; // can be called without parentheses bool isref; // true: returns a reference bool isreturn; // true: 'this' is returned by ref bool isscope; // true: 'this' is scope bool isscopeinferred; // true: 'this' is scope from inference LINK linkage; // calling convention TRUST trust; // level of trust PURE purity = PURE.impure; ubyte iswild; // bit0: inout on params, bit1: inout on qualifier Expressions* fargs; // function arguments int inuse; extern (D) this(Parameters* parameters, Type treturn, int varargs, LINK linkage, StorageClass stc = 0) { super(Tfunction, treturn); //if (!treturn) *(char*)0=0; // assert(treturn); assert(0 <= varargs && varargs <= 2); this.parameters = parameters; this.varargs = varargs; this.linkage = linkage; if (stc & STC.pure_) this.purity = PURE.fwdref; if (stc & STC.nothrow_) this.isnothrow = true; if (stc & STC.nogc) this.isnogc = true; if (stc & STC.property) this.isproperty = true; if (stc & STC.ref_) this.isref = true; if (stc & STC.return_) this.isreturn = true; if (stc & STC.scope_) this.isscope = true; if (stc & STC.scopeinferred) this.isscopeinferred = true; this.trust = TRUST.default_; if (stc & STC.safe) this.trust = TRUST.safe; if (stc & STC.system) this.trust = TRUST.system; if (stc & STC.trusted) this.trust = TRUST.trusted; } static TypeFunction create(Parameters* parameters, Type treturn, int varargs, LINK linkage, StorageClass stc = 0) { return new TypeFunction(parameters, treturn, varargs, linkage, stc); } override const(char)* kind() const { return "function"; } override Type syntaxCopy() { Type treturn = next ? next.syntaxCopy() : null; Parameters* params = Parameter.arraySyntaxCopy(parameters); auto t = new TypeFunction(params, treturn, varargs, linkage); t.mod = mod; t.isnothrow = isnothrow; t.isnogc = isnogc; t.purity = purity; t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; t.isscope = isscope; t.isscopeinferred = isscopeinferred; t.iswild = iswild; t.trust = trust; t.fargs = fargs; return t; } /******************************************** * Set 'purity' field of 'this'. * Do this lazily, as the parameter types might be forward referenced. */ void purityLevel() { TypeFunction tf = this; if (tf.purity != PURE.fwdref) return; /* Determine purity level based on mutability of t * and whether it is a 'ref' type or not. */ static PURE purityOfType(bool isref, Type t) { if (isref) { if (t.mod & MODFlags.immutable_) return PURE.strong; if (t.mod & (MODFlags.const_ | MODFlags.wild)) return PURE.const_; return PURE.weak; } t = t.baseElemOf(); if (!t.hasPointers() || t.mod & MODFlags.immutable_) return PURE.strong; /* Accept immutable(T)[] and immutable(T)* as being strongly pure */ if (t.ty == Tarray || t.ty == Tpointer) { Type tn = t.nextOf().toBasetype(); if (tn.mod & MODFlags.immutable_) return PURE.strong; if (tn.mod & (MODFlags.const_ | MODFlags.wild)) return PURE.const_; } /* The rest of this is too strict; fix later. * For example, the only pointer members of a struct may be immutable, * which would maintain strong purity. * (Just like for dynamic arrays and pointers above.) */ if (t.mod & (MODFlags.const_ | MODFlags.wild)) return PURE.const_; /* Should catch delegates and function pointers, and fold in their purity */ return PURE.weak; } purity = PURE.strong; // assume strong until something weakens it /* Evaluate what kind of purity based on the modifiers for the parameters */ const dim = Parameter.dim(tf.parameters); Lloop: foreach (i; 0 .. dim) { Parameter fparam = Parameter.getNth(tf.parameters, i); Type t = fparam.type; if (!t) continue; if (fparam.storageClass & (STC.lazy_ | STC.out_)) { purity = PURE.weak; break; } switch (purityOfType((fparam.storageClass & STC.ref_) != 0, t)) { case PURE.weak: purity = PURE.weak; break Lloop; // since PURE.weak, no need to check further case PURE.const_: purity = PURE.const_; continue; case PURE.strong: continue; default: assert(0); } } if (purity > PURE.weak && tf.nextOf()) { /* Adjust purity based on mutability of return type. * https://issues.dlang.org/show_bug.cgi?id=15862 */ const purity2 = purityOfType(tf.isref, tf.nextOf()); if (purity2 < purity) purity = purity2; } tf.purity = purity; } /******************************************** * Return true if there are lazy parameters. */ bool hasLazyParameters() { size_t dim = Parameter.dim(parameters); for (size_t i = 0; i < dim; i++) { Parameter fparam = Parameter.getNth(parameters, i); if (fparam.storageClass & STC.lazy_) return true; } return false; } /*************************** * Examine function signature for parameter p and see if * the value of p can 'escape' the scope of the function. * This is useful to minimize the needed annotations for the parameters. * Params: * tthis = type of `this` parameter, null if none * p = parameter to this function * Returns: * true if escapes via assignment to global or through a parameter */ bool parameterEscapes(Type tthis, Parameter p) { /* Scope parameters do not escape. * Allow 'lazy' to imply 'scope' - * lazy parameters can be passed along * as lazy parameters to the next function, but that isn't * escaping. */ if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_)) return false; return true; } /************************************ * Take the specified storage class for p, * and use the function signature to infer whether * STC.scope_ and STC.return_ should be OR'd in. * (This will not affect the name mangling.) * Params: * tthis = type of `this` parameter, null if none * p = parameter to this function * Returns: * storage class with STC.scope_ or STC.return_ OR'd in */ StorageClass parameterStorageClass(Type tthis, Parameter p) { //printf("parameterStorageClass(p: %s)\n", p.toChars()); auto stc = p.storageClass; if (!global.params.vsafe) return stc; if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) return stc; /* If haven't inferred the return type yet, can't infer storage classes */ if (!nextOf()) return stc; purityLevel(); // See if p can escape via any of the other parameters if (purity == PURE.weak) { // Check escaping through parameters const dim = Parameter.dim(parameters); foreach (const i; 0 .. dim) { Parameter fparam = Parameter.getNth(parameters, i); if (fparam == p) continue; Type t = fparam.type; if (!t) continue; t = t.baseElemOf(); if (t.isMutable() && t.hasPointers()) { if (fparam.storageClass & (STC.ref_ | STC.out_)) { } else if (t.ty == Tarray || t.ty == Tpointer) { Type tn = t.nextOf().toBasetype(); if (!(tn.isMutable() && tn.hasPointers())) continue; } return stc; } } // Check escaping through `this` if (tthis && tthis.isMutable()) { auto tb = tthis.toBasetype(); AggregateDeclaration ad; if (tb.ty == Tclass) ad = (cast(TypeClass)tb).sym; else if (tb.ty == Tstruct) ad = (cast(TypeStruct)tb).sym; else assert(0); foreach (VarDeclaration v; ad.fields) { if (v.hasPointers()) return stc; } } } stc |= STC.scope_; /* Inferring STC.return_ here has false positives * for pure functions, producing spurious error messages * about escaping references. * Give up on it for now. */ version (none) { Type tret = nextOf().toBasetype(); if (isref || tret.hasPointers()) { /* The result has references, so p could be escaping * that way. */ stc |= STC.return_; } } return stc; } override Type addStorageClass(StorageClass stc) { //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); TypeFunction t = Type.addStorageClass(stc).toTypeFunction(); if ((stc & STC.pure_ && !t.purity) || (stc & STC.nothrow_ && !t.isnothrow) || (stc & STC.nogc && !t.isnogc) || (stc & STC.scope_ && !t.isscope) || (stc & STC.safe && t.trust < TRUST.trusted)) { // Klunky to change these auto tf = new TypeFunction(t.parameters, t.next, t.varargs, t.linkage, 0); tf.mod = t.mod; tf.fargs = fargs; tf.purity = t.purity; tf.isnothrow = t.isnothrow; tf.isnogc = t.isnogc; tf.isproperty = t.isproperty; tf.isref = t.isref; tf.isreturn = t.isreturn; tf.isscope = t.isscope; tf.isscopeinferred = t.isscopeinferred; tf.trust = t.trust; tf.iswild = t.iswild; if (stc & STC.pure_) tf.purity = PURE.fwdref; if (stc & STC.nothrow_) tf.isnothrow = true; if (stc & STC.nogc) tf.isnogc = true; if (stc & STC.safe) tf.trust = TRUST.safe; if (stc & STC.scope_) { tf.isscope = true; if (stc & STC.scopeinferred) tf.isscopeinferred = true; } tf.deco = tf.merge().deco; t = tf; } return t; } override Type substWildTo(uint) { if (!iswild && !(mod & MODFlags.wild)) return this; // Substitude inout qualifier of function type to mutable or immutable // would break type system. Instead substitude inout to the most weak // qualifer - const. uint m = MODFlags.const_; assert(next); Type tret = next.substWildTo(m); Parameters* params = parameters; if (mod & MODFlags.wild) params = parameters.copy(); for (size_t i = 0; i < params.dim; i++) { Parameter p = (*params)[i]; Type t = p.type.substWildTo(m); if (t == p.type) continue; if (params == parameters) params = parameters.copy(); (*params)[i] = new Parameter(p.storageClass, t, null, null, null); } if (next == tret && params == parameters) return this; // Similar to TypeFunction::syntaxCopy; auto t = new TypeFunction(params, tret, varargs, linkage); t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod); t.isnothrow = isnothrow; t.isnogc = isnogc; t.purity = purity; t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; t.isscope = isscope; t.isscopeinferred = isscopeinferred; t.iswild = 0; t.trust = trust; t.fargs = fargs; return t.merge(); } // arguments get specially formatted private const(char)* getParamError(Expression arg, Parameter par) { if (global.gag && !global.params.showGaggedErrors) return null; // show qualification when toChars() is the same but types are different auto at = arg.type.toChars(); bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0; if (qual) at = arg.type.toPrettyChars(true); OutBuffer buf; // only mention rvalue if it's relevant const rv = !arg.isLvalue() && par.storageClass & (STC.ref_ | STC.out_); buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, parameterToChars(par, this, qual)); return buf.extractString(); } /******************************** * 'args' are being matched to function 'this' * Determine match level. * Input: * flag 1 performing a partial ordering match * pMessage address to store error message, or null * Returns: * MATCHxxxx */ extern (D) MATCH callMatch(Type tthis, Expressions* args, int flag = 0, const(char)** pMessage = null) { //printf("TypeFunction::callMatch() %s\n", toChars()); MATCH match = MATCH.exact; // assume exact match ubyte wildmatch = 0; if (tthis) { Type t = tthis; if (t.toBasetype().ty == Tpointer) t = t.toBasetype().nextOf(); // change struct* to struct if (t.mod != mod) { if (MODimplicitConv(t.mod, mod)) match = MATCH.constant; else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) { match = MATCH.constant; } else return MATCH.nomatch; } if (isWild()) { if (t.isWild()) wildmatch |= MODFlags.wild; else if (t.isConst()) wildmatch |= MODFlags.const_; else if (t.isImmutable()) wildmatch |= MODFlags.immutable_; else wildmatch |= MODFlags.mutable; } } size_t nparams = Parameter.dim(parameters); size_t nargs = args ? args.dim : 0; if (nparams == nargs) { } else if (nargs > nparams) { if (varargs == 0) goto Nomatch; // too many args; no match match = MATCH.convert; // match ... with a "conversion" match level } for (size_t u = 0; u < nargs; u++) { if (u >= nparams) break; Parameter p = Parameter.getNth(parameters, u); Expression arg = (*args)[u]; assert(arg); Type tprm = p.type; Type targ = arg.type; if (!(p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid)) { bool isRef = (p.storageClass & (STC.ref_ | STC.out_)) != 0; wildmatch |= targ.deduceWild(tprm, isRef); } } if (wildmatch) { /* Calculate wild matching modifier */ if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) wildmatch = MODFlags.const_; else if (wildmatch & MODFlags.immutable_) wildmatch = MODFlags.immutable_; else if (wildmatch & MODFlags.wild) wildmatch = MODFlags.wild; else { assert(wildmatch & MODFlags.mutable); wildmatch = MODFlags.mutable; } } for (size_t u = 0; u < nparams; u++) { MATCH m; Parameter p = Parameter.getNth(parameters, u); assert(p); if (u >= nargs) { if (p.defaultArg) continue; goto L1; // try typesafe variadics } { Expression arg = (*args)[u]; assert(arg); //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); Type targ = arg.type; Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; if (p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid) m = MATCH.convert; else { //printf("%s of type %s implicitConvTo %s\n", arg.toChars(), targ.toChars(), tprm.toChars()); if (flag) { // for partial ordering, value is an irrelevant mockup, just look at the type m = targ.implicitConvTo(tprm); } else m = arg.implicitConvTo(tprm); //printf("match %d\n", m); } // Non-lvalues do not match ref or out parameters if (p.storageClass & (STC.ref_ | STC.out_)) { // https://issues.dlang.org/show_bug.cgi?id=13783 // Don't use toBasetype() to handle enum types. Type ta = targ; Type tp = tprm; //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); if (m && !arg.isLvalue()) { if (p.storageClass & STC.out_) { if (pMessage) *pMessage = getParamError(arg, p); goto Nomatch; } if (arg.op == TOK.string_ && tp.ty == Tsarray) { if (ta.ty != Tsarray) { Type tn = tp.nextOf().castMod(ta.nextOf().mod); dinteger_t dim = (cast(StringExp)arg).len; ta = tn.sarrayOf(dim); } } else if (arg.op == TOK.slice && tp.ty == Tsarray) { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] if (ta.ty != Tsarray) { Type tn = ta.nextOf(); dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); ta = tn.sarrayOf(dim); } } else { if (pMessage) *pMessage = getParamError(arg, p); goto Nomatch; } } /* Find most derived alias this type being matched. * https://issues.dlang.org/show_bug.cgi?id=15674 * Allow on both ref and out parameters. */ while (1) { Type tab = ta.toBasetype(); Type tat = tab.aliasthisOf(); if (!tat || !tat.implicitConvTo(tprm)) break; if (tat == tab) break; ta = tat; } /* A ref variable should work like a head-const reference. * e.g. disallows: * ref T <- an lvalue of const(T) argument * ref T[dim] <- an lvalue of const(T[dim]) argument */ if (!ta.constConv(tp)) { if (pMessage) *pMessage = getParamError(arg, p); goto Nomatch; } } } /* prefer matching the element type rather than the array * type when more arguments are present with T[]... */ if (varargs == 2 && u + 1 == nparams && nargs > nparams) goto L1; //printf("\tm = %d\n", m); if (m == MATCH.nomatch) // if no match { L1: if (varargs == 2 && u + 1 == nparams) // if last varargs param { Type tb = p.type.toBasetype(); TypeSArray tsa; dinteger_t sz; switch (tb.ty) { case Tsarray: tsa = cast(TypeSArray)tb; sz = tsa.dim.toInteger(); if (sz != nargs - u) goto Nomatch; goto case Tarray; case Tarray: { TypeArray ta = cast(TypeArray)tb; for (; u < nargs; u++) { Expression arg = (*args)[u]; assert(arg); /* If lazy array of delegates, * convert arg(s) to delegate(s) */ Type tret = p.isLazyArray(); if (tret) { if (ta.next.equals(arg.type)) m = MATCH.exact; else if (tret.toBasetype().ty == Tvoid) m = MATCH.convert; else { m = arg.implicitConvTo(tret); if (m == MATCH.nomatch) m = arg.implicitConvTo(ta.next); } } else m = arg.implicitConvTo(ta.next); if (m == MATCH.nomatch) { if (pMessage) *pMessage = getParamError(arg, p); goto Nomatch; } if (m < match) match = m; } goto Ldone; } case Tclass: // Should see if there's a constructor match? // Or just leave it ambiguous? goto Ldone; default: break; } } if (pMessage && u < nargs) *pMessage = getParamError((*args)[u], p); goto Nomatch; } if (m < match) match = m; // pick worst match } Ldone: //printf("match = %d\n", match); return match; Nomatch: //printf("no match\n"); return MATCH.nomatch; } extern (D) bool checkRetType(const ref Loc loc) { Type tb = next.toBasetype(); if (tb.ty == Tfunction) { error(loc, "functions cannot return a function"); next = Type.terror; } if (tb.ty == Ttuple) { error(loc, "functions cannot return a tuple"); next = Type.terror; } if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray)) { Type tb2 = tb.baseElemOf(); if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members) { error(loc, "functions cannot return opaque type `%s` by value", tb.toChars()); next = Type.terror; } } if (tb.ty == Terror) return true; return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeDelegate : TypeNext { // .next is a TypeFunction extern (D) this(Type t) { super(Tfunction, t); ty = Tdelegate; } static TypeDelegate create(Type t) { return new TypeDelegate(t); } override const(char)* kind() const { return "delegate"; } override Type syntaxCopy() { Type t = next.syntaxCopy(); if (t == next) t = this; else { t = new TypeDelegate(t); t.mod = mod; } return t; } override Type addStorageClass(StorageClass stc) { TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc); if (!global.params.vsafe) return t; /* The rest is meant to add 'scope' to a delegate declaration if it is of the form: * alias dg_t = void* delegate(); * scope dg_t dg = ...; */ if(stc & STC.scope_) { auto n = t.next.addStorageClass(STC.scope_ | STC.scopeinferred); if (n != t.next) { t.next = n; t.deco = t.merge().deco; // mangling supposed to not be changed due to STC.scope_inferrred } } return t; } override d_uns64 size(const ref Loc loc) const { return Target.ptrsize * 2; } override uint alignsize() const { return Target.ptrsize; } override MATCH implicitConvTo(Type to) { //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to.toChars()); if (this == to) return MATCH.exact; version (all) { // not allowing covariant conversions because it interferes with overriding if (to.ty == Tdelegate && this.nextOf().covariant(to.nextOf()) == 1) { Type tret = this.next.nextOf(); Type toret = (cast(TypeDelegate)to).next.nextOf(); if (tret.ty == Tclass && toret.ty == Tclass) { /* https://issues.dlang.org/show_bug.cgi?id=10219 * Check covariant interface return with offset tweaking. * interface I {} * class C : Object, I {} * I delegate() dg = delegate C() {} // should be error */ int offset = 0; if (toret.isBaseOf(tret, &offset) && offset != 0) return MATCH.nomatch; } return MATCH.convert; } } return MATCH.nomatch; } override bool isZeroInit(const ref Loc loc) const { return true; } override bool isBoolean() const { return true; } override bool hasPointers() const { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) abstract class TypeQualified : Type { Loc loc; // array of Identifier and TypeInstance, // representing ident.ident!tiargs.ident. ... etc. Objects idents; final extern (D) this(TY ty, Loc loc) { super(ty); this.loc = loc; } final void syntaxCopyHelper(TypeQualified t) { //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars()); idents.setDim(t.idents.dim); for (size_t i = 0; i < idents.dim; i++) { RootObject id = t.idents[i]; if (id.dyncast() == DYNCAST.dsymbol) { TemplateInstance ti = cast(TemplateInstance)id; ti = cast(TemplateInstance)ti.syntaxCopy(null); id = ti; } else if (id.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)id; e = e.syntaxCopy(); id = e; } else if (id.dyncast() == DYNCAST.type) { Type tx = cast(Type)id; tx = tx.syntaxCopy(); id = tx; } idents[i] = id; } } final void addIdent(Identifier ident) { idents.push(ident); } final void addInst(TemplateInstance inst) { idents.push(inst); } final void addIndex(RootObject e) { idents.push(e); } override d_uns64 size(const ref Loc loc) { error(this.loc, "size of type `%s` is not known", toChars()); return SIZE_INVALID; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeIdentifier : TypeQualified { Identifier ident; // The symbol representing this identifier, before alias resolution Dsymbol originalSymbol; extern (D) this(const ref Loc loc, Identifier ident) { super(Tident, loc); this.ident = ident; } override const(char)* kind() const { return "identifier"; } override Type syntaxCopy() { auto t = new TypeIdentifier(loc, ident); t.syntaxCopyHelper(this); t.mod = mod; return t; } /***************************************** * See if type resolves to a symbol, if so, * return that symbol. */ override Dsymbol toDsymbol(Scope* sc) { //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); if (!sc) return null; Type t; Expression e; Dsymbol s; resolve(this, loc, sc, &e, &t, &s); if (t && t.ty != Tident) s = t.toDsymbol(sc); if (e) s = getDsymbol(e); return s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Similar to TypeIdentifier, but with a TemplateInstance as the root */ extern (C++) final class TypeInstance : TypeQualified { TemplateInstance tempinst; extern (D) this(const ref Loc loc, TemplateInstance tempinst) { super(Tinstance, loc); this.tempinst = tempinst; } override const(char)* kind() const { return "instance"; } override Type syntaxCopy() { //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); auto t = new TypeInstance(loc, cast(TemplateInstance)tempinst.syntaxCopy(null)); t.syntaxCopyHelper(this); t.mod = mod; return t; } override Dsymbol toDsymbol(Scope* sc) { Type t; Expression e; Dsymbol s; //printf("TypeInstance::semantic(%s)\n", toChars()); resolve(this, loc, sc, &e, &t, &s); if (t && t.ty != Tinstance) s = t.toDsymbol(sc); return s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeTypeof : TypeQualified { Expression exp; int inuse; extern (D) this(const ref Loc loc, Expression exp) { super(Ttypeof, loc); this.exp = exp; } override const(char)* kind() const { return "typeof"; } override Type syntaxCopy() { //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); auto t = new TypeTypeof(loc, exp.syntaxCopy()); t.syntaxCopyHelper(this); t.mod = mod; return t; } override Dsymbol toDsymbol(Scope* sc) { //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); Expression e; Type t; Dsymbol s; resolve(this, loc, sc, &e, &t, &s); return s; } override d_uns64 size(const ref Loc loc) { if (exp.type) return exp.type.size(loc); else return TypeQualified.size(loc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeReturn : TypeQualified { extern (D) this(const ref Loc loc) { super(Treturn, loc); } override const(char)* kind() const { return "return"; } override Type syntaxCopy() { auto t = new TypeReturn(loc); t.syntaxCopyHelper(this); t.mod = mod; return t; } override Dsymbol toDsymbol(Scope* sc) { Expression e; Type t; Dsymbol s; resolve(this, loc, sc, &e, &t, &s); return s; } override void accept(Visitor v) { v.visit(this); } } // Whether alias this dependency is recursive or not. enum AliasThisRec : int { no = 0, // no alias this recursion yes = 1, // alias this has recursive dependency fwdref = 2, // not yet known typeMask = 3, // mask to read no/yes/fwdref tracing = 0x4, // mark in progress of implicitConvTo/deduceWild tracingDT = 0x8, // mark in progress of deduceType } /*********************************************************** */ extern (C++) final class TypeStruct : Type { StructDeclaration sym; AliasThisRec att = AliasThisRec.fwdref; CPPMANGLE cppmangle = CPPMANGLE.def; extern (D) this(StructDeclaration sym) { super(Tstruct); this.sym = sym; } static TypeStruct create(StructDeclaration sym) { return new TypeStruct(sym); } override const(char)* kind() const { return "struct"; } override d_uns64 size(const ref Loc loc) { return sym.size(loc); } override uint alignsize() { sym.size(Loc.initial); // give error for forward references return sym.alignsize; } override Type syntaxCopy() { return this; } override Dsymbol toDsymbol(Scope* sc) { return sym; } override structalign_t alignment() { if (sym.alignment == 0) sym.size(sym.loc); return sym.alignment; } /*************************************** * Use when we prefer the default initializer to be a literal, * rather than a global immutable variable. */ override Expression defaultInitLiteral(const ref Loc loc) { static if (LOGDEFAULTINIT) { printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); } sym.size(loc); if (sym.sizeok != Sizeok.done) return new ErrorExp(); auto structelems = new Expressions(sym.fields.dim - sym.isNested()); uint offset = 0; for (size_t j = 0; j < structelems.dim; j++) { VarDeclaration vd = sym.fields[j]; Expression e; if (vd.inuse) { error(loc, "circular reference to `%s`", vd.toPrettyChars()); return new ErrorExp(); } if (vd.offset < offset || vd.type.size() == 0) e = null; else if (vd._init) { if (vd._init.isVoidInitializer()) e = null; else e = vd.getConstInitializer(false); } else e = vd.type.defaultInitLiteral(loc); if (e && e.op == TOK.error) return e; if (e) offset = vd.offset + cast(uint)vd.type.size(); (*structelems)[j] = e; } auto structinit = new StructLiteralExp(loc, sym, structelems); /* Copy from the initializer symbol for larger symbols, * otherwise the literals expressed as code get excessively large. */ if (size(loc) > Target.ptrsize * 4 && !needsNested()) structinit.useStaticInit = true; structinit.type = this; return structinit; } override bool isZeroInit(const ref Loc loc) const { return sym.zeroInit; } override bool isAssignable() { bool assignable = true; uint offset = ~0; // dead-store initialize to prevent spurious warning /* If any of the fields are const or immutable, * then one cannot assign this struct. */ for (size_t i = 0; i < sym.fields.dim; i++) { VarDeclaration v = sym.fields[i]; //printf("%s [%d] v = (%s) %s, v.offset = %d, v.parent = %s", sym.toChars(), i, v.kind(), v.toChars(), v.offset, v.parent.kind()); if (i == 0) { } else if (v.offset == offset) { /* If any fields of anonymous union are assignable, * then regard union as assignable. * This is to support unsafe things like Rebindable templates. */ if (assignable) continue; } else { if (!assignable) return false; } assignable = v.type.isMutable() && v.type.isAssignable(); offset = v.offset; //printf(" -> assignable = %d\n", assignable); } return assignable; } override bool isBoolean() const { return false; } override bool needsDestruction() const { return sym.dtor !is null; } override bool needsNested() { if (sym.isNested()) return true; for (size_t i = 0; i < sym.fields.dim; i++) { VarDeclaration v = sym.fields[i]; if (!v.isDataseg() && v.type.needsNested()) return true; } return false; } override bool hasPointers() { // Probably should cache this information in sym rather than recompute StructDeclaration s = sym; sym.size(Loc.initial); // give error for forward references foreach (VarDeclaration v; s.fields) { if (v.storage_class & STC.ref_ || v.hasPointers()) return true; } return false; } override bool hasVoidInitPointers() { // Probably should cache this information in sym rather than recompute StructDeclaration s = sym; sym.size(Loc.initial); // give error for forward references foreach (VarDeclaration v; s.fields) { if (v._init && v._init.isVoidInitializer() && v.type.hasPointers()) return true; if (!v._init && v.type.hasVoidInitPointers()) return true; } return false; } override MATCH implicitConvTo(Type to) { MATCH m; //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars()); if (ty == to.ty && sym == (cast(TypeStruct)to).sym) { m = MATCH.exact; // exact match if (mod != to.mod) { m = MATCH.constant; if (MODimplicitConv(mod, to.mod)) { } else { /* Check all the fields. If they can all be converted, * allow the conversion. */ uint offset = ~0; // dead-store to prevent spurious warning for (size_t i = 0; i < sym.fields.dim; i++) { VarDeclaration v = sym.fields[i]; if (i == 0) { } else if (v.offset == offset) { if (m > MATCH.nomatch) continue; } else { if (m <= MATCH.nomatch) return m; } // 'from' type Type tvf = v.type.addMod(mod); // 'to' type Type tv = v.type.addMod(to.mod); // field match MATCH mf = tvf.implicitConvTo(tv); //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf); if (mf <= MATCH.nomatch) return mf; if (mf < m) // if field match is worse m = mf; offset = v.offset; } } } } else if (sym.aliasthis && !(att & AliasThisRec.tracing)) { if (auto ato = aliasthisOf()) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); m = ato.implicitConvTo(to); att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); } else m = MATCH.nomatch; // no match } else m = MATCH.nomatch; // no match return m; } override MATCH constConv(Type to) { if (equals(to)) return MATCH.exact; if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod)) return MATCH.constant; return MATCH.nomatch; } override MOD deduceWild(Type t, bool isRef) { if (ty == t.ty && sym == (cast(TypeStruct)t).sym) return Type.deduceWild(t, isRef); ubyte wm = 0; if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) { if (auto ato = aliasthisOf()) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); wm = ato.deduceWild(t, isRef); att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); } } return wm; } override Type toHeadMutable() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeEnum : Type { EnumDeclaration sym; extern (D) this(EnumDeclaration sym) { super(Tenum); this.sym = sym; } override const(char)* kind() const { return "enum"; } override Type syntaxCopy() { return this; } override d_uns64 size(const ref Loc loc) { return sym.getMemtype(loc).size(loc); } override uint alignsize() { Type t = sym.getMemtype(Loc.initial); if (t.ty == Terror) return 4; return t.alignsize(); } override Dsymbol toDsymbol(Scope* sc) { return sym; } override bool isintegral() { return sym.getMemtype(Loc.initial).isintegral(); } override bool isfloating() { return sym.getMemtype(Loc.initial).isfloating(); } override bool isreal() { return sym.getMemtype(Loc.initial).isreal(); } override bool isimaginary() { return sym.getMemtype(Loc.initial).isimaginary(); } override bool iscomplex() { return sym.getMemtype(Loc.initial).iscomplex(); } override bool isscalar() { return sym.getMemtype(Loc.initial).isscalar(); } override bool isunsigned() { return sym.getMemtype(Loc.initial).isunsigned(); } override bool isBoolean() { return sym.getMemtype(Loc.initial).isBoolean(); } override bool isString() { return sym.getMemtype(Loc.initial).isString(); } override bool isAssignable() { return sym.getMemtype(Loc.initial).isAssignable(); } override bool needsDestruction() { return sym.getMemtype(Loc.initial).needsDestruction(); } override bool needsNested() { return sym.getMemtype(Loc.initial).needsNested(); } override MATCH implicitConvTo(Type to) { MATCH m; //printf("TypeEnum::implicitConvTo()\n"); if (ty == to.ty && sym == (cast(TypeEnum)to).sym) m = (mod == to.mod) ? MATCH.exact : MATCH.constant; else if (sym.getMemtype(Loc.initial).implicitConvTo(to)) m = MATCH.convert; // match with conversions else m = MATCH.nomatch; // no match return m; } override MATCH constConv(Type to) { if (equals(to)) return MATCH.exact; if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod)) return MATCH.constant; return MATCH.nomatch; } override Type toBasetype() { if (!sym.members && !sym.memtype) return this; auto tb = sym.getMemtype(Loc.initial).toBasetype(); return tb.castMod(mod); // retain modifier bits from 'this' } override bool isZeroInit(const ref Loc loc) { return sym.getDefaultValue(loc).isBool(false); } override bool hasPointers() { return sym.getMemtype(Loc.initial).hasPointers(); } override bool hasVoidInitPointers() { return sym.getMemtype(Loc.initial).hasVoidInitPointers(); } override Type nextOf() { return sym.getMemtype(Loc.initial).nextOf(); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeClass : Type { ClassDeclaration sym; AliasThisRec att = AliasThisRec.fwdref; CPPMANGLE cppmangle = CPPMANGLE.def; extern (D) this(ClassDeclaration sym) { super(Tclass); this.sym = sym; } override const(char)* kind() const { return "class"; } override d_uns64 size(const ref Loc loc) const { return Target.ptrsize; } override Type syntaxCopy() { return this; } override Dsymbol toDsymbol(Scope* sc) { return sym; } override inout(ClassDeclaration) isClassHandle() inout { return sym; } override bool isBaseOf(Type t, int* poffset) { if (t && t.ty == Tclass) { ClassDeclaration cd = (cast(TypeClass)t).sym; if (sym.isBaseOf(cd, poffset)) return true; } return false; } override MATCH implicitConvTo(Type to) { //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); MATCH m = constConv(to); if (m > MATCH.nomatch) return m; ClassDeclaration cdto = to.isClassHandle(); if (cdto) { //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) cdto.dsymbolSemantic(null); if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) sym.dsymbolSemantic(null); if (cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod)) { //printf("'to' is base\n"); return MATCH.convert; } } m = MATCH.nomatch; if (sym.aliasthis && !(att & AliasThisRec.tracing)) { if (auto ato = aliasthisOf()) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); m = ato.implicitConvTo(to); att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); } } return m; } override MATCH constConv(Type to) { if (equals(to)) return MATCH.exact; if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod)) return MATCH.constant; /* Conversion derived to const(base) */ int offset = 0; if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) { // Disallow: // derived to base // inout(derived) to inout(base) if (!to.isMutable() && !to.isWild()) return MATCH.convert; } return MATCH.nomatch; } override MOD deduceWild(Type t, bool isRef) { ClassDeclaration cd = t.isClassHandle(); if (cd && (sym == cd || cd.isBaseOf(sym, null))) return Type.deduceWild(t, isRef); ubyte wm = 0; if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing)) { if (auto ato = aliasthisOf()) { att = cast(AliasThisRec)(att | AliasThisRec.tracing); wm = ato.deduceWild(t, isRef); att = cast(AliasThisRec)(att & ~AliasThisRec.tracing); } } return wm; } override Type toHeadMutable() { return this; } override bool isZeroInit(const ref Loc loc) const { return true; } override bool isscope() const { return sym.stack; } override bool isBoolean() const { return true; } override bool hasPointers() const { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeTuple : Type { Parameters* arguments; // types making up the tuple extern (D) this(Parameters* arguments) { super(Ttuple); //printf("TypeTuple(this = %p)\n", this); this.arguments = arguments; //printf("TypeTuple() %p, %s\n", this, toChars()); debug { if (arguments) { for (size_t i = 0; i < arguments.dim; i++) { Parameter arg = (*arguments)[i]; assert(arg && arg.type); } } } } /**************** * Form TypeTuple from the types of the expressions. * Assume exps[] is already tuple expanded. */ extern (D) this(Expressions* exps) { super(Ttuple); auto arguments = new Parameters(); if (exps) { arguments.setDim(exps.dim); for (size_t i = 0; i < exps.dim; i++) { Expression e = (*exps)[i]; if (e.type.ty == Ttuple) e.error("cannot form tuple of tuples"); auto arg = new Parameter(STC.undefined_, e.type, null, null, null); (*arguments)[i] = arg; } } this.arguments = arguments; //printf("TypeTuple() %p, %s\n", this, toChars()); } static TypeTuple create(Parameters* arguments) { return new TypeTuple(arguments); } /******************************************* * Type tuple with 0, 1 or 2 types in it. */ extern (D) this() { super(Ttuple); arguments = new Parameters(); } extern (D) this(Type t1) { super(Ttuple); arguments = new Parameters(); arguments.push(new Parameter(0, t1, null, null, null)); } extern (D) this(Type t1, Type t2) { super(Ttuple); arguments = new Parameters(); arguments.push(new Parameter(0, t1, null, null, null)); arguments.push(new Parameter(0, t2, null, null, null)); } override const(char)* kind() const { return "tuple"; } override Type syntaxCopy() { Parameters* args = Parameter.arraySyntaxCopy(arguments); Type t = new TypeTuple(args); t.mod = mod; return t; } override bool equals(RootObject o) const { Type t = cast(Type)o; //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars()); if (this == t) return true; if (t.ty == Ttuple) { TypeTuple tt = cast(TypeTuple)t; if (arguments.dim == tt.arguments.dim) { for (size_t i = 0; i < tt.arguments.dim; i++) { const Parameter arg1 = (*arguments)[i]; Parameter arg2 = (*tt.arguments)[i]; if (!arg1.type.equals(arg2.type)) return false; } return true; } } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * This is so we can slice a TypeTuple */ extern (C++) final class TypeSlice : TypeNext { Expression lwr; Expression upr; extern (D) this(Type next, Expression lwr, Expression upr) { super(Tslice, next); //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars()); this.lwr = lwr; this.upr = upr; } override const(char)* kind() const { return "slice"; } override Type syntaxCopy() { Type t = new TypeSlice(next.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy()); t.mod = mod; return t; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TypeNull : Type { extern (D) this() { //printf("TypeNull %p\n", this); super(Tnull); } override const(char)* kind() const { return "null"; } override Type syntaxCopy() { // No semantic analysis done, no need to copy return this; } override MATCH implicitConvTo(Type to) { //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to.toChars()); MATCH m = Type.implicitConvTo(to); if (m != MATCH.nomatch) return m; // NULL implicitly converts to any pointer type or dynamic array //if (type.ty == Tpointer && type.nextOf().ty == Tvoid) { Type tb = to.toBasetype(); if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate) return MATCH.constant; } return MATCH.nomatch; } override bool isBoolean() const { return true; } override d_uns64 size(const ref Loc loc) const { return tvoidptr.size(loc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class Parameter : RootObject { import dmd.attrib : UserAttributeDeclaration; StorageClass storageClass; Type type; Identifier ident; Expression defaultArg; UserAttributeDeclaration userAttribDecl; // user defined attributes extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) { this.type = type; this.ident = ident; this.storageClass = storageClass; this.defaultArg = defaultArg; this.userAttribDecl = userAttribDecl; } static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) { return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl); } Parameter syntaxCopy() { return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? cast(UserAttributeDeclaration) userAttribDecl.syntaxCopy(null) : null); } /**************************************************** * Determine if parameter is a lazy array of delegates. * If so, return the return type of those delegates. * If not, return NULL. * * Returns T if the type is one of the following forms: * T delegate()[] * T delegate()[dim] */ Type isLazyArray() { Type tb = type.toBasetype(); if (tb.ty == Tsarray || tb.ty == Tarray) { Type tel = (cast(TypeArray)tb).next.toBasetype(); if (tel.ty == Tdelegate) { TypeDelegate td = cast(TypeDelegate)tel; TypeFunction tf = td.next.toTypeFunction(); if (!tf.varargs && Parameter.dim(tf.parameters) == 0) { return tf.next; // return type of delegate } } } return null; } // kludge for template.isType() override DYNCAST dyncast() const { return DYNCAST.parameter; } void accept(Visitor v) { v.visit(this); } extern (D) static Parameters* arraySyntaxCopy(Parameters* parameters) { Parameters* params = null; if (parameters) { params = new Parameters(parameters.dim); for (size_t i = 0; i < params.dim; i++) (*params)[i] = (*parameters)[i].syntaxCopy(); } return params; } /*************************************** * Determine number of arguments, folding in tuples. */ static size_t dim(Parameters* parameters) { size_t nargs = 0; int dimDg(size_t n, Parameter p) { ++nargs; return 0; } _foreach(parameters, &dimDg); return nargs; } /*************************************** * Get nth Parameter, folding in tuples. * Returns: * Parameter* nth Parameter * NULL not found, *pn gets incremented by the number * of Parameters */ static Parameter getNth(Parameters* parameters, size_t nth, size_t* pn = null) { Parameter param; int getNthParamDg(size_t n, Parameter p) { if (n == nth) { param = p; return 1; } return 0; } int res = _foreach(parameters, &getNthParamDg); return res ? param : null; } alias ForeachDg = extern (D) int delegate(size_t paramidx, Parameter param); /*************************************** * Expands tuples in args in depth first order. Calls * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. * If dg returns !=0, stops and returns that value else returns 0. * Use this function to avoid the O(N + N^2/2) complexity of * calculating dim and calling N times getNth. */ extern (D) static int _foreach(Parameters* parameters, scope ForeachDg dg, size_t* pn = null) { assert(dg); if (!parameters) return 0; size_t n = pn ? *pn : 0; // take over index int result = 0; foreach (i; 0 .. parameters.dim) { Parameter p = (*parameters)[i]; Type t = p.type.toBasetype(); if (t.ty == Ttuple) { TypeTuple tu = cast(TypeTuple)t; result = _foreach(tu.arguments, dg, &n); } else result = dg(n++, p); if (result) break; } if (pn) *pn = n; // update index return result; } override const(char)* toChars() const { return ident ? ident.toChars() : "__anonymous_param"; } /********************************* * Compute covariance of parameters `this` and `p` * as determined by the storage classes of both. * Params: * returnByRef = true if the function returns by ref * p = Parameter to compare with * Returns: * true = `this` can be used in place of `p` * false = nope */ bool isCovariant(bool returnByRef, const Parameter p) const pure nothrow @nogc @safe { enum stc = STC.ref_ | STC.in_ | STC.out_ | STC.lazy_; if ((this.storageClass & stc) != (p.storageClass & stc)) return false; return isCovariantScope(returnByRef, this.storageClass, p.storageClass); } extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe { if (from == to) return true; /* Shrinking the representation is necessary because StorageClass is so wide * Params: * returnByRef = true if the function returns by ref * stc = storage class of parameter */ static uint buildSR(bool returnByRef, StorageClass stc) pure nothrow @nogc @safe { uint result; final switch (stc & (STC.ref_ | STC.scope_ | STC.return_)) { case 0: result = SR.None; break; case STC.ref_: result = SR.Ref; break; case STC.scope_: result = SR.Scope; break; case STC.return_ | STC.ref_: result = SR.ReturnRef; break; case STC.return_ | STC.scope_: result = SR.ReturnScope; break; case STC.ref_ | STC.scope_: result = SR.RefScope; break; case STC.return_ | STC.ref_ | STC.scope_: result = returnByRef ? SR.ReturnRef_Scope : SR.Ref_ReturnScope; break; } return result; } /* result is true if the 'from' can be used as a 'to' */ if ((from ^ to) & STC.ref_) // differing in 'ref' means no covariance return false; return covariant[buildSR(returnByRef, from)][buildSR(returnByRef, to)]; } /* Classification of 'scope-return-ref' possibilities */ private enum SR { None, Scope, ReturnScope, Ref, ReturnRef, RefScope, ReturnRef_Scope, Ref_ReturnScope, } extern (D) private static bool[SR.max + 1][SR.max + 1] covariantInit() pure nothrow @nogc @safe { /* Initialize covariant[][] with this: From\To n rs s None X ReturnScope X X Scope X X X From\To r rr rs rr-s r-rs Ref X X ReturnRef X RefScope X X X X X ReturnRef-Scope X X Ref-ReturnScope X X X */ bool[SR.max + 1][SR.max + 1] covariant; foreach (i; 0 .. SR.max + 1) { covariant[i][i] = true; covariant[SR.RefScope][i] = true; } covariant[SR.ReturnScope][SR.None] = true; covariant[SR.Scope ][SR.None] = true; covariant[SR.Scope ][SR.ReturnScope] = true; covariant[SR.Ref ][SR.ReturnRef] = true; covariant[SR.ReturnRef_Scope][SR.ReturnRef] = true; covariant[SR.Ref_ReturnScope][SR.Ref ] = true; covariant[SR.Ref_ReturnScope][SR.ReturnRef] = true; return covariant; } extern (D) private static immutable bool[SR.max + 1][SR.max + 1] covariant = covariantInit(); } /************************************************************* * For printing two types with qualification when necessary. * Params: * t1 = The first type to receive the type name for * t2 = The second type to receive the type name for * Returns: * The fully-qualified names of both types if the two type names are not the same, * or the unqualified names of both types if the two type names are the same. */ const(char*)[2] toAutoQualChars(Type t1, Type t2) { auto s1 = t1.toChars(); auto s2 = t2.toChars(); // show qualification only if it's different if (!t1.equals(t2) && strcmp(s1, s2) == 0) { s1 = t1.toPrettyChars(true); s2 = t2.toPrettyChars(true); } return [s1, s2]; } /** * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a * void* for the work param and a string representation of the attribute. */ int modifiersApply(TypeFunction tf, void* param, int function(void*, string) fp) { immutable ubyte[4] modsArr = [MODFlags.const_, MODFlags.immutable_, MODFlags.wild, MODFlags.shared_]; foreach (modsarr; modsArr) { if (tf.mod & modsarr) { if (int res = fp(param, MODtoString(modsarr))) return res; } } return 0; } /** * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the * work param and a string representation of the attribute. */ int attributesApply(TypeFunction tf, void* param, int function(void*, string) fp, TRUSTformat trustFormat = TRUSTformatDefault) { int res = 0; if (tf.purity) res = fp(param, "pure"); if (res) return res; if (tf.isnothrow) res = fp(param, "nothrow"); if (res) return res; if (tf.isnogc) res = fp(param, "@nogc"); if (res) return res; if (tf.isproperty) res = fp(param, "@property"); if (res) return res; if (tf.isref) res = fp(param, "ref"); if (res) return res; if (tf.isreturn) res = fp(param, "return"); if (res) return res; if (tf.isscope && !tf.isscopeinferred) res = fp(param, "scope"); if (res) return res; TRUST trustAttrib = tf.trust; if (trustAttrib == TRUST.default_) { // Print out "@system" when trust equals TRUST.default_ (if desired). if (trustFormat == TRUSTformatSystem) trustAttrib = TRUST.system; else return res; // avoid calling with an empty string } return fp(param, trustToString(trustAttrib)); } ================================================ FILE: gcc/d/dmd/mtype.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/mtype.h */ #pragma once #include "root/rmem.h" // for d_size_t #include "arraytypes.h" #include "globals.h" #include "visitor.h" struct Scope; class Identifier; class Expression; class StructDeclaration; class ClassDeclaration; class EnumDeclaration; class TypeInfoDeclaration; class Dsymbol; class TemplateInstance; class TemplateDeclaration; class TypeBasic; class Parameter; // Back end #ifdef IN_GCC typedef union tree_node type; #else typedef struct TYPE type; #endif void semanticTypeInfo(Scope *sc, Type *t); MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0); StorageClass ModToStc(unsigned mod); enum ENUMTY { Tarray, // slice array, aka T[] Tsarray, // static array, aka T[dimension] Taarray, // associative array, aka T[type] Tpointer, Treference, Tfunction, Tident, Tclass, Tstruct, Tenum, Tdelegate, Tnone, Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, Tfloat32, Tfloat64, Tfloat80, Timaginary32, Timaginary64, Timaginary80, Tcomplex32, Tcomplex64, Tcomplex80, Tbool, Tchar, Twchar, Tdchar, Terror, Tinstance, Ttypeof, Ttuple, Tslice, Treturn, Tnull, Tvector, Tint128, Tuns128, TMAX }; typedef unsigned char TY; // ENUMTY extern int Tsize_t; extern int Tptrdiff_t; #define SIZE_INVALID (~(d_uns64)0) // error return from size() functions /** * type modifiers * pick this order of numbers so switch statements work better */ enum MODFlags { MODconst = 1, // type is const MODimmutable = 4, // type is immutable MODshared = 2, // type is shared MODwild = 8, // type is wild MODwildconst = (MODwild | MODconst), // type is wild const MODmutable = 0x10 // type is mutable (only used in wildcard matching) }; typedef unsigned char MOD; // These tables are for implicit conversion of binary ops; // the indices are the type of operand one, followed by operand two. extern unsigned char impcnvResult[TMAX][TMAX]; extern unsigned char impcnvType1[TMAX][TMAX]; extern unsigned char impcnvType2[TMAX][TMAX]; // If !=0, give warning on implicit conversion extern unsigned char impcnvWarn[TMAX][TMAX]; class Type : public RootObject { public: TY ty; MOD mod; // modifiers MODxxxx char *deco; /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc. * They should not be referenced by anybody but mtype.c. * They can be NULL if not lazily evaluated yet. * Note that there is no "shared immutable", because that is just immutable * Naked == no MOD bits */ Type *cto; // MODconst ? naked version of this type : const version Type *ito; // MODimmutable ? naked version of this type : immutable version Type *sto; // MODshared ? naked version of this type : shared mutable version Type *scto; // MODshared | MODconst ? naked version of this type : shared const version Type *wto; // MODwild ? naked version of this type : wild version Type *wcto; // MODwildconst ? naked version of this type : wild const version Type *swto; // MODshared | MODwild ? naked version of this type : shared wild version Type *swcto; // MODshared | MODwildconst ? naked version of this type : shared wild const version Type *pto; // merged pointer to this type Type *rto; // reference to this type Type *arrayof; // array of this type TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type type *ctype; // for back end static Type *tvoid; static Type *tint8; static Type *tuns8; static Type *tint16; static Type *tuns16; static Type *tint32; static Type *tuns32; static Type *tint64; static Type *tuns64; static Type *tint128; static Type *tuns128; static Type *tfloat32; static Type *tfloat64; static Type *tfloat80; static Type *timaginary32; static Type *timaginary64; static Type *timaginary80; static Type *tcomplex32; static Type *tcomplex64; static Type *tcomplex80; static Type *tbool; static Type *tchar; static Type *twchar; static Type *tdchar; // Some special types static Type *tshiftcnt; static Type *tvoidptr; // void* static Type *tstring; // immutable(char)[] static Type *twstring; // immutable(wchar)[] static Type *tdstring; // immutable(dchar)[] static Type *tvalist; // va_list alias static Type *terror; // for error recovery static Type *tnull; // for null type static Type *tsize_t; // matches size_t alias static Type *tptrdiff_t; // matches ptrdiff_t alias static Type *thash_t; // matches hash_t alias static ClassDeclaration *dtypeinfo; static ClassDeclaration *typeinfoclass; static ClassDeclaration *typeinfointerface; static ClassDeclaration *typeinfostruct; static ClassDeclaration *typeinfopointer; static ClassDeclaration *typeinfoarray; static ClassDeclaration *typeinfostaticarray; static ClassDeclaration *typeinfoassociativearray; static ClassDeclaration *typeinfovector; static ClassDeclaration *typeinfoenum; static ClassDeclaration *typeinfofunction; static ClassDeclaration *typeinfodelegate; static ClassDeclaration *typeinfotypelist; static ClassDeclaration *typeinfoconst; static ClassDeclaration *typeinfoinvariant; static ClassDeclaration *typeinfoshared; static ClassDeclaration *typeinfowild; static TemplateDeclaration *rtinfo; static Type *basic[TMAX]; virtual const char *kind(); Type *copy(); virtual Type *syntaxCopy(); bool equals(RootObject *o); bool equivalent(Type *t); // kludge for template.isType() int dyncast() const { return DYNCAST_TYPE; } int covariant(Type *t, StorageClass *pstc = NULL, bool fix17349 = true); const char *toChars(); char *toPrettyChars(bool QualifyTypes = false); static void _init(); d_uns64 size(); virtual d_uns64 size(const Loc &loc); virtual unsigned alignsize(); Type *trySemantic(const Loc &loc, Scope *sc); Type *merge2(); void modToBuffer(OutBuffer *buf); char *modToChars(); virtual bool isintegral(); virtual bool isfloating(); // real, imaginary, or complex virtual bool isreal(); virtual bool isimaginary(); virtual bool iscomplex(); virtual bool isscalar(); virtual bool isunsigned(); virtual bool isscope(); virtual bool isString(); virtual bool isAssignable(); virtual bool isBoolean(); virtual void checkDeprecated(const Loc &loc, Scope *sc); bool isConst() const { return (mod & MODconst) != 0; } bool isImmutable() const { return (mod & MODimmutable) != 0; } bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; } bool isShared() const { return (mod & MODshared) != 0; } bool isSharedConst() const { return (mod & (MODshared | MODconst)) == (MODshared | MODconst); } bool isWild() const { return (mod & MODwild) != 0; } bool isWildConst() const { return (mod & MODwildconst) == MODwildconst; } bool isSharedWild() const { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); } bool isNaked() const { return mod == 0; } Type *nullAttributes(); Type *constOf(); Type *immutableOf(); Type *mutableOf(); Type *sharedOf(); Type *sharedConstOf(); Type *unSharedOf(); Type *wildOf(); Type *wildConstOf(); Type *sharedWildOf(); Type *sharedWildConstOf(); void fixTo(Type *t); void check(); Type *addSTC(StorageClass stc); Type *castMod(MOD mod); Type *addMod(MOD mod); virtual Type *addStorageClass(StorageClass stc); Type *pointerTo(); Type *referenceTo(); Type *arrayOf(); Type *sarrayOf(dinteger_t dim); Type *aliasthisOf(); virtual Type *makeConst(); virtual Type *makeImmutable(); virtual Type *makeShared(); virtual Type *makeSharedConst(); virtual Type *makeWild(); virtual Type *makeWildConst(); virtual Type *makeSharedWild(); virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); virtual Dsymbol *toDsymbol(Scope *sc); virtual Type *toBasetype(); virtual bool isBaseOf(Type *t, int *poffset); virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); virtual Type *substWildTo(unsigned mod); Type *unqualify(unsigned m); virtual Type *toHeadMutable(); virtual ClassDeclaration *isClassHandle(); virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 Identifier *getTypeInfoIdent(); void resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps); virtual int hasWild() const; virtual bool hasPointers(); virtual bool hasVoidInitPointers(); virtual Type *nextOf(); Type *baseElemOf(); uinteger_t sizemask(); virtual bool needsDestruction(); virtual bool needsNested(); // For eliminating dynamic_cast virtual TypeBasic *isTypeBasic(); virtual void accept(Visitor *v) { v->visit(this); } }; class TypeError : public Type { public: Type *syntaxCopy(); d_uns64 size(const Loc &loc); Expression *defaultInitLiteral(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; class TypeNext : public Type { public: Type *next; void checkDeprecated(const Loc &loc, Scope *sc); int hasWild() const; Type *nextOf(); Type *makeConst(); Type *makeImmutable(); Type *makeShared(); Type *makeSharedConst(); Type *makeWild(); Type *makeWildConst(); Type *makeSharedWild(); Type *makeSharedWildConst(); Type *makeMutable(); MATCH constConv(Type *to); unsigned char deduceWild(Type *t, bool isRef); void transitive(); void accept(Visitor *v) { v->visit(this); } }; class TypeBasic : public Type { public: const char *dstring; unsigned flags; const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc) /*const*/; unsigned alignsize(); bool isintegral(); bool isfloating() /*const*/; bool isreal() /*const*/; bool isimaginary() /*const*/; bool iscomplex() /*const*/; bool isscalar() /*const*/; bool isunsigned() /*const*/; MATCH implicitConvTo(Type *to); bool isZeroInit(const Loc &loc) /*const*/; // For eliminating dynamic_cast TypeBasic *isTypeBasic(); void accept(Visitor *v) { v->visit(this); } }; class TypeVector : public Type { public: Type *basetype; static TypeVector *create(Type *basetype); const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc); unsigned alignsize(); bool isintegral(); bool isfloating(); bool isscalar(); bool isunsigned(); bool isBoolean() /*const*/; MATCH implicitConvTo(Type *to); Expression *defaultInitLiteral(const Loc &loc); TypeBasic *elementType(); bool isZeroInit(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; class TypeArray : public TypeNext { public: void accept(Visitor *v) { v->visit(this); } }; // Static array, one with a fixed dimension class TypeSArray : public TypeArray { public: Expression *dim; const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc); unsigned alignsize(); bool isString(); bool isZeroInit(const Loc &loc); structalign_t alignment(); MATCH constConv(Type *to); MATCH implicitConvTo(Type *to); Expression *defaultInitLiteral(const Loc &loc); bool hasPointers(); bool needsDestruction(); bool needsNested(); void accept(Visitor *v) { v->visit(this); } }; // Dynamic array, no dimension class TypeDArray : public TypeArray { public: const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc) /*const*/; unsigned alignsize() /*const*/; bool isString(); bool isZeroInit(const Loc &loc) /*const*/; bool isBoolean() /*const*/; MATCH implicitConvTo(Type *to); bool hasPointers() /*const*/; void accept(Visitor *v) { v->visit(this); } }; class TypeAArray : public TypeArray { public: Type *index; // key type Loc loc; Scope *sc; static TypeAArray *create(Type *t, Type *index); const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc); bool isZeroInit(const Loc &loc) /*const*/; bool isBoolean() /*const*/; bool hasPointers() /*const*/; MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); void accept(Visitor *v) { v->visit(this); } }; class TypePointer : public TypeNext { public: static TypePointer *create(Type *t); const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc) /*const*/; MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); bool isscalar() /*const*/; bool isZeroInit(const Loc &loc) /*const*/; bool hasPointers() /*const*/; void accept(Visitor *v) { v->visit(this); } }; class TypeReference : public TypeNext { public: const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc) /*const*/; bool isZeroInit(const Loc &loc) /*const*/; void accept(Visitor *v) { v->visit(this); } }; enum RET { RETregs = 1, // returned in registers RETstack = 2 // returned on stack }; enum TRUST { TRUSTdefault = 0, TRUSTsystem = 1, // @system (same as TRUSTdefault) TRUSTtrusted = 2, // @trusted TRUSTsafe = 3 // @safe }; enum TRUSTformat { TRUSTformatDefault, // do not emit @system when trust == TRUSTdefault TRUSTformatSystem // emit @system when trust == TRUSTdefault }; enum PURE { PUREimpure = 0, // not pure at all PUREfwdref = 1, // it's pure, but not known which level yet PUREweak = 2, // no mutable globals are read or written PUREconst = 3, // parameters are values or const PUREstrong = 4 // parameters are values or immutable }; class TypeFunction : public TypeNext { public: // .next is the return type Parameters *parameters; // function parameters int varargs; // 1: T t, ...) style for variable number of arguments // 2: T t ...) style for variable number of arguments bool isnothrow; // true: nothrow bool isnogc; // true: is @nogc bool isproperty; // can be called without parentheses bool isref; // true: returns a reference bool isreturn; // true: 'this' is returned by ref bool isscope; // true: 'this' is scope bool isscopeinferred; // true: 'this' is scope from inference LINK linkage; // calling convention TRUST trust; // level of trust PURE purity; // PURExxxx unsigned char iswild; // bit0: inout on params, bit1: inout on qualifier Expressions *fargs; // function arguments int inuse; static TypeFunction *create(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0); const char *kind(); Type *syntaxCopy(); void purityLevel(); bool hasLazyParameters(); bool parameterEscapes(Parameter *p); StorageClass parameterStorageClass(Parameter *p); Type *addStorageClass(StorageClass stc); Type *substWildTo(unsigned mod); void accept(Visitor *v) { v->visit(this); } }; class TypeDelegate : public TypeNext { public: // .next is a TypeFunction static TypeDelegate *create(Type *t); const char *kind(); Type *syntaxCopy(); Type *addStorageClass(StorageClass stc); d_uns64 size(const Loc &loc) /*const*/; unsigned alignsize() /*const*/; MATCH implicitConvTo(Type *to); bool isZeroInit(const Loc &loc) /*const*/; bool isBoolean() /*const*/; bool hasPointers() /*const*/; void accept(Visitor *v) { v->visit(this); } }; class TypeQualified : public Type { public: Loc loc; // array of Identifier and TypeInstance, // representing ident.ident!tiargs.ident. ... etc. Objects idents; void syntaxCopyHelper(TypeQualified *t); void addIdent(Identifier *ident); void addInst(TemplateInstance *inst); void addIndex(RootObject *expr); d_uns64 size(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; class TypeIdentifier : public TypeQualified { public: Identifier *ident; Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; /* Similar to TypeIdentifier, but with a TemplateInstance as the root */ class TypeInstance : public TypeQualified { public: TemplateInstance *tempinst; const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class TypeTypeof : public TypeQualified { public: Expression *exp; int inuse; const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); d_uns64 size(const Loc &loc); void accept(Visitor *v) { v->visit(this); } }; class TypeReturn : public TypeQualified { public: const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; // Whether alias this dependency is recursive or not. enum AliasThisRec { RECno = 0, // no alias this recursion RECyes = 1, // alias this has recursive dependency RECfwdref = 2, // not yet known RECtypeMask = 3,// mask to read no/yes/fwdref RECtracing = 0x4, // mark in progress of implicitConvTo/deduceWild RECtracingDT = 0x8 // mark in progress of deduceType }; class TypeStruct : public Type { public: StructDeclaration *sym; AliasThisRec att; CPPMANGLE cppmangle; static TypeStruct *create(StructDeclaration *sym); const char *kind(); d_uns64 size(const Loc &loc); unsigned alignsize(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); structalign_t alignment(); Expression *defaultInitLiteral(const Loc &loc); bool isZeroInit(const Loc &loc) /*const*/; bool isAssignable(); bool isBoolean() /*const*/; bool needsDestruction() /*const*/; bool needsNested(); bool hasPointers(); bool hasVoidInitPointers(); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); unsigned char deduceWild(Type *t, bool isRef); Type *toHeadMutable(); void accept(Visitor *v) { v->visit(this); } }; class TypeEnum : public Type { public: EnumDeclaration *sym; const char *kind(); Type *syntaxCopy(); d_uns64 size(const Loc &loc); unsigned alignsize(); Dsymbol *toDsymbol(Scope *sc); bool isintegral(); bool isfloating(); bool isreal(); bool isimaginary(); bool iscomplex(); bool isscalar(); bool isunsigned(); bool isBoolean(); bool isString(); bool isAssignable(); bool needsDestruction(); bool needsNested(); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); Type *toBasetype(); bool isZeroInit(const Loc &loc); bool hasPointers(); bool hasVoidInitPointers(); Type *nextOf(); void accept(Visitor *v) { v->visit(this); } }; class TypeClass : public Type { public: ClassDeclaration *sym; AliasThisRec att; CPPMANGLE cppmangle; const char *kind(); d_uns64 size(const Loc &loc) /*const*/; Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); ClassDeclaration *isClassHandle(); bool isBaseOf(Type *t, int *poffset); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); unsigned char deduceWild(Type *t, bool isRef); Type *toHeadMutable(); bool isZeroInit(const Loc &loc) /*const*/; bool isscope() /*const*/; bool isBoolean() /*const*/; bool hasPointers() /*const*/; void accept(Visitor *v) { v->visit(this); } }; class TypeTuple : public Type { public: Parameters *arguments; // types making up the tuple static TypeTuple *create(Parameters *arguments); const char *kind(); Type *syntaxCopy(); bool equals(RootObject *o); void accept(Visitor *v) { v->visit(this); } }; class TypeSlice : public TypeNext { public: Expression *lwr; Expression *upr; const char *kind(); Type *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class TypeNull : public Type { public: const char *kind(); Type *syntaxCopy(); MATCH implicitConvTo(Type *to); bool isBoolean() /*const*/; d_uns64 size(const Loc &loc) /*const*/; void accept(Visitor *v) { v->visit(this); } }; /**************************************************************/ //enum InOut { None, In, Out, InOut, Lazy }; class Parameter : public RootObject { public: //enum InOut inout; StorageClass storageClass; Type *type; Identifier *ident; Expression *defaultArg; UserAttributeDeclaration *userAttribDecl; // user defined attributes static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg, UserAttributeDeclaration *userAttribDecl); Parameter *syntaxCopy(); Type *isLazyArray(); // kludge for template.isType() int dyncast() const { return DYNCAST_PARAMETER; } virtual void accept(Visitor *v) { v->visit(this); } static size_t dim(Parameters *parameters); static Parameter *getNth(Parameters *parameters, d_size_t nth, d_size_t *pn = NULL); const char *toChars(); bool isCovariant(bool returnByRef, const Parameter *p) const; }; bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2); bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2); ================================================ FILE: gcc/d/dmd/nogc.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/nogc.d, _nogc.d) * Documentation: https://dlang.org/phobos/dmd_nogc.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nogc.d */ module dmd.nogc; import dmd.aggregate; import dmd.apply; import dmd.declaration; import dmd.dscope; import dmd.expression; import dmd.func; import dmd.globals; import dmd.init; import dmd.mtype; import dmd.tokens; import dmd.visitor; /************************************** * Look for GC-allocations */ extern (C++) final class NOGCVisitor : StoppableVisitor { alias visit = typeof(super).visit; public: FuncDeclaration f; bool err; extern (D) this(FuncDeclaration f) { this.f = f; } void doCond(Expression exp) { if (exp) walkPostorder(exp, this); } override void visit(Expression e) { } override void visit(DeclarationExp e) { // Note that, walkPostorder does not support DeclarationExp today. VarDeclaration v = e.declaration.isVarDeclaration(); if (v && !(v.storage_class & STC.manifest) && !v.isDataseg() && v._init) { if (ExpInitializer ei = v._init.isExpInitializer()) { doCond(ei.exp); } } } override void visit(CallExp e) { } override void visit(ArrayLiteralExp e) { if (e.type.ty != Tarray || !e.elements || !e.elements.dim) return; if (f.setGC()) { e.error("array literal in `@nogc` %s `%s` may cause a GC allocation", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "array literal may cause a GC allocation"); } override void visit(AssocArrayLiteralExp e) { if (!e.keys.dim) return; if (f.setGC()) { e.error("associative array literal in `@nogc` %s `%s` may cause a GC allocation", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "associative array literal may cause a GC allocation"); } override void visit(NewExp e) { if (e.member && !e.member.isNogc() && f.setGC()) { // @nogc-ness is already checked in NewExp::semantic return; } if (e.onstack) return; if (e.allocator) return; if (global.params.ehnogc && e.thrownew) return; // separate allocator is called for this, not the GC if (f.setGC()) { e.error("cannot use `new` in `@nogc` %s `%s`", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "`new` causes a GC allocation"); } override void visit(DeleteExp e) { if (e.e1.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); if (v && v.onstack) return; // delete for scope allocated class object } Type tb = e.e1.type.toBasetype(); AggregateDeclaration ad = null; switch (tb.ty) { case Tclass: ad = (cast(TypeClass)tb).sym; break; case Tpointer: tb = (cast(TypePointer)tb).next.toBasetype(); if (tb.ty == Tstruct) ad = (cast(TypeStruct)tb).sym; break; default: break; } if (ad && ad.aggDelete) return; if (f.setGC()) { e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "`delete` requires the GC"); } override void visit(IndexExp e) { Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Taarray) { if (f.setGC()) { e.error("indexing an associative array in `@nogc` %s `%s` may cause a GC allocation", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "indexing an associative array may cause a GC allocation"); } } override void visit(AssignExp e) { if (e.e1.op == TOK.arrayLength) { if (f.setGC()) { e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } } override void visit(CatAssignExp e) { if (f.setGC()) { e.error("cannot use operator `~=` in `@nogc` %s `%s`", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); } override void visit(CatExp e) { if (f.setGC()) { e.error("cannot use operator `~` in `@nogc` %s `%s`", f.kind(), f.toPrettyChars()); err = true; return; } f.printGCUsage(e.loc, "operator `~` may cause a GC allocation"); } } Expression checkGC(Scope* sc, Expression e) { FuncDeclaration f = sc.func; if (e && e.op != TOK.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) && (f.type.ty == Tfunction && (cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) && !(sc.flags & SCOPE.debug_)) { scope NOGCVisitor gcv = new NOGCVisitor(f); walkPostorder(e, gcv); if (gcv.err) return new ErrorExp(); } return e; } ================================================ FILE: gcc/d/dmd/nspace.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/nspace.d, _nspace.d) * Documentation: https://dlang.org/phobos/dmd_nspace.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d */ module dmd.nspace; import dmd.aggregate; import dmd.arraytypes; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.globals; import dmd.identifier; import dmd.visitor; import core.stdc.stdio; private enum LOG = false; /*********************************************************** * A namespace corresponding to a C++ namespace. * Implies extern(C++). */ extern (C++) final class Nspace : ScopeDsymbol { /** * Determines whether the symbol for this namespace should be included in the symbol table. */ bool mangleOnly; extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* members, bool mangleOnly) { super(ident); //printf("Nspace::Nspace(ident = %s)\n", ident.toChars()); this.loc = loc; this.members = members; this.mangleOnly = mangleOnly; } override Dsymbol syntaxCopy(Dsymbol s) { auto ns = new Nspace(loc, ident, null, mangleOnly); return ScopeDsymbol.syntaxCopy(ns); } override void addMember(Scope* sc, ScopeDsymbol sds) { if(!mangleOnly) ScopeDsymbol.addMember(sc, sds); if (members) { if (!symtab) symtab = new DsymbolTable(); // The namespace becomes 'imported' into the enclosing scope for (Scope* sce = sc; 1; sce = sce.enclosing) { ScopeDsymbol sds2 = sce.scopesym; if (sds2) { sds2.importScope(this, Prot(Prot.Kind.public_)); break; } } assert(sc); sc = sc.push(this); sc.linkage = LINK.cpp; // namespaces default to C++ linkage sc.parent = this; foreach (s; *members) { //printf("add %s to scope %s\n", s.toChars(), toChars()); s.addMember(sc, this); } sc.pop(); } } override void setScope(Scope* sc) { ScopeDsymbol.setScope(sc); if (members) { assert(sc); sc = sc.push(this); sc.linkage = LINK.cpp; // namespaces default to C++ linkage sc.parent = this; foreach (s; *members) { s.setScope(sc); } sc.pop(); } } override bool oneMember(Dsymbol* ps, Identifier ident) { return Dsymbol.oneMember(ps, ident); } override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) { //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); if (_scope && !symtab) dsymbolSemantic(this, _scope); if (!members || !symtab) // opaque or semantic() is not yet called { error("is forward referenced when looking for `%s`", ident.toChars()); return null; } return ScopeDsymbol.search(loc, ident, flags); } override int apply(Dsymbol_apply_ft_t fp, void* param) { if (members) { foreach (s; *members) { if (s) { if (s.apply(fp, param)) return 1; } } } return 0; } override bool hasPointers() { //printf("Nspace::hasPointers() %s\n", toChars()); if (members) { foreach (s; *members) { //printf(" s = %s %s\n", s.kind(), s.toChars()); if (s.hasPointers()) { return true; } } } return false; } override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) { //printf("Nspace::setFieldOffset() %s\n", toChars()); if (_scope) // if fwd reference dsymbolSemantic(this, null); // try to resolve it if (members) { foreach (s; *members) { //printf("\t%s\n", s.toChars()); s.setFieldOffset(ad, poffset, isunion); } } } override const(char)* kind() const { return "namespace"; } override inout(Nspace) isNspace() inout { return this; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/nspace.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/nspace.h */ #pragma once #include "dsymbol.h" /* A namespace corresponding to a C++ namespace. * Implies extern(C++). */ class Nspace : public ScopeDsymbol { public: bool mangleOnly; Dsymbol *syntaxCopy(Dsymbol *s); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); bool oneMember(Dsymbol **ps, Identifier *ident); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); int apply(Dsymbol_apply_ft_t fp, void *param); bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *kind() const; Nspace *isNspace() { return this; } void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/objc.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/objc.d, _objc.d) * Documentation: https://dlang.org/phobos/dmd_objc.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/objc.d */ module dmd.objc; import dmd.aggregate; import dmd.arraytypes; import dmd.cond; import dmd.dclass; import dmd.declaration; import dmd.dmangle; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.gluelayer; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.stringtable; struct ObjcSelector { // MARK: Selector private __gshared StringTable stringtable; private __gshared StringTable vTableDispatchSelectors; private __gshared int incnum = 0; const(char)* stringvalue; size_t stringlen; size_t paramCount; extern (C++) static void _init() { stringtable._init(); } extern (D) this(const(char)* sv, size_t len, size_t pcount) { stringvalue = sv; stringlen = len; paramCount = pcount; } extern (D) static ObjcSelector* lookup(const(char)* s) { size_t len = 0; size_t pcount = 0; const(char)* i = s; while (*i != 0) { ++len; if (*i == ':') ++pcount; ++i; } return lookup(s, len, pcount); } extern (D) static ObjcSelector* lookup(const(char)* s, size_t len, size_t pcount) { StringValue* sv = stringtable.update(s, len); ObjcSelector* sel = cast(ObjcSelector*)sv.ptrvalue; if (!sel) { sel = new ObjcSelector(sv.toDchars(), len, pcount); sv.ptrvalue = cast(char*)sel; } return sel; } extern (C++) static ObjcSelector* create(FuncDeclaration fdecl) { OutBuffer buf; size_t pcount = 0; TypeFunction ftype = cast(TypeFunction)fdecl.type; const id = fdecl.ident.toString(); // Special case: property setter if (ftype.isproperty && ftype.parameters && ftype.parameters.dim == 1) { // rewrite "identifier" as "setIdentifier" char firstChar = id[0]; if (firstChar >= 'a' && firstChar <= 'z') firstChar = cast(char)(firstChar - 'a' + 'A'); buf.writestring("set"); buf.writeByte(firstChar); buf.write(id.ptr + 1, id.length - 1); buf.writeByte(':'); goto Lcomplete; } // write identifier in selector buf.write(id.ptr, id.length); // add mangled type and colon for each parameter if (ftype.parameters && ftype.parameters.dim) { buf.writeByte('_'); Parameters* arguments = ftype.parameters; size_t dim = Parameter.dim(arguments); for (size_t i = 0; i < dim; i++) { Parameter arg = Parameter.getNth(arguments, i); mangleToBuffer(arg.type, &buf); buf.writeByte(':'); } pcount = dim; } Lcomplete: buf.writeByte('\0'); return lookup(cast(const(char)*)buf.data, buf.size, pcount); } extern (D) const(char)[] toString() const pure { return stringvalue[0 .. stringlen]; } } private __gshared Objc _objc; Objc objc() { return _objc; } /** * Contains all data for a class declaration that is needed for the Objective-C * integration. */ struct ObjcClassDeclaration { /// `true` if this class is a metaclass. bool isMeta = false; /// The metaclass of this class. ClassDeclaration metaclass; } // Should be an interface extern(C++) abstract class Objc { static void _init() { if (global.params.isOSX && global.params.is64bit) _objc = new Supported; else _objc = new Unsupported; } abstract void setObjc(ClassDeclaration cd); abstract void setObjc(InterfaceDeclaration); abstract void setSelector(FuncDeclaration, Scope* sc); abstract void validateSelector(FuncDeclaration fd); abstract void checkLinkage(FuncDeclaration fd); /** * Returns the `this` pointer of the given function declaration. * * This is only used for class/static methods. For instance methods, no * Objective-C specialization is necessary. * * Params: * funcDeclaration = the function declaration to get the `this` pointer for * * Returns: the `this` pointer of the given function declaration, or `null` * if the given function declaration is not an Objective-C method. */ abstract inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const; /** * Creates and sets the metaclass on the given class/interface declaration. * * Will only be performed on regular Objective-C classes, not on metaclasses. * * Params: * classDeclaration = the class/interface declaration to set the metaclass on */ abstract void setMetaclass(InterfaceDeclaration interfaceDeclaration) const; /// ditto abstract void setMetaclass(ClassDeclaration classDeclaration) const; /** * Returns Objective-C runtime metaclass of the given class declaration. * * `ClassDeclaration.ObjcClassDeclaration.metaclass` contains the metaclass * from the semantic point of view. This function returns the metaclass from * the Objective-C runtime's point of view. Here, the metaclass of a * metaclass is the root metaclass, not `null`. The root metaclass's * metaclass is itself. * * Params: * classDeclaration = The class declaration to return the metaclass of * * Returns: the Objective-C runtime metaclass of the given class declaration */ abstract ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const; /** * Issues a compile time error if the `.offsetof`/`.tupleof` property is * used on a field of an Objective-C class. * * To solve the fragile base class problem in Objective-C, fields have a * dynamic offset instead of a static offset. The compiler outputs a * statically known offset which later the dynamic loader can update, if * necessary, when the application is loaded. Due to this behavior it * doesn't make sense to be able to get the offset of a field at compile * time, because this offset might not actually be the same at runtime. * * To get the offset of a field that is correct at runtime, functionality * from the Objective-C runtime can be used instead. * * Params: * expression = the `.offsetof`/`.tupleof` expression * aggregateDeclaration = the aggregate declaration the field of the * `.offsetof`/`.tupleof` expression belongs to * type = the type of the receiver of the `.tupleof` expression * * See_Also: * $(LINK2 https://en.wikipedia.org/wiki/Fragile_binary_interface_problem, * Fragile Binary Interface Problem) * * See_Also: * $(LINK2 https://developer.apple.com/documentation/objectivec/objective_c_runtime, * Objective-C Runtime) */ abstract void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const; /// ditto abstract void checkTupleof(Expression expression, TypeClass type) const; } extern(C++) private final class Unsupported : Objc { extern(D) final this() { ObjcGlue.initialize(); } override void setObjc(ClassDeclaration cd) { cd.error("Objective-C classes not supported"); } override void setObjc(InterfaceDeclaration id) { id.error("Objective-C interfaces not supported"); } override void setSelector(FuncDeclaration, Scope*) { // noop } override void validateSelector(FuncDeclaration) { // noop } override void checkLinkage(FuncDeclaration) { // noop } override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const { return null; } override void setMetaclass(InterfaceDeclaration) const { // noop } override void setMetaclass(ClassDeclaration) const { // noop } override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const { assert(0, "Should never be called when Objective-C is not supported"); } override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const { // noop } override void checkTupleof(Expression expression, TypeClass type) const { // noop } } extern(C++) private final class Supported : Objc { extern(D) final this() { VersionCondition.addPredefinedGlobalIdent("D_ObjectiveC"); ObjcGlue.initialize(); ObjcSelector._init(); } override void setObjc(ClassDeclaration cd) { cd.classKind = ClassKind.objc; } override void setObjc(InterfaceDeclaration id) { id.classKind = ClassKind.objc; } override void setSelector(FuncDeclaration fd, Scope* sc) { import dmd.tokens; if (!fd.userAttribDecl) return; Expressions* udas = fd.userAttribDecl.getAttributes(); arrayExpressionSemantic(udas, sc, true); for (size_t i = 0; i < udas.dim; i++) { Expression uda = (*udas)[i]; assert(uda); if (uda.op != TOK.tuple) continue; Expressions* exps = (cast(TupleExp)uda).exps; for (size_t j = 0; j < exps.dim; j++) { Expression e = (*exps)[j]; assert(e); if (e.op != TOK.structLiteral) continue; StructLiteralExp literal = cast(StructLiteralExp)e; assert(literal.sd); if (!isUdaSelector(literal.sd)) continue; if (fd.selector) { fd.error("can only have one Objective-C selector per method"); return; } assert(literal.elements.dim == 1); StringExp se = (*literal.elements)[0].toStringExp(); assert(se); fd.selector = ObjcSelector.lookup(cast(const(char)*)se.toUTF8(sc).string); } } } override void validateSelector(FuncDeclaration fd) { if (!fd.selector) return; TypeFunction tf = cast(TypeFunction)fd.type; if (fd.selector.paramCount != tf.parameters.dim) fd.error("number of colons in Objective-C selector must match number of parameters"); if (fd.parent && fd.parent.isTemplateInstance()) fd.error("template cannot have an Objective-C selector attached"); } override void checkLinkage(FuncDeclaration fd) { if (fd.linkage != LINK.objc && fd.selector) fd.error("must have Objective-C linkage to attach a selector"); } override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const { with(funcDeclaration) { if (!selector) return null; // Use Objective-C class object as 'this' auto cd = isMember2().isClassDeclaration(); if (cd.classKind == ClassKind.objc) { if (!cd.objc.isMeta) return cd.objc.metaclass; } return null; } } override void setMetaclass(InterfaceDeclaration interfaceDeclaration) const { static auto newMetaclass(Loc loc, BaseClasses* metaBases) { return new InterfaceDeclaration(loc, Id.Class, metaBases); } .setMetaclass!newMetaclass(interfaceDeclaration); } override void setMetaclass(ClassDeclaration classDeclaration) const { auto newMetaclass(Loc loc, BaseClasses* metaBases) { auto members = new Dsymbols(); members.push(classDeclaration); return new ClassDeclaration(loc, Id.Class, metaBases, members, 0); } .setMetaclass!newMetaclass(classDeclaration); } override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const { if (!classDeclaration.objc.metaclass && classDeclaration.objc.isMeta) { if (classDeclaration.baseClass) return getRuntimeMetaclass(classDeclaration.baseClass); else return classDeclaration; } else return classDeclaration.objc.metaclass; } override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const { if (aggregateDeclaration.classKind != ClassKind.objc) return; enum errorMessage = "no property `offsetof` for member `%s` of type " ~ "`%s`"; enum supplementalMessage = "`offsetof` is not available for members " ~ "of Objective-C classes. Please use the Objective-C runtime instead"; expression.error(errorMessage, expression.toChars(), expression.type.toChars()); expression.errorSupplemental(supplementalMessage); } override void checkTupleof(Expression expression, TypeClass type) const { if (type.sym.classKind != ClassKind.objc) return; expression.error("no property `tupleof` for type `%s`", type.toChars()); expression.errorSupplemental("`tupleof` is not available for members " ~ "of Objective-C classes. Please use the Objective-C runtime instead"); } extern(D) private bool isUdaSelector(StructDeclaration sd) { if (sd.ident != Id.udaSelector || !sd.parent) return false; Module _module = sd.parent.isModule(); return _module && _module.isCoreModule(Id.attribute); } } /* * Creates and sets the metaclass on the given class/interface declaration. * * Will only be performed on regular Objective-C classes, not on metaclasses. * * Params: * newMetaclass = a function that returns the metaclass to set. This should * return the same type as `T`. * classDeclaration = the class/interface declaration to set the metaclass on */ private void setMetaclass(alias newMetaclass, T)(T classDeclaration) if (is(T == ClassDeclaration) || is(T == InterfaceDeclaration)) { static if (is(T == ClassDeclaration)) enum errorType = "class"; else enum errorType = "interface"; with (classDeclaration) { if (classKind != ClassKind.objc || objc.isMeta || objc.metaclass) return; auto metaBases = new BaseClasses(); foreach (base ; baseclasses.opSlice) { auto baseCd = base.sym; assert(baseCd); if (baseCd.classKind == ClassKind.objc) { assert(baseCd.objc.metaclass); assert(baseCd.objc.metaclass.objc.isMeta); assert(baseCd.objc.metaclass.type.ty == Tclass); auto metaBase = new BaseClass(baseCd.objc.metaclass.type); metaBase.sym = baseCd.objc.metaclass; metaBases.push(metaBase); } else { error("base " ~ errorType ~ " for an Objective-C " ~ errorType ~ " must be `extern (Objective-C)`"); } } objc.metaclass = newMetaclass(loc, metaBases); objc.metaclass.storage_class |= STC.static_; objc.metaclass.classKind = ClassKind.objc; objc.metaclass.objc.isMeta = true; objc.metaclass.members = new Dsymbols(); members.push(objc.metaclass); } } ================================================ FILE: gcc/d/dmd/objc.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 2015-2018 by The D Language Foundation, All Rights Reserved * written by Michel Fortin * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/objc.h */ #pragma once class AggregateDeclaration; class FuncDeclaration; class ClassDeclaration; class InterfaceDeclaration; struct Scope; struct ObjcSelector { const char *stringvalue; size_t stringlen; size_t paramCount; static void _init(); ObjcSelector(const char *sv, size_t len, size_t pcount); static ObjcSelector *create(FuncDeclaration *fdecl); }; struct ObjcClassDeclaration { bool isMeta; ClassDeclaration* metaclass; }; class Objc { public: static void _init(); virtual void setObjc(ClassDeclaration* cd) = 0; virtual void setObjc(InterfaceDeclaration*) = 0; virtual void setSelector(FuncDeclaration*, Scope* sc) = 0; virtual void validateSelector(FuncDeclaration* fd) = 0; virtual void checkLinkage(FuncDeclaration* fd) = 0; virtual AggregateDeclaration* isThis(FuncDeclaration* fd) = 0; virtual void setMetaclass(InterfaceDeclaration* id) = 0; virtual void setMetaclass(ClassDeclaration* id) = 0; virtual ClassDeclaration* getRuntimeMetaclass(ClassDeclaration* cd) = 0; }; ================================================ FILE: gcc/d/dmd/opover.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/opover.d, _opover.d) * Documentation: https://dlang.org/phobos/dmd_opover.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/opover.d */ module dmd.opover; import core.stdc.stdio; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.dclass; import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.statement; import dmd.tokens; import dmd.typesem; import dmd.visitor; /*********************************** * Determine if operands of binary op can be reversed * to fit operator overload. */ bool isCommutative(TOK op) { switch (op) { case TOK.add: case TOK.mul: case TOK.and: case TOK.or: case TOK.xor: // EqualExp case TOK.equal: case TOK.notEqual: // CmpExp case TOK.lessThan: case TOK.lessOrEqual: case TOK.greaterThan: case TOK.greaterOrEqual: return true; default: break; } return false; } /*********************************** * Get Identifier for operator overload. */ private Identifier opId(Expression e) { extern (C++) final class OpIdVisitor : Visitor { alias visit = Visitor.visit; public: Identifier id; override void visit(Expression e) { assert(0); } override void visit(UAddExp e) { id = Id.uadd; } override void visit(NegExp e) { id = Id.neg; } override void visit(ComExp e) { id = Id.com; } override void visit(CastExp e) { id = Id._cast; } override void visit(InExp e) { id = Id.opIn; } override void visit(PostExp e) { id = (e.op == TOK.plusPlus) ? Id.postinc : Id.postdec; } override void visit(AddExp e) { id = Id.add; } override void visit(MinExp e) { id = Id.sub; } override void visit(MulExp e) { id = Id.mul; } override void visit(DivExp e) { id = Id.div; } override void visit(ModExp e) { id = Id.mod; } override void visit(PowExp e) { id = Id.pow; } override void visit(ShlExp e) { id = Id.shl; } override void visit(ShrExp e) { id = Id.shr; } override void visit(UshrExp e) { id = Id.ushr; } override void visit(AndExp e) { id = Id.iand; } override void visit(OrExp e) { id = Id.ior; } override void visit(XorExp e) { id = Id.ixor; } override void visit(CatExp e) { id = Id.cat; } override void visit(AssignExp e) { id = Id.assign; } override void visit(AddAssignExp e) { id = Id.addass; } override void visit(MinAssignExp e) { id = Id.subass; } override void visit(MulAssignExp e) { id = Id.mulass; } override void visit(DivAssignExp e) { id = Id.divass; } override void visit(ModAssignExp e) { id = Id.modass; } override void visit(AndAssignExp e) { id = Id.andass; } override void visit(OrAssignExp e) { id = Id.orass; } override void visit(XorAssignExp e) { id = Id.xorass; } override void visit(ShlAssignExp e) { id = Id.shlass; } override void visit(ShrAssignExp e) { id = Id.shrass; } override void visit(UshrAssignExp e) { id = Id.ushrass; } override void visit(CatAssignExp e) { id = Id.catass; } override void visit(PowAssignExp e) { id = Id.powass; } override void visit(EqualExp e) { id = Id.eq; } override void visit(CmpExp e) { id = Id.cmp; } override void visit(ArrayExp e) { id = Id.index; } override void visit(PtrExp e) { id = Id.opStar; } } scope OpIdVisitor v = new OpIdVisitor(); e.accept(v); return v.id; } /*********************************** * Get Identifier for reverse operator overload, * NULL if not supported for this operator. */ private Identifier opId_r(Expression e) { extern (C++) final class OpIdRVisitor : Visitor { alias visit = Visitor.visit; public: Identifier id; override void visit(Expression e) { id = null; } override void visit(InExp e) { id = Id.opIn_r; } override void visit(AddExp e) { id = Id.add_r; } override void visit(MinExp e) { id = Id.sub_r; } override void visit(MulExp e) { id = Id.mul_r; } override void visit(DivExp e) { id = Id.div_r; } override void visit(ModExp e) { id = Id.mod_r; } override void visit(PowExp e) { id = Id.pow_r; } override void visit(ShlExp e) { id = Id.shl_r; } override void visit(ShrExp e) { id = Id.shr_r; } override void visit(UshrExp e) { id = Id.ushr_r; } override void visit(AndExp e) { id = Id.iand_r; } override void visit(OrExp e) { id = Id.ior_r; } override void visit(XorExp e) { id = Id.ixor_r; } override void visit(CatExp e) { id = Id.cat_r; } } scope OpIdRVisitor v = new OpIdRVisitor(); e.accept(v); return v.id; } /************************************ * If type is a class or struct, return the symbol for it, * else NULL */ AggregateDeclaration isAggregate(Type t) { t = t.toBasetype(); if (t.ty == Tclass) { return (cast(TypeClass)t).sym; } else if (t.ty == Tstruct) { return (cast(TypeStruct)t).sym; } return null; } /******************************************* * Helper function to turn operator into template argument list */ Objects* opToArg(Scope* sc, TOK op) { /* Remove the = from op= */ switch (op) { case TOK.addAssign: op = TOK.add; break; case TOK.minAssign: op = TOK.min; break; case TOK.mulAssign: op = TOK.mul; break; case TOK.divAssign: op = TOK.div; break; case TOK.modAssign: op = TOK.mod; break; case TOK.andAssign: op = TOK.and; break; case TOK.orAssign: op = TOK.or; break; case TOK.xorAssign: op = TOK.xor; break; case TOK.leftShiftAssign: op = TOK.leftShift; break; case TOK.rightShiftAssign: op = TOK.rightShift; break; case TOK.unsignedRightShiftAssign: op = TOK.unsignedRightShift; break; case TOK.concatenateAssign: op = TOK.concatenate; break; case TOK.powAssign: op = TOK.pow; break; default: break; } Expression e = new StringExp(Loc.initial, cast(char*)Token.toChars(op)); e = e.expressionSemantic(sc); auto tiargs = new Objects(); tiargs.push(e); return tiargs; } // Try alias this on first operand private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e) { if (!ad || !ad.aliasthis) return null; /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ if (e.att1 && e.e1.type == e.att1) return null; //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars()); Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident); BinExp be = cast(BinExp)e.copy(); if (!be.att1 && e.e1.type.checkAliasThisRec()) be.att1 = e.e1.type; be.e1 = e1; return be.trySemantic(sc); } // Try alias this on second operand private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e) { if (!ad || !ad.aliasthis) return null; /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ if (e.att2 && e.e2.type == e.att2) return null; //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars()); Expression e2 = new DotIdExp(e.loc, e.e2, ad.aliasthis.ident); BinExp be = cast(BinExp)e.copy(); if (!be.att2 && e.e2.type.checkAliasThisRec()) be.att2 = e.e2.type; be.e2 = e2; return be.trySemantic(sc); } /************************************ * Operator overload. * Check for operator overload, if so, replace * with function call. * Return NULL if not an operator overload. */ Expression op_overload(Expression e, Scope* sc) { extern (C++) final class OpOverload : Visitor { alias visit = Visitor.visit; public: Scope* sc; Expression result; extern (D) this(Scope* sc) { this.sc = sc; } override void visit(Expression e) { assert(0); } override void visit(UnaExp e) { //printf("UnaExp::op_overload() (%s)\n", e.toChars()); if (e.e1.op == TOK.array) { ArrayExp ae = cast(ArrayExp)e.e1; ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { assert((*ae.arguments)[0].op == TOK.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { if (ae.e1.op == TOK.error) { result = ae.e1; return; } Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; Type t1b = ae.e1.type.toBasetype(); AggregateDeclaration ad = isAggregate(t1b); if (!ad) break; if (search_function(ad, Id.opIndexUnary)) { // Deal with $ result = resolveOpDollar(sc, ae, &e0); if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) goto Lfallback; if (result.op == TOK.error) return; /* Rewrite op(a[arguments]) as: * a.opIndexUnary!(op)(arguments) */ Expressions* a = ae.arguments.copy(); Objects* tiargs = opToArg(sc, e.op); result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs); result = new CallExp(e.loc, result, a); if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)() result = result.trySemantic(sc); else result = result.expressionSemantic(sc); if (result) { result = Expression.combine(e0, result); return; } } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceUnary)) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); if (result.op == TOK.error) return; /* Rewrite op(a[i..j]) as: * a.opSliceUnary!(op)(i, j) */ auto a = new Expressions(); if (ie) { a.push(ie.lwr); a.push(ie.upr); } Objects* tiargs = opToArg(sc, e.op); result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs); result = new CallExp(e.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); return; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && t1b != ae.att1) { if (!ae.att1 && t1b.checkAliasThisRec()) ae.att1 = t1b; /* Rewrite op(a[arguments]) as: * op(a.aliasthis[arguments]) */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; } break; } ae.e1 = ae1old; // recovery ae.lengthVar = null; } e.e1 = e.e1.expressionSemantic(sc); e.e1 = resolveProperties(sc, e.e1); if (e.e1.op == TOK.error) { result = e.e1; return; } AggregateDeclaration ad = isAggregate(e.e1.type); if (ad) { Dsymbol fd = null; version (all) { // Old way, kept for compatibility with D1 if (e.op != TOK.prePlusPlus && e.op != TOK.preMinusMinus) { fd = search_function(ad, opId(e)); if (fd) { // Rewrite +e1 as e1.add() result = build_overload(e.loc, sc, e.e1, null, fd); return; } } } /* Rewrite as: * e1.opUnary!(op)() */ fd = search_function(ad, Id.opUnary); if (fd) { Objects* tiargs = opToArg(sc, e.op); result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); result = new CallExp(e.loc, result); result = result.expressionSemantic(sc); return; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && e.e1.type != e.att1) { /* Rewrite op(e1) as: * op(e1.aliasthis) */ //printf("att una %s e1 = %s\n", Token::toChars(op), this.e1.type.toChars()); Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident); UnaExp ue = cast(UnaExp)e.copy(); if (!ue.att1 && e.e1.type.checkAliasThisRec()) ue.att1 = e.e1.type; ue.e1 = e1; result = ue.trySemantic(sc); return; } } } override void visit(ArrayExp ae) { //printf("ArrayExp::op_overload() (%s)\n", ae.toChars()); ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { assert((*ae.arguments)[0].op == TOK.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { if (ae.e1.op == TOK.error) { result = ae.e1; return; } Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; Type t1b = ae.e1.type.toBasetype(); AggregateDeclaration ad = isAggregate(t1b); if (!ad) { // If the non-aggregate expression ae.e1 is indexable or sliceable, // convert it to the corresponding concrete expression. if (t1b.ty == Tpointer || t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Taarray || t1b.ty == Ttuple || t1b.ty == Tvector || ae.e1.op == TOK.type) { // Convert to SliceExp if (maybeSlice) { result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); return; } // Convert to IndexExp if (ae.arguments.dim == 1) { result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]); result = result.expressionSemantic(sc); return; } } break; } if (search_function(ad, Id.index)) { // Deal with $ result = resolveOpDollar(sc, ae, &e0); if (!result) // a[i..j] might be: a.opSlice(i, j) goto Lfallback; if (result.op == TOK.error) return; /* Rewrite e1[arguments] as: * e1.opIndex(arguments) */ Expressions* a = ae.arguments.copy(); result = new DotIdExp(ae.loc, ae.e1, Id.index); result = new CallExp(ae.loc, result, a); if (maybeSlice) // a[] might be: a.opSlice() result = result.trySemantic(sc); else result = result.expressionSemantic(sc); if (result) { result = Expression.combine(e0, result); return; } } Lfallback: if (maybeSlice && ae.e1.op == TOK.type) { result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); return; } if (maybeSlice && search_function(ad, Id.slice)) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); if (result.op == TOK.error) return; /* Rewrite a[i..j] as: * a.opSlice(i, j) */ auto a = new Expressions(); if (ie) { a.push(ie.lwr); a.push(ie.upr); } result = new DotIdExp(ae.loc, ae.e1, Id.slice); result = new CallExp(ae.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); return; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && t1b != ae.att1) { if (!ae.att1 && t1b.checkAliasThisRec()) ae.att1 = t1b; //printf("att arr e1 = %s\n", this.e1.type.toChars()); /* Rewrite op(a[arguments]) as: * op(a.aliasthis[arguments]) */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; } break; } ae.e1 = ae1old; // recovery ae.lengthVar = null; } /*********************************************** * This is mostly the same as UnaryExp::op_overload(), but has * a different rewrite. */ override void visit(CastExp e) { //printf("CastExp::op_overload() (%s)\n", e.toChars()); AggregateDeclaration ad = isAggregate(e.e1.type); if (ad) { Dsymbol fd = null; /* Rewrite as: * e1.opCast!(T)() */ fd = search_function(ad, Id._cast); if (fd) { version (all) { // Backwards compatibility with D1 if opCast is a function, not a template if (fd.isFuncDeclaration()) { // Rewrite as: e1.opCast() result = build_overload(e.loc, sc, e.e1, null, fd); return; } } auto tiargs = new Objects(); tiargs.push(e.to); result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); result = new CallExp(e.loc, result); result = result.expressionSemantic(sc); return; } // Didn't find it. Forward to aliasthis if (ad.aliasthis) { /* Rewrite op(e1) as: * op(e1.aliasthis) */ Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident); result = e.copy(); (cast(UnaExp)result).e1 = e1; result = result.trySemantic(sc); return; } } } override void visit(BinExp e) { //printf("BinExp::op_overload() (%s)\n", e.toChars()); Identifier id = opId(e); Identifier id_r = opId_r(e); Expressions args1; Expressions args2; int argsset = 0; AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); if (e.op == TOK.assign && ad1 == ad2) { StructDeclaration sd = ad1.isStructDeclaration(); if (sd && !sd.hasIdentityAssign) { /* This is bitwise struct assignment. */ return; } } Dsymbol s = null; Dsymbol s_r = null; version (all) { // the old D1 scheme if (ad1 && id) { s = search_function(ad1, id); } if (ad2 && id_r) { s_r = search_function(ad2, id_r); // https://issues.dlang.org/show_bug.cgi?id=12778 // If both x.opBinary(y) and y.opBinaryRight(x) found, // and they are exactly same symbol, x.opBinary(y) should be preferred. if (s_r && s_r == s) s_r = null; } } Objects* tiargs = null; if (e.op == TOK.plusPlus || e.op == TOK.minusMinus) { // Bug4099 fix if (ad1 && search_function(ad1, Id.opUnary)) return; } if (!s && !s_r && e.op != TOK.equal && e.op != TOK.notEqual && e.op != TOK.assign && e.op != TOK.plusPlus && e.op != TOK.minusMinus) { /* Try the new D2 scheme, opBinary and opBinaryRight */ if (ad1) { s = search_function(ad1, Id.opBinary); if (s && !s.isTemplateDeclaration()) { e.e1.error("`%s.opBinary` isn't a template", e.e1.toChars()); result = new ErrorExp(); return; } } if (ad2) { s_r = search_function(ad2, Id.opBinaryRight); if (s_r && !s_r.isTemplateDeclaration()) { e.e2.error("`%s.opBinaryRight` isn't a template", e.e2.toChars()); result = new ErrorExp(); return; } if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778 s_r = null; } // Set tiargs, the template argument list, which will be the operator string if (s || s_r) { id = Id.opBinary; id_r = Id.opBinaryRight; tiargs = opToArg(sc, e.op); } } if (s || s_r) { /* Try: * a.opfunc(b) * b.opfunc_r(a) * and see which is better. */ args1.setDim(1); args1[0] = e.e1; expandTuples(&args1); args2.setDim(1); args2[0] = e.e2; expandTuples(&args2); argsset = 1; Match m; m.last = MATCH.nomatch; if (s) { functionResolve(&m, s, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { result = new ErrorExp(); return; } } FuncDeclaration lastf = m.lastf; if (s_r) { functionResolve(&m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { result = new ErrorExp(); return; } } if (m.count > 1) { // Error, ambiguous e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); } else if (m.last <= MATCH.nomatch) { m.lastf = m.anyf; if (tiargs) goto L1; } if (e.op == TOK.plusPlus || e.op == TOK.minusMinus) { // Kludge because operator overloading regards e++ and e-- // as unary, but it's implemented as a binary. // Rewrite (e1 ++ e2) as e1.postinc() // Rewrite (e1 -- e2) as e1.postdec() result = build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s); } else if (lastf && m.lastf == lastf || !s_r && m.last <= MATCH.nomatch) { // Rewrite (e1 op e2) as e1.opfunc(e2) result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); } else { // Rewrite (e1 op e2) as e2.opfunc_r(e1) result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); } return; } L1: version (all) { // Retained for D1 compatibility if (isCommutative(e.op) && !tiargs) { s = null; s_r = null; if (ad1 && id_r) { s_r = search_function(ad1, id_r); } if (ad2 && id) { s = search_function(ad2, id); if (s && s == s_r) // https://issues.dlang.org/show_bug.cgi?id=12778 s = null; } if (s || s_r) { /* Try: * a.opfunc_r(b) * b.opfunc(a) * and see which is better. */ if (!argsset) { args1.setDim(1); args1[0] = e.e1; expandTuples(&args1); args2.setDim(1); args2[0] = e.e2; expandTuples(&args2); } Match m; m.last = MATCH.nomatch; if (s_r) { functionResolve(&m, s_r, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { result = new ErrorExp(); return; } } FuncDeclaration lastf = m.lastf; if (s) { functionResolve(&m, s, e.loc, sc, tiargs, e.e2.type, &args1); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { result = new ErrorExp(); return; } } if (m.count > 1) { // Error, ambiguous e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); } else if (m.last <= MATCH.nomatch) { m.lastf = m.anyf; } if (lastf && m.lastf == lastf || !s && m.last <= MATCH.nomatch) { // Rewrite (e1 op e2) as e1.opfunc_r(e2) result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r); } else { // Rewrite (e1 op e2) as e2.opfunc(e1) result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s); } // When reversing operands of comparison operators, // need to reverse the sense of the op switch (e.op) { case TOK.lessThan: e.op = TOK.greaterThan; break; case TOK.greaterThan: e.op = TOK.lessThan; break; case TOK.lessOrEqual: e.op = TOK.greaterOrEqual; break; case TOK.greaterOrEqual: e.op = TOK.lessOrEqual; break; default: break; } return; } } } if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { result = checkAliasThisForLhs(ad1, sc, e); if (result) return; } if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { result = checkAliasThisForRhs(ad2, sc, e); return; } } override void visit(EqualExp e) { //printf("EqualExp::op_overload() (%s)\n", e.toChars()); Type t1 = e.e1.type.toBasetype(); Type t2 = e.e2.type.toBasetype(); /* Check for array equality. */ if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) { bool needsDirectEq() { Type t1n = t1.nextOf().toBasetype(); Type t2n = t2.nextOf().toBasetype(); if (((t1n.ty == Tchar || t1n.ty == Twchar || t1n.ty == Tdchar) && (t2n.ty == Tchar || t2n.ty == Twchar || t2n.ty == Tdchar)) || (t1n.ty == Tvoid || t2n.ty == Tvoid)) { return false; } if (t1n.constOf() != t2n.constOf()) return true; Type t = t1n; while (t.toBasetype().nextOf()) t = t.nextOf().toBasetype(); if (t.ty != Tstruct) return false; if (global.params.useTypeInfo && Type.dtypeinfo) semanticTypeInfo(sc, t); return (cast(TypeStruct)t).sym.hasIdentityEquals; } if (needsDirectEq() && !(t1.ty == Tarray && t2.ty == Tarray)) { /* Rewrite as: * __ArrayEq(e1, e2) */ Expression eeq = new IdentifierExp(e.loc, Id.__ArrayEq); result = new CallExp(e.loc, eeq, e.e1, e.e2); if (e.op == TOK.notEqual) result = new NotExp(e.loc, result); result = result.trySemantic(sc); // for better error message if (!result) { e.error("cannot compare `%s` and `%s`", t1.toChars(), t2.toChars()); result = new ErrorExp(); } return; } } /* Check for class equality with null literal or typeof(null). */ if (t1.ty == Tclass && e.e2.op == TOK.null_ || t2.ty == Tclass && e.e1.op == TOK.null_) { e.error("use `%s` instead of `%s` when comparing with `null`", Token.toChars(e.op == TOK.equal ? TOK.identity : TOK.notIdentity), Token.toChars(e.op)); result = new ErrorExp(); return; } if (t1.ty == Tclass && t2.ty == Tnull || t1.ty == Tnull && t2.ty == Tclass) { // Comparing a class with typeof(null) should not call opEquals return; } /* Check for class equality. */ if (t1.ty == Tclass && t2.ty == Tclass) { ClassDeclaration cd1 = t1.isClassHandle(); ClassDeclaration cd2 = t2.isClassHandle(); if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp)) { /* Rewrite as: * .object.opEquals(e1, e2) */ Expression e1x = e.e1; Expression e2x = e.e2; /* The explicit cast is necessary for interfaces * https://issues.dlang.org/show_bug.cgi?id=4088 */ Type to = ClassDeclaration.object.getType(); if (cd1.isInterfaceDeclaration()) e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf()); if (cd2.isInterfaceDeclaration()) e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf()); result = new IdentifierExp(e.loc, Id.empty); result = new DotIdExp(e.loc, result, Id.object); result = new DotIdExp(e.loc, result, Id.eq); result = new CallExp(e.loc, result, e1x, e2x); if (e.op == TOK.notEqual) result = new NotExp(e.loc, result); result = result.expressionSemantic(sc); return; } } result = compare_overload(e, sc, Id.eq); if (result) { if (result.op == TOK.call && e.op == TOK.notEqual) { result = new NotExp(result.loc, result); result = result.expressionSemantic(sc); } return; } if (t1.ty == Tarray && t2.ty == Tarray) return; /* Check for pointer equality. */ if (t1.ty == Tpointer || t2.ty == Tpointer) { /* Rewrite: * ptr1 == ptr2 * as: * ptr1 is ptr2 * * This is just a rewriting for deterministic AST representation * as the backend input. */ auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity; result = new IdentityExp(op2, e.loc, e.e1, e.e2); result = result.expressionSemantic(sc); return; } /* Check for struct equality without opEquals. */ if (t1.ty == Tstruct && t2.ty == Tstruct) { auto sd = (cast(TypeStruct)t1).sym; if (sd != (cast(TypeStruct)t2).sym) return; import dmd.clone : needOpEquals; if (!needOpEquals(sd)) { // Use bitwise equality. auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity; result = new IdentityExp(op2, e.loc, e.e1, e.e2); result = result.expressionSemantic(sc); return; } /* Do memberwise equality. * Rewrite: * e1 == e2 * as: * e1.tupleof == e2.tupleof * * If sd is a nested struct, and if it's nested in a class, it will * also compare the parent class's equality. Otherwise, compares * the identity of parent context through void*. */ if (e.att1 && t1 == e.att1) return; if (e.att2 && t2 == e.att2) return; e = cast(EqualExp)e.copy(); if (!e.att1) e.att1 = t1; if (!e.att2) e.att2 = t2; e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof); e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof); result = e.expressionSemantic(sc); /* https://issues.dlang.org/show_bug.cgi?id=15292 * if the rewrite result is same with the original, * the equality is unresolvable because it has recursive definition. */ if (result.op == e.op && (cast(EqualExp)result).e1.type.toBasetype() == t1) { e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition", t1.toChars()); result = new ErrorExp(); } return; } /* Check for tuple equality. */ if (e.e1.op == TOK.tuple && e.e2.op == TOK.tuple) { auto tup1 = cast(TupleExp)e.e1; auto tup2 = cast(TupleExp)e.e2; size_t dim = tup1.exps.dim; if (dim != tup2.exps.dim) { e.error("mismatched tuple lengths, `%d` and `%d`", cast(int)dim, cast(int)tup2.exps.dim); result = new ErrorExp(); return; } if (dim == 0) { // zero-length tuple comparison should always return true or false. result = new IntegerExp(e.loc, (e.op == TOK.equal), Type.tbool); } else { for (size_t i = 0; i < dim; i++) { auto ex1 = (*tup1.exps)[i]; auto ex2 = (*tup2.exps)[i]; auto eeq = new EqualExp(e.op, e.loc, ex1, ex2); eeq.att1 = e.att1; eeq.att2 = e.att2; if (!result) result = eeq; else if (e.op == TOK.equal) result = new LogicalExp(e.loc, TOK.andAnd, result, eeq); else result = new LogicalExp(e.loc, TOK.orOr, result, eeq); } assert(result); } result = Expression.combine(tup1.e0, tup2.e0, result); result = result.expressionSemantic(sc); return; } } override void visit(CmpExp e) { //printf("CmpExp:: () (%s)\n", e.toChars()); result = compare_overload(e, sc, Id.cmp); } /********************************* * Operator overloading for op= */ override void visit(BinAssignExp e) { //printf("BinAssignExp::op_overload() (%s)\n", e.toChars()); if (e.e1.op == TOK.array) { ArrayExp ae = cast(ArrayExp)e.e1; ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { assert((*ae.arguments)[0].op == TOK.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { if (ae.e1.op == TOK.error) { result = ae.e1; return; } Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; Type t1b = ae.e1.type.toBasetype(); AggregateDeclaration ad = isAggregate(t1b); if (!ad) break; if (search_function(ad, Id.opIndexOpAssign)) { // Deal with $ result = resolveOpDollar(sc, ae, &e0); if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) goto Lfallback; if (result.op == TOK.error) return; result = e.e2.expressionSemantic(sc); if (result.op == TOK.error) return; e.e2 = result; /* Rewrite a[arguments] op= e2 as: * a.opIndexOpAssign!(op)(e2, arguments) */ Expressions* a = ae.arguments.copy(); a.insert(0, e.e2); Objects* tiargs = opToArg(sc, e.op); result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs); result = new CallExp(e.loc, result, a); if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2) result = result.trySemantic(sc); else result = result.expressionSemantic(sc); if (result) { result = Expression.combine(e0, result); return; } } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); if (result.op == TOK.error) return; result = e.e2.expressionSemantic(sc); if (result.op == TOK.error) return; e.e2 = result; /* Rewrite (a[i..j] op= e2) as: * a.opSliceOpAssign!(op)(e2, i, j) */ auto a = new Expressions(); a.push(e.e2); if (ie) { a.push(ie.lwr); a.push(ie.upr); } Objects* tiargs = opToArg(sc, e.op); result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs); result = new CallExp(e.loc, result, a); result = result.expressionSemantic(sc); result = Expression.combine(e0, result); return; } // Didn't find it. Forward to aliasthis if (ad.aliasthis && t1b != ae.att1) { if (!ae.att1 && t1b.checkAliasThisRec()) ae.att1 = t1b; /* Rewrite (a[arguments] op= e2) as: * a.aliasthis[arguments] op= e2 */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; } break; } ae.e1 = ae1old; // recovery ae.lengthVar = null; } result = e.binSemanticProp(sc); if (result) return; // Don't attempt 'alias this' if an error occurred if (e.e1.type.ty == Terror || e.e2.type.ty == Terror) { result = new ErrorExp(); return; } Identifier id = opId(e); Expressions args2; AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = null; version (all) { // the old D1 scheme if (ad1 && id) { s = search_function(ad1, id); } } Objects* tiargs = null; if (!s) { /* Try the new D2 scheme, opOpAssign */ if (ad1) { s = search_function(ad1, Id.opOpAssign); if (s && !s.isTemplateDeclaration()) { e.error("`%s.opOpAssign` isn't a template", e.e1.toChars()); result = new ErrorExp(); return; } } // Set tiargs, the template argument list, which will be the operator string if (s) { id = Id.opOpAssign; tiargs = opToArg(sc, e.op); } } if (s) { /* Try: * a.opOpAssign(b) */ args2.setDim(1); args2[0] = e.e2; expandTuples(&args2); Match m; m.last = MATCH.nomatch; if (s) { functionResolve(&m, s, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) { result = new ErrorExp(); return; } } if (m.count > 1) { // Error, ambiguous e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); } else if (m.last <= MATCH.nomatch) { m.lastf = m.anyf; if (tiargs) goto L1; } // Rewrite (e1 op e2) as e1.opOpAssign(e2) result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); return; } L1: result = checkAliasThisForLhs(ad1, sc, e); if (result) return; result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); } } scope OpOverload v = new OpOverload(sc); e.accept(v); return v.result; } /****************************************** * Common code for overloading of EqualExp and CmpExp */ private Expression compare_overload(BinExp e, Scope* sc, Identifier id) { //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars()); AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); Dsymbol s = null; Dsymbol s_r = null; if (ad1) { s = search_function(ad1, id); } if (ad2) { s_r = search_function(ad2, id); if (s == s_r) s_r = null; } Objects* tiargs = null; if (s || s_r) { /* Try: * a.opEquals(b) * b.opEquals(a) * and see which is better. */ Expressions args1 = Expressions(1); args1[0] = e.e1; expandTuples(&args1); Expressions args2 = Expressions(1); args2[0] = e.e2; expandTuples(&args2); Match m; m.last = MATCH.nomatch; if (0 && s && s_r) { printf("s : %s\n", s.toPrettyChars()); printf("s_r: %s\n", s_r.toPrettyChars()); } if (s) { functionResolve(&m, s, e.loc, sc, tiargs, e.e1.type, &args2); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) return new ErrorExp(); } FuncDeclaration lastf = m.lastf; int count = m.count; if (s_r) { functionResolve(&m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) return new ErrorExp(); } if (m.count > 1) { /* The following if says "not ambiguous" if there's one match * from s and one from s_r, in which case we pick s. * This doesn't follow the spec, but is a workaround for the case * where opEquals was generated from templates and we cannot figure * out if both s and s_r came from the same declaration or not. * The test case is: * import std.typecons; * void main() { * assert(tuple("has a", 2u) == tuple("has a", 1)); * } */ if (!(m.lastf == lastf && m.count == 2 && count == 1)) { // Error, ambiguous e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars()); } } else if (m.last <= MATCH.nomatch) { m.lastf = m.anyf; } Expression result; if (lastf && m.lastf == lastf || !s_r && m.last <= MATCH.nomatch) { // Rewrite (e1 op e2) as e1.opfunc(e2) result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s); } else { // Rewrite (e1 op e2) as e2.opfunc_r(e1) result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); // When reversing operands of comparison operators, // need to reverse the sense of the op switch (e.op) { case TOK.lessThan: e.op = TOK.greaterThan; break; case TOK.greaterThan: e.op = TOK.lessThan; break; case TOK.lessOrEqual: e.op = TOK.greaterOrEqual; break; case TOK.greaterOrEqual: e.op = TOK.lessOrEqual; break; default: break; } } return result; } Expression result = checkAliasThisForLhs(ad1, sc, e); return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); } /*********************************** * Utility to build a function call out of this reference and argument. */ Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expression earg, Dsymbol d) { assert(d); Expression e; Declaration decl = d.isDeclaration(); if (decl) e = new DotVarExp(loc, ethis, decl, false); else e = new DotIdExp(loc, ethis, d.ident); e = new CallExp(loc, e, earg); e = e.expressionSemantic(sc); return e; } /*************************************** * Search for function funcid in aggregate ad. */ Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) { Dsymbol s = ad.search(Loc.initial, funcid); if (s) { //printf("search_function: s = '%s'\n", s.kind()); Dsymbol s2 = s.toAlias(); //printf("search_function: s2 = '%s'\n", s2.kind()); FuncDeclaration fd = s2.isFuncDeclaration(); if (fd && fd.type.ty == Tfunction) return fd; TemplateDeclaration td = s2.isTemplateDeclaration(); if (td) return td; } return null; } /************************************** * Figure out what is being foreach'd over by looking at the ForeachAggregate. * Params: * sc = context * isForeach = true for foreach, false for foreach_reverse * feaggr = ForeachAggregate * sapply = set to function opApply/opApplyReverse, or delegate, or null. * Overload resolution is not done. * Returns: * true if successfully figured it out; feaggr updated with semantic analysis. * false for failed, which is an error. */ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out Dsymbol sapply) { //printf("inferForeachAggregate(%s)\n", feaggr.toChars()); bool sliced; Type att = null; auto aggr = feaggr; while (1) { aggr = aggr.expressionSemantic(sc); aggr = resolveProperties(sc, aggr); aggr = aggr.optimize(WANTvalue); if (!aggr.type || aggr.op == TOK.error) return false; Type tab = aggr.type.toBasetype(); switch (tab.ty) { case Tarray: // https://dlang.org/spec/statement.html#foreach_over_arrays case Tsarray: // https://dlang.org/spec/statement.html#foreach_over_arrays case Ttuple: // https://dlang.org/spec/statement.html#foreach_over_tuples case Taarray: // https://dlang.org/spec/statement.html#foreach_over_associative_arrays break; case Tclass: case Tstruct: { AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym : (cast(TypeStruct)tab).sym; if (!sliced) { sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse); if (sapply) { // https://dlang.org/spec/statement.html#foreach_over_struct_and_classes // opApply aggregate break; } if (feaggr.op != TOK.type) { /* See if rewriting `aggr` to `aggr[]` will work */ Expression rinit = new ArrayExp(aggr.loc, feaggr); rinit = rinit.trySemantic(sc); if (rinit) // if it worked { aggr = rinit; sliced = true; // only try it once continue; } } } if (ad.search(Loc.initial, isForeach ? Id.Ffront : Id.Fback)) { // https://dlang.org/spec/statement.html#foreach-with-ranges // range aggregate break; } if (ad.aliasthis) { if (att == tab) // error, circular alias this return false; if (!att && tab.checkAliasThisRec()) att = tab; aggr = resolveAliasThis(sc, aggr); continue; } return false; } case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates if (aggr.op == TOK.delegate_) { sapply = (cast(DelegateExp)aggr).func; } break; case Terror: break; default: return false; } feaggr = aggr; return true; } assert(0); } /***************************************** * Given array of foreach parameters and an aggregate type, * find best opApply overload, * if any of the parameter types are missing, attempt to infer * them from the aggregate type. * Params: * fes = the foreach statement * sc = context * sapply = null or opApply or delegate * Returns: * false for errors */ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) { if (!fes.parameters || !fes.parameters.dim) return false; if (sapply) // prefer opApply { foreach (Parameter p; *fes.parameters) { if (p.type) { p.type = p.type.typeSemantic(fes.loc, sc); p.type = p.type.addStorageClass(p.storageClass); } } // Determine ethis for sapply Expression ethis; Type tab = fes.aggr.type.toBasetype(); if (tab.ty == Tclass || tab.ty == Tstruct) ethis = fes.aggr; else { assert(tab.ty == Tdelegate && fes.aggr.op == TOK.delegate_); ethis = (cast(DelegateExp)fes.aggr).e1; } /* Look for like an * int opApply(int delegate(ref Type [, ...]) dg); * overload */ if (FuncDeclaration fd = sapply.isFuncDeclaration()) { auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters); if (fdapply) { // Fill in any missing types on foreach parameters[] matchParamsToOpApply(cast(TypeFunction)fdapply.type, fes.parameters, true); sapply = fdapply; return true; } return false; } return sapply !is null; } Parameter p = (*fes.parameters)[0]; Type taggr = fes.aggr.type; assert(taggr); Type tab = taggr.toBasetype(); switch (tab.ty) { case Tarray: case Tsarray: case Ttuple: if (fes.parameters.dim == 2) { if (!p.type) { p.type = Type.tsize_t; // key type p.type = p.type.addStorageClass(p.storageClass); } p = (*fes.parameters)[1]; } if (!p.type && tab.ty != Ttuple) { p.type = tab.nextOf(); // value type p.type = p.type.addStorageClass(p.storageClass); } break; case Taarray: { TypeAArray taa = cast(TypeAArray)tab; if (fes.parameters.dim == 2) { if (!p.type) { p.type = taa.index; // key type p.type = p.type.addStorageClass(p.storageClass); if (p.storageClass & STC.ref_) // key must not be mutated via ref p.type = p.type.addMod(MODFlags.const_); } p = (*fes.parameters)[1]; } if (!p.type) { p.type = taa.next; // value type p.type = p.type.addStorageClass(p.storageClass); } break; } case Tclass: case Tstruct: { AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym : (cast(TypeStruct)tab).sym; if (fes.parameters.dim == 1) { if (!p.type) { /* Look for a front() or back() overload */ Identifier id = (fes.op == TOK.foreach_) ? Id.Ffront : Id.Fback; Dsymbol s = ad.search(Loc.initial, id); FuncDeclaration fd = s ? s.isFuncDeclaration() : null; if (fd) { // Resolve inout qualifier of front type p.type = fd.type.nextOf(); if (p.type) { p.type = p.type.substWildTo(tab.mod); p.type = p.type.addStorageClass(p.storageClass); } } else if (s && s.isTemplateDeclaration()) { } else if (s && s.isDeclaration()) p.type = (cast(Declaration)s).type; else break; } break; } break; } case Tdelegate: if (!matchParamsToOpApply(cast(TypeFunction)tab.nextOf(), fes.parameters, true)) return false; break; default: break; // ignore error, caught later } return true; } /********************************************* * Find best overload match on fstart given ethis and parameters[]. * Params: * ethis = expression to use for `this` * fstart = opApply or foreach delegate * parameters = ForeachTypeList (i.e. foreach parameters) * Returns: * best match if there is one, null if error */ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration fstart, Parameters* parameters) { MOD mod = ethis.type.mod; MATCH match = MATCH.nomatch; FuncDeclaration fd_best; FuncDeclaration fd_ambig; overloadApply(fstart, (Dsymbol s) { auto f = s.isFuncDeclaration(); if (!f) return 0; // continue auto tf = cast(TypeFunction)f.type; MATCH m = MATCH.exact; if (f.isThis()) { if (!MODimplicitConv(mod, tf.mod)) m = MATCH.nomatch; else if (mod != tf.mod) m = MATCH.constant; } if (!matchParamsToOpApply(tf, parameters, false)) m = MATCH.nomatch; if (m > match) { fd_best = f; fd_ambig = null; match = m; } else if (m == match && m > MATCH.nomatch) { assert(fd_best); /* Ignore covariant matches, as later on it can be redone * after the opApply delegate has its attributes inferred. */ if (tf.covariant(fd_best.type) != 1 && fd_best.type.covariant(tf) != 1) fd_ambig = f; // not covariant, so ambiguous } return 0; // continue }); if (fd_ambig) { .error(ethis.loc, "`%s.%s` matches more than one declaration:\n`%s`: `%s`\nand:\n`%s`: `%s`", ethis.toChars(), fstart.ident.toChars(), fd_best.loc.toChars(), fd_best.type.toChars(), fd_ambig.loc.toChars(), fd_ambig.type.toChars()); return null; } return fd_best; } /****************************** * Determine if foreach parameters match opApply parameters. * Infer missing foreach parameter types from type of opApply delegate. * Params: * tf = type of opApply or delegate * parameters = foreach parameters * infer = infer missing parameter types * Returns: * true for match for this function * false for no match for this function */ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool infer) { enum nomatch = false; /* opApply/delegate has exactly one parameter, and that parameter * is a delegate that looks like: * int opApply(int delegate(ref Type [, ...]) dg); */ if (Parameter.dim(tf.parameters) != 1) return nomatch; /* Get the type of opApply's dg parameter */ Parameter p0 = Parameter.getNth(tf.parameters, 0); if (p0.type.ty != Tdelegate) return nomatch; TypeFunction tdg = cast(TypeFunction)p0.type.nextOf(); assert(tdg.ty == Tfunction); /* We now have tdg, the type of the delegate. * tdg's parameters must match that of the foreach arglist (i.e. parameters). * Fill in missing types in parameters. */ const nparams = Parameter.dim(tdg.parameters); if (nparams == 0 || nparams != parameters.dim || tdg.varargs) return nomatch; // parameter mismatch foreach (u, p; *parameters) { Parameter param = Parameter.getNth(tdg.parameters, u); if (p.type) { if (!p.type.equals(param.type)) return nomatch; } else if (infer) { p.type = param.type; p.type = p.type.addStorageClass(p.storageClass); } } return true; } ================================================ FILE: gcc/d/dmd/optimize.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/optimize.d, _optimize.d) * Documentation: https://dlang.org/phobos/dmd_optimize.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/optimize.d */ module dmd.optimize; import core.stdc.stdio; import dmd.constfold; import dmd.ctfeexpr; import dmd.dclass; import dmd.declaration; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.expression; import dmd.expressionsem; import dmd.globals; import dmd.init; import dmd.mtype; import dmd.root.ctfloat; import dmd.sideeffect; import dmd.tokens; import dmd.visitor; /************************************* * If variable has a const initializer, * return that initializer. * Returns: * initializer if there is one, * null if not, * ErrorExp if error */ Expression expandVar(int result, VarDeclaration v) { //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); /******** * Params: * e = initializer expression */ Expression initializerReturn(Expression e) { if (e.type != v.type) { e = e.castTo(null, v.type); } v.inuse++; e = e.optimize(result); v.inuse--; //if (e) printf("\te = %p, %s, e.type = %d, %s\n", e, e.toChars(), e.type.ty, e.type.toChars()); return e; } static Expression nullReturn() { return null; } static Expression errorReturn() { return new ErrorExp(); } if (!v) return nullReturn(); if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run v.dsymbolSemantic(null); if (v.type && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest)) { Type tb = v.type.toBasetype(); if (v.storage_class & STC.manifest || tb.isscalar() || ((result & WANTexpand) && (tb.ty != Tsarray && tb.ty != Tstruct))) { if (v._init) { if (v.inuse) { if (v.storage_class & STC.manifest) { v.error("recursive initialization of constant"); return errorReturn(); } return nullReturn(); } Expression ei = v.getConstInitializer(); if (!ei) { if (v.storage_class & STC.manifest) { v.error("enum cannot be initialized with `%s`", v._init.toChars()); return errorReturn(); } return nullReturn(); } if (ei.op == TOK.construct || ei.op == TOK.blit) { AssignExp ae = cast(AssignExp)ei; ei = ae.e2; if (ei.isConst() == 1) { } else if (ei.op == TOK.string_) { // https://issues.dlang.org/show_bug.cgi?id=14459 // Do not constfold the string literal // if it's typed as a C string, because the value expansion // will drop the pointer identity. if (!(result & WANTexpand) && ei.type.toBasetype().ty == Tpointer) return nullReturn(); } else return nullReturn(); if (ei.type == v.type) { // const variable initialized with const expression } else if (ei.implicitConvTo(v.type) >= MATCH.constant) { // const var initialized with non-const expression ei = ei.implicitCastTo(null, v.type); ei = ei.expressionSemantic(null); } else return nullReturn(); } else if (!(v.storage_class & STC.manifest) && ei.isConst() != 1 && ei.op != TOK.string_ && ei.op != TOK.address) { return nullReturn(); } if (!ei.type) { return nullReturn(); } else { // Should remove the copy() operation by // making all mods to expressions copy-on-write return initializerReturn(ei.copy()); } } else { // v does not have an initializer version (all) { return nullReturn(); } else { // BUG: what if const is initialized in constructor? auto e = v.type.defaultInit(); e.loc = e1.loc; return initializerReturn(e); } } assert(0); } } return nullReturn(); } private Expression fromConstInitializer(int result, Expression e1) { //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars()); //static int xx; if (xx++ == 10) assert(0); Expression e = e1; if (e1.op == TOK.variable) { VarExp ve = cast(VarExp)e1; VarDeclaration v = ve.var.isVarDeclaration(); e = expandVar(result, v); if (e) { // If it is a comma expression involving a declaration, we mustn't // perform a copy -- we'd get two declarations of the same variable. // See bugzilla 4465. if (e.op == TOK.comma && (cast(CommaExp)e).e1.op == TOK.declaration) e = e1; else if (e.type != e1.type && e1.type && e1.type.ty != Tident) { // Type 'paint' operation e = e.copy(); e.type = e1.type; } e.loc = e1.loc; } else { e = e1; } } return e; } /* It is possible for constant folding to change an array expression of * unknown length, into one where the length is known. * If the expression 'arr' is a literal, set lengthVar to be its length. */ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr) { if (!lengthVar) return; if (lengthVar._init && !lengthVar._init.isVoidInitializer()) return; // we have previously calculated the length size_t len; if (arr.op == TOK.string_) len = (cast(StringExp)arr).len; else if (arr.op == TOK.arrayLiteral) len = (cast(ArrayLiteralExp)arr).elements.dim; else { Type t = arr.type.toBasetype(); if (t.ty == Tsarray) len = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); else return; // we don't know the length yet } Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); lengthVar._init = new ExpInitializer(Loc.initial, dollar); lengthVar.storage_class |= STC.static_ | STC.const_; } /* Same as above, but determines the length from 'type'. */ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) { if (!lengthVar) return; if (lengthVar._init && !lengthVar._init.isVoidInitializer()) return; // we have previously calculated the length size_t len; Type t = type.toBasetype(); if (t.ty == Tsarray) len = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); else return; // we don't know the length yet Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); lengthVar._init = new ExpInitializer(Loc.initial, dollar); lengthVar.storage_class |= STC.static_ | STC.const_; } /********************************* * Constant fold an Expression. * Params: * e = expression to const fold; this may get modified in-place * result = WANTvalue, WANTexpand, or both * keepLvalue = `e` is an lvalue, and keep it as an lvalue since it is * an argument to a `ref` or `out` parameter, or the operand of `&` operator * Returns: * Constant folded version of `e` */ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { extern (C++) final class OptimizeVisitor : Visitor { alias visit = Visitor.visit; Expression ret; private const int result; private const bool keepLvalue; extern (D) this(Expression e, int result, bool keepLvalue) { this.ret = e; // default result is original expression this.result = result; this.keepLvalue = keepLvalue; } void error() { ret = new ErrorExp(); } bool expOptimize(ref Expression e, int flags, bool keepLvalue = false) { if (!e) return false; Expression ex = Expression_optimize(e, flags, keepLvalue); if (ex.op == TOK.error) { ret = ex; // store error result return true; } else { e = ex; // modify original return false; } } bool unaOptimize(UnaExp e, int flags) { return expOptimize(e.e1, flags); } bool binOptimize(BinExp e, int flags) { expOptimize(e.e1, flags); expOptimize(e.e2, flags); return ret.op == TOK.error; } override void visit(Expression e) { //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars()); } override void visit(VarExp e) { if (keepLvalue) { VarDeclaration v = e.var.isVarDeclaration(); if (v && !(v.storage_class & STC.manifest)) return; } ret = fromConstInitializer(result, e); } override void visit(TupleExp e) { expOptimize(e.e0, WANTvalue); for (size_t i = 0; i < e.exps.dim; i++) { expOptimize((*e.exps)[i], WANTvalue); } } override void visit(ArrayLiteralExp e) { if (e.elements) { expOptimize(e.basis, result & WANTexpand); for (size_t i = 0; i < e.elements.dim; i++) { expOptimize((*e.elements)[i], result & WANTexpand); } } } override void visit(AssocArrayLiteralExp e) { assert(e.keys.dim == e.values.dim); for (size_t i = 0; i < e.keys.dim; i++) { expOptimize((*e.keys)[i], result & WANTexpand); expOptimize((*e.values)[i], result & WANTexpand); } } override void visit(StructLiteralExp e) { if (e.stageflags & stageOptimize) return; int old = e.stageflags; e.stageflags |= stageOptimize; if (e.elements) { for (size_t i = 0; i < e.elements.dim; i++) { expOptimize((*e.elements)[i], result & WANTexpand); } } e.stageflags = old; } override void visit(UnaExp e) { //printf("UnaExp::optimize() %s\n", e.toChars()); if (unaOptimize(e, result)) return; } override void visit(NegExp e) { if (unaOptimize(e, result)) return; if (e.e1.isConst() == 1) { ret = Neg(e.type, e.e1).copy(); } } override void visit(ComExp e) { if (unaOptimize(e, result)) return; if (e.e1.isConst() == 1) { ret = Com(e.type, e.e1).copy(); } } override void visit(NotExp e) { if (unaOptimize(e, result)) return; if (e.e1.isConst() == 1) { ret = Not(e.type, e.e1).copy(); } } override void visit(SymOffExp e) { assert(e.var); } override void visit(AddrExp e) { //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars()); /* Rewrite &(a,b) as (a,&b) */ if (e.e1.op == TOK.comma) { CommaExp ce = cast(CommaExp)e.e1; auto ae = new AddrExp(e.loc, ce.e2, e.type); ret = new CommaExp(ce.loc, ce.e1, ae); ret.type = e.type; return; } // Keep lvalue-ness if (expOptimize(e.e1, result, true)) return; // Convert &*ex to ex if (e.e1.op == TOK.star) { Expression ex = (cast(PtrExp)e.e1).e1; if (e.type.equals(ex.type)) ret = ex; else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) { ret = ex.copy(); ret.type = e.type; } return; } if (e.e1.op == TOK.variable) { VarExp ve = cast(VarExp)e.e1; if (!ve.var.isOut() && !ve.var.isRef() && !ve.var.isImportedSymbol()) { ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads); ret.type = e.type; return; } } if (e.e1.op == TOK.index) { // Convert &array[n] to &array+n IndexExp ae = cast(IndexExp)e.e1; if (ae.e2.op == TOK.int64 && ae.e1.op == TOK.variable) { sinteger_t index = ae.e2.toInteger(); VarExp ve = cast(VarExp)ae.e1; if (ve.type.ty == Tsarray && !ve.var.isImportedSymbol()) { TypeSArray ts = cast(TypeSArray)ve.type; sinteger_t dim = ts.dim.toInteger(); if (index < 0 || index >= dim) { e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); return error(); } import core.checkedint : mulu; bool overflow; const offset = mulu(index, ts.nextOf().size(e.loc), overflow); if (overflow) { e.error("array offset overflow"); return error(); } ret = new SymOffExp(e.loc, ve.var, offset); ret.type = e.type; return; } } } } override void visit(PtrExp e) { //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars()); if (expOptimize(e.e1, result)) return; // Convert *&ex to ex // But only if there is no type punning involved if (e.e1.op == TOK.address) { Expression ex = (cast(AddrExp)e.e1).e1; if (e.type.equals(ex.type)) ret = ex; else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) { ret = ex.copy(); ret.type = e.type; } } if (keepLvalue) return; // Constant fold *(&structliteral + offset) if (e.e1.op == TOK.add) { Expression ex = Ptr(e.type, e.e1).copy(); if (!CTFEExp.isCantExp(ex)) { ret = ex; return; } } if (e.e1.op == TOK.symbolOffset) { SymOffExp se = cast(SymOffExp)e.e1; VarDeclaration v = se.var.isVarDeclaration(); Expression ex = expandVar(result, v); if (ex && ex.op == TOK.structLiteral) { StructLiteralExp sle = cast(StructLiteralExp)ex; ex = sle.getField(e.type, cast(uint)se.offset); if (ex && !CTFEExp.isCantExp(ex)) { ret = ex; return; } } } } override void visit(DotVarExp e) { //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars()); if (expOptimize(e.e1, result)) return; if (keepLvalue) return; Expression ex = e.e1; if (ex.op == TOK.variable) { VarExp ve = cast(VarExp)ex; VarDeclaration v = ve.var.isVarDeclaration(); ex = expandVar(result, v); } if (ex && ex.op == TOK.structLiteral) { StructLiteralExp sle = cast(StructLiteralExp)ex; VarDeclaration vf = e.var.isVarDeclaration(); if (vf && !vf.overlapped) { /* https://issues.dlang.org/show_bug.cgi?id=13021 * Prevent optimization if vf has overlapped fields. */ ex = sle.getField(e.type, vf.offset); if (ex && !CTFEExp.isCantExp(ex)) { ret = ex; return; } } } } override void visit(NewExp e) { expOptimize(e.thisexp, WANTvalue); // Optimize parameters if (e.newargs) { for (size_t i = 0; i < e.newargs.dim; i++) { expOptimize((*e.newargs)[i], WANTvalue); } } if (e.arguments) { for (size_t i = 0; i < e.arguments.dim; i++) { expOptimize((*e.arguments)[i], WANTvalue); } } } override void visit(CallExp e) { //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars()); // Optimize parameters with keeping lvalue-ness if (expOptimize(e.e1, result)) return; if (e.arguments) { Type t1 = e.e1.type.toBasetype(); if (t1.ty == Tdelegate) t1 = t1.nextOf(); assert(t1.ty == Tfunction); TypeFunction tf = cast(TypeFunction)t1; for (size_t i = 0; i < e.arguments.dim; i++) { Parameter p = Parameter.getNth(tf.parameters, i); bool keep = p && (p.storageClass & (STC.ref_ | STC.out_)) != 0; expOptimize((*e.arguments)[i], WANTvalue, keep); } } } override void visit(CastExp e) { //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars()); //printf("from %s to %s\n", e.type.toChars(), e.to.toChars()); //printf("from %s\n", e.type.toChars()); //printf("e1.type %s\n", e.e1.type.toChars()); //printf("type = %p\n", e.type); assert(e.type); TOK op1 = e.e1.op; Expression e1old = e.e1; if (expOptimize(e.e1, result)) return; e.e1 = fromConstInitializer(result, e.e1); if (e.e1 == e1old && e.e1.op == TOK.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray) { // Casting this will result in the same expression, and // infinite loop because of Expression::implicitCastTo() return; // no change } if ((e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral) && (e.type.ty == Tpointer || e.type.ty == Tarray)) { const esz = e.type.nextOf().size(e.loc); const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc); if (esz == SIZE_INVALID || e1sz == SIZE_INVALID) return error(); if (e1sz == esz) { // https://issues.dlang.org/show_bug.cgi?id=12937 // If target type is void array, trying to paint // e.e1 with that type will cause infinite recursive optimization. if (e.type.nextOf().ty == Tvoid) return; ret = e.e1.castTo(null, e.type); //printf(" returning1 %s\n", ret.toChars()); return; } } if (e.e1.op == TOK.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) { //printf(" returning2 %s\n", e.e1.toChars()); L1: // Returning e1 with changing its type ret = (e1old == e.e1 ? e.e1.copy() : e.e1); ret.type = e.type; return; } /* The first test here is to prevent infinite loops */ if (op1 != TOK.arrayLiteral && e.e1.op == TOK.arrayLiteral) { ret = e.e1.castTo(null, e.to); return; } if (e.e1.op == TOK.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray)) { //printf(" returning3 %s\n", e.e1.toChars()); goto L1; } if (e.type.ty == Tclass && e.e1.type.ty == Tclass) { import dmd.aggregate : Sizeok; // See if we can remove an unnecessary cast ClassDeclaration cdfrom = e.e1.type.isClassHandle(); ClassDeclaration cdto = e.type.isClassHandle(); if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration()) goto L1; // can always convert a class to Object // Need to determine correct offset before optimizing away the cast. // https://issues.dlang.org/show_bug.cgi?id=16980 cdfrom.size(e.loc); assert(cdfrom.sizeok == Sizeok.done); assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null)); int offset; if (cdto.isBaseOf(cdfrom, &offset) && offset == 0) { //printf(" returning4 %s\n", e.e1.toChars()); goto L1; } } // We can convert 'head const' to mutable if (e.to.mutableOf().constOf().equals(e.e1.type.mutableOf().constOf())) { //printf(" returning5 %s\n", e.e1.toChars()); goto L1; } if (e.e1.isConst()) { if (e.e1.op == TOK.symbolOffset) { if (e.type.toBasetype().ty != Tsarray) { const esz = e.type.size(e.loc); const e1sz = e.e1.type.size(e.e1.loc); if (esz == SIZE_INVALID || e1sz == SIZE_INVALID) return error(); if (esz == e1sz) goto L1; } return; } if (e.to.toBasetype().ty != Tvoid) { if (e.e1.type.equals(e.type) && e.type.equals(e.to)) ret = e.e1; else ret = Cast(e.loc, e.type, e.to, e.e1).copy(); } } //printf(" returning6 %s\n", ret.toChars()); } override void visit(BinExp e) { //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars()); // don't replace const variable with its initializer in e1 bool e2only = (e.op == TOK.construct || e.op == TOK.blit); if (e2only ? expOptimize(e.e2, result) : binOptimize(e, result)) return; if (e.op == TOK.leftShiftAssign || e.op == TOK.rightShiftAssign || e.op == TOK.unsignedRightShiftAssign) { if (e.e2.isConst() == 1) { sinteger_t i2 = e.e2.toInteger(); d_uns64 sz = e.e1.type.size(e.e1.loc); assert(sz != SIZE_INVALID); sz *= 8; if (i2 < 0 || i2 >= sz) { e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); return error(); } } } } override void visit(AddExp e) { //printf("AddExp::optimize(%s)\n", e.toChars()); if (binOptimize(e, result)) return; if (e.e1.isConst() && e.e2.isConst()) { if (e.e1.op == TOK.symbolOffset && e.e2.op == TOK.symbolOffset) return; ret = Add(e.loc, e.type, e.e1, e.e2).copy(); } } override void visit(MinExp e) { if (binOptimize(e, result)) return; if (e.e1.isConst() && e.e2.isConst()) { if (e.e2.op == TOK.symbolOffset) return; ret = Min(e.loc, e.type, e.e1, e.e2).copy(); } } override void visit(MulExp e) { //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars()); if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { ret = Mul(e.loc, e.type, e.e1, e.e2).copy(); } } override void visit(DivExp e) { //printf("DivExp::optimize(%s)\n", e.toChars()); if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { ret = Div(e.loc, e.type, e.e1, e.e2).copy(); } } override void visit(ModExp e) { if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { ret = Mod(e.loc, e.type, e.e1, e.e2).copy(); } } extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift) { if (binOptimize(e, result)) return; if (e.e2.isConst() == 1) { sinteger_t i2 = e.e2.toInteger(); d_uns64 sz = e.e1.type.size(e.e1.loc); assert(sz != SIZE_INVALID); sz *= 8; if (i2 < 0 || i2 >= sz) { e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); return error(); } if (e.e1.isConst() == 1) ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy(); } } override void visit(ShlExp e) { //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars()); shift_optimize(e, &Shl); } override void visit(ShrExp e) { //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars()); shift_optimize(e, &Shr); } override void visit(UshrExp e) { //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); shift_optimize(e, &Ushr); } override void visit(AndExp e) { if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) ret = And(e.loc, e.type, e.e1, e.e2).copy(); } override void visit(OrExp e) { if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) ret = Or(e.loc, e.type, e.e1, e.e2).copy(); } override void visit(XorExp e) { if (binOptimize(e, result)) return; if (e.e1.isConst() == 1 && e.e2.isConst() == 1) ret = Xor(e.loc, e.type, e.e1, e.e2).copy(); } override void visit(PowExp e) { if (binOptimize(e, result)) return; // Replace 1 ^^ x or 1.0^^x by (x, 1) if ((e.e1.op == TOK.int64 && e.e1.toInteger() == 1) || (e.e1.op == TOK.float64 && e.e1.toReal() == CTFloat.one)) { ret = new CommaExp(e.loc, e.e2, e.e1); ret.type = e.type; return; } // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral if (e.e2.type.isintegral() && e.e1.op == TOK.int64 && cast(sinteger_t)e.e1.toInteger() == -1) { ret = new AndExp(e.loc, e.e2, new IntegerExp(e.loc, 1, e.e2.type)); ret.type = e.e2.type; ret = new CondExp(e.loc, ret, new IntegerExp(e.loc, -1, e.type), new IntegerExp(e.loc, 1, e.type)); ret.type = e.type; return; } // Replace x ^^ 0 or x^^0.0 by (x, 1) if ((e.e2.op == TOK.int64 && e.e2.toInteger() == 0) || (e.e2.op == TOK.float64 && e.e2.toReal() == CTFloat.zero)) { if (e.e1.type.isintegral()) ret = new IntegerExp(e.loc, 1, e.e1.type); else ret = new RealExp(e.loc, CTFloat.one, e.e1.type); ret = new CommaExp(e.loc, e.e1, ret); ret.type = e.type; return; } // Replace x ^^ 1 or x^^1.0 by (x) if ((e.e2.op == TOK.int64 && e.e2.toInteger() == 1) || (e.e2.op == TOK.float64 && e.e2.toReal() == CTFloat.one)) { ret = e.e1; return; } // Replace x ^^ -1.0 by (1.0 / x) if (e.e2.op == TOK.float64 && e.e2.toReal() == CTFloat.minusone) { ret = new DivExp(e.loc, new RealExp(e.loc, CTFloat.one, e.e2.type), e.e1); ret.type = e.type; return; } // All other negative integral powers are illegal if (e.e1.type.isintegral() && (e.e2.op == TOK.int64) && cast(sinteger_t)e.e2.toInteger() < 0) { e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars()); return error(); } // If e2 *could* have been an integer, make it one. if (e.e2.op == TOK.float64) { if (e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal())) e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64); } if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy(); if (!CTFEExp.isCantExp(ex)) { ret = ex; return; } } // (2 ^^ n) ^^ p -> 1 << n * p if (e.e1.op == TOK.int64 && e.e1.toInteger() > 0 && !((e.e1.toInteger() - 1) & e.e1.toInteger()) && e.e2.type.isintegral() && e.e2.type.isunsigned()) { dinteger_t i = e.e1.toInteger(); dinteger_t mul = 1; while ((i >>= 1) > 1) mul++; Expression shift = new MulExp(e.loc, e.e2, new IntegerExp(e.loc, mul, e.e2.type)); shift.type = e.e2.type; shift = shift.castTo(null, Type.tshiftcnt); ret = new ShlExp(e.loc, new IntegerExp(e.loc, 1, e.e1.type), shift); ret.type = e.type; return; } } override void visit(CommaExp e) { //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars()); // Comma needs special treatment, because it may // contain compiler-generated declarations. We can interpret them, but // otherwise we must NOT attempt to constant-fold them. // In particular, if the comma returns a temporary variable, it needs // to be an lvalue (this is particularly important for struct constructors) expOptimize(e.e1, WANTvalue); expOptimize(e.e2, result, keepLvalue); if (ret.op == TOK.error) return; if (!e.e1 || e.e1.op == TOK.int64 || e.e1.op == TOK.float64 || !hasSideEffect(e.e1)) { ret = e.e2; if (ret) ret.type = e.type; } //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars()); } override void visit(ArrayLengthExp e) { //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars()); if (unaOptimize(e, WANTexpand)) return; // CTFE interpret static immutable arrays (to get better diagnostics) if (e.e1.op == TOK.variable) { VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init) { if (Expression ci = v.getConstInitializer()) e.e1 = ci; } } if (e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral || e.e1.op == TOK.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray) { ret = ArrayLength(e.type, e.e1).copy(); } } override void visit(EqualExp e) { //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars()); if (binOptimize(e, WANTvalue)) return; Expression e1 = fromConstInitializer(result, e.e1); Expression e2 = fromConstInitializer(result, e.e2); if (e1.op == TOK.error) { ret = e1; return; } if (e2.op == TOK.error) { ret = e2; return; } ret = Equal(e.op, e.loc, e.type, e1, e2).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } override void visit(IdentityExp e) { //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars()); if (binOptimize(e, WANTvalue)) return; if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == TOK.null_ && e.e2.op == TOK.null_)) { ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } } override void visit(IndexExp e) { //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars()); if (expOptimize(e.e1, result & WANTexpand)) return; Expression ex = fromConstInitializer(result, e.e1); // We might know $ now setLengthVarIfKnown(e.lengthVar, ex); if (expOptimize(e.e2, WANTvalue)) return; if (keepLvalue) return; ret = Index(e.type, ex, e.e2).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } override void visit(SliceExp e) { //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars()); if (expOptimize(e.e1, result & WANTexpand)) return; if (!e.lwr) { if (e.e1.op == TOK.string_) { // Convert slice of string literal into dynamic array Type t = e.e1.type.toBasetype(); if (Type tn = t.nextOf()) ret = e.e1.castTo(null, tn.arrayOf()); } } else { e.e1 = fromConstInitializer(result, e.e1); // We might know $ now setLengthVarIfKnown(e.lengthVar, e.e1); expOptimize(e.lwr, WANTvalue); expOptimize(e.upr, WANTvalue); if (ret.op == TOK.error) return; ret = Slice(e.type, e.e1, e.lwr, e.upr).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } // https://issues.dlang.org/show_bug.cgi?id=14649 // Leave the slice form so it might be // a part of array operation. // Assume that the backend codegen will handle the form `e[]` // as an equal to `e` itself. if (ret.op == TOK.string_) { e.e1 = ret; e.lwr = null; e.upr = null; ret = e; } //printf("-SliceExp::optimize() %s\n", ret.toChars()); } override void visit(LogicalExp e) { //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars()); if (expOptimize(e.e1, WANTvalue)) return; const oror = e.op == TOK.orOr; if (e.e1.isBool(oror)) { // Replace with (e1, oror) ret = new IntegerExp(e.loc, oror, Type.tbool); ret = Expression.combine(e.e1, ret); if (e.type.toBasetype().ty == Tvoid) { ret = new CastExp(e.loc, ret, Type.tvoid); ret.type = e.type; } ret = Expression_optimize(ret, result, false); return; } if (expOptimize(e.e2, WANTvalue)) return; if (e.e1.isConst()) { if (e.e2.isConst()) { bool n1 = e.e1.isBool(true); bool n2 = e.e2.isBool(true); ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type); } else if (e.e1.isBool(!oror)) { if (e.type.toBasetype().ty == Tvoid) ret = e.e2; else { ret = new CastExp(e.loc, e.e2, e.type); ret.type = e.type; } } } } override void visit(CmpExp e) { //printf("CmpExp::optimize() %s\n", e.toChars()); if (binOptimize(e, WANTvalue)) return; Expression e1 = fromConstInitializer(result, e.e1); Expression e2 = fromConstInitializer(result, e.e2); ret = Cmp(e.op, e.loc, e.type, e1, e2).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } override void visit(CatExp e) { //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); if (binOptimize(e, result)) return; if (e.e1.op == TOK.concatenate) { // https://issues.dlang.org/show_bug.cgi?id=12798 // optimize ((expr ~ str1) ~ str2) CatExp ce1 = cast(CatExp)e.e1; scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); cex.type = e.type; Expression ex = Expression_optimize(cex, result, false); if (ex != cex) { e.e1 = ce1.e1; e.e2 = ex; } } // optimize "str"[] -> "str" if (e.e1.op == TOK.slice) { SliceExp se1 = cast(SliceExp)e.e1; if (se1.e1.op == TOK.string_ && !se1.lwr) e.e1 = se1.e1; } if (e.e2.op == TOK.slice) { SliceExp se2 = cast(SliceExp)e.e2; if (se2.e1.op == TOK.string_ && !se2.lwr) e.e2 = se2.e1; } ret = Cat(e.type, e.e1, e.e2).copy(); if (CTFEExp.isCantExp(ret)) ret = e; } override void visit(CondExp e) { if (expOptimize(e.econd, WANTvalue)) return; if (e.econd.isBool(true)) ret = Expression_optimize(e.e1, result, keepLvalue); else if (e.econd.isBool(false)) ret = Expression_optimize(e.e2, result, keepLvalue); else { expOptimize(e.e1, result, keepLvalue); expOptimize(e.e2, result, keepLvalue); } } } scope OptimizeVisitor v = new OptimizeVisitor(e, result, keepLvalue); // Optimize the expression until it can no longer be simplified. while (1) { auto ex = v.ret; ex.accept(v); if (ex == v.ret) break; } return v.ret; } ================================================ FILE: gcc/d/dmd/parse.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/parse.d, _parse.d) * Documentation: https://dlang.org/phobos/dmd_parse.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d */ module dmd.parse; import core.stdc.stdio; import core.stdc.string; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.lexer; import dmd.errors; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.tokens; // How multiple declarations are parsed. // If 1, treat as C. // If 0, treat: // int *p, i; // as: // int* p; // int* i; enum CDECLSYNTAX = 0; // Support C cast syntax: // (type)(expression) enum CCASTSYNTAX = 1; // Support postfix C array declarations, such as // int a[3][4]; enum CARRAYDECL = 1; /********************************** * Set operator precedence for each operator. */ __gshared PREC[TOK.max_] precedence = [ TOK.type : PREC.expr, TOK.error : PREC.expr, TOK.typeof_ : PREC.primary, TOK.mixin_ : PREC.primary, TOK.import_ : PREC.primary, TOK.dotVariable : PREC.primary, TOK.scope_ : PREC.primary, TOK.identifier : PREC.primary, TOK.this_ : PREC.primary, TOK.super_ : PREC.primary, TOK.int64 : PREC.primary, TOK.float64 : PREC.primary, TOK.complex80 : PREC.primary, TOK.null_ : PREC.primary, TOK.string_ : PREC.primary, TOK.arrayLiteral : PREC.primary, TOK.assocArrayLiteral : PREC.primary, TOK.classReference : PREC.primary, TOK.file : PREC.primary, TOK.fileFullPath : PREC.primary, TOK.line : PREC.primary, TOK.moduleString : PREC.primary, TOK.functionString : PREC.primary, TOK.prettyFunction : PREC.primary, TOK.typeid_ : PREC.primary, TOK.is_ : PREC.primary, TOK.assert_ : PREC.primary, TOK.halt : PREC.primary, TOK.template_ : PREC.primary, TOK.dSymbol : PREC.primary, TOK.function_ : PREC.primary, TOK.variable : PREC.primary, TOK.symbolOffset : PREC.primary, TOK.structLiteral : PREC.primary, TOK.arrayLength : PREC.primary, TOK.delegatePointer : PREC.primary, TOK.delegateFunctionPointer : PREC.primary, TOK.remove : PREC.primary, TOK.tuple : PREC.primary, TOK.traits : PREC.primary, TOK.default_ : PREC.primary, TOK.overloadSet : PREC.primary, TOK.void_ : PREC.primary, // post TOK.dotTemplateInstance : PREC.primary, TOK.dotIdentifier : PREC.primary, TOK.dotTemplateDeclaration : PREC.primary, TOK.dot : PREC.primary, TOK.dotType : PREC.primary, TOK.plusPlus : PREC.primary, TOK.minusMinus : PREC.primary, TOK.prePlusPlus : PREC.primary, TOK.preMinusMinus : PREC.primary, TOK.call : PREC.primary, TOK.slice : PREC.primary, TOK.array : PREC.primary, TOK.index : PREC.primary, TOK.delegate_ : PREC.unary, TOK.address : PREC.unary, TOK.star : PREC.unary, TOK.negate : PREC.unary, TOK.uadd : PREC.unary, TOK.not : PREC.unary, TOK.tilde : PREC.unary, TOK.delete_ : PREC.unary, TOK.new_ : PREC.unary, TOK.newAnonymousClass : PREC.unary, TOK.cast_ : PREC.unary, TOK.vector : PREC.unary, TOK.pow : PREC.pow, TOK.mul : PREC.mul, TOK.div : PREC.mul, TOK.mod : PREC.mul, TOK.add : PREC.add, TOK.min : PREC.add, TOK.concatenate : PREC.add, TOK.leftShift : PREC.shift, TOK.rightShift : PREC.shift, TOK.unsignedRightShift : PREC.shift, TOK.lessThan : PREC.rel, TOK.lessOrEqual : PREC.rel, TOK.greaterThan : PREC.rel, TOK.greaterOrEqual : PREC.rel, TOK.in_ : PREC.rel, /* Note that we changed precedence, so that < and != have the same * precedence. This change is in the parser, too. */ TOK.equal : PREC.rel, TOK.notEqual : PREC.rel, TOK.identity : PREC.rel, TOK.notIdentity : PREC.rel, TOK.and : PREC.and, TOK.xor : PREC.xor, TOK.or : PREC.or, TOK.andAnd : PREC.andand, TOK.orOr : PREC.oror, TOK.question : PREC.cond, TOK.assign : PREC.assign, TOK.construct : PREC.assign, TOK.blit : PREC.assign, TOK.addAssign : PREC.assign, TOK.minAssign : PREC.assign, TOK.concatenateAssign : PREC.assign, TOK.concatenateElemAssign : PREC.assign, TOK.concatenateDcharAssign : PREC.assign, TOK.mulAssign : PREC.assign, TOK.divAssign : PREC.assign, TOK.modAssign : PREC.assign, TOK.powAssign : PREC.assign, TOK.leftShiftAssign : PREC.assign, TOK.rightShiftAssign : PREC.assign, TOK.unsignedRightShiftAssign : PREC.assign, TOK.andAssign : PREC.assign, TOK.orAssign : PREC.assign, TOK.xorAssign : PREC.assign, TOK.comma : PREC.expr, TOK.declaration : PREC.expr, TOK.interval : PREC.assign, ]; enum ParseStatementFlags : int { semi = 1, // empty ';' statements are allowed, but deprecated scope_ = 2, // start a new scope curly = 4, // { } statement is required curlyScope = 8, // { } starts a new scope semiOk = 0x10, // empty ';' are really ok } struct PrefixAttributes(AST) { StorageClass storageClass; AST.Expression depmsg; LINK link; AST.Prot protection; bool setAlignment; AST.Expression ealign; AST.Expressions* udas; const(char)* comment; } /***************************** * Destructively extract storage class from pAttrs. */ private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs) { StorageClass stc = AST.STC.undefined_; if (pAttrs) { stc = pAttrs.storageClass; pAttrs.storageClass = AST.STC.undefined_; } return stc; } /*********************************************************** */ final class Parser(AST) : Lexer { AST.Module mod; AST.ModuleDeclaration* md; LINK linkage; CPPMANGLE cppmangle; Loc endloc; // set to location of last right curly int inBrackets; // inside [] of array index or slice Loc lookingForElse; // location of lonely if looking for an else /********************* * Use this constructor for string mixins. * Input: * loc location in source file of mixin */ extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment) { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); scanloc = loc; if (loc.filename) { /* Create a pseudo-filename for the mixin string, as it may not even exist * in the source file. */ char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1); sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum); scanloc.filename = filename; } mod = _module; linkage = LINK.d; //nextToken(); // start up the scanner } extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment) { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); mod = _module; linkage = LINK.d; //nextToken(); // start up the scanner } AST.Dsymbols* parseModule() { const comment = token.blockComment; bool isdeprecated = false; AST.Expression msg = null; AST.Expressions* udas = null; AST.Dsymbols* decldefs; AST.Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl Token* tk; if (skipAttributes(&token, &tk) && tk.value == TOK.module_) { while (token.value != TOK.module_) { switch (token.value) { case TOK.deprecated_: { // deprecated (...) module ... if (isdeprecated) { error("there is only one deprecation attribute allowed for module declaration"); } else { isdeprecated = true; } nextToken(); if (token.value == TOK.leftParentheses) { check(TOK.leftParentheses); msg = parseAssignExp(); check(TOK.rightParentheses); } break; } case TOK.at: { AST.Expressions* exps = null; const stc = parseAttribute(&exps); if (stc == AST.STC.property || stc == AST.STC.nogc || stc == AST.STC.disable || stc == AST.STC.safe || stc == AST.STC.trusted || stc == AST.STC.system) { error("`@%s` attribute for module declaration is not supported", token.toChars()); } else { udas = AST.UserAttributeDeclaration.concat(udas, exps); } if (stc) nextToken(); break; } default: { error("`module` expected instead of `%s`", token.toChars()); nextToken(); break; } } } } if (udas) { auto a = new AST.Dsymbols(); auto udad = new AST.UserAttributeDeclaration(udas, a); mod.userAttribDecl = udad; } // ModuleDeclation leads off if (token.value == TOK.module_) { const loc = token.loc; nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `module`"); goto Lerr; } else { AST.Identifiers* a = null; Identifier id = token.ident; while (nextToken() == TOK.dot) { if (!a) a = new AST.Identifiers(); a.push(id); nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `package`"); goto Lerr; } id = token.ident; } md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated); if (token.value != TOK.semicolon) error("`;` expected following module declaration instead of `%s`", token.toChars()); nextToken(); addComment(mod, comment); } } decldefs = parseDeclDefs(0, &lastDecl); if (token.value != TOK.endOfFile) { error(token.loc, "unrecognized declaration"); goto Lerr; } return decldefs; Lerr: while (token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); nextToken(); return new AST.Dsymbols(); } private StorageClass parseDeprecatedAttribute(ref AST.Expression msg) { if (peek(&token).value != TOK.leftParentheses) return AST.STC.deprecated_; nextToken(); check(TOK.leftParentheses); AST.Expression e = parseAssignExp(); check(TOK.rightParentheses); if (msg) { error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars()); } msg = e; return AST.STC.undefined_; } AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null) { AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration if (!pLastDecl) pLastDecl = &lastDecl; const linksave = linkage; // save global state //printf("Parser::parseDeclDefs()\n"); auto decldefs = new AST.Dsymbols(); do { // parse result AST.Dsymbol s = null; AST.Dsymbols* a = null; PrefixAttributes!AST attrs; if (!once || !pAttrs) { pAttrs = &attrs; pAttrs.comment = token.blockComment; } AST.Prot.Kind prot; StorageClass stc; AST.Condition condition; linkage = linksave; switch (token.value) { case TOK.enum_: { /* Determine if this is a manifest constant declaration, * or a conventional enum. */ Token* t = peek(&token); if (t.value == TOK.leftCurly || t.value == TOK.colon) s = parseEnum(); else if (t.value != TOK.identifier) goto Ldeclaration; else { t = peek(t); if (t.value == TOK.leftCurly || t.value == TOK.colon || t.value == TOK.semicolon) s = parseEnum(); else goto Ldeclaration; } break; } case TOK.import_: a = parseImport(); // keep pLastDecl break; case TOK.template_: s = cast(AST.Dsymbol)parseTemplateDeclaration(); break; case TOK.mixin_: { const loc = token.loc; switch (peekNext()) { case TOK.leftParentheses: { // mixin(string) nextToken(); auto exps = parseArguments(); check(TOK.semicolon); s = new AST.CompileDeclaration(loc, exps); break; } case TOK.template_: // mixin template nextToken(); s = cast(AST.Dsymbol)parseTemplateDeclaration(true); break; default: s = parseMixin(); break; } break; } case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: case TOK.alias_: case TOK.identifier: case TOK.super_: case TOK.typeof_: case TOK.dot: case TOK.vector: case TOK.struct_: case TOK.union_: case TOK.class_: case TOK.interface_: Ldeclaration: a = parseDeclarations(false, pAttrs, pAttrs.comment); if (a && a.dim) *pLastDecl = (*a)[a.dim - 1]; break; case TOK.this_: if (peekNext() == TOK.dot) goto Ldeclaration; else s = parseCtor(pAttrs); break; case TOK.tilde: s = parseDtor(pAttrs); break; case TOK.invariant_: { Token* t = peek(&token); if (t.value == TOK.leftParentheses || t.value == TOK.leftCurly) { // invariant { statements... } // invariant() { statements... } // invariant (expression); s = parseInvariant(pAttrs); } else { error("invariant body expected, not `%s`", token.toChars()); goto Lerror; } break; } case TOK.unittest_: if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration) { s = parseUnitTest(pAttrs); if (*pLastDecl) (*pLastDecl).ddocUnittest = cast(AST.UnitTestDeclaration)s; } else { // Skip over unittest block by counting { } Loc loc = token.loc; int braces = 0; while (1) { nextToken(); switch (token.value) { case TOK.leftCurly: ++braces; continue; case TOK.rightCurly: if (--braces) continue; nextToken(); break; case TOK.endOfFile: /* { */ error(loc, "closing `}` of unittest not found before end of file"); goto Lerror; default: continue; } break; } // Workaround 14894. Add an empty unittest declaration to keep // the number of symbols in this scope independent of -unittest. s = new AST.UnitTestDeclaration(loc, token.loc, AST.STC.undefined_, null); } break; case TOK.new_: s = parseNew(pAttrs); break; case TOK.delete_: s = parseDelete(pAttrs); break; case TOK.colon: case TOK.leftCurly: error("declaration expected, not `%s`", token.toChars()); goto Lerror; case TOK.rightCurly: case TOK.endOfFile: if (once) error("declaration expected, not `%s`", token.toChars()); return decldefs; case TOK.static_: { const next = peekNext(); if (next == TOK.this_) s = parseStaticCtor(pAttrs); else if (next == TOK.tilde) s = parseStaticDtor(pAttrs); else if (next == TOK.assert_) s = parseStaticAssert(); else if (next == TOK.if_) { condition = parseStaticIfCondition(); AST.Dsymbols* athen; if (token.value == TOK.colon) athen = parseBlock(pLastDecl); else { const lookingForElseSave = lookingForElse; lookingForElse = token.loc; athen = parseBlock(pLastDecl); lookingForElse = lookingForElseSave; } AST.Dsymbols* aelse = null; if (token.value == TOK.else_) { const elseloc = token.loc; nextToken(); aelse = parseBlock(pLastDecl); checkDanglingElse(elseloc); } s = new AST.StaticIfDeclaration(condition, athen, aelse); } else if (next == TOK.import_) { a = parseImport(); // keep pLastDecl } else if (next == TOK.foreach_ || next == TOK.foreach_reverse_) { s = parseForeach!(true,true)(loc, pLastDecl); } else { stc = AST.STC.static_; goto Lstc; } break; } case TOK.const_: if (peekNext() == TOK.leftParentheses) goto Ldeclaration; stc = AST.STC.const_; goto Lstc; case TOK.immutable_: if (peekNext() == TOK.leftParentheses) goto Ldeclaration; stc = AST.STC.immutable_; goto Lstc; case TOK.shared_: { const next = peekNext(); if (next == TOK.leftParentheses) goto Ldeclaration; if (next == TOK.static_) { TOK next2 = peekNext2(); if (next2 == TOK.this_) { s = parseSharedStaticCtor(pAttrs); break; } if (next2 == TOK.tilde) { s = parseSharedStaticDtor(pAttrs); break; } } stc = AST.STC.shared_; goto Lstc; } case TOK.inout_: if (peekNext() == TOK.leftParentheses) goto Ldeclaration; stc = AST.STC.wild; goto Lstc; case TOK.final_: stc = AST.STC.final_; goto Lstc; case TOK.auto_: stc = AST.STC.auto_; goto Lstc; case TOK.scope_: stc = AST.STC.scope_; goto Lstc; case TOK.override_: stc = AST.STC.override_; goto Lstc; case TOK.abstract_: stc = AST.STC.abstract_; goto Lstc; case TOK.synchronized_: stc = AST.STC.synchronized_; goto Lstc; case TOK.nothrow_: stc = AST.STC.nothrow_; goto Lstc; case TOK.pure_: stc = AST.STC.pure_; goto Lstc; case TOK.ref_: stc = AST.STC.ref_; goto Lstc; case TOK.gshared: stc = AST.STC.gshared; goto Lstc; //case TOK.manifest: stc = STC.manifest; goto Lstc; case TOK.at: { AST.Expressions* exps = null; stc = parseAttribute(&exps); if (stc) goto Lstc; // it's a predefined attribute // no redundant/conflicting check for UDAs pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps); goto Lautodecl; } Lstc: pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc); nextToken(); Lautodecl: Token* tk; /* Look for auto initializers: * storage_class identifier = initializer; * storage_class identifier(...) = initializer; */ if (token.value == TOK.identifier && skipParensIf(peek(&token), &tk) && tk.value == TOK.assign) { a = parseAutoDeclarations(getStorageClass!AST(pAttrs), pAttrs.comment); if (a && a.dim) *pLastDecl = (*a)[a.dim - 1]; if (pAttrs.udas) { s = new AST.UserAttributeDeclaration(pAttrs.udas, a); pAttrs.udas = null; } break; } /* Look for return type inference for template functions. */ if (token.value == TOK.identifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) && (tk.value == TOK.leftParentheses || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.dim) *pLastDecl = (*a)[a.dim - 1]; if (pAttrs.udas) { s = new AST.UserAttributeDeclaration(pAttrs.udas, a); pAttrs.udas = null; } break; } a = parseBlock(pLastDecl, pAttrs); auto stc2 = getStorageClass!AST(pAttrs); if (stc2 != AST.STC.undefined_) { s = new AST.StorageClassDeclaration(stc2, a); } if (pAttrs.udas) { if (s) { a = new AST.Dsymbols(); a.push(s); } s = new AST.UserAttributeDeclaration(pAttrs.udas, a); pAttrs.udas = null; } break; case TOK.deprecated_: { AST.Expression e; if (StorageClass _stc = parseDeprecatedAttribute(pAttrs.depmsg)) { stc = _stc; goto Lstc; } a = parseBlock(pLastDecl, pAttrs); if (pAttrs.depmsg) { s = new AST.DeprecatedDeclaration(pAttrs.depmsg, a); pAttrs.depmsg = null; } break; } case TOK.leftBracket: { if (peekNext() == TOK.rightBracket) error("empty attribute list is not allowed"); error("use `@(attributes)` instead of `[attributes]`"); AST.Expressions* exps = parseArguments(); // no redundant/conflicting check for UDAs pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps); a = parseBlock(pLastDecl, pAttrs); if (pAttrs.udas) { s = new AST.UserAttributeDeclaration(pAttrs.udas, a); pAttrs.udas = null; } break; } case TOK.extern_: { if (peek(&token).value != TOK.leftParentheses) { stc = AST.STC.extern_; goto Lstc; } const linkLoc = token.loc; AST.Identifiers* idents = null; CPPMANGLE cppmangle; bool cppMangleOnly = false; const link = parseLinkage(&idents, cppmangle, cppMangleOnly); if (pAttrs.link != LINK.default_) { if (pAttrs.link != link) { error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(link)); } else if (idents) { // Allow: // extern(C++, foo) extern(C++, bar) void foo(); // to be equivalent with: // extern(C++, foo.bar) void foo(); } else error("redundant linkage `extern (%s)`", AST.linkageToChars(pAttrs.link)); } pAttrs.link = link; this.linkage = link; a = parseBlock(pLastDecl, pAttrs); if (idents) { assert(link == LINK.cpp); assert(idents.dim); for (size_t i = idents.dim; i;) { Identifier id = (*idents)[--i]; if (s) { a = new AST.Dsymbols(); a.push(s); } s = new AST.Nspace(linkLoc, id, a, cppMangleOnly); } pAttrs.link = LINK.default_; } else if (cppmangle != CPPMANGLE.def) { assert(link == LINK.cpp); s = new AST.CPPMangleDeclaration(cppmangle, a); } else if (pAttrs.link != LINK.default_) { s = new AST.LinkDeclaration(pAttrs.link, a); pAttrs.link = LINK.default_; } break; } case TOK.private_: prot = AST.Prot.Kind.private_; goto Lprot; case TOK.package_: prot = AST.Prot.Kind.package_; goto Lprot; case TOK.protected_: prot = AST.Prot.Kind.protected_; goto Lprot; case TOK.public_: prot = AST.Prot.Kind.public_; goto Lprot; case TOK.export_: prot = AST.Prot.Kind.export_; goto Lprot; Lprot: { if (pAttrs.protection.kind != AST.Prot.Kind.undefined) { if (pAttrs.protection.kind != prot) error("conflicting protection attribute `%s` and `%s`", AST.protectionToChars(pAttrs.protection.kind), AST.protectionToChars(prot)); else error("redundant protection attribute `%s`", AST.protectionToChars(prot)); } pAttrs.protection.kind = prot; nextToken(); // optional qualified package identifier to bind // protection to AST.Identifiers* pkg_prot_idents = null; if (pAttrs.protection.kind == AST.Prot.Kind.package_ && token.value == TOK.leftParentheses) { pkg_prot_idents = parseQualifiedIdentifier("protection package"); if (pkg_prot_idents) check(TOK.rightParentheses); else { while (token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); nextToken(); break; } } const attrloc = token.loc; a = parseBlock(pLastDecl, pAttrs); if (pAttrs.protection.kind != AST.Prot.Kind.undefined) { if (pAttrs.protection.kind == AST.Prot.Kind.package_ && pkg_prot_idents) s = new AST.ProtDeclaration(attrloc, pkg_prot_idents, a); else s = new AST.ProtDeclaration(attrloc, pAttrs.protection, a); pAttrs.protection = AST.Prot(AST.Prot.Kind.undefined); } break; } case TOK.align_: { const attrLoc = token.loc; nextToken(); AST.Expression e = null; // default if (token.value == TOK.leftParentheses) { nextToken(); e = parseAssignExp(); check(TOK.rightParentheses); } if (pAttrs.setAlignment) { if (e) error("redundant alignment attribute `align(%s)`", e.toChars()); else error("redundant alignment attribute `align`"); } pAttrs.setAlignment = true; pAttrs.ealign = e; a = parseBlock(pLastDecl, pAttrs); if (pAttrs.setAlignment) { s = new AST.AlignDeclaration(attrLoc, pAttrs.ealign, a); pAttrs.setAlignment = false; pAttrs.ealign = null; } break; } case TOK.pragma_: { AST.Expressions* args = null; const loc = token.loc; nextToken(); check(TOK.leftParentheses); if (token.value != TOK.identifier) { error("`pragma(identifier)` expected"); goto Lerror; } Identifier ident = token.ident; nextToken(); if (token.value == TOK.comma && peekNext() != TOK.rightParentheses) args = parseArguments(); // pragma(identifier, args...) else check(TOK.rightParentheses); // pragma(identifier) AST.Dsymbols* a2 = null; if (token.value == TOK.semicolon) { /* https://issues.dlang.org/show_bug.cgi?id=2354 * Accept single semicolon as an empty * DeclarationBlock following attribute. * * Attribute DeclarationBlock * Pragma DeclDef * ; */ nextToken(); } else a2 = parseBlock(pLastDecl); s = new AST.PragmaDeclaration(loc, ident, args, a2); break; } case TOK.debug_: nextToken(); if (token.value == TOK.assign) { nextToken(); if (token.value == TOK.identifier) s = new AST.DebugSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue); else { error("identifier or integer expected, not `%s`", token.toChars()); s = null; } nextToken(); if (token.value != TOK.semicolon) error("semicolon expected"); nextToken(); break; } condition = parseDebugCondition(); goto Lcondition; case TOK.version_: nextToken(); if (token.value == TOK.assign) { nextToken(); if (token.value == TOK.identifier) s = new AST.VersionSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue); else { error("identifier or integer expected, not `%s`", token.toChars()); s = null; } nextToken(); if (token.value != TOK.semicolon) error("semicolon expected"); nextToken(); break; } condition = parseVersionCondition(); goto Lcondition; Lcondition: { AST.Dsymbols* athen; if (token.value == TOK.colon) athen = parseBlock(pLastDecl); else { const lookingForElseSave = lookingForElse; lookingForElse = token.loc; athen = parseBlock(pLastDecl); lookingForElse = lookingForElseSave; } AST.Dsymbols* aelse = null; if (token.value == TOK.else_) { const elseloc = token.loc; nextToken(); aelse = parseBlock(pLastDecl); checkDanglingElse(elseloc); } s = new AST.ConditionalDeclaration(condition, athen, aelse); break; } case TOK.semicolon: // empty declaration //error("empty declaration"); nextToken(); continue; default: error("declaration expected, not `%s`", token.toChars()); Lerror: while (token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); nextToken(); s = null; continue; } if (s) { if (!s.isAttribDeclaration()) *pLastDecl = s; decldefs.push(s); addComment(s, pAttrs.comment); } else if (a && a.dim) { decldefs.append(a); } } while (!once); linkage = linksave; return decldefs; } /***************************************** * Parse auto declarations of the form: * storageClass ident = init, ident = init, ... ; * and return the array of them. * Starts with token on the first ident. * Ends with scanner past closing ';' */ AST.Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment) { //printf("parseAutoDeclarations\n"); Token* tk; auto a = new AST.Dsymbols(); while (1) { const loc = token.loc; Identifier ident = token.ident; nextToken(); // skip over ident AST.TemplateParameters* tpl = null; if (token.value == TOK.leftParentheses) tpl = parseTemplateParameterList(); check(TOK.assign); // skip over '=' AST.Initializer _init = parseInitializer(); auto v = new AST.VarDeclaration(loc, null, ident, _init, storageClass); AST.Dsymbol s = v; if (tpl) { auto a2 = new AST.Dsymbols(); a2.push(v); auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0); s = tempdecl; } a.push(s); switch (token.value) { case TOK.semicolon: nextToken(); addComment(s, comment); break; case TOK.comma: nextToken(); if (!(token.value == TOK.identifier && skipParensIf(peek(&token), &tk) && tk.value == TOK.assign)) { error("identifier expected following comma"); break; } addComment(s, comment); continue; default: error("semicolon expected following auto declaration, not `%s`", token.toChars()); break; } break; } return a; } /******************************************** * Parse declarations after an align, protection, or extern decl. */ AST.Dsymbols* parseBlock(AST.Dsymbol* pLastDecl, PrefixAttributes!AST* pAttrs = null) { AST.Dsymbols* a = null; //printf("parseBlock()\n"); switch (token.value) { case TOK.semicolon: error("declaration expected following attribute, not `;`"); nextToken(); break; case TOK.endOfFile: error("declaration expected following attribute, not end of file"); break; case TOK.leftCurly: { const lookingForElseSave = lookingForElse; lookingForElse = Loc(); nextToken(); a = parseDeclDefs(0, pLastDecl); if (token.value != TOK.rightCurly) { /* { */ error("matching `}` expected, not `%s`", token.toChars()); } else nextToken(); lookingForElse = lookingForElseSave; break; } case TOK.colon: nextToken(); a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket break; default: a = parseDeclDefs(1, pLastDecl, pAttrs); break; } return a; } /********************************************* * Give error on redundant/conflicting storage class. */ StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc) { if ((storageClass & stc) || (storageClass & AST.STC.in_ && stc & (AST.STC.const_ | AST.STC.scope_)) || (stc & AST.STC.in_ && storageClass & (AST.STC.const_ | AST.STC.scope_))) { OutBuffer buf; AST.stcToBuffer(&buf, stc); error("redundant attribute `%s`", buf.peekString()); return storageClass | stc; } storageClass |= stc; if (stc & (AST.STC.const_ | AST.STC.immutable_ | AST.STC.manifest)) { StorageClass u = storageClass & (AST.STC.const_ | AST.STC.immutable_ | AST.STC.manifest); if (u & (u - 1)) error("conflicting attribute `%s`", Token.toChars(token.value)); } if (stc & (AST.STC.gshared | AST.STC.shared_ | AST.STC.tls)) { StorageClass u = storageClass & (AST.STC.gshared | AST.STC.shared_ | AST.STC.tls); if (u & (u - 1)) error("conflicting attribute `%s`", Token.toChars(token.value)); } if (stc & (AST.STC.safe | AST.STC.system | AST.STC.trusted)) { StorageClass u = storageClass & (AST.STC.safe | AST.STC.system | AST.STC.trusted); if (u & (u - 1)) error("conflicting attribute `@%s`", token.toChars()); } return storageClass; } /*********************************************** * Parse attribute, lexer is on '@'. * Input: * pudas array of UDAs to append to * Returns: * storage class if a predefined attribute; also scanner remains on identifier. * 0 if not a predefined attribute * *pudas set if user defined attribute, scanner is past UDA * *pudas NULL if not a user defined attribute */ StorageClass parseAttribute(AST.Expressions** pudas) { nextToken(); AST.Expressions* udas = null; StorageClass stc = 0; if (token.value == TOK.identifier) { if (token.ident == Id.property) stc = AST.STC.property; else if (token.ident == Id.nogc) stc = AST.STC.nogc; else if (token.ident == Id.safe) stc = AST.STC.safe; else if (token.ident == Id.trusted) stc = AST.STC.trusted; else if (token.ident == Id.system) stc = AST.STC.system; else if (token.ident == Id.disable) stc = AST.STC.disable; else if (token.ident == Id.future) stc = AST.STC.future; else { // Allow identifier, template instantiation, or function call AST.Expression exp = parsePrimaryExp(); if (token.value == TOK.leftParentheses) { const loc = token.loc; exp = new AST.CallExp(loc, exp, parseArguments()); } udas = new AST.Expressions(); udas.push(exp); } } else if (token.value == TOK.leftParentheses) { // @( ArgumentList ) // Concatenate with existing if (peekNext() == TOK.rightParentheses) error("empty attribute list is not allowed"); udas = parseArguments(); } else { error("@identifier or @(ArgumentList) expected, not `@%s`", token.toChars()); } if (stc) { } else if (udas) { *pudas = AST.UserAttributeDeclaration.concat(*pudas, udas); } else error("valid attributes are `@property`, `@safe`, `@trusted`, `@system`, `@disable`, `@nogc`"); return stc; } /*********************************************** * Parse const/immutable/shared/inout/nothrow/pure postfix */ StorageClass parsePostfix(StorageClass storageClass, AST.Expressions** pudas) { while (1) { StorageClass stc; switch (token.value) { case TOK.const_: stc = AST.STC.const_; break; case TOK.immutable_: stc = AST.STC.immutable_; break; case TOK.shared_: stc = AST.STC.shared_; break; case TOK.inout_: stc = AST.STC.wild; break; case TOK.nothrow_: stc = AST.STC.nothrow_; break; case TOK.pure_: stc = AST.STC.pure_; break; case TOK.return_: stc = AST.STC.return_; break; case TOK.scope_: stc = AST.STC.scope_; break; case TOK.at: { AST.Expressions* udas = null; stc = parseAttribute(&udas); if (udas) { if (pudas) *pudas = AST.UserAttributeDeclaration.concat(*pudas, udas); else { // Disallow: // void function() @uda fp; // () @uda { return 1; } error("user-defined attributes cannot appear as postfixes"); } continue; } break; } default: return storageClass; } storageClass = appendStorageClass(storageClass, stc); nextToken(); } } StorageClass parseTypeCtor() { StorageClass storageClass = AST.STC.undefined_; while (1) { if (peek(&token).value == TOK.leftParentheses) return storageClass; StorageClass stc; switch (token.value) { case TOK.const_: stc = AST.STC.const_; break; case TOK.immutable_: stc = AST.STC.immutable_; break; case TOK.shared_: stc = AST.STC.shared_; break; case TOK.inout_: stc = AST.STC.wild; break; default: return storageClass; } storageClass = appendStorageClass(storageClass, stc); nextToken(); } } /************************************** * Parse constraint. * Constraint is of the form: * if ( ConstraintExpression ) */ AST.Expression parseConstraint() { AST.Expression e = null; if (token.value == TOK.if_) { nextToken(); // skip over 'if' check(TOK.leftParentheses); e = parseExpression(); check(TOK.rightParentheses); } return e; } /************************************** * Parse a TemplateDeclaration. */ AST.TemplateDeclaration parseTemplateDeclaration(bool ismixin = false) { AST.TemplateDeclaration tempdecl; Identifier id; AST.TemplateParameters* tpl; AST.Dsymbols* decldefs; AST.Expression constraint = null; const loc = token.loc; nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `template`"); goto Lerr; } id = token.ident; nextToken(); tpl = parseTemplateParameterList(); if (!tpl) goto Lerr; constraint = parseConstraint(); if (token.value != TOK.leftCurly) { error("members of template declaration expected"); goto Lerr; } else decldefs = parseBlock(null); tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin); return tempdecl; Lerr: return null; } /****************************************** * Parse template parameter list. * Input: * flag 0: parsing "( list )" * 1: parsing non-empty "list $(RPAREN)" */ AST.TemplateParameters* parseTemplateParameterList(int flag = 0) { auto tpl = new AST.TemplateParameters(); if (!flag && token.value != TOK.leftParentheses) { error("parenthesized template parameter list expected following template identifier"); goto Lerr; } nextToken(); // Get array of TemplateParameters if (flag || token.value != TOK.rightParentheses) { int isvariadic = 0; while (token.value != TOK.rightParentheses) { AST.TemplateParameter tp; Loc loc; Identifier tp_ident = null; AST.Type tp_spectype = null; AST.Type tp_valtype = null; AST.Type tp_defaulttype = null; AST.Expression tp_specvalue = null; AST.Expression tp_defaultvalue = null; Token* t; // Get TemplateParameter // First, look ahead to see if it is a TypeParameter or a ValueParameter t = peek(&token); if (token.value == TOK.alias_) { // AliasParameter nextToken(); loc = token.loc; // todo AST.Type spectype = null; if (isDeclaration(&token, NeedDeclaratorId.must, TOK.reserved, null)) { spectype = parseType(&tp_ident); } else { if (token.value != TOK.identifier) { error("identifier expected for template alias parameter"); goto Lerr; } tp_ident = token.ident; nextToken(); } RootObject spec = null; if (token.value == TOK.colon) // : Type { nextToken(); if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null)) spec = parseType(); else spec = parseCondExp(); } RootObject def = null; if (token.value == TOK.assign) // = Type { nextToken(); if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null)) def = parseType(); else def = parseCondExp(); } tp = new AST.TemplateAliasParameter(loc, tp_ident, spectype, spec, def); } else if (t.value == TOK.colon || t.value == TOK.assign || t.value == TOK.comma || t.value == TOK.rightParentheses) { // TypeParameter if (token.value != TOK.identifier) { error("identifier expected for template type parameter"); goto Lerr; } loc = token.loc; tp_ident = token.ident; nextToken(); if (token.value == TOK.colon) // : Type { nextToken(); tp_spectype = parseType(); } if (token.value == TOK.assign) // = Type { nextToken(); tp_defaulttype = parseType(); } tp = new AST.TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); } else if (token.value == TOK.identifier && t.value == TOK.dotDotDot) { // ident... if (isvariadic) error("variadic template parameter must be last"); isvariadic = 1; loc = token.loc; tp_ident = token.ident; nextToken(); nextToken(); tp = new AST.TemplateTupleParameter(loc, tp_ident); } else if (token.value == TOK.this_) { // ThisParameter nextToken(); if (token.value != TOK.identifier) { error("identifier expected for template this parameter"); goto Lerr; } loc = token.loc; tp_ident = token.ident; nextToken(); if (token.value == TOK.colon) // : Type { nextToken(); tp_spectype = parseType(); } if (token.value == TOK.assign) // = Type { nextToken(); tp_defaulttype = parseType(); } tp = new AST.TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); } else { // ValueParameter loc = token.loc; // todo tp_valtype = parseType(&tp_ident); if (!tp_ident) { error("identifier expected for template value parameter"); tp_ident = Identifier.idPool("error"); } if (token.value == TOK.colon) // : CondExpression { nextToken(); tp_specvalue = parseCondExp(); } if (token.value == TOK.assign) // = CondExpression { nextToken(); tp_defaultvalue = parseDefaultInitExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } tpl.push(tp); if (token.value != TOK.comma) break; nextToken(); } } check(TOK.rightParentheses); Lerr: return tpl; } /****************************************** * Parse template mixin. * mixin Foo; * mixin Foo!(args); * mixin a.b.c!(args).Foo!(args); * mixin Foo!(args) identifier; * mixin typeof(expr).identifier!(args); */ AST.Dsymbol parseMixin() { AST.TemplateMixin tm; Identifier id; AST.Objects* tiargs; //printf("parseMixin()\n"); const locMixin = token.loc; nextToken(); // skip 'mixin' auto loc = token.loc; AST.TypeQualified tqual = null; if (token.value == TOK.dot) { id = Id.empty; } else { if (token.value == TOK.typeof_) { tqual = parseTypeof(); check(TOK.dot); } if (token.value != TOK.identifier) { error("identifier expected, not `%s`", token.toChars()); id = Id.empty; } else id = token.ident; nextToken(); } while (1) { tiargs = null; if (token.value == TOK.not) { tiargs = parseTemplateArguments(); } if (tiargs && token.value == TOK.dot) { auto tempinst = new AST.TemplateInstance(loc, id, tiargs); if (!tqual) tqual = new AST.TypeInstance(loc, tempinst); else tqual.addInst(tempinst); tiargs = null; } else { if (!tqual) tqual = new AST.TypeIdentifier(loc, id); else tqual.addIdent(id); } if (token.value != TOK.dot) break; nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `.` instead of `%s`", token.toChars()); break; } loc = token.loc; id = token.ident; nextToken(); } if (token.value == TOK.identifier) { id = token.ident; nextToken(); } else id = null; tm = new AST.TemplateMixin(locMixin, id, tqual, tiargs); if (token.value != TOK.semicolon) error("`;` expected after mixin"); nextToken(); return tm; } /****************************************** * Parse template arguments. * Input: * current token is opening '!' * Output: * current token is one after closing '$(RPAREN)' */ AST.Objects* parseTemplateArguments() { AST.Objects* tiargs; nextToken(); if (token.value == TOK.leftParentheses) { // ident!(template_arguments) tiargs = parseTemplateArgumentList(); } else { // ident!template_argument tiargs = parseTemplateSingleArgument(); } if (token.value == TOK.not) { TOK tok = peekNext(); if (tok != TOK.is_ && tok != TOK.in_) { error("multiple ! arguments are not allowed"); Lagain: nextToken(); if (token.value == TOK.leftParentheses) parseTemplateArgumentList(); else parseTemplateSingleArgument(); if (token.value == TOK.not && (tok = peekNext()) != TOK.is_ && tok != TOK.in_) goto Lagain; } } return tiargs; } /****************************************** * Parse template argument list. * Input: * current token is opening '$(LPAREN)', * or ',' for __traits * Output: * current token is one after closing '$(RPAREN)' */ AST.Objects* parseTemplateArgumentList() { //printf("Parser::parseTemplateArgumentList()\n"); auto tiargs = new AST.Objects(); TOK endtok = TOK.rightParentheses; assert(token.value == TOK.leftParentheses || token.value == TOK.comma); nextToken(); // Get TemplateArgumentList while (token.value != endtok) { // See if it is an Expression or a Type if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null)) { // Template argument is a type AST.Type ta = parseType(); tiargs.push(ta); } else { // Template argument is an expression AST.Expression ea = parseAssignExp(); tiargs.push(ea); } if (token.value != TOK.comma) break; nextToken(); } check(endtok, "template argument list"); return tiargs; } /***************************** * Parse single template argument, to support the syntax: * foo!arg * Input: * current token is the arg */ AST.Objects* parseTemplateSingleArgument() { //printf("parseTemplateSingleArgument()\n"); auto tiargs = new AST.Objects(); AST.Type ta; switch (token.value) { case TOK.identifier: ta = new AST.TypeIdentifier(token.loc, token.ident); goto LabelX; case TOK.vector: ta = parseVector(); goto LabelX; case TOK.void_: ta = AST.Type.tvoid; goto LabelX; case TOK.int8: ta = AST.Type.tint8; goto LabelX; case TOK.uns8: ta = AST.Type.tuns8; goto LabelX; case TOK.int16: ta = AST.Type.tint16; goto LabelX; case TOK.uns16: ta = AST.Type.tuns16; goto LabelX; case TOK.int32: ta = AST.Type.tint32; goto LabelX; case TOK.uns32: ta = AST.Type.tuns32; goto LabelX; case TOK.int64: ta = AST.Type.tint64; goto LabelX; case TOK.uns64: ta = AST.Type.tuns64; goto LabelX; case TOK.int128: ta = AST.Type.tint128; goto LabelX; case TOK.uns128: ta = AST.Type.tuns128; goto LabelX; case TOK.float32: ta = AST.Type.tfloat32; goto LabelX; case TOK.float64: ta = AST.Type.tfloat64; goto LabelX; case TOK.float80: ta = AST.Type.tfloat80; goto LabelX; case TOK.imaginary32: ta = AST.Type.timaginary32; goto LabelX; case TOK.imaginary64: ta = AST.Type.timaginary64; goto LabelX; case TOK.imaginary80: ta = AST.Type.timaginary80; goto LabelX; case TOK.complex32: ta = AST.Type.tcomplex32; goto LabelX; case TOK.complex64: ta = AST.Type.tcomplex64; goto LabelX; case TOK.complex80: ta = AST.Type.tcomplex80; goto LabelX; case TOK.bool_: ta = AST.Type.tbool; goto LabelX; case TOK.char_: ta = AST.Type.tchar; goto LabelX; case TOK.wchar_: ta = AST.Type.twchar; goto LabelX; case TOK.dchar_: ta = AST.Type.tdchar; goto LabelX; LabelX: tiargs.push(ta); nextToken(); break; case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: case TOK.uns64Literal: case TOK.int128Literal: case TOK.uns128Literal: case TOK.float32Literal: case TOK.float64Literal: case TOK.float80Literal: case TOK.imaginary32Literal: case TOK.imaginary64Literal: case TOK.imaginary80Literal: case TOK.null_: case TOK.true_: case TOK.false_: case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: case TOK.this_: { // Template argument is an expression AST.Expression ea = parsePrimaryExp(); tiargs.push(ea); break; } default: error("template argument expected following `!`"); break; } return tiargs; } /********************************** * Parse a static assertion. * Current token is 'static'. */ AST.StaticAssert parseStaticAssert() { const loc = token.loc; AST.Expression exp; AST.Expression msg = null; //printf("parseStaticAssert()\n"); nextToken(); nextToken(); check(TOK.leftParentheses); exp = parseAssignExp(); if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.rightParentheses) { msg = parseAssignExp(); if (token.value == TOK.comma) nextToken(); } } check(TOK.rightParentheses); check(TOK.semicolon); return new AST.StaticAssert(loc, exp, msg); } /*********************************** * Parse typeof(expression). * Current token is on the 'typeof'. */ AST.TypeQualified parseTypeof() { AST.TypeQualified t; const loc = token.loc; nextToken(); check(TOK.leftParentheses); if (token.value == TOK.return_) // typeof(return) { nextToken(); t = new AST.TypeReturn(loc); } else { AST.Expression exp = parseExpression(); // typeof(expression) t = new AST.TypeTypeof(loc, exp); } check(TOK.rightParentheses); return t; } /*********************************** * Parse __vector(type). * Current token is on the '__vector'. */ AST.Type parseVector() { nextToken(); check(TOK.leftParentheses); AST.Type tb = parseType(); check(TOK.rightParentheses); return new AST.TypeVector(tb); } /*********************************** * Parse: * extern (linkage) * extern (C++, namespaces) * extern (C++, "namespace", "namespaces", ...) * The parser is on the 'extern' token. */ LINK parseLinkage(AST.Identifiers** pidents, out CPPMANGLE cppmangle, out bool cppMangleOnly) { AST.Identifiers* idents = null; cppmangle = CPPMANGLE.def; LINK link = LINK.default_; nextToken(); assert(token.value == TOK.leftParentheses); nextToken(); if (token.value == TOK.identifier) { Identifier id = token.ident; nextToken(); if (id == Id.Windows) link = LINK.windows; else if (id == Id.Pascal) link = LINK.pascal; else if (id == Id.D) link = LINK.d; else if (id == Id.C) { link = LINK.c; if (token.value == TOK.plusPlus) { link = LINK.cpp; nextToken(); if (token.value == TOK.comma) // , namespaces or class or struct { nextToken(); if (token.value == TOK.class_ || token.value == TOK.struct_) { cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct; nextToken(); } else if (token.value == TOK.string_) // extern(C++, "namespace", "namespaces") { cppMangleOnly = true; idents = new AST.Identifiers(); while (1) { AST.StringExp stringExp = cast(AST.StringExp)parsePrimaryExp(); const(char)[] name = stringExp.toStringz(); if (name.length == 0) { error("invalid zero length C++ namespace"); idents = null; break; } else if (!Identifier.isValidIdentifier(name)) { error("expected valid identifer for C++ namespace but got `%s`", name.ptr); idents = null; break; } idents.push(Identifier.idPool(name)); if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.string_) { error("string expected following `,` for C++ namespace, not `%s`", token.toChars()); idents = null; break; } } else break; } } else { idents = new AST.Identifiers(); while (1) { if (token.value == TOK.identifier) { Identifier idn = token.ident; idents.push(idn); nextToken(); if (token.value == TOK.dot) { nextToken(); continue; } } else { error("identifier expected for C++ namespace"); idents = null; // error occurred, invalidate list of elements. } break; } } } } } else if (id == Id.Objective) // Looking for tokens "Objective-C" { if (token.value == TOK.min) { nextToken(); if (token.ident == Id.C) { link = LINK.objc; nextToken(); } else goto LinvalidLinkage; } else goto LinvalidLinkage; } else if (id == Id.System) { link = LINK.system; } else { LinvalidLinkage: error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Pascal`, `Windows`, `System`"); link = LINK.d; } } else { link = LINK.d; // default } check(TOK.rightParentheses); *pidents = idents; return link; } /*********************************** * Parse ident1.ident2.ident3 * * Params: * entity = what qualified identifier is expected to resolve into. * Used only for better error message * * Returns: * array of identifiers with actual qualified one stored last */ AST.Identifiers* parseQualifiedIdentifier(const(char)* entity) { AST.Identifiers* qualified = null; do { nextToken(); if (token.value != TOK.identifier) { error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars()); return null; } Identifier id = token.ident; if (!qualified) qualified = new AST.Identifiers(); qualified.push(id); nextToken(); } while (token.value == TOK.dot); return qualified; } /************************************** * Parse a debug conditional */ AST.Condition parseDebugCondition() { uint level = 1; Identifier id = null; if (token.value == TOK.leftParentheses) { nextToken(); if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) level = cast(uint)token.unsvalue; else error("identifier or integer expected inside debug(...), not `%s`", token.toChars()); nextToken(); check(TOK.rightParentheses); } return new AST.DebugCondition(mod, level, id); } /************************************** * Parse a version conditional */ AST.Condition parseVersionCondition() { uint level = 1; Identifier id = null; if (token.value == TOK.leftParentheses) { nextToken(); /* Allow: * version (unittest) * version (assert) * even though they are keywords */ if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) level = cast(uint)token.unsvalue; else if (token.value == TOK.unittest_) id = Identifier.idPool(Token.toString(TOK.unittest_)); else if (token.value == TOK.assert_) id = Identifier.idPool(Token.toString(TOK.assert_)); else error("identifier or integer expected inside version(...), not `%s`", token.toChars()); nextToken(); check(TOK.rightParentheses); } else error("(condition) expected following `version`"); return new AST.VersionCondition(mod, level, id); } /*********************************************** * static if (expression) * body * else * body * Current token is 'static'. */ AST.Condition parseStaticIfCondition() { AST.Expression exp; AST.Condition condition; const loc = token.loc; nextToken(); nextToken(); if (token.value == TOK.leftParentheses) { nextToken(); exp = parseAssignExp(); check(TOK.rightParentheses); } else { error("(expression) expected following `static if`"); exp = null; } condition = new AST.StaticIfCondition(loc, exp); return condition; } /***************************************** * Parse a constructor definition: * this(parameters) { body } * or postblit: * this(this) { body } * or constructor template: * this(templateparameters)(parameters) { body } * Current token is 'this'. */ AST.Dsymbol parseCtor(PrefixAttributes!AST* pAttrs) { AST.Expressions* udas = null; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); if (token.value == TOK.leftParentheses && peekNext() == TOK.this_ && peekNext2() == TOK.rightParentheses) { // this(this) { ... } nextToken(); nextToken(); check(TOK.rightParentheses); stc = parsePostfix(stc, &udas); if (stc & AST.STC.immutable_) deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit."); if (stc & AST.STC.shared_) deprecation("`shared` postblit is deprecated. Please use an unqualified postblit."); if (stc & AST.STC.const_) deprecation("`const` postblit is deprecated. Please use an unqualified postblit."); if (stc & AST.STC.static_) error(loc, "postblit cannot be `static`"); auto f = new AST.PostBlitDeclaration(loc, Loc.initial, stc, Id.postblit); AST.Dsymbol s = parseContracts(f); if (udas) { auto a = new AST.Dsymbols(); a.push(f); s = new AST.UserAttributeDeclaration(udas, a); } return s; } /* Look ahead to see if: * this(...)(...) * which is a constructor template */ AST.TemplateParameters* tpl = null; if (token.value == TOK.leftParentheses && peekPastParen(&token).value == TOK.leftParentheses) { tpl = parseTemplateParameterList(); } /* Just a regular constructor */ int varargs; AST.Parameters* parameters = parseParameters(&varargs); stc = parsePostfix(stc, &udas); if (varargs != 0 || AST.Parameter.dim(parameters) != 0) { if (stc & AST.STC.static_) error(loc, "constructor cannot be static"); } else if (StorageClass ss = stc & (AST.STC.shared_ | AST.STC.static_)) // this() { if (ss == AST.STC.static_) error(loc, "use `static this()` to declare a static constructor"); else if (ss == (AST.STC.shared_ | AST.STC.static_)) error(loc, "use `shared static this()` to declare a shared static constructor"); } AST.Expression constraint = tpl ? parseConstraint() : null; AST.Type tf = new AST.TypeFunction(parameters, null, varargs, linkage, stc); // RetrunType -> auto tf = tf.addSTC(stc); auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf); AST.Dsymbol s = parseContracts(f); if (udas) { auto a = new AST.Dsymbols(); a.push(f); s = new AST.UserAttributeDeclaration(udas, a); } if (tpl) { // Wrap a template around it auto decldefs = new AST.Dsymbols(); decldefs.push(s); s = new AST.TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs); } return s; } /***************************************** * Parse a destructor definition: * ~this() { body } * Current token is '~'. */ AST.Dsymbol parseDtor(PrefixAttributes!AST* pAttrs) { AST.Expressions* udas = null; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); check(TOK.this_); check(TOK.leftParentheses); check(TOK.rightParentheses); stc = parsePostfix(stc, &udas); if (StorageClass ss = stc & (AST.STC.shared_ | AST.STC.static_)) { if (ss == AST.STC.static_) error(loc, "use `static ~this()` to declare a static destructor"); else if (ss == (AST.STC.shared_ | AST.STC.static_)) error(loc, "use `shared static ~this()` to declare a shared static destructor"); } auto f = new AST.DtorDeclaration(loc, Loc.initial, stc, Id.dtor); AST.Dsymbol s = parseContracts(f); if (udas) { auto a = new AST.Dsymbols(); a.push(f); s = new AST.UserAttributeDeclaration(udas, a); } return s; } /***************************************** * Parse a static constructor definition: * static this() { body } * Current token is 'static'. */ AST.Dsymbol parseStaticCtor(PrefixAttributes!AST* pAttrs) { //Expressions *udas = NULL; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); nextToken(); check(TOK.leftParentheses); check(TOK.rightParentheses); stc = parsePostfix(stc & ~AST.STC.TYPECTOR, null) | stc; if (stc & AST.STC.shared_) error(loc, "use `shared static this()` to declare a shared static constructor"); else if (stc & AST.STC.static_) appendStorageClass(stc, AST.STC.static_); // complaint for the redundancy else if (StorageClass modStc = stc & AST.STC.TYPECTOR) { OutBuffer buf; AST.stcToBuffer(&buf, modStc); error(loc, "static constructor cannot be `%s`", buf.peekString()); } stc &= ~(AST.STC.static_ | AST.STC.TYPECTOR); auto f = new AST.StaticCtorDeclaration(loc, Loc.initial, stc); AST.Dsymbol s = parseContracts(f); return s; } /***************************************** * Parse a static destructor definition: * static ~this() { body } * Current token is 'static'. */ AST.Dsymbol parseStaticDtor(PrefixAttributes!AST* pAttrs) { AST.Expressions* udas = null; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); nextToken(); check(TOK.this_); check(TOK.leftParentheses); check(TOK.rightParentheses); stc = parsePostfix(stc & ~AST.STC.TYPECTOR, &udas) | stc; if (stc & AST.STC.shared_) error(loc, "use `shared static ~this()` to declare a shared static destructor"); else if (stc & AST.STC.static_) appendStorageClass(stc, AST.STC.static_); // complaint for the redundancy else if (StorageClass modStc = stc & AST.STC.TYPECTOR) { OutBuffer buf; AST.stcToBuffer(&buf, modStc); error(loc, "static destructor cannot be `%s`", buf.peekString()); } stc &= ~(AST.STC.static_ | AST.STC.TYPECTOR); auto f = new AST.StaticDtorDeclaration(loc, Loc.initial, stc); AST.Dsymbol s = parseContracts(f); if (udas) { auto a = new AST.Dsymbols(); a.push(f); s = new AST.UserAttributeDeclaration(udas, a); } return s; } /***************************************** * Parse a shared static constructor definition: * shared static this() { body } * Current token is 'shared'. */ AST.Dsymbol parseSharedStaticCtor(PrefixAttributes!AST* pAttrs) { //Expressions *udas = NULL; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); nextToken(); nextToken(); check(TOK.leftParentheses); check(TOK.rightParentheses); stc = parsePostfix(stc & ~AST.STC.TYPECTOR, null) | stc; if (StorageClass ss = stc & (AST.STC.shared_ | AST.STC.static_)) appendStorageClass(stc, ss); // complaint for the redundancy else if (StorageClass modStc = stc & AST.STC.TYPECTOR) { OutBuffer buf; AST.stcToBuffer(&buf, modStc); error(loc, "shared static constructor cannot be `%s`", buf.peekString()); } stc &= ~(AST.STC.static_ | AST.STC.TYPECTOR); auto f = new AST.SharedStaticCtorDeclaration(loc, Loc.initial, stc); AST.Dsymbol s = parseContracts(f); return s; } /***************************************** * Parse a shared static destructor definition: * shared static ~this() { body } * Current token is 'shared'. */ AST.Dsymbol parseSharedStaticDtor(PrefixAttributes!AST* pAttrs) { AST.Expressions* udas = null; const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); nextToken(); nextToken(); check(TOK.this_); check(TOK.leftParentheses); check(TOK.rightParentheses); stc = parsePostfix(stc & ~AST.STC.TYPECTOR, &udas) | stc; if (StorageClass ss = stc & (AST.STC.shared_ | AST.STC.static_)) appendStorageClass(stc, ss); // complaint for the redundancy else if (StorageClass modStc = stc & AST.STC.TYPECTOR) { OutBuffer buf; AST.stcToBuffer(&buf, modStc); error(loc, "shared static destructor cannot be `%s`", buf.peekString()); } stc &= ~(AST.STC.static_ | AST.STC.TYPECTOR); auto f = new AST.SharedStaticDtorDeclaration(loc, Loc.initial, stc); AST.Dsymbol s = parseContracts(f); if (udas) { auto a = new AST.Dsymbols(); a.push(f); s = new AST.UserAttributeDeclaration(udas, a); } return s; } /***************************************** * Parse an invariant definition: * invariant { statements... } * invariant() { statements... } * invariant (expression); * Current token is 'invariant'. */ AST.Dsymbol parseInvariant(PrefixAttributes!AST* pAttrs) { const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); if (token.value == TOK.leftParentheses) // optional () or invariant (expression); { nextToken(); if (token.value != TOK.rightParentheses) // invariant (expression); { AST.Expression e = parseAssignExp(), msg = null; if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.rightParentheses) { msg = parseAssignExp(); if (token.value == TOK.comma) nextToken(); } } check(TOK.rightParentheses); check(TOK.semicolon); e = new AST.AssertExp(loc, e, msg); auto fbody = new AST.ExpStatement(loc, e); auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody); return f; } else { nextToken(); } } auto fbody = parseStatement(ParseStatementFlags.curly); auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody); return f; } /***************************************** * Parse a unittest definition: * unittest { body } * Current token is 'unittest'. */ AST.Dsymbol parseUnitTest(PrefixAttributes!AST* pAttrs) { const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); const(char)* begPtr = token.ptr + 1; // skip '{' const(char)* endPtr = null; AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr); /** Extract unittest body as a string. Must be done eagerly since memory will be released by the lexer before doc gen. */ char* docline = null; if (global.params.doDocComments && endPtr > begPtr) { /* Remove trailing whitespaces */ for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p) { endPtr = p; } size_t len = endPtr - begPtr; if (len > 0) { docline = cast(char*)mem.xmalloc(len + 2); memcpy(docline, begPtr, len); docline[len] = '\n'; // Terminate all lines by LF docline[len + 1] = '\0'; } } auto f = new AST.UnitTestDeclaration(loc, token.loc, stc, docline); f.fbody = sbody; return f; } /***************************************** * Parse a new definition: * new(parameters) { body } * Current token is 'new'. */ AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs) { const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); int varargs; AST.Parameters* parameters = parseParameters(&varargs); auto f = new AST.NewDeclaration(loc, Loc.initial, stc, parameters, varargs); AST.Dsymbol s = parseContracts(f); return s; } /***************************************** * Parse a delete definition: * delete(parameters) { body } * Current token is 'delete'. */ AST.Dsymbol parseDelete(PrefixAttributes!AST* pAttrs) { const loc = token.loc; StorageClass stc = getStorageClass!AST(pAttrs); nextToken(); int varargs; AST.Parameters* parameters = parseParameters(&varargs); if (varargs) error("`...` not allowed in delete function parameter list"); auto f = new AST.DeleteDeclaration(loc, Loc.initial, stc, parameters); AST.Dsymbol s = parseContracts(f); return s; } /********************************************** * Parse parameter list. */ AST.Parameters* parseParameters(int* pvarargs, AST.TemplateParameters** tpl = null) { auto parameters = new AST.Parameters(); int varargs = 0; int hasdefault = 0; check(TOK.leftParentheses); while (1) { Identifier ai = null; AST.Type at; StorageClass storageClass = 0; StorageClass stc; AST.Expression ae; AST.Expressions* udas = null; for (; 1; nextToken()) { L3: switch (token.value) { case TOK.rightParentheses: break; case TOK.dotDotDot: varargs = 1; nextToken(); break; case TOK.const_: if (peek(&token).value == TOK.leftParentheses) goto default; stc = AST.STC.const_; goto L2; case TOK.immutable_: if (peek(&token).value == TOK.leftParentheses) goto default; stc = AST.STC.immutable_; goto L2; case TOK.shared_: if (peek(&token).value == TOK.leftParentheses) goto default; stc = AST.STC.shared_; goto L2; case TOK.inout_: if (peek(&token).value == TOK.leftParentheses) goto default; stc = AST.STC.wild; goto L2; case TOK.at: { AST.Expressions* exps = null; StorageClass stc2 = parseAttribute(&exps); if (stc2 == AST.STC.property || stc2 == AST.STC.nogc || stc2 == AST.STC.disable || stc2 == AST.STC.safe || stc2 == AST.STC.trusted || stc2 == AST.STC.system) { error("`@%s` attribute for function parameter is not supported", token.toChars()); } else { udas = AST.UserAttributeDeclaration.concat(udas, exps); } if (token.value == TOK.dotDotDot) error("variadic parameter cannot have user-defined attributes"); if (stc2) nextToken(); goto L3; // Don't call nextToken again. } case TOK.in_: stc = AST.STC.in_; goto L2; case TOK.out_: stc = AST.STC.out_; goto L2; case TOK.ref_: stc = AST.STC.ref_; goto L2; case TOK.lazy_: stc = AST.STC.lazy_; goto L2; case TOK.scope_: stc = AST.STC.scope_; goto L2; case TOK.final_: stc = AST.STC.final_; goto L2; case TOK.auto_: stc = AST.STC.auto_; goto L2; case TOK.return_: stc = AST.STC.return_; goto L2; L2: storageClass = appendStorageClass(storageClass, stc); continue; version (none) { case TOK.static_: stc = STC.static_; goto L2; case TOK.auto_: storageClass = STC.auto_; goto L4; case TOK.alias_: storageClass = STC.alias_; goto L4; L4: nextToken(); if (token.value == TOK.identifier) { ai = token.ident; nextToken(); } else ai = null; at = null; // no type ae = null; // no default argument if (token.value == TOK.assign) // = defaultArg { nextToken(); ae = parseDefaultInitExp(); hasdefault = 1; } else { if (hasdefault) error("default argument expected for `alias %s`", ai ? ai.toChars() : ""); } goto L3; } default: { stc = storageClass & (AST.STC.in_ | AST.STC.out_ | AST.STC.ref_ | AST.STC.lazy_); // if stc is not a power of 2 if (stc & (stc - 1) && !(stc == (AST.STC.in_ | AST.STC.ref_))) error("incompatible parameter storage classes"); //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_))) //error("scope cannot be ref or out"); if (tpl && token.value == TOK.identifier) { Token* t = peek(&token); if (t.value == TOK.comma || t.value == TOK.rightParentheses || t.value == TOK.dotDotDot) { Identifier id = Identifier.generateId("__T"); const loc = token.loc; at = new AST.TypeIdentifier(loc, id); if (!*tpl) *tpl = new AST.TemplateParameters(); AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null); (*tpl).push(tp); ai = token.ident; nextToken(); } else goto _else; } else { _else: at = parseType(&ai); } ae = null; if (token.value == TOK.assign) // = defaultArg { nextToken(); ae = parseDefaultInitExp(); hasdefault = 1; } else { if (hasdefault) error("default argument expected for `%s`", ai ? ai.toChars() : at.toChars()); } auto param = new AST.Parameter(storageClass, at, ai, ae, null); if (udas) { auto a = new AST.Dsymbols(); auto udad = new AST.UserAttributeDeclaration(udas, a); param.userAttribDecl = udad; } if (token.value == TOK.at) { AST.Expressions* exps = null; StorageClass stc2 = parseAttribute(&exps); if (stc2 == AST.STC.property || stc2 == AST.STC.nogc || stc2 == AST.STC.disable || stc2 == AST.STC.safe || stc2 == AST.STC.trusted || stc2 == AST.STC.system) { error("`@%s` attribute for function parameter is not supported", token.toChars()); } else { error("user-defined attributes cannot appear as postfixes", token.toChars()); } if (stc2) nextToken(); } if (token.value == TOK.dotDotDot) { /* This is: * at ai ... */ if (storageClass & (AST.STC.out_ | AST.STC.ref_)) error("variadic argument cannot be `out` or `ref`"); varargs = 2; parameters.push(param); nextToken(); break; } parameters.push(param); if (token.value == TOK.comma) { nextToken(); goto L1; } break; } } break; } break; L1: } check(TOK.rightParentheses); *pvarargs = varargs; return parameters; } /************************************* */ AST.EnumDeclaration parseEnum() { AST.EnumDeclaration e; Identifier id; AST.Type memtype; auto loc = token.loc; // printf("Parser::parseEnum()\n"); nextToken(); if (token.value == TOK.identifier) { id = token.ident; nextToken(); } else id = null; if (token.value == TOK.colon) { nextToken(); int alt = 0; const typeLoc = token.loc; memtype = parseBasicType(); memtype = parseDeclarator(memtype, &alt, null); checkCstyleTypeSyntax(typeLoc, memtype, alt, null); } else memtype = null; e = new AST.EnumDeclaration(loc, id, memtype); if (token.value == TOK.semicolon && id) nextToken(); else if (token.value == TOK.leftCurly) { bool isAnonymousEnum = !id; //printf("enum definition\n"); e.members = new AST.Dsymbols(); nextToken(); const(char)* comment = token.blockComment; while (token.value != TOK.rightCurly) { /* Can take the following forms... * 1. ident * 2. ident = value * 3. type ident = value * ... prefixed by valid attributes */ loc = token.loc; AST.Type type = null; Identifier ident = null; AST.Expressions* udas; StorageClass stc; AST.Expression deprecationMessage; enum attributeErrorMessage = "`%s` is not a valid attribute for enum members"; while(token.value != TOK.rightCurly && token.value != TOK.comma && token.value != TOK.assign) { switch(token.value) { case TOK.at: if (StorageClass _stc = parseAttribute(&udas)) { if (_stc == AST.STC.disable) stc |= _stc; else { OutBuffer buf; AST.stcToBuffer(&buf, _stc); error(attributeErrorMessage, buf.peekString()); } nextToken(); } break; case TOK.deprecated_: if (StorageClass _stc = parseDeprecatedAttribute(deprecationMessage)) { stc |= _stc; nextToken(); } break; case TOK.identifier: Token* tp = peek(&token); if (tp.value == TOK.assign || tp.value == TOK.comma || tp.value == TOK.rightCurly) { ident = token.ident; type = null; nextToken(); } else { goto default; } break; default: if (isAnonymousEnum) { type = parseType(&ident, null); if (type == AST.Type.terror) { type = null; nextToken(); } } else { error(attributeErrorMessage, token.toChars()); nextToken(); } break; } } if (type && type != AST.Type.terror) { if (!ident) error("no identifier for declarator `%s`", type.toChars()); if (!isAnonymousEnum) error("type only allowed if anonymous enum and no enum type"); } AST.Expression value; if (token.value == TOK.assign) { nextToken(); value = parseAssignExp(); } else { value = null; if (type && type != AST.Type.terror && isAnonymousEnum) error("if type, there must be an initializer"); } AST.UserAttributeDeclaration uad; if (udas) uad = new AST.UserAttributeDeclaration(udas, null); AST.DeprecatedDeclaration dd; if (deprecationMessage) { dd = new AST.DeprecatedDeclaration(deprecationMessage, null); stc |= AST.STC.deprecated_; } auto em = new AST.EnumMember(loc, ident, value, type, stc, uad, dd); e.members.push(em); if (token.value == TOK.rightCurly) { } else { addComment(em, comment); comment = null; check(TOK.comma); } addComment(em, comment); comment = token.blockComment; if (token.value == TOK.endOfFile) { error("premature end of file"); break; } } nextToken(); } else error("enum declaration is invalid"); //printf("-parseEnum() %s\n", e.toChars()); return e; } /******************************** * Parse struct, union, interface, class. */ AST.Dsymbol parseAggregate() { AST.TemplateParameters* tpl = null; AST.Expression constraint; const loc = token.loc; TOK tok = token.value; //printf("Parser::parseAggregate()\n"); nextToken(); Identifier id; if (token.value != TOK.identifier) { id = null; } else { id = token.ident; nextToken(); if (token.value == TOK.leftParentheses) { // struct/class template declaration. tpl = parseTemplateParameterList(); constraint = parseConstraint(); } } // Collect base class(es) AST.BaseClasses* baseclasses = null; if (token.value == TOK.colon) { if (tok != TOK.interface_ && tok != TOK.class_) error("base classes are not allowed for `%s`, did you mean `;`?", Token.toChars(tok)); nextToken(); baseclasses = parseBaseClasses(); } if (token.value == TOK.if_) { if (constraint) error("template constraints appear both before and after BaseClassList, put them before"); constraint = parseConstraint(); } if (constraint) { if (!id) error("template constraints not allowed for anonymous `%s`", Token.toChars(tok)); if (!tpl) error("template constraints only allowed for templates"); } AST.Dsymbols* members = null; if (token.value == TOK.leftCurly) { //printf("aggregate definition\n"); const lookingForElseSave = lookingForElse; lookingForElse = Loc(); nextToken(); members = parseDeclDefs(0); lookingForElse = lookingForElseSave; if (token.value != TOK.rightCurly) { /* { */ error("`}` expected following members in `%s` declaration at %s", Token.toChars(tok), loc.toChars()); } nextToken(); } else if (token.value == TOK.semicolon && id) { if (baseclasses || constraint) error("members expected"); nextToken(); } else { error("{ } expected following `%s` declaration", Token.toChars(tok)); } AST.AggregateDeclaration a; switch (tok) { case TOK.interface_: if (!id) error(loc, "anonymous interfaces not allowed"); a = new AST.InterfaceDeclaration(loc, id, baseclasses); a.members = members; break; case TOK.class_: if (!id) error(loc, "anonymous classes not allowed"); bool inObject = md && !md.packages && md.id == Id.object; a = new AST.ClassDeclaration(loc, id, baseclasses, members, inObject); break; case TOK.struct_: if (id) { bool inObject = md && !md.packages && md.id == Id.object; a = new AST.StructDeclaration(loc, id, inObject); a.members = members; } else { /* Anonymous structs/unions are more like attributes. */ assert(!tpl); return new AST.AnonDeclaration(loc, false, members); } break; case TOK.union_: if (id) { a = new AST.UnionDeclaration(loc, id); a.members = members; } else { /* Anonymous structs/unions are more like attributes. */ assert(!tpl); return new AST.AnonDeclaration(loc, true, members); } break; default: assert(0); } if (tpl) { // Wrap a template around the aggregate declaration auto decldefs = new AST.Dsymbols(); decldefs.push(a); auto tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs); return tempdecl; } return a; } /******************************************* */ AST.BaseClasses* parseBaseClasses() { auto baseclasses = new AST.BaseClasses(); for (; 1; nextToken()) { auto b = new AST.BaseClass(parseBasicType()); baseclasses.push(b); if (token.value != TOK.comma) break; } return baseclasses; } AST.Dsymbols* parseImport() { auto decldefs = new AST.Dsymbols(); Identifier aliasid = null; int isstatic = token.value == TOK.static_; if (isstatic) nextToken(); //printf("Parser::parseImport()\n"); do { L1: nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `import`"); break; } const loc = token.loc; Identifier id = token.ident; AST.Identifiers* a = null; nextToken(); if (!aliasid && token.value == TOK.assign) { aliasid = id; goto L1; } while (token.value == TOK.dot) { if (!a) a = new AST.Identifiers(); a.push(id); nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `package`"); break; } id = token.ident; nextToken(); } auto s = new AST.Import(loc, a, id, aliasid, isstatic); decldefs.push(s); /* Look for * : alias=name, alias=name; * syntax. */ if (token.value == TOK.colon) { do { nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `:`"); break; } Identifier _alias = token.ident; Identifier name; nextToken(); if (token.value == TOK.assign) { nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `%s=`", _alias.toChars()); break; } name = token.ident; nextToken(); } else { name = _alias; _alias = null; } s.addAlias(name, _alias); } while (token.value == TOK.comma); break; // no comma-separated imports of this form } aliasid = null; } while (token.value == TOK.comma); if (token.value == TOK.semicolon) nextToken(); else { error("`;` expected"); nextToken(); } return decldefs; } AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null) { /* Take care of the storage class prefixes that * serve as type attributes: * const type * immutable type * shared type * inout type * inout const type * shared const type * shared inout type * shared inout const type */ StorageClass stc = 0; while (1) { switch (token.value) { case TOK.const_: if (peekNext() == TOK.leftParentheses) break; // const as type constructor stc |= AST.STC.const_; // const as storage class nextToken(); continue; case TOK.immutable_: if (peekNext() == TOK.leftParentheses) break; stc |= AST.STC.immutable_; nextToken(); continue; case TOK.shared_: if (peekNext() == TOK.leftParentheses) break; stc |= AST.STC.shared_; nextToken(); continue; case TOK.inout_: if (peekNext() == TOK.leftParentheses) break; stc |= AST.STC.wild; nextToken(); continue; default: break; } break; } const typeLoc = token.loc; AST.Type t; t = parseBasicType(); int alt = 0; t = parseDeclarator(t, &alt, pident, ptpl); checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null); t = t.addSTC(stc); return t; } AST.Type parseBasicType(bool dontLookDotIdents = false) { AST.Type t; Loc loc; Identifier id; //printf("parseBasicType()\n"); switch (token.value) { case TOK.void_: t = AST.Type.tvoid; goto LabelX; case TOK.int8: t = AST.Type.tint8; goto LabelX; case TOK.uns8: t = AST.Type.tuns8; goto LabelX; case TOK.int16: t = AST.Type.tint16; goto LabelX; case TOK.uns16: t = AST.Type.tuns16; goto LabelX; case TOK.int32: t = AST.Type.tint32; goto LabelX; case TOK.uns32: t = AST.Type.tuns32; goto LabelX; case TOK.int64: t = AST.Type.tint64; nextToken(); if (token.value == TOK.int64) // if `long long` { error("use `long` for a 64 bit integer instead of `long long`"); nextToken(); } else if (token.value == TOK.float64) // if `long double` { error("use `real` instead of `long double`"); t = AST.Type.tfloat80; nextToken(); } break; case TOK.uns64: t = AST.Type.tuns64; goto LabelX; case TOK.int128: t = AST.Type.tint128; goto LabelX; case TOK.uns128: t = AST.Type.tuns128; goto LabelX; case TOK.float32: t = AST.Type.tfloat32; goto LabelX; case TOK.float64: t = AST.Type.tfloat64; goto LabelX; case TOK.float80: t = AST.Type.tfloat80; goto LabelX; case TOK.imaginary32: t = AST.Type.timaginary32; goto LabelX; case TOK.imaginary64: t = AST.Type.timaginary64; goto LabelX; case TOK.imaginary80: t = AST.Type.timaginary80; goto LabelX; case TOK.complex32: t = AST.Type.tcomplex32; goto LabelX; case TOK.complex64: t = AST.Type.tcomplex64; goto LabelX; case TOK.complex80: t = AST.Type.tcomplex80; goto LabelX; case TOK.bool_: t = AST.Type.tbool; goto LabelX; case TOK.char_: t = AST.Type.tchar; goto LabelX; case TOK.wchar_: t = AST.Type.twchar; goto LabelX; case TOK.dchar_: t = AST.Type.tdchar; goto LabelX; LabelX: nextToken(); break; case TOK.this_: case TOK.super_: case TOK.identifier: loc = token.loc; id = token.ident; nextToken(); if (token.value == TOK.not) { // ident!(template_arguments) auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments()); t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents); } else { t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents); } break; case TOK.dot: // Leading . as in .foo t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents); break; case TOK.typeof_: // typeof(expression) t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents); break; case TOK.vector: t = parseVector(); break; case TOK.const_: // const(type) nextToken(); check(TOK.leftParentheses); t = parseType().addSTC(AST.STC.const_); check(TOK.rightParentheses); break; case TOK.immutable_: // immutable(type) nextToken(); check(TOK.leftParentheses); t = parseType().addSTC(AST.STC.immutable_); check(TOK.rightParentheses); break; case TOK.shared_: // shared(type) nextToken(); check(TOK.leftParentheses); t = parseType().addSTC(AST.STC.shared_); check(TOK.rightParentheses); break; case TOK.inout_: // wild(type) nextToken(); check(TOK.leftParentheses); t = parseType().addSTC(AST.STC.wild); check(TOK.rightParentheses); break; default: error("basic type expected, not `%s`", token.toChars()); if (token.value == TOK.else_) errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); t = AST.Type.terror; break; } return t; } AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents) { AST.Type maybeArray = null; // See https://issues.dlang.org/show_bug.cgi?id=1215 // A basic type can look like MyType (typical case), but also: // MyType.T -> A type // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple) // MyType[expr].T -> A type. // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type // (iif MyType[expr].T is a Ttuple) while (1) { switch (token.value) { case TOK.dot: { nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `.` instead of `%s`", token.toChars()); break; } if (maybeArray) { // This is actually a TypeTuple index, not an {a/s}array. // We need to have a while loop to unwind all index taking: // T[e1][e2].U -> T, addIndex(e1), addIndex(e2) AST.Objects dimStack; AST.Type t = maybeArray; while (true) { if (t.ty == AST.Tsarray) { // The index expression is an Expression. AST.TypeSArray a = cast(AST.TypeSArray)t; dimStack.push(a.dim.syntaxCopy()); t = a.next.syntaxCopy(); } else if (t.ty == AST.Taarray) { // The index expression is a Type. It will be interpreted as an expression at semantic time. AST.TypeAArray a = cast(AST.TypeAArray)t; dimStack.push(a.index.syntaxCopy()); t = a.next.syntaxCopy(); } else { break; } } assert(dimStack.dim > 0); // We're good. Replay indices in the reverse order. tid = cast(AST.TypeQualified)t; while (dimStack.dim) { tid.addIndex(dimStack.pop()); } maybeArray = null; } const loc = token.loc; Identifier id = token.ident; nextToken(); if (token.value == TOK.not) { auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments()); tid.addInst(tempinst); } else tid.addIdent(id); continue; } case TOK.leftBracket: { if (dontLookDotIdents) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911 goto Lend; nextToken(); AST.Type t = maybeArray ? maybeArray : cast(AST.Type)tid; if (token.value == TOK.rightBracket) { // It's a dynamic array, and we're done: // T[].U does not make sense. t = new AST.TypeDArray(t); nextToken(); return t; } else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null)) { // This can be one of two things: // 1 - an associative array declaration, T[type] // 2 - an associative array declaration, T[expr] // These can only be disambiguated later. AST.Type index = parseType(); // [ type ] maybeArray = new AST.TypeAArray(t, index); check(TOK.rightBracket); } else { // This can be one of three things: // 1 - an static array declaration, T[expr] // 2 - a slice, T[expr .. expr] // 3 - a template parameter pack index expression, T[expr].U // 1 and 3 can only be disambiguated later. //printf("it's type[expression]\n"); inBrackets++; AST.Expression e = parseAssignExp(); // [ expression ] if (token.value == TOK.slice) { // It's a slice, and we're done. nextToken(); AST.Expression e2 = parseAssignExp(); // [ exp .. exp ] t = new AST.TypeSlice(t, e, e2); inBrackets--; check(TOK.rightBracket); return t; } else { maybeArray = new AST.TypeSArray(t, e); inBrackets--; check(TOK.rightBracket); continue; } } break; } default: goto Lend; } } Lend: return maybeArray ? maybeArray : cast(AST.Type)tid; } /****************************************** * Parse things that follow the initial type t. * t * * t [] * t [type] * t [expression] * t [expression .. expression] * t function * t delegate */ AST.Type parseBasicType2(AST.Type t) { //printf("parseBasicType2()\n"); while (1) { switch (token.value) { case TOK.mul: t = new AST.TypePointer(t); nextToken(); continue; case TOK.leftBracket: // Handle []. Make sure things like // int[3][1] a; // is (array[1] of array[3] of int) nextToken(); if (token.value == TOK.rightBracket) { t = new AST.TypeDArray(t); // [] nextToken(); } else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null)) { // It's an associative array declaration //printf("it's an associative array\n"); AST.Type index = parseType(); // [ type ] t = new AST.TypeAArray(t, index); check(TOK.rightBracket); } else { //printf("it's type[expression]\n"); inBrackets++; AST.Expression e = parseAssignExp(); // [ expression ] if (token.value == TOK.slice) { nextToken(); AST.Expression e2 = parseAssignExp(); // [ exp .. exp ] t = new AST.TypeSlice(t, e, e2); } else { t = new AST.TypeSArray(t, e); } inBrackets--; check(TOK.rightBracket); } continue; case TOK.delegate_: case TOK.function_: { // Handle delegate declaration: // t delegate(parameter list) nothrow pure // t function(parameter list) nothrow pure TOK save = token.value; nextToken(); int varargs; AST.Parameters* parameters = parseParameters(&varargs); StorageClass stc = parsePostfix(AST.STC.undefined_, null); auto tf = new AST.TypeFunction(parameters, t, varargs, linkage, stc); if (stc & (AST.STC.const_ | AST.STC.immutable_ | AST.STC.shared_ | AST.STC.wild | AST.STC.return_)) { if (save == TOK.function_) error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions"); else tf = cast(AST.TypeFunction)tf.addSTC(stc); } if (save == TOK.delegate_) t = new AST.TypeDelegate(tf); else t = new AST.TypePointer(tf); // pointer to function continue; } default: return t; } assert(0); } assert(0); } AST.Type parseDeclarator(AST.Type t, int* palt, Identifier* pident, AST.TemplateParameters** tpl = null, StorageClass storageClass = 0, int* pdisable = null, AST.Expressions** pudas = null) { //printf("parseDeclarator(tpl = %p)\n", tpl); t = parseBasicType2(t); AST.Type ts; switch (token.value) { case TOK.identifier: if (pident) *pident = token.ident; else error("unexpected identifier `%s` in declarator", token.ident.toChars()); ts = t; nextToken(); break; case TOK.leftParentheses: { // like: T (*fp)(); // like: T ((*fp))(); if (peekNext() == TOK.mul || peekNext() == TOK.leftParentheses) { /* Parse things with parentheses around the identifier, like: * int (*ident[3])[] * although the D style would be: * int[]*[3] ident */ *palt |= 1; nextToken(); ts = parseDeclarator(t, palt, pident); check(TOK.rightParentheses); break; } ts = t; Token* peekt = &token; /* Completely disallow C-style things like: * T (a); * Improve error messages for the common bug of a missing return type * by looking to see if (a) looks like a parameter list. */ if (isParameters(&peekt)) { error("function declaration without return type. (Note that constructors are always named `this`)"); } else error("unexpected `(` in declarator"); break; } default: ts = t; break; } // parse DeclaratorSuffixes while (1) { switch (token.value) { static if (CARRAYDECL) { /* Support C style array syntax: * int ident[] * as opposed to D-style: * int[] ident */ case TOK.leftBracket: { // This is the old C-style post [] syntax. AST.TypeNext ta; nextToken(); if (token.value == TOK.rightBracket) { // It's a dynamic array ta = new AST.TypeDArray(t); // [] nextToken(); *palt |= 2; } else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null)) { // It's an associative array //printf("it's an associative array\n"); AST.Type index = parseType(); // [ type ] check(TOK.rightBracket); ta = new AST.TypeAArray(t, index); *palt |= 2; } else { //printf("It's a static array\n"); AST.Expression e = parseAssignExp(); // [ expression ] ta = new AST.TypeSArray(t, e); check(TOK.rightBracket); *palt |= 2; } /* Insert ta into * ts -> ... -> t * so that * ts -> ... -> ta -> t */ AST.Type* pt; for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) { } *pt = ta; continue; } } case TOK.leftParentheses: { if (tpl) { Token* tk = peekPastParen(&token); if (tk.value == TOK.leftParentheses) { /* Look ahead to see if this is (...)(...), * i.e. a function template declaration */ //printf("function template declaration\n"); // Gather template parameter list *tpl = parseTemplateParameterList(); } else if (tk.value == TOK.assign) { /* or (...) =, * i.e. a variable template declaration */ //printf("variable template declaration\n"); *tpl = parseTemplateParameterList(); break; } } int varargs; AST.Parameters* parameters = parseParameters(&varargs); /* Parse const/immutable/shared/inout/nothrow/pure/return postfix */ // merge prefix storage classes StorageClass stc = parsePostfix(storageClass, pudas); AST.Type tf = new AST.TypeFunction(parameters, t, varargs, linkage, stc); tf = tf.addSTC(stc); if (pdisable) *pdisable = stc & AST.STC.disable ? 1 : 0; /* Insert tf into * ts -> ... -> t * so that * ts -> ... -> tf -> t */ AST.Type* pt; for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next) { } *pt = tf; break; } default: break; } break; } return ts; } void parseStorageClasses(ref StorageClass storage_class, ref LINK link, ref bool setAlignment, ref AST.Expression ealign, ref AST.Expressions* udas) { StorageClass stc; bool sawLinkage = false; // seen a linkage declaration while (1) { switch (token.value) { case TOK.const_: if (peek(&token).value == TOK.leftParentheses) break; // const as type constructor stc = AST.STC.const_; // const as storage class goto L1; case TOK.immutable_: if (peek(&token).value == TOK.leftParentheses) break; stc = AST.STC.immutable_; goto L1; case TOK.shared_: if (peek(&token).value == TOK.leftParentheses) break; stc = AST.STC.shared_; goto L1; case TOK.inout_: if (peek(&token).value == TOK.leftParentheses) break; stc = AST.STC.wild; goto L1; case TOK.static_: stc = AST.STC.static_; goto L1; case TOK.final_: stc = AST.STC.final_; goto L1; case TOK.auto_: stc = AST.STC.auto_; goto L1; case TOK.scope_: stc = AST.STC.scope_; goto L1; case TOK.override_: stc = AST.STC.override_; goto L1; case TOK.abstract_: stc = AST.STC.abstract_; goto L1; case TOK.synchronized_: stc = AST.STC.synchronized_; goto L1; case TOK.deprecated_: stc = AST.STC.deprecated_; goto L1; case TOK.nothrow_: stc = AST.STC.nothrow_; goto L1; case TOK.pure_: stc = AST.STC.pure_; goto L1; case TOK.ref_: stc = AST.STC.ref_; goto L1; case TOK.gshared: stc = AST.STC.gshared; goto L1; case TOK.enum_: { Token* t = peek(&token); if (t.value == TOK.leftCurly || t.value == TOK.colon) break; else if (t.value == TOK.identifier) { t = peek(t); if (t.value == TOK.leftCurly || t.value == TOK.colon || t.value == TOK.semicolon) break; } stc = AST.STC.manifest; goto L1; } case TOK.at: { stc = parseAttribute(&udas); if (stc) goto L1; continue; } L1: storage_class = appendStorageClass(storage_class, stc); nextToken(); continue; case TOK.extern_: { if (peek(&token).value != TOK.leftParentheses) { stc = AST.STC.extern_; goto L1; } if (sawLinkage) error("redundant linkage declaration"); sawLinkage = true; AST.Identifiers* idents = null; CPPMANGLE cppmangle; bool cppMangleOnly = false; link = parseLinkage(&idents, cppmangle, cppMangleOnly); if (idents) { error("C++ name spaces not allowed here"); } if (cppmangle != CPPMANGLE.def) { error("C++ mangle declaration not allowed here"); } continue; } case TOK.align_: { nextToken(); setAlignment = true; if (token.value == TOK.leftParentheses) { nextToken(); ealign = parseExpression(); check(TOK.rightParentheses); } continue; } default: break; } break; } } /********************************** * Parse Declarations. * These can be: * 1. declarations at global/class level * 2. declarations at statement level * Return array of Declaration *'s. */ AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment) { StorageClass storage_class = AST.STC.undefined_; AST.Type ts; AST.Type t; AST.Type tfirst; Identifier ident; TOK tok = TOK.reserved; LINK link = linkage; bool setAlignment = false; AST.Expression ealign; auto loc = token.loc; AST.Expressions* udas = null; Token* tk; //printf("parseDeclarations() %s\n", token.toChars()); if (!comment) comment = token.blockComment; if (autodecl) { ts = null; // infer type goto L2; } if (token.value == TOK.alias_) { tok = token.value; nextToken(); /* Look for: * alias identifier this; */ if (token.value == TOK.identifier && peekNext() == TOK.this_) { auto s = new AST.AliasThis(loc, token.ident); nextToken(); check(TOK.this_); check(TOK.semicolon); auto a = new AST.Dsymbols(); a.push(s); addComment(s, comment); return a; } version (none) { /* Look for: * alias this = identifier; */ if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier) { check(TOK.this_); check(TOK.assign); auto s = new AliasThis(loc, token.ident); nextToken(); check(TOK.semicolon); auto a = new Dsymbols(); a.push(s); addComment(s, comment); return a; } } /* Look for: * alias identifier = type; * alias identifier(...) = type; */ if (token.value == TOK.identifier && skipParensIf(peek(&token), &tk) && tk.value == TOK.assign) { auto a = new AST.Dsymbols(); while (1) { ident = token.ident; nextToken(); AST.TemplateParameters* tpl = null; if (token.value == TOK.leftParentheses) tpl = parseTemplateParameterList(); check(TOK.assign); bool hasParsedAttributes; void parseAttributes() { if (hasParsedAttributes) // only parse once return; hasParsedAttributes = true; udas = null; storage_class = AST.STC.undefined_; link = linkage; setAlignment = false; ealign = null; parseStorageClasses(storage_class, link, setAlignment, ealign, udas); } if (token.value == TOK.at) parseAttributes; AST.Declaration v; if (token.value == TOK.function_ || token.value == TOK.delegate_ || token.value == TOK.leftParentheses && skipAttributes(peekPastParen(&token), &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) || token.value == TOK.leftCurly || token.value == TOK.identifier && peekNext() == TOK.goesTo ) { // function (parameters) { statements... } // delegate (parameters) { statements... } // (parameters) { statements... } // (parameters) => expression // { statements... } // identifier => expression AST.Dsymbol s = parseFunctionLiteral(); if (udas !is null) { if (storage_class != 0) error("Cannot put a storage-class in an alias declaration."); // parseAttributes shouldn't have set these variables assert(link == linkage && !setAlignment && ealign is null); auto tpl_ = cast(AST.TemplateDeclaration) s; assert(tpl_ !is null && tpl_.members.dim == 1); auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0]; auto tf = cast(AST.TypeFunction) fd.type; assert(tf.parameters.dim > 0); auto as = new AST.Dsymbols(); (*tf.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as); } v = new AST.AliasDeclaration(loc, ident, s); } else { parseAttributes(); // StorageClasses type if (udas) error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok)); t = parseType(); v = new AST.AliasDeclaration(loc, ident, t); } v.storage_class = storage_class; AST.Dsymbol s = v; if (tpl) { auto a2 = new AST.Dsymbols(); a2.push(s); auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2); s = tempdecl; } if (link != linkage) { auto a2 = new AST.Dsymbols(); a2.push(s); s = new AST.LinkDeclaration(link, a2); } a.push(s); switch (token.value) { case TOK.semicolon: nextToken(); addComment(s, comment); break; case TOK.comma: nextToken(); addComment(s, comment); if (token.value != TOK.identifier) { error("identifier expected following comma, not `%s`", token.toChars()); break; } if (peekNext() != TOK.assign && peekNext() != TOK.leftParentheses) { error("`=` expected following identifier"); nextToken(); break; } continue; default: error("semicolon expected to close `%s` declaration", Token.toChars(tok)); break; } break; } return a; } // alias StorageClasses type ident; } parseStorageClasses(storage_class, link, setAlignment, ealign, udas); if (token.value == TOK.enum_) { AST.Dsymbol d = parseEnum(); auto a = new AST.Dsymbols(); a.push(d); if (udas) { d = new AST.UserAttributeDeclaration(udas, a); a = new AST.Dsymbols(); a.push(d); } addComment(d, comment); return a; } else if (token.value == TOK.struct_ || token.value == TOK.union_ || token.value == TOK.class_ || token.value == TOK.interface_) { AST.Dsymbol s = parseAggregate(); auto a = new AST.Dsymbols(); a.push(s); if (storage_class) { s = new AST.StorageClassDeclaration(storage_class, a); a = new AST.Dsymbols(); a.push(s); } if (setAlignment) { s = new AST.AlignDeclaration(s.loc, ealign, a); a = new AST.Dsymbols(); a.push(s); } if (link != linkage) { s = new AST.LinkDeclaration(link, a); a = new AST.Dsymbols(); a.push(s); } if (udas) { s = new AST.UserAttributeDeclaration(udas, a); a = new AST.Dsymbols(); a.push(s); } addComment(s, comment); return a; } /* Look for auto initializers: * storage_class identifier = initializer; * storage_class identifier(...) = initializer; */ if ((storage_class || udas) && token.value == TOK.identifier && skipParensIf(peek(&token), &tk) && tk.value == TOK.assign) { AST.Dsymbols* a = parseAutoDeclarations(storage_class, comment); if (udas) { AST.Dsymbol s = new AST.UserAttributeDeclaration(udas, a); a = new AST.Dsymbols(); a.push(s); } return a; } /* Look for return type inference for template functions. */ if ((storage_class || udas) && token.value == TOK.identifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) && (tk.value == TOK.leftParentheses || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { ts = null; } else { ts = parseBasicType(); ts = parseBasicType2(ts); } L2: tfirst = null; auto a = new AST.Dsymbols(); if (pAttrs) { storage_class |= pAttrs.storageClass; //pAttrs.storageClass = STC.undefined_; } while (1) { AST.TemplateParameters* tpl = null; int disable; int alt = 0; loc = token.loc; ident = null; t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas); assert(t); if (!tfirst) tfirst = t; else if (t != tfirst) error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); bool isThis = (t.ty == AST.Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign); if (ident) checkCstyleTypeSyntax(loc, t, alt, ident); else if (!isThis && (t != AST.Type.terror)) error("no identifier for declarator `%s`", t.toChars()); if (tok == TOK.alias_) { AST.Declaration v; AST.Initializer _init = null; /* Aliases can no longer have multiple declarators, storage classes, * linkages, or auto declarations. * These never made any sense, anyway. * The code below needs to be fixed to reject them. * The grammar has already been fixed to preclude them. */ if (udas) error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok)); if (token.value == TOK.assign) { nextToken(); _init = parseInitializer(); } if (_init) { if (isThis) error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); else error("alias cannot have initializer"); } v = new AST.AliasDeclaration(loc, ident, t); v.storage_class = storage_class; if (pAttrs) { /* AliasDeclaration distinguish @safe, @system, @trusted attributes * on prefix and postfix. * @safe alias void function() FP1; * alias @safe void function() FP2; // FP2 is not @safe * alias void function() @safe FP3; */ pAttrs.storageClass &= (AST.STC.safe | AST.STC.system | AST.STC.trusted); } AST.Dsymbol s = v; if (link != linkage) { auto ax = new AST.Dsymbols(); ax.push(v); s = new AST.LinkDeclaration(link, ax); } a.push(s); switch (token.value) { case TOK.semicolon: nextToken(); addComment(s, comment); break; case TOK.comma: nextToken(); addComment(s, comment); continue; default: error("semicolon expected to close `%s` declaration", Token.toChars(tok)); break; } } else if (t.ty == AST.Tfunction) { AST.Expression constraint = null; //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class); auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? AST.STC.disable : 0), t); if (pAttrs) pAttrs.storageClass = AST.STC.undefined_; if (tpl) constraint = parseConstraint(); AST.Dsymbol s = parseContracts(f); auto tplIdent = s.ident; if (link != linkage) { auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.LinkDeclaration(link, ax); } if (udas) { auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.UserAttributeDeclaration(udas, ax); } /* A template parameter list means it's a function template */ if (tpl) { // Wrap a template around the function declaration auto decldefs = new AST.Dsymbols(); decldefs.push(s); auto tempdecl = new AST.TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs); s = tempdecl; if (storage_class & AST.STC.static_) { assert(f.storage_class & AST.STC.static_); f.storage_class &= ~AST.STC.static_; auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.StorageClassDeclaration(AST.STC.static_, ax); } } a.push(s); addComment(s, comment); } else if (ident) { AST.Initializer _init = null; if (token.value == TOK.assign) { nextToken(); _init = parseInitializer(); } auto v = new AST.VarDeclaration(loc, t, ident, _init); v.storage_class = storage_class; if (pAttrs) pAttrs.storageClass = AST.STC.undefined_; AST.Dsymbol s = v; if (tpl && _init) { auto a2 = new AST.Dsymbols(); a2.push(s); auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0); s = tempdecl; } if (setAlignment) { auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.AlignDeclaration(v.loc, ealign, ax); } if (link != linkage) { auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.LinkDeclaration(link, ax); } if (udas) { auto ax = new AST.Dsymbols(); ax.push(s); s = new AST.UserAttributeDeclaration(udas, ax); } a.push(s); switch (token.value) { case TOK.semicolon: nextToken(); addComment(s, comment); break; case TOK.comma: nextToken(); addComment(s, comment); continue; default: error("semicolon expected, not `%s`", token.toChars()); break; } } break; } return a; } AST.Dsymbol parseFunctionLiteral() { const loc = token.loc; AST.TemplateParameters* tpl = null; AST.Parameters* parameters = null; int varargs = 0; AST.Type tret = null; StorageClass stc = 0; TOK save = TOK.reserved; switch (token.value) { case TOK.function_: case TOK.delegate_: save = token.value; nextToken(); if (token.value != TOK.leftParentheses && token.value != TOK.leftCurly) { // function type (parameters) { statements... } // delegate type (parameters) { statements... } tret = parseBasicType(); tret = parseBasicType2(tret); // function return type } if (token.value == TOK.leftParentheses) { // function (parameters) { statements... } // delegate (parameters) { statements... } } else { // function { statements... } // delegate { statements... } break; } goto case TOK.leftParentheses; case TOK.leftParentheses: { // (parameters) => expression // (parameters) { statements... } parameters = parseParameters(&varargs, &tpl); stc = parsePostfix(AST.STC.undefined_, null); if (StorageClass modStc = stc & AST.STC.TYPECTOR) { if (save == TOK.function_) { OutBuffer buf; AST.stcToBuffer(&buf, modStc); error("function literal cannot be `%s`", buf.peekString()); } else save = TOK.delegate_; } break; } case TOK.leftCurly: // { statements... } break; case TOK.identifier: { // identifier => expression parameters = new AST.Parameters(); Identifier id = Identifier.generateId("__T"); AST.Type t = new AST.TypeIdentifier(loc, id); parameters.push(new AST.Parameter(0, t, token.ident, null, null)); tpl = new AST.TemplateParameters(); AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null); tpl.push(tp); nextToken(); break; } default: assert(0); } if (!parameters) parameters = new AST.Parameters(); auto tf = new AST.TypeFunction(parameters, tret, varargs, linkage, stc); tf = cast(AST.TypeFunction)tf.addSTC(stc); auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null); if (token.value == TOK.goesTo) { check(TOK.goesTo); const returnloc = token.loc; AST.Expression ae = parseAssignExp(); fd.fbody = new AST.ReturnStatement(returnloc, ae); fd.endloc = token.loc; } else { parseContracts(fd); } if (tpl) { // Wrap a template around function fd auto decldefs = new AST.Dsymbols(); decldefs.push(fd); return new AST.TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs, false, true); } else return fd; } /***************************************** * Parse contracts following function declaration. */ AST.FuncDeclaration parseContracts(AST.FuncDeclaration f) { LINK linksave = linkage; bool literal = f.isFuncLiteralDeclaration() !is null; // The following is irrelevant, as it is overridden by sc.linkage in // TypeFunction::semantic linkage = LINK.d; // nested functions have D linkage bool requireDo = false; L1: switch (token.value) { case TOK.leftCurly: if (requireDo) error("missing `do { ... }` after `in` or `out`"); f.fbody = parseStatement(ParseStatementFlags.semi); f.endloc = endloc; break; case TOK.identifier: if (token.ident == Id._body) goto case TOK.do_; goto default; case TOK.do_: nextToken(); f.fbody = parseStatement(ParseStatementFlags.curly); f.endloc = endloc; break; version (none) { // Do we want this for function declarations, so we can do: // int x, y, foo(), z; case TOK.comma: nextToken(); continue; } version (none) { // Dumped feature case TOK.throw_: if (!f.fthrows) f.fthrows = new Types(); nextToken(); check(TOK.leftParentheses); while (1) { Type tb = parseBasicType(); f.fthrows.push(tb); if (token.value == TOK.comma) { nextToken(); continue; } break; } check(TOK.rightParentheses); goto L1; } case TOK.in_: // in { statements... } // in (expression) auto loc = token.loc; nextToken(); if (!f.frequires) { f.frequires = new AST.Statements; } if (token.value == TOK.leftParentheses) { nextToken(); AST.Expression e = parseAssignExp(), msg = null; if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.rightParentheses) { msg = parseAssignExp(); if (token.value == TOK.comma) nextToken(); } } check(TOK.rightParentheses); e = new AST.AssertExp(loc, e, msg); f.frequires.push(new AST.ExpStatement(loc, e)); requireDo = false; } else { f.frequires.push(parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_)); requireDo = true; } goto L1; case TOK.out_: // out { statements... } // out (; expression) // out (identifier) { statements... } // out (identifier; expression) auto loc = token.loc; nextToken(); if (!f.fensures) { f.fensures = new AST.Ensures; } Identifier id = null; if (token.value != TOK.leftCurly) { check(TOK.leftParentheses); if (token.value != TOK.identifier && token.value != TOK.semicolon) error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars()); if (token.value != TOK.semicolon) { id = token.ident; nextToken(); } if (token.value == TOK.semicolon) { nextToken(); AST.Expression e = parseAssignExp(), msg = null; if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.rightParentheses) { msg = parseAssignExp(); if (token.value == TOK.comma) nextToken(); } } check(TOK.rightParentheses); e = new AST.AssertExp(loc, e, msg); f.fensures.push(AST.Ensure(id, new AST.ExpStatement(loc, e))); requireDo = false; goto L1; } check(TOK.rightParentheses); } f.fensures.push(AST.Ensure(id, parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_))); requireDo = true; goto L1; case TOK.semicolon: if (!literal) { // https://issues.dlang.org/show_bug.cgi?id=15799 // Semicolon becomes a part of function declaration // only when 'do' is not required if (!requireDo) nextToken(); break; } goto default; default: if (literal) { const(char)* sbody = requireDo ? "do " : ""; error("missing `%s{ ... }` for function literal", sbody); } else if (!requireDo) // allow contracts even with no body { TOK t = token.value; if (t == TOK.const_ || t == TOK.immutable_ || t == TOK.inout_ || t == TOK.return_ || t == TOK.shared_ || t == TOK.nothrow_ || t == TOK.pure_) error("'%s' cannot be placed after a template constraint", token.toChars); else if (t == TOK.at) error("attributes cannot be placed after a template constraint"); else if (t == TOK.if_) error("cannot use function constraints for non-template functions. Use `static if` instead"); else error("semicolon expected following function declaration"); } break; } if (literal && !f.fbody) { // Set empty function body for error recovery f.fbody = new AST.CompoundStatement(Loc.initial, cast(AST.Statement)null); } linkage = linksave; return f; } /***************************************** */ void checkDanglingElse(Loc elseloc) { if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0) { warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); } } void checkCstyleTypeSyntax(Loc loc, AST.Type t, int alt, Identifier ident) { if (!alt) return; const(char)* sp = !ident ? "" : " "; const(char)* s = !ident ? "" : ident.toChars(); error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t.toChars(), sp, s); } /***************************************** * Determines additional argument types for parseForeach. */ private template ParseForeachArgs(bool isStatic, bool isDecl) { static alias Seq(T...) = T; static if(isDecl) { alias ParseForeachArgs = Seq!(AST.Dsymbol*); } else { alias ParseForeachArgs = Seq!(); } } /***************************************** * Determines the result type for parseForeach. */ private template ParseForeachRet(bool isStatic, bool isDecl) { static if(!isStatic) { alias ParseForeachRet = AST.Statement; } else static if(isDecl) { alias ParseForeachRet = AST.StaticForeachDeclaration; } else { alias ParseForeachRet = AST.StaticForeachStatement; } } /***************************************** * Parses `foreach` statements, `static foreach` statements and * `static foreach` declarations. The template parameter * `isStatic` is true, iff a `static foreach` should be parsed. * If `isStatic` is true, `isDecl` can be true to indicate that a * `static foreach` declaration should be parsed. */ ParseForeachRet!(isStatic, isDecl) parseForeach(bool isStatic, bool isDecl)(Loc loc, ParseForeachArgs!(isStatic, isDecl) args) { static if(isDecl) { static assert(isStatic); } static if(isStatic) { nextToken(); static if(isDecl) auto pLastDecl = args[0]; } TOK op = token.value; nextToken(); check(TOK.leftParentheses); auto parameters = new AST.Parameters(); while (1) { Identifier ai = null; AST.Type at; StorageClass storageClass = 0; StorageClass stc = 0; Lagain: if (stc) { storageClass = appendStorageClass(storageClass, stc); nextToken(); } switch (token.value) { case TOK.ref_: stc = AST.STC.ref_; goto Lagain; case TOK.enum_: stc = AST.STC.manifest; goto Lagain; case TOK.alias_: storageClass = appendStorageClass(storageClass, AST.STC.alias_); nextToken(); break; case TOK.const_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.const_; goto Lagain; } break; case TOK.immutable_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.immutable_; goto Lagain; } break; case TOK.shared_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.shared_; goto Lagain; } break; case TOK.inout_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.wild; goto Lagain; } break; default: break; } if (token.value == TOK.identifier) { Token* t = peek(&token); if (t.value == TOK.comma || t.value == TOK.semicolon) { ai = token.ident; at = null; // infer argument type nextToken(); goto Larg; } } at = parseType(&ai); if (!ai) error("no identifier for declarator `%s`", at.toChars()); Larg: auto p = new AST.Parameter(storageClass, at, ai, null, null); parameters.push(p); if (token.value == TOK.comma) { nextToken(); continue; } break; } check(TOK.semicolon); AST.Expression aggr = parseExpression(); if (token.value == TOK.slice && parameters.dim == 1) { AST.Parameter p = (*parameters)[0]; nextToken(); AST.Expression upr = parseExpression(); check(TOK.rightParentheses); Loc endloc; static if (!isDecl) { AST.Statement _body = parseStatement(0, null, &endloc); } else { AST.Statement _body = null; } auto rangefe = new AST.ForeachRangeStatement(loc, op, p, aggr, upr, _body, endloc); static if (!isStatic) { return rangefe; } else static if(isDecl) { return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, null, rangefe), parseBlock(pLastDecl)); } else { return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, null, rangefe)); } } else { check(TOK.rightParentheses); Loc endloc; static if (!isDecl) { AST.Statement _body = parseStatement(0, null, &endloc); } else { AST.Statement _body = null; } auto aggrfe = new AST.ForeachStatement(loc, op, parameters, aggr, _body, endloc); static if(!isStatic) { return aggrfe; } else static if(isDecl) { return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, aggrfe, null), parseBlock(pLastDecl)); } else { return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, aggrfe, null)); } } } /***************************************** * Input: * flags PSxxxx * Output: * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement */ AST.Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null) { AST.Statement s; AST.Condition cond; AST.Statement ifbody; AST.Statement elsebody; bool isfinal; const loc = token.loc; //printf("parseStatement()\n"); if (flags & ParseStatementFlags.curly && token.value != TOK.leftCurly) error("statement expected to be `{ }`, not `%s`", token.toChars()); switch (token.value) { case TOK.identifier: { /* A leading identifier can be a declaration, label, or expression. * The easiest case to check first is label: */ Token* t = peek(&token); if (t.value == TOK.colon) { Token* nt = peek(t); if (nt.value == TOK.colon) { // skip ident:: nextToken(); nextToken(); nextToken(); error("use `.` for member lookup, not `::`"); break; } // It's a label Identifier ident = token.ident; nextToken(); nextToken(); if (token.value == TOK.rightCurly) s = null; else if (token.value == TOK.leftCurly) s = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_); else s = parseStatement(ParseStatementFlags.semiOk); s = new AST.LabelStatement(loc, ident, s); break; } goto case TOK.dot; } case TOK.dot: case TOK.typeof_: case TOK.vector: /* https://issues.dlang.org/show_bug.cgi?id=15163 * If tokens can be handled as * old C-style declaration or D expression, prefer the latter. */ if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null)) goto Ldeclaration; else goto Lexp; case TOK.assert_: case TOK.this_: case TOK.super_: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: case TOK.uns64Literal: case TOK.int128Literal: case TOK.uns128Literal: case TOK.float32Literal: case TOK.float64Literal: case TOK.float80Literal: case TOK.imaginary32Literal: case TOK.imaginary64Literal: case TOK.imaginary80Literal: case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.null_: case TOK.true_: case TOK.false_: case TOK.string_: case TOK.hexadecimalString: case TOK.leftParentheses: case TOK.cast_: case TOK.mul: case TOK.min: case TOK.add: case TOK.tilde: case TOK.not: case TOK.plusPlus: case TOK.minusMinus: case TOK.new_: case TOK.delete_: case TOK.delegate_: case TOK.function_: case TOK.typeid_: case TOK.is_: case TOK.leftBracket: case TOK.traits: case TOK.file: case TOK.fileFullPath: case TOK.line: case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: Lexp: { AST.Expression exp = parseExpression(); check(TOK.semicolon, "statement"); s = new AST.ExpStatement(loc, exp); break; } case TOK.static_: { // Look ahead to see if it's static assert() or static if() Token* t = peek(&token); if (t.value == TOK.assert_) { s = new AST.StaticAssertStatement(parseStaticAssert()); break; } if (t.value == TOK.if_) { cond = parseStaticIfCondition(); goto Lcondition; } else if(t.value == TOK.foreach_ || t.value == TOK.foreach_reverse_) { s = parseForeach!(true,false)(loc); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; } if (t.value == TOK.import_) { AST.Dsymbols* imports = parseImport(); s = new AST.ImportStatement(loc, imports); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; } goto Ldeclaration; } case TOK.final_: if (peekNext() == TOK.switch_) { nextToken(); isfinal = true; goto Lswitch; } goto Ldeclaration; case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: // bug 7773: int.max is always a part of expression if (peekNext() == TOK.dot) goto Lexp; if (peekNext() == TOK.leftParentheses) goto Lexp; goto case; case TOK.alias_: case TOK.const_: case TOK.auto_: case TOK.abstract_: case TOK.extern_: case TOK.align_: case TOK.immutable_: case TOK.shared_: case TOK.inout_: case TOK.deprecated_: case TOK.nothrow_: case TOK.pure_: case TOK.ref_: case TOK.gshared: case TOK.at: case TOK.struct_: case TOK.union_: case TOK.class_: case TOK.interface_: Ldeclaration: { AST.Dsymbols* a = parseDeclarations(false, null, null); if (a.dim > 1) { auto as = new AST.Statements(); as.reserve(a.dim); foreach (i; 0 .. a.dim) { AST.Dsymbol d = (*a)[i]; s = new AST.ExpStatement(loc, d); as.push(s); } s = new AST.CompoundDeclarationStatement(loc, as); } else if (a.dim == 1) { AST.Dsymbol d = (*a)[0]; s = new AST.ExpStatement(loc, d); } else s = new AST.ExpStatement(loc, cast(AST.Expression)null); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; } case TOK.enum_: { /* Determine if this is a manifest constant declaration, * or a conventional enum. */ AST.Dsymbol d; Token* t = peek(&token); if (t.value == TOK.leftCurly || t.value == TOK.colon) d = parseEnum(); else if (t.value != TOK.identifier) goto Ldeclaration; else { t = peek(t); if (t.value == TOK.leftCurly || t.value == TOK.colon || t.value == TOK.semicolon) d = parseEnum(); else goto Ldeclaration; } s = new AST.ExpStatement(loc, d); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; } case TOK.mixin_: { Token* t = peek(&token); if (t.value == TOK.leftParentheses) { // mixin(string) AST.Expression e = parseAssignExp(); check(TOK.semicolon); if (e.op == TOK.mixin_) { AST.CompileExp cpe = cast(AST.CompileExp)e; s = new AST.CompileStatement(loc, cpe.exps); } else { s = new AST.ExpStatement(loc, e); } break; } AST.Dsymbol d = parseMixin(); s = new AST.ExpStatement(loc, d); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; } case TOK.leftCurly: { const lookingForElseSave = lookingForElse; lookingForElse = Loc.initial; nextToken(); //if (token.value == TOK.semicolon) // error("use `{ }` for an empty statement, not `;`"); auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); } if (endPtr) *endPtr = token.ptr; endloc = token.loc; if (pEndloc) { *pEndloc = token.loc; pEndloc = null; // don't set it again } s = new AST.CompoundStatement(loc, statements); if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)) s = new AST.ScopeStatement(loc, s, token.loc); check(TOK.rightCurly, "compound statement"); lookingForElse = lookingForElseSave; break; } case TOK.while_: { nextToken(); check(TOK.leftParentheses); AST.Expression condition = parseExpression(); check(TOK.rightParentheses); Loc endloc; AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); s = new AST.WhileStatement(loc, condition, _body, endloc); break; } case TOK.semicolon: if (!(flags & ParseStatementFlags.semiOk)) { if (flags & ParseStatementFlags.semi) deprecation("use `{ }` for an empty statement, not `;`"); else error("use `{ }` for an empty statement, not `;`"); } nextToken(); s = new AST.ExpStatement(loc, cast(AST.Expression)null); break; case TOK.do_: { AST.Statement _body; AST.Expression condition; nextToken(); const lookingForElseSave = lookingForElse; lookingForElse = Loc.initial; _body = parseStatement(ParseStatementFlags.scope_); lookingForElse = lookingForElseSave; check(TOK.while_); check(TOK.leftParentheses); condition = parseExpression(); check(TOK.rightParentheses); if (token.value == TOK.semicolon) nextToken(); else error("terminating `;` required after do-while statement"); s = new AST.DoStatement(loc, _body, condition, token.loc); break; } case TOK.for_: { AST.Statement _init; AST.Expression condition; AST.Expression increment; nextToken(); check(TOK.leftParentheses); if (token.value == TOK.semicolon) { _init = null; nextToken(); } else { const lookingForElseSave = lookingForElse; lookingForElse = Loc.initial; _init = parseStatement(0); lookingForElse = lookingForElseSave; } if (token.value == TOK.semicolon) { condition = null; nextToken(); } else { condition = parseExpression(); check(TOK.semicolon, "`for` condition"); } if (token.value == TOK.rightParentheses) { increment = null; nextToken(); } else { increment = parseExpression(); check(TOK.rightParentheses); } Loc endloc; AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc); break; } case TOK.foreach_: case TOK.foreach_reverse_: { s = parseForeach!(false,false)(loc); break; } case TOK.if_: { AST.Parameter param = null; AST.Expression condition; nextToken(); check(TOK.leftParentheses); StorageClass storageClass = 0; StorageClass stc = 0; LagainStc: if (stc) { storageClass = appendStorageClass(storageClass, stc); nextToken(); } switch (token.value) { case TOK.ref_: stc = AST.STC.ref_; goto LagainStc; case TOK.auto_: stc = AST.STC.auto_; goto LagainStc; case TOK.const_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.const_; goto LagainStc; } break; case TOK.immutable_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.immutable_; goto LagainStc; } break; case TOK.shared_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.shared_; goto LagainStc; } break; case TOK.inout_: if (peekNext() != TOK.leftParentheses) { stc = AST.STC.wild; goto LagainStc; } break; default: break; } if (storageClass != 0 && token.value == TOK.identifier && peek(&token).value == TOK.assign) { Identifier ai = token.ident; AST.Type at = null; // infer parameter type nextToken(); check(TOK.assign); param = new AST.Parameter(storageClass, at, ai, null, null); } else if (isDeclaration(&token, NeedDeclaratorId.must, TOK.assign, null)) { Identifier ai; AST.Type at = parseType(&ai); check(TOK.assign); param = new AST.Parameter(storageClass, at, ai, null, null); } condition = parseExpression(); check(TOK.rightParentheses); { const lookingForElseSave = lookingForElse; lookingForElse = loc; ifbody = parseStatement(ParseStatementFlags.scope_); lookingForElse = lookingForElseSave; } if (token.value == TOK.else_) { const elseloc = token.loc; nextToken(); elsebody = parseStatement(ParseStatementFlags.scope_); checkDanglingElse(elseloc); } else elsebody = null; if (condition && ifbody) s = new AST.IfStatement(loc, param, condition, ifbody, elsebody, token.loc); else s = null; // don't propagate parsing errors break; } case TOK.else_: error("found `else` without a corresponding `if`, `version` or `debug` statement"); goto Lerror; case TOK.scope_: if (peek(&token).value != TOK.leftParentheses) goto Ldeclaration; // scope used as storage class nextToken(); check(TOK.leftParentheses); if (token.value != TOK.identifier) { error("scope identifier expected"); goto Lerror; } else { TOK t = TOK.onScopeExit; Identifier id = token.ident; if (id == Id.exit) t = TOK.onScopeExit; else if (id == Id.failure) t = TOK.onScopeFailure; else if (id == Id.success) t = TOK.onScopeSuccess; else error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id.toChars()); nextToken(); check(TOK.rightParentheses); AST.Statement st = parseStatement(ParseStatementFlags.scope_); s = new AST.OnScopeStatement(loc, t, st); break; } case TOK.debug_: nextToken(); if (token.value == TOK.assign) { error("debug conditions can only be declared at module scope"); nextToken(); nextToken(); goto Lerror; } cond = parseDebugCondition(); goto Lcondition; case TOK.version_: nextToken(); if (token.value == TOK.assign) { error("version conditions can only be declared at module scope"); nextToken(); nextToken(); goto Lerror; } cond = parseVersionCondition(); goto Lcondition; Lcondition: { const lookingForElseSave = lookingForElse; lookingForElse = loc; ifbody = parseStatement(0); lookingForElse = lookingForElseSave; } elsebody = null; if (token.value == TOK.else_) { const elseloc = token.loc; nextToken(); elsebody = parseStatement(0); checkDanglingElse(elseloc); } s = new AST.ConditionalStatement(loc, cond, ifbody, elsebody); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); break; case TOK.pragma_: { Identifier ident; AST.Expressions* args = null; AST.Statement _body; nextToken(); check(TOK.leftParentheses); if (token.value != TOK.identifier) { error("`pragma(identifier)` expected"); goto Lerror; } ident = token.ident; nextToken(); if (token.value == TOK.comma && peekNext() != TOK.rightParentheses) args = parseArguments(); // pragma(identifier, args...); else check(TOK.rightParentheses); // pragma(identifier); if (token.value == TOK.semicolon) { nextToken(); _body = null; } else _body = parseStatement(ParseStatementFlags.semi); s = new AST.PragmaStatement(loc, ident, args, _body); break; } case TOK.switch_: isfinal = false; goto Lswitch; Lswitch: { nextToken(); check(TOK.leftParentheses); AST.Expression condition = parseExpression(); check(TOK.rightParentheses); AST.Statement _body = parseStatement(ParseStatementFlags.scope_); s = new AST.SwitchStatement(loc, condition, _body, isfinal); break; } case TOK.case_: { AST.Expression exp; AST.Expressions cases; // array of Expression's AST.Expression last = null; while (1) { nextToken(); exp = parseAssignExp(); cases.push(exp); if (token.value != TOK.comma) break; } check(TOK.colon); /* case exp: .. case last: */ if (token.value == TOK.slice) { if (cases.dim > 1) error("only one `case` allowed for start of case range"); nextToken(); check(TOK.case_); last = parseAssignExp(); check(TOK.colon); } if (flags & ParseStatementFlags.curlyScope) { auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else { s = parseStatement(ParseStatementFlags.semi); } s = new AST.ScopeStatement(loc, s, token.loc); if (last) { s = new AST.CaseRangeStatement(loc, exp, last, s); } else { // Keep cases in order by building the case statements backwards for (size_t i = cases.dim; i; i--) { exp = cases[i - 1]; s = new AST.CaseStatement(loc, exp, s); } } break; } case TOK.default_: { nextToken(); check(TOK.colon); if (flags & ParseStatementFlags.curlyScope) { auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else s = parseStatement(ParseStatementFlags.semi); s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.DefaultStatement(loc, s); break; } case TOK.return_: { AST.Expression exp; nextToken(); if (token.value == TOK.semicolon) exp = null; else exp = parseExpression(); check(TOK.semicolon, "`return` statement"); s = new AST.ReturnStatement(loc, exp); break; } case TOK.break_: { Identifier ident; nextToken(); if (token.value == TOK.identifier) { ident = token.ident; nextToken(); } else ident = null; check(TOK.semicolon, "`break` statement"); s = new AST.BreakStatement(loc, ident); break; } case TOK.continue_: { Identifier ident; nextToken(); if (token.value == TOK.identifier) { ident = token.ident; nextToken(); } else ident = null; check(TOK.semicolon, "`continue` statement"); s = new AST.ContinueStatement(loc, ident); break; } case TOK.goto_: { Identifier ident; nextToken(); if (token.value == TOK.default_) { nextToken(); s = new AST.GotoDefaultStatement(loc); } else if (token.value == TOK.case_) { AST.Expression exp = null; nextToken(); if (token.value != TOK.semicolon) exp = parseExpression(); s = new AST.GotoCaseStatement(loc, exp); } else { if (token.value != TOK.identifier) { error("identifier expected following `goto`"); ident = null; } else { ident = token.ident; nextToken(); } s = new AST.GotoStatement(loc, ident); } check(TOK.semicolon, "`goto` statement"); break; } case TOK.synchronized_: { AST.Expression exp; AST.Statement _body; Token* t = peek(&token); if (skipAttributes(t, &t) && t.value == TOK.class_) goto Ldeclaration; nextToken(); if (token.value == TOK.leftParentheses) { nextToken(); exp = parseExpression(); check(TOK.rightParentheses); } else exp = null; _body = parseStatement(ParseStatementFlags.scope_); s = new AST.SynchronizedStatement(loc, exp, _body); break; } case TOK.with_: { AST.Expression exp; AST.Statement _body; Loc endloc = loc; nextToken(); check(TOK.leftParentheses); exp = parseExpression(); check(TOK.rightParentheses); _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); s = new AST.WithStatement(loc, exp, _body, endloc); break; } case TOK.try_: { AST.Statement _body; AST.Catches* catches = null; AST.Statement finalbody = null; nextToken(); const lookingForElseSave = lookingForElse; lookingForElse = Loc.initial; _body = parseStatement(ParseStatementFlags.scope_); lookingForElse = lookingForElseSave; while (token.value == TOK.catch_) { AST.Statement handler; AST.Catch c; AST.Type t; Identifier id; const catchloc = token.loc; nextToken(); if (token.value == TOK.leftCurly || token.value != TOK.leftParentheses) { t = null; id = null; } else { check(TOK.leftParentheses); id = null; t = parseType(&id); check(TOK.rightParentheses); } handler = parseStatement(0); c = new AST.Catch(catchloc, t, id, handler); if (!catches) catches = new AST.Catches(); catches.push(c); } if (token.value == TOK.finally_) { nextToken(); finalbody = parseStatement(ParseStatementFlags.scope_); } s = _body; if (!catches && !finalbody) error("`catch` or `finally` expected following `try`"); else { if (catches) s = new AST.TryCatchStatement(loc, _body, catches); if (finalbody) s = new AST.TryFinallyStatement(loc, s, finalbody); } break; } case TOK.throw_: { AST.Expression exp; nextToken(); exp = parseExpression(); check(TOK.semicolon, "`throw` statement"); s = new AST.ThrowStatement(loc, exp); break; } case TOK.asm_: { // Parse the asm block into a sequence of AsmStatements, // each AsmStatement is one instruction. // Separate out labels. // Defer parsing of AsmStatements until semantic processing. Loc labelloc; nextToken(); StorageClass stc = parsePostfix(AST.STC.undefined_, null); if (stc & (AST.STC.const_ | AST.STC.immutable_ | AST.STC.shared_ | AST.STC.wild)) error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks"); check(TOK.leftCurly); Token* toklist = null; Token** ptoklist = &toklist; Identifier label = null; auto statements = new AST.Statements(); size_t nestlevel = 0; while (1) { switch (token.value) { case TOK.identifier: if (!toklist) { // Look ahead to see if it is a label Token* t = peek(&token); if (t.value == TOK.colon) { // It's a label label = token.ident; labelloc = token.loc; nextToken(); nextToken(); continue; } } goto default; case TOK.leftCurly: ++nestlevel; goto default; case TOK.rightCurly: if (nestlevel > 0) { --nestlevel; goto default; } if (toklist || label) { error("`asm` statements must end in `;`"); } break; case TOK.semicolon: if (nestlevel != 0) error("mismatched number of curly brackets"); s = null; if (toklist || label) { // Create AsmStatement from list of tokens we've saved s = new AST.AsmStatement(token.loc, toklist); toklist = null; ptoklist = &toklist; if (label) { s = new AST.LabelStatement(labelloc, label, s); label = null; } statements.push(s); } nextToken(); continue; case TOK.endOfFile: /* { */ error("matching `}` expected, not end of file"); goto Lerror; default: *ptoklist = Token.alloc(); memcpy(*ptoklist, &token, Token.sizeof); ptoklist = &(*ptoklist).next; *ptoklist = null; nextToken(); continue; } break; } s = new AST.CompoundAsmStatement(loc, statements, stc); nextToken(); break; } case TOK.import_: { /* https://issues.dlang.org/show_bug.cgi?id=16088 * * At this point it can either be an * https://dlang.org/spec/grammar.html#ImportExpression * or an * https://dlang.org/spec/grammar.html#ImportDeclaration. * See if the next token after `import` is a `(`; if so, * then it is an import expression. */ if (peekNext() == TOK.leftParentheses) { AST.Expression e = parseExpression(); check(TOK.semicolon); s = new AST.ExpStatement(loc, e); } else { AST.Dsymbols* imports = parseImport(); s = new AST.ImportStatement(loc, imports); if (flags & ParseStatementFlags.scope_) s = new AST.ScopeStatement(loc, s, token.loc); } break; } case TOK.template_: { AST.Dsymbol d = parseTemplateDeclaration(); s = new AST.ExpStatement(loc, d); break; } default: error("found `%s` instead of statement", token.toChars()); goto Lerror; Lerror: while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); if (token.value == TOK.semicolon) nextToken(); s = null; break; } if (pEndloc) *pEndloc = prevloc; return s; } /***************************************** * Parse initializer for variable declaration. */ AST.Initializer parseInitializer() { AST.StructInitializer _is; AST.ArrayInitializer ia; AST.ExpInitializer ie; AST.Expression e; Identifier id; AST.Initializer value; int comma; const loc = token.loc; Token* t; int braces; int brackets; switch (token.value) { case TOK.leftCurly: /* Scan ahead to discern between a struct initializer and * parameterless function literal. * * We'll scan the topmost curly bracket level for statement-related * tokens, thereby ruling out a struct initializer. (A struct * initializer which itself contains function literals may have * statements at nested curly bracket levels.) * * It's important that this function literal check not be * pendantic, otherwise a function having the slightest syntax * error would emit confusing errors when we proceed to parse it * as a struct initializer. * * The following two ambiguous cases will be treated as a struct * initializer (best we can do without type info): * {} * {{statements...}} - i.e. it could be struct initializer * with one function literal, or function literal having an * extra level of curly brackets * If a function literal is intended in these cases (unlikely), * source can use a more explicit function literal syntax * (e.g. prefix with "()" for empty parameter list). */ braces = 1; for (t = peek(&token); 1; t = peek(t)) { switch (t.value) { /* Look for a semicolon or keyword of statements which don't * require a semicolon (typically containing BlockStatement). * Tokens like "else", "catch", etc. are omitted where the * leading token of the statement is sufficient. */ case TOK.asm_: case TOK.class_: case TOK.debug_: case TOK.enum_: case TOK.if_: case TOK.interface_: case TOK.pragma_: case TOK.scope_: case TOK.semicolon: case TOK.struct_: case TOK.switch_: case TOK.synchronized_: case TOK.try_: case TOK.union_: case TOK.version_: case TOK.while_: case TOK.with_: if (braces == 1) goto Lexpression; continue; case TOK.leftCurly: braces++; continue; case TOK.rightCurly: if (--braces == 0) break; continue; case TOK.endOfFile: break; default: continue; } break; } _is = new AST.StructInitializer(loc); nextToken(); comma = 2; while (1) { switch (token.value) { case TOK.identifier: if (comma == 1) error("comma expected separating field initializers"); t = peek(&token); if (t.value == TOK.colon) { id = token.ident; nextToken(); nextToken(); // skip over ':' } else { id = null; } value = parseInitializer(); _is.addInit(id, value); comma = 1; continue; case TOK.comma: if (comma == 2) error("expression expected, not `,`"); nextToken(); comma = 2; continue; case TOK.rightCurly: // allow trailing comma's nextToken(); break; case TOK.endOfFile: error("found end of file instead of initializer"); break; default: if (comma == 1) error("comma expected separating field initializers"); value = parseInitializer(); _is.addInit(null, value); comma = 1; continue; //error("found `%s` instead of field initializer", token.toChars()); //break; } break; } return _is; case TOK.leftBracket: /* Scan ahead to see if it is an array initializer or * an expression. * If it ends with a ';' ',' or '}', it is an array initializer. */ brackets = 1; for (t = peek(&token); 1; t = peek(t)) { switch (t.value) { case TOK.leftBracket: brackets++; continue; case TOK.rightBracket: if (--brackets == 0) { t = peek(t); if (t.value != TOK.semicolon && t.value != TOK.comma && t.value != TOK.rightBracket && t.value != TOK.rightCurly) goto Lexpression; break; } continue; case TOK.endOfFile: break; default: continue; } break; } ia = new AST.ArrayInitializer(loc); nextToken(); comma = 2; while (1) { switch (token.value) { default: if (comma == 1) { error("comma expected separating array initializers, not `%s`", token.toChars()); nextToken(); break; } e = parseAssignExp(); if (!e) break; if (token.value == TOK.colon) { nextToken(); value = parseInitializer(); } else { value = new AST.ExpInitializer(e.loc, e); e = null; } ia.addInit(e, value); comma = 1; continue; case TOK.leftCurly: case TOK.leftBracket: if (comma == 1) error("comma expected separating array initializers, not `%s`", token.toChars()); value = parseInitializer(); if (token.value == TOK.colon) { nextToken(); AST.ExpInitializer expInit = value.isExpInitializer(); assert(expInit); e = expInit.exp; value = parseInitializer(); } else e = null; ia.addInit(e, value); comma = 1; continue; case TOK.comma: if (comma == 2) error("expression expected, not `,`"); nextToken(); comma = 2; continue; case TOK.rightBracket: // allow trailing comma's nextToken(); break; case TOK.endOfFile: error("found `%s` instead of array initializer", token.toChars()); break; } break; } return ia; case TOK.void_: t = peek(&token); if (t.value == TOK.semicolon || t.value == TOK.comma) { nextToken(); return new AST.VoidInitializer(loc); } goto Lexpression; default: Lexpression: e = parseAssignExp(); ie = new AST.ExpInitializer(loc, e); return ie; } } /***************************************** * Parses default argument initializer expression that is an assign expression, * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. */ AST.Expression parseDefaultInitExp() { if (token.value == TOK.file || token.value == TOK.fileFullPath || token.value == TOK.line || token.value == TOK.moduleString || token.value == TOK.functionString || token.value == TOK.prettyFunction) { Token* t = peek(&token); if (t.value == TOK.comma || t.value == TOK.rightParentheses) { AST.Expression e = null; if (token.value == TOK.file) e = new AST.FileInitExp(token.loc, TOK.file); else if (token.value == TOK.fileFullPath) e = new AST.FileInitExp(token.loc, TOK.fileFullPath); else if (token.value == TOK.line) e = new AST.LineInitExp(token.loc); else if (token.value == TOK.moduleString) e = new AST.ModuleInitExp(token.loc); else if (token.value == TOK.functionString) e = new AST.FuncInitExp(token.loc); else if (token.value == TOK.prettyFunction) e = new AST.PrettyFuncInitExp(token.loc); else assert(0); nextToken(); return e; } } AST.Expression e = parseAssignExp(); return e; } void check(Loc loc, TOK value) { if (token.value != value) error(loc, "found `%s` when expecting `%s`", token.toChars(), Token.toChars(value)); nextToken(); } void check(TOK value) { check(token.loc, value); } void check(TOK value, const(char)* string) { if (token.value != value) error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string); nextToken(); } void checkParens(TOK value, AST.Expression e) { if (precedence[e.op] == PREC.rel && !e.parens) error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value)); } /// enum NeedDeclaratorId { no, // Declarator part must have no identifier opt, // Declarator part identifier is optional must, // Declarator part must have identifier mustIfDstyle, // Declarator part must have identifier, but don't recognize old C-style syntax } /************************************ * Determine if the scanner is sitting on the start of a declaration. * Params: * t = current token of the scanner * needId = flag with additional requirements for a declaration * endtok = ending token * pt = will be set ending token (if not null) * Output: * true if the token `t` is a declaration, false otherwise */ bool isDeclaration(Token* t, NeedDeclaratorId needId, TOK endtok, Token** pt) { //printf("isDeclaration(needId = %d)\n", needId); int haveId = 0; int haveTpl = 0; while (1) { if ((t.value == TOK.const_ || t.value == TOK.immutable_ || t.value == TOK.inout_ || t.value == TOK.shared_) && peek(t).value != TOK.leftParentheses) { /* const type * immutable type * shared type * wild type */ t = peek(t); continue; } break; } if (!isBasicType(&t)) { goto Lisnot; } if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle)) goto Lisnot; if ((needId == NeedDeclaratorId.no && !haveId) || (needId == NeedDeclaratorId.opt) || (needId == NeedDeclaratorId.must && haveId) || (needId == NeedDeclaratorId.mustIfDstyle && haveId)) { if (pt) *pt = t; goto Lis; } else goto Lisnot; Lis: //printf("\tis declaration, t = %s\n", t.toChars()); return true; Lisnot: //printf("\tis not declaration\n"); return false; } bool isBasicType(Token** pt) { // This code parallels parseBasicType() Token* t = *pt; switch (t.value) { case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: t = peek(t); break; case TOK.identifier: L5: t = peek(t); if (t.value == TOK.not) { goto L4; } goto L3; while (1) { L2: t = peek(t); L3: if (t.value == TOK.dot) { Ldot: t = peek(t); if (t.value != TOK.identifier) goto Lfalse; t = peek(t); if (t.value != TOK.not) goto L3; L4: /* Seen a ! * Look for: * !( args ), !identifier, etc. */ t = peek(t); switch (t.value) { case TOK.identifier: goto L5; case TOK.leftParentheses: if (!skipParens(t, &t)) goto Lfalse; goto L3; case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: case TOK.uns64Literal: case TOK.int128Literal: case TOK.uns128Literal: case TOK.float32Literal: case TOK.float64Literal: case TOK.float80Literal: case TOK.imaginary32Literal: case TOK.imaginary64Literal: case TOK.imaginary80Literal: case TOK.null_: case TOK.true_: case TOK.false_: case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: goto L2; default: goto Lfalse; } } else break; } break; case TOK.dot: goto Ldot; case TOK.typeof_: case TOK.vector: /* typeof(exp).identifier... */ t = peek(t); if (!skipParens(t, &t)) goto Lfalse; goto L3; case TOK.const_: case TOK.immutable_: case TOK.shared_: case TOK.inout_: // const(type) or immutable(type) or shared(type) or wild(type) t = peek(t); if (t.value != TOK.leftParentheses) goto Lfalse; t = peek(t); if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParentheses, &t)) { goto Lfalse; } t = peek(t); break; default: goto Lfalse; } *pt = t; //printf("is\n"); return true; Lfalse: //printf("is not\n"); return false; } bool isDeclarator(Token** pt, int* haveId, int* haveTpl, TOK endtok, bool allowAltSyntax = true) { // This code parallels parseDeclarator() Token* t = *pt; int parens; //printf("Parser::isDeclarator() %s\n", t.toChars()); if (t.value == TOK.assign) return false; while (1) { parens = false; switch (t.value) { case TOK.mul: //case TOK.and: t = peek(t); continue; case TOK.leftBracket: t = peek(t); if (t.value == TOK.rightBracket) { t = peek(t); } else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t)) { // It's an associative array declaration t = peek(t); // ...[type].ident if (t.value == TOK.dot && peek(t).value == TOK.identifier) { t = peek(t); t = peek(t); } } else { // [ expression ] // [ expression .. expression ] if (!isExpression(&t)) return false; if (t.value == TOK.slice) { t = peek(t); if (!isExpression(&t)) return false; if (t.value != TOK.rightBracket) return false; t = peek(t); } else { if (t.value != TOK.rightBracket) return false; t = peek(t); // ...[index].ident if (t.value == TOK.dot && peek(t).value == TOK.identifier) { t = peek(t); t = peek(t); } } } continue; case TOK.identifier: if (*haveId) return false; *haveId = true; t = peek(t); break; case TOK.leftParentheses: if (!allowAltSyntax) return false; // Do not recognize C-style declarations. t = peek(t); if (t.value == TOK.rightParentheses) return false; // () is not a declarator /* Regard ( identifier ) as not a declarator * BUG: what about ( *identifier ) in * f(*p)(x); * where f is a class instance with overloaded () ? * Should we just disallow C-style function pointer declarations? */ if (t.value == TOK.identifier) { Token* t2 = peek(t); if (t2.value == TOK.rightParentheses) return false; } if (!isDeclarator(&t, haveId, null, TOK.rightParentheses)) return false; t = peek(t); parens = true; break; case TOK.delegate_: case TOK.function_: t = peek(t); if (!isParameters(&t)) return false; skipAttributes(t, &t); continue; default: break; } break; } while (1) { switch (t.value) { static if (CARRAYDECL) { case TOK.leftBracket: parens = false; t = peek(t); if (t.value == TOK.rightBracket) { t = peek(t); } else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t)) { // It's an associative array declaration t = peek(t); } else { // [ expression ] if (!isExpression(&t)) return false; if (t.value != TOK.rightBracket) return false; t = peek(t); } continue; } case TOK.leftParentheses: parens = false; if (Token* tk = peekPastParen(t)) { if (tk.value == TOK.leftParentheses) { if (!haveTpl) return false; *haveTpl = 1; t = tk; } else if (tk.value == TOK.assign) { if (!haveTpl) return false; *haveTpl = 1; *pt = tk; return true; } } if (!isParameters(&t)) return false; while (1) { switch (t.value) { case TOK.const_: case TOK.immutable_: case TOK.shared_: case TOK.inout_: case TOK.pure_: case TOK.nothrow_: case TOK.return_: case TOK.scope_: t = peek(t); continue; case TOK.at: t = peek(t); // skip '@' t = peek(t); // skip identifier continue; default: break; } break; } continue; // Valid tokens that follow a declaration case TOK.rightParentheses: case TOK.rightBracket: case TOK.assign: case TOK.comma: case TOK.dotDotDot: case TOK.semicolon: case TOK.leftCurly: case TOK.in_: case TOK.out_: case TOK.do_: // The !parens is to disallow unnecessary parentheses if (!parens && (endtok == TOK.reserved || endtok == t.value)) { *pt = t; return true; } return false; case TOK.identifier: if (t.ident == Id._body) goto case TOK.do_; goto default; case TOK.if_: return haveTpl ? true : false; default: return false; } } assert(0); } bool isParameters(Token** pt) { // This code parallels parseParameters() Token* t = *pt; //printf("isParameters()\n"); if (t.value != TOK.leftParentheses) return false; t = peek(t); for (; 1; t = peek(t)) { L1: switch (t.value) { case TOK.rightParentheses: break; case TOK.dotDotDot: t = peek(t); break; case TOK.in_: case TOK.out_: case TOK.ref_: case TOK.lazy_: case TOK.scope_: case TOK.final_: case TOK.auto_: case TOK.return_: continue; case TOK.const_: case TOK.immutable_: case TOK.shared_: case TOK.inout_: t = peek(t); if (t.value == TOK.leftParentheses) { t = peek(t); if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParentheses, &t)) return false; t = peek(t); // skip past closing ')' goto L2; } goto L1; version (none) { case TOK.static_: continue; case TOK.auto_: case TOK.alias_: t = peek(t); if (t.value == TOK.identifier) t = peek(t); if (t.value == TOK.assign) { t = peek(t); if (!isExpression(&t)) return false; } goto L3; } default: { if (!isBasicType(&t)) return false; L2: int tmp = false; if (t.value != TOK.dotDotDot && !isDeclarator(&t, &tmp, null, TOK.reserved)) return false; if (t.value == TOK.assign) { t = peek(t); if (!isExpression(&t)) return false; } if (t.value == TOK.dotDotDot) { t = peek(t); break; } } if (t.value == TOK.comma) { continue; } break; } break; } if (t.value != TOK.rightParentheses) return false; t = peek(t); *pt = t; return true; } bool isExpression(Token** pt) { // This is supposed to determine if something is an expression. // What it actually does is scan until a closing right bracket // is found. Token* t = *pt; int brnest = 0; int panest = 0; int curlynest = 0; for (;; t = peek(t)) { switch (t.value) { case TOK.leftBracket: brnest++; continue; case TOK.rightBracket: if (--brnest >= 0) continue; break; case TOK.leftParentheses: panest++; continue; case TOK.comma: if (brnest || panest) continue; break; case TOK.rightParentheses: if (--panest >= 0) continue; break; case TOK.leftCurly: curlynest++; continue; case TOK.rightCurly: if (--curlynest >= 0) continue; return false; case TOK.slice: if (brnest) continue; break; case TOK.semicolon: if (curlynest) continue; return false; case TOK.endOfFile: return false; default: continue; } break; } *pt = t; return true; } /******************************************* * Skip parens, brackets. * Input: * t is on opening $(LPAREN) * Output: * *pt is set to closing token, which is '$(RPAREN)' on success * Returns: * true successful * false some parsing error */ bool skipParens(Token* t, Token** pt) { if (t.value != TOK.leftParentheses) return false; int parens = 0; while (1) { switch (t.value) { case TOK.leftParentheses: parens++; break; case TOK.rightParentheses: parens--; if (parens < 0) goto Lfalse; if (parens == 0) goto Ldone; break; case TOK.endOfFile: goto Lfalse; default: break; } t = peek(t); } Ldone: if (pt) *pt = peek(t); // skip found rparen return true; Lfalse: return false; } bool skipParensIf(Token* t, Token** pt) { if (t.value != TOK.leftParentheses) { if (pt) *pt = t; return true; } return skipParens(t, pt); } /******************************************* * Skip attributes. * Input: * t is on a candidate attribute * Output: * *pt is set to first non-attribute token on success * Returns: * true successful * false some parsing error */ bool skipAttributes(Token* t, Token** pt) { while (1) { switch (t.value) { case TOK.const_: case TOK.immutable_: case TOK.shared_: case TOK.inout_: case TOK.final_: case TOK.auto_: case TOK.scope_: case TOK.override_: case TOK.abstract_: case TOK.synchronized_: break; case TOK.deprecated_: if (peek(t).value == TOK.leftParentheses) { t = peek(t); if (!skipParens(t, &t)) goto Lerror; // t is on the next of closing parenthesis continue; } break; case TOK.nothrow_: case TOK.pure_: case TOK.ref_: case TOK.gshared: case TOK.return_: //case TOK.manifest: break; case TOK.at: t = peek(t); if (t.value == TOK.identifier) { /* @identifier * @identifier!arg * @identifier!(arglist) * any of the above followed by (arglist) * @predefined_attribute */ if (t.ident == Id.property || t.ident == Id.nogc || t.ident == Id.safe || t.ident == Id.trusted || t.ident == Id.system || t.ident == Id.disable) break; t = peek(t); if (t.value == TOK.not) { t = peek(t); if (t.value == TOK.leftParentheses) { // @identifier!(arglist) if (!skipParens(t, &t)) goto Lerror; // t is on the next of closing parenthesis } else { // @identifier!arg // Do low rent skipTemplateArgument if (t.value == TOK.vector) { // identifier!__vector(type) t = peek(t); if (!skipParens(t, &t)) goto Lerror; } else t = peek(t); } } if (t.value == TOK.leftParentheses) { if (!skipParens(t, &t)) goto Lerror; // t is on the next of closing parenthesis continue; } continue; } if (t.value == TOK.leftParentheses) { // @( ArgumentList ) if (!skipParens(t, &t)) goto Lerror; // t is on the next of closing parenthesis continue; } goto Lerror; default: goto Ldone; } t = peek(t); } Ldone: if (pt) *pt = t; return true; Lerror: return false; } AST.Expression parseExpression() { auto loc = token.loc; //printf("Parser::parseExpression() loc = %d\n", loc.linnum); auto e = parseAssignExp(); while (token.value == TOK.comma) { nextToken(); auto e2 = parseAssignExp(); e = new AST.CommaExp(loc, e, e2, false); loc = token.loc; } return e; } /********************************* Expression Parser ***************************/ AST.Expression parsePrimaryExp() { AST.Expression e; AST.Type t; Identifier id; const loc = token.loc; //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); switch (token.value) { case TOK.identifier: { Token* t1 = peek(&token); Token* t2 = peek(t1); if (t1.value == TOK.min && t2.value == TOK.greaterThan) { // skip ident. nextToken(); nextToken(); nextToken(); error("use `.` for member lookup, not `->`"); goto Lerr; } if (peekNext() == TOK.goesTo) goto case_delegate; id = token.ident; nextToken(); TOK save; if (token.value == TOK.not && (save = peekNext()) != TOK.is_ && save != TOK.in_) { // identifier!(template-argument-list) auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments()); e = new AST.ScopeExp(loc, tempinst); } else e = new AST.IdentifierExp(loc, id); break; } case TOK.dollar: if (!inBrackets) error("`$` is valid only inside [] of index or slice"); e = new AST.DollarExp(loc); nextToken(); break; case TOK.dot: // Signal global scope '.' operator with "" identifier e = new AST.IdentifierExp(loc, Id.empty); break; case TOK.this_: e = new AST.ThisExp(loc); nextToken(); break; case TOK.super_: e = new AST.SuperExp(loc); nextToken(); break; case TOK.int32Literal: e = new AST.IntegerExp(loc, cast(d_int32)token.intvalue, AST.Type.tint32); nextToken(); break; case TOK.uns32Literal: e = new AST.IntegerExp(loc, cast(d_uns32)token.unsvalue, AST.Type.tuns32); nextToken(); break; case TOK.int64Literal: e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64); nextToken(); break; case TOK.uns64Literal: e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64); nextToken(); break; case TOK.float32Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32); nextToken(); break; case TOK.float64Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64); nextToken(); break; case TOK.float80Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80); nextToken(); break; case TOK.imaginary32Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32); nextToken(); break; case TOK.imaginary64Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64); nextToken(); break; case TOK.imaginary80Literal: e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80); nextToken(); break; case TOK.null_: e = new AST.NullExp(loc); nextToken(); break; case TOK.file: { const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); e = new AST.StringExp(loc, cast(char*)s); nextToken(); break; } case TOK.fileFullPath: assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); e = new AST.StringExp(loc, cast(char*)FileName.toAbsolute(loc.filename)); nextToken(); break; case TOK.line: e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); nextToken(); break; case TOK.moduleString: { const(char)* s = md ? md.toChars() : mod.toChars(); e = new AST.StringExp(loc, cast(char*)s); nextToken(); break; } case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); break; case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(loc); nextToken(); break; case TOK.true_: e = new AST.IntegerExp(loc, 1, AST.Type.tbool); nextToken(); break; case TOK.false_: e = new AST.IntegerExp(loc, 0, AST.Type.tbool); nextToken(); break; case TOK.charLiteral: e = new AST.IntegerExp(loc, cast(d_uns8)token.unsvalue, AST.Type.tchar); nextToken(); break; case TOK.wcharLiteral: e = new AST.IntegerExp(loc, cast(d_uns16)token.unsvalue, AST.Type.twchar); nextToken(); break; case TOK.dcharLiteral: e = new AST.IntegerExp(loc, cast(d_uns32)token.unsvalue, AST.Type.tdchar); nextToken(); break; case TOK.string_: case TOK.hexadecimalString: { // cat adjacent strings auto s = token.ustring; auto len = token.len; auto postfix = token.postfix; while (1) { const prev = token; nextToken(); if (token.value == TOK.string_ || token.value == TOK.hexadecimalString) { if (token.postfix) { if (token.postfix != postfix) error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); postfix = token.postfix; } error("Implicit string concatenation is deprecated, use %s ~ %s instead", prev.toChars(), token.toChars()); const len1 = len; const len2 = token.len; len = len1 + len2; auto s2 = cast(char*)mem.xmalloc(len * char.sizeof); memcpy(s2, s, len1 * char.sizeof); memcpy(s2 + len1, token.ustring, len2 * char.sizeof); s = s2; } else break; } e = new AST.StringExp(loc, cast(char*)s, len, postfix); break; } case TOK.void_: t = AST.Type.tvoid; goto LabelX; case TOK.int8: t = AST.Type.tint8; goto LabelX; case TOK.uns8: t = AST.Type.tuns8; goto LabelX; case TOK.int16: t = AST.Type.tint16; goto LabelX; case TOK.uns16: t = AST.Type.tuns16; goto LabelX; case TOK.int32: t = AST.Type.tint32; goto LabelX; case TOK.uns32: t = AST.Type.tuns32; goto LabelX; case TOK.int64: t = AST.Type.tint64; goto LabelX; case TOK.uns64: t = AST.Type.tuns64; goto LabelX; case TOK.int128: t = AST.Type.tint128; goto LabelX; case TOK.uns128: t = AST.Type.tuns128; goto LabelX; case TOK.float32: t = AST.Type.tfloat32; goto LabelX; case TOK.float64: t = AST.Type.tfloat64; goto LabelX; case TOK.float80: t = AST.Type.tfloat80; goto LabelX; case TOK.imaginary32: t = AST.Type.timaginary32; goto LabelX; case TOK.imaginary64: t = AST.Type.timaginary64; goto LabelX; case TOK.imaginary80: t = AST.Type.timaginary80; goto LabelX; case TOK.complex32: t = AST.Type.tcomplex32; goto LabelX; case TOK.complex64: t = AST.Type.tcomplex64; goto LabelX; case TOK.complex80: t = AST.Type.tcomplex80; goto LabelX; case TOK.bool_: t = AST.Type.tbool; goto LabelX; case TOK.char_: t = AST.Type.tchar; goto LabelX; case TOK.wchar_: t = AST.Type.twchar; goto LabelX; case TOK.dchar_: t = AST.Type.tdchar; goto LabelX; LabelX: nextToken(); if (token.value == TOK.leftParentheses) { e = new AST.TypeExp(loc, t); e = new AST.CallExp(loc, e, parseArguments()); break; } check(TOK.dot, t.toChars()); if (token.value != TOK.identifier) { error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars()); goto Lerr; } e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident); nextToken(); break; case TOK.typeof_: { t = parseTypeof(); e = new AST.TypeExp(loc, t); break; } case TOK.vector: { t = parseVector(); e = new AST.TypeExp(loc, t); break; } case TOK.typeid_: { nextToken(); check(TOK.leftParentheses, "`typeid`"); RootObject o; if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null)) { // argument is a type o = parseType(); } else { // argument is an expression o = parseAssignExp(); } check(TOK.rightParentheses); e = new AST.TypeidExp(loc, o); break; } case TOK.traits: { /* __traits(identifier, args...) */ Identifier ident; AST.Objects* args = null; nextToken(); check(TOK.leftParentheses); if (token.value != TOK.identifier) { error("`__traits(identifier, args...)` expected"); goto Lerr; } ident = token.ident; nextToken(); if (token.value == TOK.comma) args = parseTemplateArgumentList(); // __traits(identifier, args...) else check(TOK.rightParentheses); // __traits(identifier) e = new AST.TraitsExp(loc, ident, args); break; } case TOK.is_: { AST.Type targ; Identifier ident = null; AST.Type tspec = null; TOK tok = TOK.reserved; TOK tok2 = TOK.reserved; AST.TemplateParameters* tpl = null; nextToken(); if (token.value == TOK.leftParentheses) { nextToken(); targ = parseType(&ident); if (token.value == TOK.colon || token.value == TOK.equal) { tok = token.value; nextToken(); if (tok == TOK.equal && (token.value == TOK.struct_ || token.value == TOK.union_ || token.value == TOK.class_ || token.value == TOK.super_ || token.value == TOK.enum_ || token.value == TOK.interface_ || token.value == TOK.argumentTypes || token.value == TOK.parameters || token.value == TOK.const_ && peek(&token).value == TOK.rightParentheses || token.value == TOK.immutable_ && peek(&token).value == TOK.rightParentheses || token.value == TOK.shared_ && peek(&token).value == TOK.rightParentheses || token.value == TOK.inout_ && peek(&token).value == TOK.rightParentheses || token.value == TOK.function_ || token.value == TOK.delegate_ || token.value == TOK.return_ || (token.value == TOK.vector && peek(&token).value == TOK.rightParentheses))) { tok2 = token.value; nextToken(); } else { tspec = parseType(); } } if (tspec) { if (token.value == TOK.comma) tpl = parseTemplateParameterList(1); else { tpl = new AST.TemplateParameters(); check(TOK.rightParentheses); } } else check(TOK.rightParentheses); } else { error("`type identifier : specialization` expected following `is`"); goto Lerr; } e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl); break; } case TOK.assert_: { // https://dlang.org/spec/expression.html#assert_expressions AST.Expression msg = null; nextToken(); check(TOK.leftParentheses, "`assert`"); e = parseAssignExp(); if (token.value == TOK.comma) { nextToken(); if (token.value != TOK.rightParentheses) { msg = parseAssignExp(); if (token.value == TOK.comma) nextToken(); } } check(TOK.rightParentheses); e = new AST.AssertExp(loc, e, msg); break; } case TOK.mixin_: { // https://dlang.org/spec/expression.html#mixin_expressions nextToken(); if (token.value != TOK.leftParentheses) error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(TOK.leftParentheses), "`mixin`".ptr); auto exps = parseArguments(); e = new AST.CompileExp(loc, exps); break; } case TOK.import_: { nextToken(); check(TOK.leftParentheses, "`import`"); e = parseAssignExp(); check(TOK.rightParentheses); e = new AST.ImportExp(loc, e); break; } case TOK.new_: e = parseNewExp(null); break; case TOK.leftParentheses: { Token* tk = peekPastParen(&token); if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)) { // (arguments) => expression // (arguments) { statements... } goto case_delegate; } // ( expression ) nextToken(); e = parseExpression(); e.parens = 1; check(loc, TOK.rightParentheses); break; } case TOK.leftBracket: { /* Parse array literals and associative array literals: * [ value, value, value ... ] * [ key:value, key:value, key:value ... ] */ auto values = new AST.Expressions(); AST.Expressions* keys = null; nextToken(); while (token.value != TOK.rightBracket && token.value != TOK.endOfFile) { e = parseAssignExp(); if (token.value == TOK.colon && (keys || values.dim == 0)) { nextToken(); if (!keys) keys = new AST.Expressions(); keys.push(e); e = parseAssignExp(); } else if (keys) { error("`key:value` expected for associative array literal"); keys = null; } values.push(e); if (token.value == TOK.rightBracket) break; check(TOK.comma); } check(loc, TOK.rightBracket); if (keys) e = new AST.AssocArrayLiteralExp(loc, keys, values); else e = new AST.ArrayLiteralExp(loc, null, values); break; } case TOK.leftCurly: case TOK.function_: case TOK.delegate_: case_delegate: { AST.Dsymbol s = parseFunctionLiteral(); e = new AST.FuncExp(loc, s); break; } default: error("expression expected, not `%s`", token.toChars()); Lerr: // Anything for e, as long as it's not NULL e = new AST.IntegerExp(loc, 0, AST.Type.tint32); nextToken(); break; } return e; } AST.Expression parseUnaryExp() { AST.Expression e; const loc = token.loc; switch (token.value) { case TOK.and: nextToken(); e = parseUnaryExp(); e = new AST.AddrExp(loc, e); break; case TOK.plusPlus: nextToken(); e = parseUnaryExp(); //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); e = new AST.PreExp(TOK.prePlusPlus, loc, e); break; case TOK.minusMinus: nextToken(); e = parseUnaryExp(); //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); e = new AST.PreExp(TOK.preMinusMinus, loc, e); break; case TOK.mul: nextToken(); e = parseUnaryExp(); e = new AST.PtrExp(loc, e); break; case TOK.min: nextToken(); e = parseUnaryExp(); e = new AST.NegExp(loc, e); break; case TOK.add: nextToken(); e = parseUnaryExp(); e = new AST.UAddExp(loc, e); break; case TOK.not: nextToken(); e = parseUnaryExp(); e = new AST.NotExp(loc, e); break; case TOK.tilde: nextToken(); e = parseUnaryExp(); e = new AST.ComExp(loc, e); break; case TOK.delete_: nextToken(); e = parseUnaryExp(); e = new AST.DeleteExp(loc, e, false); break; case TOK.cast_: // cast(type) expression { nextToken(); check(TOK.leftParentheses); /* Look for cast(), cast(const), cast(immutable), * cast(shared), cast(shared const), cast(wild), cast(shared wild) */ ubyte m = 0; while (1) { switch (token.value) { case TOK.const_: if (peekNext() == TOK.leftParentheses) break; // const as type constructor m |= AST.MODFlags.const_; // const as storage class nextToken(); continue; case TOK.immutable_: if (peekNext() == TOK.leftParentheses) break; m |= AST.MODFlags.immutable_; nextToken(); continue; case TOK.shared_: if (peekNext() == TOK.leftParentheses) break; m |= AST.MODFlags.shared_; nextToken(); continue; case TOK.inout_: if (peekNext() == TOK.leftParentheses) break; m |= AST.MODFlags.wild; nextToken(); continue; default: break; } break; } if (token.value == TOK.rightParentheses) { nextToken(); e = parseUnaryExp(); e = new AST.CastExp(loc, e, m); } else { AST.Type t = parseType(); // cast( type ) t = t.addMod(m); // cast( const type ) check(TOK.rightParentheses); e = parseUnaryExp(); e = new AST.CastExp(loc, e, t); } break; } case TOK.inout_: case TOK.shared_: case TOK.const_: case TOK.immutable_: // immutable(type)(arguments) / immutable(type).init { StorageClass stc = parseTypeCtor(); AST.Type t = parseBasicType(); t = t.addSTC(stc); if (stc == 0 && token.value == TOK.dot) { nextToken(); if (token.value != TOK.identifier) { error("identifier expected following `(type)`."); return null; } e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident); nextToken(); e = parsePostExp(e); } else { e = new AST.TypeExp(loc, t); if (token.value != TOK.leftParentheses) { error("`(arguments)` expected following `%s`", t.toChars()); return e; } e = new AST.CallExp(loc, e, parseArguments()); } break; } case TOK.leftParentheses: { auto tk = peek(&token); static if (CCASTSYNTAX) { // If cast if (isDeclaration(tk, NeedDeclaratorId.no, TOK.rightParentheses, &tk)) { tk = peek(tk); // skip over right parenthesis switch (tk.value) { case TOK.not: tk = peek(tk); if (tk.value == TOK.is_ || tk.value == TOK.in_) // !is or !in break; goto case; case TOK.dot: case TOK.plusPlus: case TOK.minusMinus: case TOK.delete_: case TOK.new_: case TOK.leftParentheses: case TOK.identifier: case TOK.this_: case TOK.super_: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: case TOK.uns64Literal: case TOK.int128Literal: case TOK.uns128Literal: case TOK.float32Literal: case TOK.float64Literal: case TOK.float80Literal: case TOK.imaginary32Literal: case TOK.imaginary64Literal: case TOK.imaginary80Literal: case TOK.null_: case TOK.true_: case TOK.false_: case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: version (none) { case TOK.tilde: case TOK.and: case TOK.mul: case TOK.min: case TOK.add: } case TOK.function_: case TOK.delegate_: case TOK.typeof_: case TOK.vector: case TOK.file: case TOK.fileFullPath: case TOK.line: case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: { // (type) una_exp nextToken(); auto t = parseType(); check(TOK.rightParentheses); // if .identifier // or .identifier!( ... ) if (token.value == TOK.dot) { if (peekNext() != TOK.identifier && peekNext() != TOK.new_) { error("identifier or new keyword expected following `(...)`."); return null; } e = new AST.TypeExp(loc, t); e = parsePostExp(e); } else { e = parseUnaryExp(); e = new AST.CastExp(loc, e, t); error("C style cast illegal, use `%s`", e.toChars()); } return e; } default: break; } } } e = parsePrimaryExp(); e = parsePostExp(e); break; } default: e = parsePrimaryExp(); e = parsePostExp(e); break; } assert(e); // ^^ is right associative and has higher precedence than the unary operators while (token.value == TOK.pow) { nextToken(); AST.Expression e2 = parseUnaryExp(); e = new AST.PowExp(loc, e, e2); } return e; } AST.Expression parsePostExp(AST.Expression e) { while (1) { const loc = token.loc; switch (token.value) { case TOK.dot: nextToken(); if (token.value == TOK.identifier) { Identifier id = token.ident; nextToken(); if (token.value == TOK.not && peekNext() != TOK.is_ && peekNext() != TOK.in_) { AST.Objects* tiargs = parseTemplateArguments(); e = new AST.DotTemplateInstanceExp(loc, e, id, tiargs); } else e = new AST.DotIdExp(loc, e, id); continue; } else if (token.value == TOK.new_) { e = parseNewExp(e); continue; } else error("identifier expected following `.`, not `%s`", token.toChars()); break; case TOK.plusPlus: e = new AST.PostExp(TOK.plusPlus, loc, e); break; case TOK.minusMinus: e = new AST.PostExp(TOK.minusMinus, loc, e); break; case TOK.leftParentheses: e = new AST.CallExp(loc, e, parseArguments()); continue; case TOK.leftBracket: { // array dereferences: // array[index] // array[] // array[lwr .. upr] AST.Expression index; AST.Expression upr; auto arguments = new AST.Expressions(); inBrackets++; nextToken(); while (token.value != TOK.rightBracket && token.value != TOK.endOfFile) { index = parseAssignExp(); if (token.value == TOK.slice) { // array[..., lwr..upr, ...] nextToken(); upr = parseAssignExp(); arguments.push(new AST.IntervalExp(loc, index, upr)); } else arguments.push(index); if (token.value == TOK.rightBracket) break; check(TOK.comma); } check(TOK.rightBracket); inBrackets--; e = new AST.ArrayExp(loc, e, arguments); continue; } default: return e; } nextToken(); } } AST.Expression parseMulExp() { const loc = token.loc; auto e = parseUnaryExp(); while (1) { switch (token.value) { case TOK.mul: nextToken(); auto e2 = parseUnaryExp(); e = new AST.MulExp(loc, e, e2); continue; case TOK.div: nextToken(); auto e2 = parseUnaryExp(); e = new AST.DivExp(loc, e, e2); continue; case TOK.mod: nextToken(); auto e2 = parseUnaryExp(); e = new AST.ModExp(loc, e, e2); continue; default: break; } break; } return e; } AST.Expression parseAddExp() { const loc = token.loc; auto e = parseMulExp(); while (1) { switch (token.value) { case TOK.add: nextToken(); auto e2 = parseMulExp(); e = new AST.AddExp(loc, e, e2); continue; case TOK.min: nextToken(); auto e2 = parseMulExp(); e = new AST.MinExp(loc, e, e2); continue; case TOK.tilde: nextToken(); auto e2 = parseMulExp(); e = new AST.CatExp(loc, e, e2); continue; default: break; } break; } return e; } AST.Expression parseShiftExp() { const loc = token.loc; auto e = parseAddExp(); while (1) { switch (token.value) { case TOK.leftShift: nextToken(); auto e2 = parseAddExp(); e = new AST.ShlExp(loc, e, e2); continue; case TOK.rightShift: nextToken(); auto e2 = parseAddExp(); e = new AST.ShrExp(loc, e, e2); continue; case TOK.unsignedRightShift: nextToken(); auto e2 = parseAddExp(); e = new AST.UshrExp(loc, e, e2); continue; default: break; } break; } return e; } AST.Expression parseCmpExp() { const loc = token.loc; auto e = parseShiftExp(); TOK op = token.value; switch (op) { case TOK.equal: case TOK.notEqual: nextToken(); auto e2 = parseShiftExp(); e = new AST.EqualExp(op, loc, e, e2); break; case TOK.is_: op = TOK.identity; goto L1; case TOK.not: { // Attempt to identify '!is' auto t = peek(&token); if (t.value == TOK.in_) { nextToken(); nextToken(); auto e2 = parseShiftExp(); e = new AST.InExp(loc, e, e2); e = new AST.NotExp(loc, e); break; } if (t.value != TOK.is_) break; nextToken(); op = TOK.notIdentity; goto L1; } L1: nextToken(); auto e2 = parseShiftExp(); e = new AST.IdentityExp(op, loc, e, e2); break; case TOK.lessThan: case TOK.lessOrEqual: case TOK.greaterThan: case TOK.greaterOrEqual: nextToken(); auto e2 = parseShiftExp(); e = new AST.CmpExp(op, loc, e, e2); break; case TOK.in_: nextToken(); auto e2 = parseShiftExp(); e = new AST.InExp(loc, e, e2); break; default: break; } return e; } AST.Expression parseAndExp() { Loc loc = token.loc; auto e = parseCmpExp(); while (token.value == TOK.and) { checkParens(TOK.and, e); nextToken(); auto e2 = parseCmpExp(); checkParens(TOK.and, e2); e = new AST.AndExp(loc, e, e2); loc = token.loc; } return e; } AST.Expression parseXorExp() { const loc = token.loc; auto e = parseAndExp(); while (token.value == TOK.xor) { checkParens(TOK.xor, e); nextToken(); auto e2 = parseAndExp(); checkParens(TOK.xor, e2); e = new AST.XorExp(loc, e, e2); } return e; } AST.Expression parseOrExp() { const loc = token.loc; auto e = parseXorExp(); while (token.value == TOK.or) { checkParens(TOK.or, e); nextToken(); auto e2 = parseXorExp(); checkParens(TOK.or, e2); e = new AST.OrExp(loc, e, e2); } return e; } AST.Expression parseAndAndExp() { const loc = token.loc; auto e = parseOrExp(); while (token.value == TOK.andAnd) { nextToken(); auto e2 = parseOrExp(); e = new AST.LogicalExp(loc, TOK.andAnd, e, e2); } return e; } AST.Expression parseOrOrExp() { const loc = token.loc; auto e = parseAndAndExp(); while (token.value == TOK.orOr) { nextToken(); auto e2 = parseAndAndExp(); e = new AST.LogicalExp(loc, TOK.orOr, e, e2); } return e; } AST.Expression parseCondExp() { const loc = token.loc; auto e = parseOrOrExp(); if (token.value == TOK.question) { nextToken(); auto e1 = parseExpression(); check(TOK.colon); auto e2 = parseCondExp(); e = new AST.CondExp(loc, e, e1, e2); } return e; } AST.Expression parseAssignExp() { auto e = parseCondExp(); // require parens for e.g. `t ? a = 1 : b = 2` // Deprecated in 2018-05. // @@@DEPRECATED_2.091@@@. if (e.op == TOK.question && !e.parens && precedence[token.value] == PREC.assign) dmd.errors.deprecation(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(token.value)); const loc = token.loc; switch (token.value) { case TOK.assign: nextToken(); auto e2 = parseAssignExp(); e = new AST.AssignExp(loc, e, e2); break; case TOK.addAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.AddAssignExp(loc, e, e2); break; case TOK.minAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.MinAssignExp(loc, e, e2); break; case TOK.mulAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.MulAssignExp(loc, e, e2); break; case TOK.divAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.DivAssignExp(loc, e, e2); break; case TOK.modAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.ModAssignExp(loc, e, e2); break; case TOK.powAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.PowAssignExp(loc, e, e2); break; case TOK.andAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.AndAssignExp(loc, e, e2); break; case TOK.orAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.OrAssignExp(loc, e, e2); break; case TOK.xorAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.XorAssignExp(loc, e, e2); break; case TOK.leftShiftAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.ShlAssignExp(loc, e, e2); break; case TOK.rightShiftAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.ShrAssignExp(loc, e, e2); break; case TOK.unsignedRightShiftAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.UshrAssignExp(loc, e, e2); break; case TOK.concatenateAssign: nextToken(); auto e2 = parseAssignExp(); e = new AST.CatAssignExp(loc, e, e2); break; default: break; } return e; } /************************* * Collect argument list. * Assume current token is ',', '$(LPAREN)' or '['. */ AST.Expressions* parseArguments() { // function call AST.Expressions* arguments; TOK endtok; arguments = new AST.Expressions(); if (token.value == TOK.leftBracket) endtok = TOK.rightBracket; else endtok = TOK.rightParentheses; { nextToken(); while (token.value != endtok && token.value != TOK.endOfFile) { auto arg = parseAssignExp(); arguments.push(arg); if (token.value == endtok) break; check(TOK.comma); } check(endtok); } return arguments; } /******************************************* */ AST.Expression parseNewExp(AST.Expression thisexp) { const loc = token.loc; nextToken(); AST.Expressions* newargs = null; AST.Expressions* arguments = null; if (token.value == TOK.leftParentheses) { newargs = parseArguments(); } // An anonymous nested class starts with "class" if (token.value == TOK.class_) { nextToken(); if (token.value == TOK.leftParentheses) arguments = parseArguments(); AST.BaseClasses* baseclasses = null; if (token.value != TOK.leftCurly) baseclasses = parseBaseClasses(); Identifier id = null; AST.Dsymbols* members = null; if (token.value != TOK.leftCurly) { error("`{ members }` expected for anonymous class"); } else { nextToken(); members = parseDeclDefs(0); if (token.value != TOK.rightCurly) error("class member expected"); nextToken(); } auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false); auto e = new AST.NewAnonClassExp(loc, thisexp, newargs, cd, arguments); return e; } const stc = parseTypeCtor(); auto t = parseBasicType(true); t = parseBasicType2(t); t = t.addSTC(stc); if (t.ty == AST.Taarray) { AST.TypeAArray taa = cast(AST.TypeAArray)t; AST.Type index = taa.index; auto edim = AST.typeToExpression(index); if (!edim) { error("need size of rightmost array, not type `%s`", index.toChars()); return new AST.NullExp(loc); } t = new AST.TypeSArray(taa.next, edim); } else if (t.ty == AST.Tsarray) { } else if (token.value == TOK.leftParentheses) { arguments = parseArguments(); } auto e = new AST.NewExp(loc, thisexp, newargs, t, arguments); return e; } /********************************************** */ void addComment(AST.Dsymbol s, const(char)* blockComment) { if (s !is null) { s.addComment(combineComments(blockComment, token.lineComment, true)); token.lineComment = null; } } } enum PREC : int { zero, expr, assign, cond, oror, andand, or, xor, and, equal, rel, shift, add, mul, pow, unary, primary, } ================================================ FILE: gcc/d/dmd/parsetimevisitor.d ================================================ /** * Documentation: https://dlang.org/phobos/dmd_parsetimevisitor.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parsetimevisitor.d */ module dmd.parsetimevisitor; /** Basic and dumm visitor which implements a visit method for each AST node * implemented in AST. This visitor is the parent of strict, transitive * and permissive visitors. */ extern (C++) class ParseTimeVisitor(AST) { public: void visit(AST.Dsymbol) { assert(0); } void visit(AST.Parameter) { assert(0); } void visit(AST.Statement) { assert(0); } void visit(AST.Type) { assert(0); } void visit(AST.Expression) { assert(0); } void visit(AST.TemplateParameter) { assert(0); } void visit(AST.Condition) { assert(0); } void visit(AST.Initializer) { assert(0); } //======================================================================================= // Dsymbols void visit(AST.AliasThis s) { visit(cast(AST.Dsymbol)s); } void visit(AST.Declaration s) { visit(cast(AST.Dsymbol)s); } void visit(AST.ScopeDsymbol s) { visit(cast(AST.Dsymbol)s); } void visit(AST.Import s) { visit(cast(AST.Dsymbol)s); } void visit(AST.AttribDeclaration s) { visit(cast(AST.Dsymbol)s); } void visit(AST.StaticAssert s) { visit(cast(AST.Dsymbol)s); } void visit(AST.DebugSymbol s) { visit(cast(AST.Dsymbol)s); } void visit(AST.VersionSymbol s) { visit(cast(AST.Dsymbol)s); } // ScopeDsymbols void visit(AST.Package s) { visit(cast(AST.ScopeDsymbol)s); } void visit(AST.EnumDeclaration s) { visit(cast(AST.ScopeDsymbol)s); } void visit(AST.AggregateDeclaration s) { visit(cast(AST.ScopeDsymbol)s); } void visit(AST.TemplateDeclaration s) { visit(cast(AST.ScopeDsymbol)s); } void visit(AST.TemplateInstance s) { visit(cast(AST.ScopeDsymbol)s); } void visit(AST.Nspace s) { visit(cast(AST.ScopeDsymbol)s); } //========================================================================================= // Declarations void visit(AST.VarDeclaration s) { visit(cast(AST.Declaration)s); } void visit(AST.FuncDeclaration s) { visit(cast(AST.Declaration)s); } void visit(AST.AliasDeclaration s) { visit(cast(AST.Declaration)s); } void visit(AST.TupleDeclaration s) { visit(cast(AST.Declaration)s); } // FuncDeclarations void visit(AST.FuncLiteralDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.PostBlitDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.CtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.DtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.InvariantDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.UnitTestDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.NewDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.DeleteDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.StaticCtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.StaticDtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.SharedStaticCtorDeclaration s) { visit(cast(AST.StaticCtorDeclaration)s); } void visit(AST.SharedStaticDtorDeclaration s) { visit(cast(AST.StaticDtorDeclaration)s); } // AttribDeclarations void visit(AST.CompileDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.UserAttributeDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.LinkDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.AnonDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.AlignDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.CPPMangleDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.ProtDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.PragmaDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.StorageClassDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.ConditionalDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.StaticForeachDeclaration s) { visit(cast(AST.AttribDeclaration)s); } //============================================================================================== // Miscellaneous void visit(AST.DeprecatedDeclaration s) { visit(cast(AST.StorageClassDeclaration)s); } void visit(AST.StaticIfDeclaration s) { visit(cast(AST.ConditionalDeclaration)s); } void visit(AST.EnumMember s) { visit(cast(AST.VarDeclaration)s); } void visit(AST.Module s) { visit(cast(AST.Package)s); } void visit(AST.StructDeclaration s) { visit(cast(AST.AggregateDeclaration)s); } void visit(AST.UnionDeclaration s) { visit(cast(AST.StructDeclaration)s); } void visit(AST.ClassDeclaration s) { visit(cast(AST.AggregateDeclaration)s); } void visit(AST.InterfaceDeclaration s) { visit(cast(AST.ClassDeclaration)s); } void visit(AST.TemplateMixin s) { visit(cast(AST.TemplateInstance)s); } //============================================================================================ // Statements void visit(AST.ImportStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ScopeStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ReturnStatement s) { visit(cast(AST.Statement)s); } void visit(AST.LabelStatement s) { visit(cast(AST.Statement)s); } void visit(AST.StaticAssertStatement s) { visit(cast(AST.Statement)s); } void visit(AST.CompileStatement s) { visit(cast(AST.Statement)s); } void visit(AST.WhileStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ForStatement s) { visit(cast(AST.Statement)s); } void visit(AST.DoStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ForeachRangeStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ForeachStatement s) { visit(cast(AST.Statement)s); } void visit(AST.IfStatement s) { visit(cast(AST.Statement)s); } void visit(AST.OnScopeStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ConditionalStatement s) { visit(cast(AST.Statement)s); } void visit(AST.StaticForeachStatement s) { visit(cast(AST.Statement)s); } void visit(AST.PragmaStatement s) { visit(cast(AST.Statement)s); } void visit(AST.SwitchStatement s) { visit(cast(AST.Statement)s); } void visit(AST.CaseRangeStatement s) { visit(cast(AST.Statement)s); } void visit(AST.CaseStatement s) { visit(cast(AST.Statement)s); } void visit(AST.DefaultStatement s) { visit(cast(AST.Statement)s); } void visit(AST.BreakStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ContinueStatement s) { visit(cast(AST.Statement)s); } void visit(AST.GotoDefaultStatement s) { visit(cast(AST.Statement)s); } void visit(AST.GotoCaseStatement s) { visit(cast(AST.Statement)s); } void visit(AST.GotoStatement s) { visit(cast(AST.Statement)s); } void visit(AST.SynchronizedStatement s) { visit(cast(AST.Statement)s); } void visit(AST.WithStatement s) { visit(cast(AST.Statement)s); } void visit(AST.TryCatchStatement s) { visit(cast(AST.Statement)s); } void visit(AST.TryFinallyStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ThrowStatement s) { visit(cast(AST.Statement)s); } void visit(AST.AsmStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ExpStatement s) { visit(cast(AST.Statement)s); } void visit(AST.CompoundStatement s) { visit(cast(AST.Statement)s); } // CompoundStatements void visit(AST.CompoundDeclarationStatement s) { visit(cast(AST.CompoundStatement)s); } void visit(AST.CompoundAsmStatement s) { visit(cast(AST.CompoundStatement)s); } // AsmStatements void visit(AST.InlineAsmStatement s) { visit(cast(AST.AsmStatement)s); } void visit(AST.GccAsmStatement s) { visit(cast(AST.AsmStatement)s); } //========================================================================================= // Types void visit(AST.TypeBasic t) { visit(cast(AST.Type)t); } void visit(AST.TypeError t) { visit(cast(AST.Type)t); } void visit(AST.TypeNull t) { visit(cast(AST.Type)t); } void visit(AST.TypeVector t) { visit(cast(AST.Type)t); } void visit(AST.TypeEnum t) { visit(cast(AST.Type)t); } void visit(AST.TypeTuple t) { visit(cast(AST.Type)t); } void visit(AST.TypeClass t) { visit(cast(AST.Type)t); } void visit(AST.TypeStruct t) { visit(cast(AST.Type)t); } void visit(AST.TypeNext t) { visit(cast(AST.Type)t); } void visit(AST.TypeQualified t) { visit(cast(AST.Type)t); } // TypeNext void visit(AST.TypeReference t) { visit(cast(AST.TypeNext)t); } void visit(AST.TypeSlice t) { visit(cast(AST.TypeNext)t); } void visit(AST.TypeDelegate t) { visit(cast(AST.TypeNext)t); } void visit(AST.TypePointer t) { visit(cast(AST.TypeNext)t); } void visit(AST.TypeFunction t) { visit(cast(AST.TypeNext)t); } void visit(AST.TypeArray t) { visit(cast(AST.TypeNext)t); } // TypeArray void visit(AST.TypeDArray t) { visit(cast(AST.TypeArray)t); } void visit(AST.TypeAArray t) { visit(cast(AST.TypeArray)t); } void visit(AST.TypeSArray t) { visit(cast(AST.TypeArray)t); } // TypeQualified void visit(AST.TypeIdentifier t) { visit(cast(AST.TypeQualified)t); } void visit(AST.TypeReturn t) { visit(cast(AST.TypeQualified)t); } void visit(AST.TypeTypeof t) { visit(cast(AST.TypeQualified)t); } void visit(AST.TypeInstance t) { visit(cast(AST.TypeQualified)t); } //================================================================================= // Expressions void visit(AST.DeclarationExp e) { visit(cast(AST.Expression)e); } void visit(AST.IntegerExp e) { visit(cast(AST.Expression)e); } void visit(AST.NewAnonClassExp e) { visit(cast(AST.Expression)e); } void visit(AST.IsExp e) { visit(cast(AST.Expression)e); } void visit(AST.RealExp e) { visit(cast(AST.Expression)e); } void visit(AST.NullExp e) { visit(cast(AST.Expression)e); } void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); } void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); } void visit(AST.StringExp e) { visit(cast(AST.Expression)e); } void visit(AST.NewExp e) { visit(cast(AST.Expression)e); } void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); } void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); } void visit(AST.CompileExp e) { visit(cast(AST.Expression)e); } void visit(AST.FuncExp e) { visit(cast(AST.Expression)e); } void visit(AST.IntervalExp e) { visit(cast(AST.Expression)e); } void visit(AST.TypeExp e) { visit(cast(AST.Expression)e); } void visit(AST.ScopeExp e) { visit(cast(AST.Expression)e); } void visit(AST.IdentifierExp e) { visit(cast(AST.Expression)e); } void visit(AST.UnaExp e) { visit(cast(AST.Expression)e); } void visit(AST.DefaultInitExp e) { visit(cast(AST.Expression)e); } void visit(AST.BinExp e) { visit(cast(AST.Expression)e); } void visit(AST.DsymbolExp e) { visit(cast(AST.Expression)e); } void visit(AST.TemplateExp e) { visit(cast(AST.Expression)e); } void visit(AST.SymbolExp e) { visit(cast(AST.Expression)e); } void visit(AST.TupleExp e) { visit(cast(AST.Expression)e); } void visit(AST.ThisExp e) { visit(cast(AST.Expression)e); } // Miscellaneous void visit(AST.VarExp e) { visit(cast(AST.SymbolExp)e); } void visit(AST.DollarExp e) { visit(cast(AST.IdentifierExp)e); } void visit(AST.SuperExp e) { visit(cast(AST.ThisExp)e); } // UnaExp void visit(AST.AddrExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.PreExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.PtrExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.NegExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.UAddExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.NotExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.ComExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.DeleteExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.CastExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.CallExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.DotIdExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.AssertExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.ImportExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.DotTemplateInstanceExp e) { visit(cast(AST.UnaExp)e); } void visit(AST.ArrayExp e) { visit(cast(AST.UnaExp)e); } // DefaultInitExp void visit(AST.FuncInitExp e) { visit(cast(AST.DefaultInitExp)e); } void visit(AST.PrettyFuncInitExp e) { visit(cast(AST.DefaultInitExp)e); } void visit(AST.FileInitExp e) { visit(cast(AST.DefaultInitExp)e); } void visit(AST.LineInitExp e) { visit(cast(AST.DefaultInitExp)e); } void visit(AST.ModuleInitExp e) { visit(cast(AST.DefaultInitExp)e); } // BinExp void visit(AST.CommaExp e) { visit(cast(AST.BinExp)e); } void visit(AST.PostExp e) { visit(cast(AST.BinExp)e); } void visit(AST.PowExp e) { visit(cast(AST.BinExp)e); } void visit(AST.MulExp e) { visit(cast(AST.BinExp)e); } void visit(AST.DivExp e) { visit(cast(AST.BinExp)e); } void visit(AST.ModExp e) { visit(cast(AST.BinExp)e); } void visit(AST.AddExp e) { visit(cast(AST.BinExp)e); } void visit(AST.MinExp e) { visit(cast(AST.BinExp)e); } void visit(AST.CatExp e) { visit(cast(AST.BinExp)e); } void visit(AST.ShlExp e) { visit(cast(AST.BinExp)e); } void visit(AST.ShrExp e) { visit(cast(AST.BinExp)e); } void visit(AST.UshrExp e) { visit(cast(AST.BinExp)e); } void visit(AST.EqualExp e) { visit(cast(AST.BinExp)e); } void visit(AST.InExp e) { visit(cast(AST.BinExp)e); } void visit(AST.IdentityExp e) { visit(cast(AST.BinExp)e); } void visit(AST.CmpExp e) { visit(cast(AST.BinExp)e); } void visit(AST.AndExp e) { visit(cast(AST.BinExp)e); } void visit(AST.XorExp e) { visit(cast(AST.BinExp)e); } void visit(AST.OrExp e) { visit(cast(AST.BinExp)e); } void visit(AST.LogicalExp e) { visit(cast(AST.BinExp)e); } void visit(AST.CondExp e) { visit(cast(AST.BinExp)e); } void visit(AST.AssignExp e) { visit(cast(AST.BinExp)e); } void visit(AST.BinAssignExp e) { visit(cast(AST.BinExp)e); } // BinAssignExp void visit(AST.AddAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.MinAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.MulAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.DivAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.ModAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.PowAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.AndAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.OrAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.XorAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.ShlAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.ShrAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.UshrAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.CatAssignExp e) { visit(cast(AST.BinAssignExp)e); } //=============================================================================== // TemplateParameter void visit(AST.TemplateAliasParameter tp) { visit(cast(AST.TemplateParameter)tp); } void visit(AST.TemplateTypeParameter tp) { visit(cast(AST.TemplateParameter)tp); } void visit(AST.TemplateTupleParameter tp) { visit(cast(AST.TemplateParameter)tp); } void visit(AST.TemplateValueParameter tp) { visit(cast(AST.TemplateParameter)tp); } void visit(AST.TemplateThisParameter tp) { visit(cast(AST.TemplateTypeParameter)tp); } //=============================================================================== // Condition void visit(AST.StaticIfCondition c) { visit(cast(AST.Condition)c); } void visit(AST.DVCondition c) { visit(cast(AST.Condition)c); } void visit(AST.DebugCondition c) { visit(cast(AST.DVCondition)c); } void visit(AST.VersionCondition c) { visit(cast(AST.DVCondition)c); } //=============================================================================== // Initializer void visit(AST.ExpInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); } } ================================================ FILE: gcc/d/dmd/permissivevisitor.d ================================================ /** * Documentation: https://dlang.org/phobos/dmd_permissivevisitor.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/permissivevisitor.d */ module dmd.permissivevisitor; import dmd.parsetimevisitor; /** PermissiveVisitor overrides all the visit methods in the parent class * that assert(0) in order to facilitate the traversal of subsets of the AST. * It does not implement any visiting logic. */ extern(C++) class PermissiveVisitor(AST): ParseTimeVisitor!AST { alias visit = ParseTimeVisitor!AST.visit; override void visit(AST.Dsymbol){} override void visit(AST.Parameter){} override void visit(AST.Statement){} override void visit(AST.Type){} override void visit(AST.Expression){} override void visit(AST.TemplateParameter){} override void visit(AST.Condition){} override void visit(AST.Initializer){} } ================================================ FILE: gcc/d/dmd/readme.txt ================================================ This is the source code to the DMD compiler for the D Programming Language defined in the documents at http://dlang.org/ These sources are free, they are redistributable and modifiable under the terms of the Boost Software License, Version 1.0. The terms of this license are in the file boostlicense.txt, or see http://www.boost.org/LICENSE_1_0.txt. If a particular file has a different license in it, that overrides this license for that file. -Walter Bright ================================================ FILE: gcc/d/dmd/root/aav.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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) { a ^= (a >> 20) ^ (a >> 12); 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 { 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) { //printf("paa = %p\n", paa); if (!*paa) { AA* a = cast(AA*)mem.xmalloc(AA.sizeof); a.b = cast(aaA**)a.binit; a.b_length = 4; a.nodes = 0; a.binit[0] = null; a.binit[1] = null; a.binit[2] = null; a.binit[3] = null; *paa = a; assert((*paa).b_length == 4); } //printf("paa = %p, *paa = %p\n", paa, *paa); assert((*paa).b_length); size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1); aaA** pe = &(*paa).b[i]; aaA* e; while ((e = *pe) !is null) { if (key == e.key) return &e.value; pe = &e.next; } // Not found, create new elem //printf("create new one\n"); size_t nodes = ++(*paa).nodes; e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst; //e = new aaA(); e.next = null; e.key = key; e.value = null; *pe = e; //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes); if (nodes > (*paa).b_length * 2) { //printf("rehash\n"); dmd_aaRehash(paa); } return &e.value; } /************************************************* * Get value in associative array indexed by key. * Returns NULL if it is not already there. */ private Value dmd_aaGetRvalue(AA* aa, Key key) { //printf("_aaGetRvalue(key = %p)\n", key); if (aa) { size_t i; size_t len = aa.b_length; i = hash(cast(size_t)key) & (len - 1); aaA* e = aa.b[i]; while (e) { if (key == e.key) return e.value; e = e.next; } } return null; // not found } debug { /** Gets a range of key/values for `aa`. Returns: a range of key/values for `aa`. */ @property auto asRange(AA* aa) { return AARange!(Key, Value)(aa); } private struct AARange(K,V) { AA* aa; // current index into bucket array `aa.b` size_t bIndex; aaA* current; this(AA* aa) { if (aa) { this.aa = aa; toNext(); } } @property bool empty() const { return current is null; } @property auto front() { return cast(KeyValueTemplate!(K,V))current.keyValue; } void popFront() { if (current.next) current = current.next; else { bIndex++; toNext(); } } private void toNext() { for (; bIndex < aa.b_length; bIndex++) { if (auto next = aa.b[bIndex]) { current = next; return; } } 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) { //printf("Rehash\n"); if (*paa) { AA* aa = *paa; if (aa) { size_t len = aa.b_length; if (len == 4) len = 32; else len *= 4; aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len); memset(newb, 0, len * (aaA*).sizeof); for (size_t k = 0; k < aa.b_length; k++) { aaA* e = aa.b[k]; while (e) { aaA* enext = e.next; size_t j = hash(cast(size_t)e.key) & (len - 1); e.next = newb[j]; newb[j] = e; e = enext; } } if (aa.b != cast(aaA**)aa.binit) mem.xfree(aa.b); aa.b = newb; 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 { 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) { 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) { return cast(V)dmd_aaGetRvalue(aa, cast(void*)key); } debug { /** Gets a range of key/values for `aa`. Returns: a range of key/values for `aa`. */ @property auto asRange() { 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); } ================================================ FILE: gcc/d/dmd/root/array.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/root/array.d, root/_array.d) * Documentation: https://dlang.org/phobos/dmd_root_array.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/array.d */ module dmd.root.array; import core.stdc.string; import dmd.root.rmem; extern (C++) struct Array(T) { size_t dim; T* data; private: size_t allocdim; enum SMALLARRAYCAP = 1; T[SMALLARRAYCAP] smallarray; // inline storage for small arrays public: /******************* * Params: * dim = initial length of array */ this(size_t dim) { reserve(dim); this.dim = dim; } @disable this(this); ~this() nothrow { if (data != &smallarray[0]) mem.xfree(data); } const(char)* toChars() { static if (is(typeof(T.init.toChars()))) { const(char)** buf = cast(const(char)**)mem.xmalloc(dim * (char*).sizeof); size_t len = 2; for (size_t u = 0; u < dim; u++) { buf[u] = data[u].toChars(); len += strlen(buf[u]) + 1; } char* str = cast(char*)mem.xmalloc(len); str[0] = '['; char* p = str + 1; for (size_t u = 0; u < dim; u++) { if (u) *p++ = ','; len = strlen(buf[u]); memcpy(p, buf[u], len); p += len; } *p++ = ']'; *p = 0; mem.xfree(buf); return str; } else { assert(0); } } void push(T ptr) nothrow { reserve(1); data[dim++] = ptr; } void append(typeof(this)* a) nothrow { insert(dim, a); } void reserve(size_t nentries) nothrow { //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries); if (allocdim - dim < nentries) { if (allocdim == 0) { // Not properly initialized, someone memset it to zero if (nentries <= SMALLARRAYCAP) { allocdim = SMALLARRAYCAP; data = SMALLARRAYCAP ? smallarray.ptr : null; } else { allocdim = nentries; data = cast(T*)mem.xmalloc(allocdim * (*data).sizeof); } } else if (allocdim == SMALLARRAYCAP) { allocdim = dim + nentries; data = cast(T*)mem.xmalloc(allocdim * (*data).sizeof); memcpy(data, smallarray.ptr, dim * (*data).sizeof); } else { /* Increase size by 1.5x to avoid excessive memory fragmentation */ auto increment = dim / 2; if (nentries > increment) // if 1.5 is not enough increment = nentries; allocdim = dim + increment; data = cast(T*)mem.xrealloc(data, allocdim * (*data).sizeof); } } } void remove(size_t i) nothrow { if (dim - i - 1) memmove(data + i, data + i + 1, (dim - i - 1) * (data[0]).sizeof); dim--; } void insert(size_t index, typeof(this)* a) nothrow { if (a) { size_t d = a.dim; reserve(d); if (dim != index) memmove(data + index + d, data + index, (dim - index) * (*data).sizeof); memcpy(data + index, a.data, d * (*data).sizeof); dim += d; } } void insert(size_t index, T ptr) nothrow { reserve(1); memmove(data + index + 1, data + index, (dim - index) * (*data).sizeof); data[index] = ptr; dim++; } void setDim(size_t newdim) nothrow { if (dim < newdim) { reserve(newdim - dim); } dim = newdim; } ref inout(T) opIndex(size_t i) inout nothrow pure { return data[i]; } inout(T)* tdata() inout nothrow { return data; } Array!T* copy() const nothrow { auto a = new Array!T(); a.setDim(dim); memcpy(a.data, data, dim * (void*).sizeof); return a; } void shift(T ptr) nothrow { reserve(1); memmove(data + 1, data, dim * (*data).sizeof); data[0] = ptr; dim++; } void zero() nothrow pure { data[0 .. dim] = T.init; } T pop() nothrow pure { return data[--dim]; } extern (D) inout(T)[] opSlice() inout nothrow pure { return data[0 .. dim]; } extern (D) inout(T)[] opSlice(size_t a, size_t b) inout nothrow pure { assert(a <= b && b <= dim); return data[a .. b]; } alias opDollar = dim; } struct BitArray { nothrow: size_t length() const pure { return len; } void length(size_t nlen) { immutable obytes = (len + 7) / 8; immutable nbytes = (nlen + 7) / 8; // bt*() access memory in size_t chunks, so round up. ptr = cast(size_t*)mem.xrealloc(ptr, (nbytes + (size_t.sizeof - 1)) & ~(size_t.sizeof - 1)); if (nbytes > obytes) (cast(ubyte*)ptr)[obytes .. nbytes] = 0; len = nlen; } bool opIndex(size_t idx) const pure { import core.bitop : bt; assert(idx < length); return !!bt(ptr, idx); } void opIndexAssign(bool val, size_t idx) pure { import core.bitop : btc, bts; assert(idx < length); if (val) bts(ptr, idx); else btc(ptr, idx); } @disable this(this); ~this() { mem.xfree(ptr); } private: size_t len; size_t *ptr; } /** * Exposes the given root Array as a standard D array. * Params: * array = the array to expose. * Returns: * The given array exposed to a standard D array. */ @property T[] asDArray(T)(ref Array!T array) { return array.data[0..array.dim]; } /** * Splits the array at $(D index) and expands it to make room for $(D length) * elements by shifting everything past $(D index) to the right. * Params: * array = the array to split. * index = the index to split the array from. * length = the number of elements to make room for starting at $(D index). */ void split(T)(ref Array!T array, size_t index, size_t length) { if (length > 0) { auto previousDim = array.dim; array.setDim(array.dim + length); for (size_t i = previousDim; i > index;) { i--; array[i + length] = array[i]; } } } unittest { auto array = Array!int(); array.split(0, 0); assert([] == array.asDArray); array.push(1); array.push(3); array.split(1, 1); array[1] = 2; assert([1, 2, 3] == array.asDArray); array.split(2, 3); array[2] = 8; array[3] = 20; array[4] = 4; assert([1, 2, 8, 20, 4, 3] == array.asDArray); array.split(0, 0); assert([1, 2, 8, 20, 4, 3] == array.asDArray); array.split(0, 1); array[0] = 123; assert([123, 1, 2, 8, 20, 4, 3] == array.asDArray); array.split(0, 3); array[0] = 123; array[1] = 421; array[2] = 910; assert([123, 421, 910, 123, 1, 2, 8, 20, 4, 3] == array.asDArray); } ================================================ FILE: gcc/d/dmd/root/array.h ================================================ /* Copyright (C) 2011-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/array.h */ #pragma once #include #include #include #include #include "object.h" #include "rmem.h" template struct Array { d_size_t dim; TYPE *data; private: Array(const Array&); d_size_t allocdim; #define SMALLARRAYCAP 1 TYPE smallarray[SMALLARRAYCAP]; // inline storage for small arrays public: Array() { data = SMALLARRAYCAP ? &smallarray[0] : NULL; dim = 0; allocdim = SMALLARRAYCAP; } ~Array() { if (data != &smallarray[0]) mem.xfree(data); } char *toChars() { const char **buf = (const char **)mem.xmalloc(dim * sizeof(const char *)); d_size_t len = 2; for (d_size_t u = 0; u < dim; u++) { buf[u] = ((RootObject *)data[u])->toChars(); len += strlen(buf[u]) + 1; } char *str = (char *)mem.xmalloc(len); str[0] = '['; char *p = str + 1; for (d_size_t u = 0; u < dim; u++) { if (u) *p++ = ','; len = strlen(buf[u]); memcpy(p,buf[u],len); p += len; } *p++ = ']'; *p = 0; mem.xfree(buf); return str; } void reserve(d_size_t nentries) { //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries); if (allocdim - dim < nentries) { if (allocdim == 0) { // Not properly initialized, someone memset it to zero if (nentries <= SMALLARRAYCAP) { allocdim = SMALLARRAYCAP; data = SMALLARRAYCAP ? &smallarray[0] : NULL; } else { allocdim = nentries; data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data)); } } else if (allocdim == SMALLARRAYCAP) { allocdim = dim + nentries; data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data)); memcpy(data, &smallarray[0], dim * sizeof(*data)); } else { /* Increase size by 1.5x to avoid excessive memory fragmentation */ d_size_t increment = dim / 2; if (nentries > increment) // if 1.5 is not enough increment = nentries; allocdim = dim + increment; data = (TYPE *)mem.xrealloc(data, allocdim * sizeof(*data)); } } } void setDim(d_size_t newdim) { if (dim < newdim) { reserve(newdim - dim); } dim = newdim; } TYPE pop() { return data[--dim]; } void shift(TYPE ptr) { reserve(1); memmove(data + 1, data, dim * sizeof(*data)); data[0] = ptr; dim++; } void remove(d_size_t i) { if (dim - i - 1) memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); dim--; } void zero() { memset(data,0,dim * sizeof(data[0])); } void sort() { struct ArraySort { static int #if _WIN32 __cdecl #endif Array_sort_compare(const void *x, const void *y) { RootObject *ox = *(RootObject **)const_cast(x); RootObject *oy = *(RootObject **)const_cast(y); return ox->compare(oy); } }; if (dim) { qsort(data, dim, sizeof(RootObject *), &ArraySort::Array_sort_compare); } } TYPE *tdata() { return data; } TYPE& operator[] (d_size_t index) { #ifdef DEBUG assert(index < dim); #endif return data[index]; } void insert(d_size_t index, TYPE v) { reserve(1); memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); data[index] = v; dim++; } void insert(d_size_t index, Array *a) { if (a) { d_size_t d = a->dim; reserve(d); if (dim != index) memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); memcpy(data + index, a->data, d * sizeof(*data)); dim += d; } } void append(Array *a) { insert(dim, a); } void push(TYPE a) { reserve(1); data[dim++] = a; } Array *copy() { Array *a = new Array(); a->setDim(dim); memcpy(a->data, data, dim * sizeof(*data)); return a; } }; struct BitArray { BitArray() : len(0) , ptr(NULL) {} ~BitArray() { mem.xfree(ptr); } d_size_t len; d_size_t *ptr; private: BitArray(const BitArray&); }; ================================================ FILE: gcc/d/dmd/root/ctfloat.d ================================================ /* ctfloat.d -- Compile-time floating-pointer helper functions. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.root.ctfloat; nothrow: // Type used by the front-end for compile-time reals public import dmd.root.longdouble : real_t = longdouble; // Compile-time floating-point helper extern (C++) struct CTFloat { nothrow: enum yl2x_supported = false; enum yl2xp1_supported = false; static real_t fabs(real_t x); static real_t ldexp(real_t n, int exp); static bool isIdentical(real_t a, real_t b); static size_t hash(real_t a); static bool isNaN(real_t r); static bool isSNaN(real_t r); static bool isInfinity(real_t r); static real_t parse(const(char)* literal, bool* isOutOfRange = null); static int sprint(char* str, char fmt, real_t x); // Constant real values 0, 1, -1 and 0.5. __gshared real_t zero; __gshared real_t one; __gshared real_t minusone; __gshared real_t half; static void initialize(); } ================================================ FILE: gcc/d/dmd/root/ctfloat.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.h */ #pragma once #include "longdouble.h" // Type used by the front-end for compile-time reals typedef longdouble real_t; // Compile-time floating-point helper struct CTFloat { static void yl2x(const real_t *x, const real_t *y, real_t *res); static void yl2xp1(const real_t *x, const real_t *y, real_t *res); static real_t sin(real_t x); static real_t cos(real_t x); static real_t tan(real_t x); static real_t sqrt(real_t x); static real_t fabs(real_t x); static real_t ldexp(real_t n, int exp); static real_t round(real_t x); static real_t floor(real_t x); static real_t ceil(real_t x); static real_t trunc(real_t x); static real_t log(real_t x); static real_t log2(real_t x); static real_t log10(real_t x); static real_t pow(real_t x, real_t y); static real_t expm1(real_t x); static real_t exp2(real_t x); static real_t fmin(real_t x, real_t y); static real_t fmax(real_t x, real_t y); static real_t copysign(real_t x, real_t s); static real_t fma(real_t x, real_t y, real_t z); static bool isIdentical(real_t a, real_t b); static bool isNaN(real_t r); static bool isSNaN(real_t r); static bool isInfinity(real_t r); static real_t parse(const char *literal, bool *isOutOfRange = NULL); static int sprint(char *str, char fmt, real_t x); static size_t hash(real_t a); // Constant real values 0, 1, -1 and 0.5. static real_t zero; static real_t one; static real_t minusone; static real_t half; static void initialize(); }; ================================================ FILE: gcc/d/dmd/root/dcompat.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/dcompat.h */ #pragma once #include /// Represents a D [ ] array template struct DArray { size_t length; T *ptr; }; ================================================ FILE: gcc/d/dmd/root/file.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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/file.d, root/_file.d) * Documentation: https://dlang.org/phobos/dmd_root_file.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/file.d */ module dmd.root.file; import core.stdc.errno; import core.stdc.stdio; import core.stdc.stdlib; import core.sys.posix.fcntl; import core.sys.posix.unistd; import core.sys.windows.windows; import dmd.root.filename; import dmd.root.rmem; import dmd.utils; /*********************************************************** */ struct File { int _ref; // != 0 if this is a reference to someone else's buffer ubyte* buffer; // data for our file size_t len; // amount of data in buffer[] const(FileName) name; // name of our file nothrow: extern (D) this(const(char)* n) { this(n.toDString()); } extern (D) this(const(char)[] n) { _ref = 0; buffer = null; len = 0; name = FileName(n); } extern (C++) static File* create(const(char)* n) { return new File(n.toDString()); } extern (C++) ~this() { if (buffer) { if (_ref == 0) mem.xfree(buffer); version (Windows) { if (_ref == 2) UnmapViewOfFile(buffer); } } } extern (C++) const(char)* toChars() const pure nothrow @safe { return name.toChars(); } const(char)[] toString() const nothrow pure @safe { return name.toString(); } /** * Read the full content of a file * * Returns: * `true` if there was an error */ extern (C++) bool read() { if (len) return false; // already read the file import core.stdc.string : strcmp; const(char)* name = this.name.toChars(); if (strcmp(name, "__stdin.d") == 0) { /* Read from stdin */ enum bufIncrement = 128 * 1024; size_t pos = 0; size_t sz = bufIncrement; if (!_ref) .free(buffer); buffer = null; L1: for (;;) { buffer = cast(ubyte*).realloc(buffer, sz + 2); // +2 for sentinel if (!buffer) { printf("\tmalloc error, errno = %d\n", errno); break L1; } // Fill up buffer do { assert(sz > pos); size_t rlen = fread(buffer + pos, 1, sz - pos, stdin); pos += rlen; if (ferror(stdin)) { printf("\tread error, errno = %d\n", errno); break L1; } if (feof(stdin)) { // We're done assert(pos < sz + 2); len = pos; buffer[pos] = '\0'; buffer[pos + 1] = '\0'; return false; } } while (pos < sz); // Buffer full, expand sz += bufIncrement; } .free(buffer); buffer = null; len = 0; return true; } version (Posix) { size_t size; stat_t buf; ssize_t numread; //printf("File::read('%s')\n",name); int fd = open(name, O_RDONLY); if (fd == -1) { //printf("\topen error, errno = %d\n",errno); goto err1; } if (!_ref) { .free(buffer); buffer = null; } _ref = 0; // we own the buffer now //printf("\tfile opened\n"); if (fstat(fd, &buf)) { printf("\tfstat error, errno = %d\n", errno); goto err2; } size = cast(size_t)buf.st_size; buffer = cast(ubyte*).malloc(size + 2); if (!buffer) { printf("\tmalloc error, errno = %d\n", errno); goto err2; } numread = .read(fd, buffer, size); if (numread != size) { printf("\tread error, errno = %d\n", errno); goto err2; } if (close(fd) == -1) { printf("\tclose error, errno = %d\n", errno); goto err; } len = size; // Always store a wchar ^Z past end of buffer so scanner has a sentinel buffer[size] = 0; // ^Z is obsolete, use 0 buffer[size + 1] = 0; return false; err2: close(fd); err: .free(buffer); buffer = null; len = 0; err1: return true; } else version (Windows) { DWORD size; DWORD numread; // work around Windows file path length limitation // (see documentation for extendedPathThen). HANDLE h = name.toDString.extendedPathThen! (p => CreateFileW(p.ptr, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null)); if (h == INVALID_HANDLE_VALUE) goto err1; if (!_ref) .free(buffer); _ref = 0; size = GetFileSize(h, null); buffer = cast(ubyte*).malloc(size + 2); if (!buffer) goto err2; if (ReadFile(h, buffer, size, &numread, null) != TRUE) goto err2; if (numread != size) goto err2; if (!CloseHandle(h)) goto err; len = size; // Always store a wchar ^Z past end of buffer so scanner has a sentinel buffer[size] = 0; // ^Z is obsolete, use 0 buffer[size + 1] = 0; return 0; err2: CloseHandle(h); err: .free(buffer); buffer = null; len = 0; err1: return true; } else { assert(0); } } /********************************************* * Write a file. * Returns: * false success */ extern (C++) bool write() { version (Posix) { ssize_t numwritten; const(char)* name = this.name.toChars(); int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4); if (fd == -1) goto err; numwritten = .write(fd, buffer, len); if (len != numwritten) goto err2; if (close(fd) == -1) goto err; return false; err2: close(fd); .remove(name); err: return true; } else version (Windows) { DWORD numwritten; // here because of the gotos const(char)* name = this.name.toChars(); // work around Windows file path length limitation // (see documentation for extendedPathThen). HANDLE h = name.toDString.extendedPathThen! (p => CreateFileW(p.ptr, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null)); if (h == INVALID_HANDLE_VALUE) goto err; if (WriteFile(h, buffer, cast(DWORD)len, &numwritten, null) != TRUE) goto err2; if (len != numwritten) goto err2; if (!CloseHandle(h)) goto err; return false; err2: CloseHandle(h); DeleteFileA(name); err: return true; } else { assert(0); } } /* Set buffer */ extern (C++) void setbuffer(void* buffer, size_t len) { this.buffer = cast(ubyte*)buffer; this.len = len; } // delete file extern (C++) void remove() { version (Posix) { int dummy = .remove(this.name.toChars()); } else version (Windows) { DeleteFileA(this.name.toChars()); } else { assert(0); } } } ================================================ FILE: gcc/d/dmd/root/file.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/file.h */ #pragma once #include #include "array.h" #include "filename.h" typedef Array Files; struct File { int ref; // != 0 if this is a reference to someone else's buffer unsigned char *buffer; // data for our file size_t len; // amount of data in buffer[] FileName name; // name of our file static File *create(const char *); ~File(); const char *toChars() const; /* Read file, return true if error */ bool read(); /* Write file, return true if error */ bool write(); /* Set buffer */ void setbuffer(void *buffer, size_t len) { this->buffer = (unsigned char *)buffer; this->len = len; } void remove(); // delete file }; ================================================ FILE: gcc/d/dmd/root/filename.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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/filename.d, root/_filename.d) * Documentation: https://dlang.org/phobos/dmd_root_filename.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/filename.d */ module dmd.root.filename; import core.stdc.ctype; import core.stdc.errno; import core.stdc.string; import core.sys.posix.stdlib; import core.sys.posix.sys.stat; import core.sys.windows.windows; import dmd.root.array; import dmd.root.file; import dmd.root.outbuffer; import dmd.root.port; import dmd.root.rmem; import dmd.root.rootobject; import dmd.utils; nothrow { version (Windows) extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) @nogc; version (Windows) extern (Windows) void SetLastError(DWORD) @nogc; version (Windows) extern (C) char* getcwd(char* buffer, size_t maxlen); version (Posix) extern (C) char* canonicalize_file_name(const char*); version (Posix) import core.sys.posix.unistd : getcwd; } alias Strings = Array!(const(char)*); alias Files = Array!(File*); /*********************************************************** * Encapsulate path and file names. */ struct FileName { nothrow: private const(char)[] str; /// extern (D) this(const(char)[] str) { this.str = str.xarraydup; } /// Compare two name according to the platform's rules (case sensitive or not) extern (C++) static bool equals(const(char)* name1, const(char)* name2) pure { return equals(name1.toDString, name2.toDString); } /// Ditto extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure { if (name1.length != name2.length) return false; version (Windows) { return Port.memicmp(name1.ptr, name2.ptr, name1.length) == 0; } else { return name1 == name2; } } /************************************ * Determine if path is absolute. * Params: * name = path * Returns: * true if absolute path name. */ extern (C++) static bool absolute(const(char)* name) pure { return absolute(name.toDString); } /// Ditto extern (D) static bool absolute(const(char)[] name) pure { if (!name.length) return false; version (Windows) { return (name[0] == '\\') || (name[0] == '/') || (name.length >= 2 && name[1] == ':'); } else version (Posix) { return (name[0] == '/'); } else { assert(0); } } unittest { assert(absolute("/"[]) == true); assert(absolute(""[]) == false); } /** Return the given name as an absolute path Params: name = path base = the absolute base to prefix name with if it is relative Returns: name as an absolute path relative to base */ extern (C++) static const(char)* toAbsolute(const(char)* name, const(char)* base = null) { const name_ = name.toDString(); const base_ = base ? base.toDString() : getcwd(null, 0).toDString(); return absolute(name_) ? name : combine(base_, name_).ptr; } /******************************** * Determine file name extension as slice of input. * Params: * str = file name * Returns: * filename extension (read-only). * Points past '.' of extension. * If there isn't one, return null. */ extern (C++) static const(char)* ext(const(char)* str) pure { return ext(str.toDString).ptr; } /// Ditto extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc { foreach_reverse (idx, char e; str) { switch (e) { case '.': return str[idx + 1 .. $]; version (Posix) { case '/': return null; } version (Windows) { case '\\': case ':': case '/': return null; } default: continue; } } return null; } unittest { assert(ext("/foo/bar/dmd.conf"[]) == "conf"); assert(ext("object.o"[]) == "o"); assert(ext("/foo/bar/dmd"[]) == null); assert(ext(".objdir.o/object"[]) == null); assert(ext([]) == null); } extern (C++) const(char)* ext() const pure { return ext(str).ptr; } /******************************** * Return file name without extension. * * TODO: * Once slice are used everywhere and `\0` is not assumed, * this can be turned into a simple slicing. * * Params: * str = file name * * Returns: * mem.xmalloc'd filename with extension removed. */ extern (C++) static const(char)* removeExt(const(char)* str) { return removeExt(str.toDString).ptr; } /// Ditto extern (D) static const(char)[] removeExt(const(char)[] str) { auto e = ext(str); if (e.length) { const len = (str.length - e.length) - 1; // -1 for the dot char* n = cast(char*)mem.xmalloc(len + 1); memcpy(n, str.ptr, len); n[len] = 0; return n[0 .. len]; } return mem.xstrdup(str.ptr)[0 .. str.length]; } unittest { assert(removeExt("/foo/bar/object.d"[]) == "/foo/bar/object"); assert(removeExt("/foo/bar/frontend.di"[]) == "/foo/bar/frontend"); } /******************************** * Return filename name excluding path (read-only). */ extern (C++) static const(char)* name(const(char)* str) pure { return name(str.toDString).ptr; } /// Ditto extern (D) static const(char)[] name(const(char)[] str) pure { foreach_reverse (idx, char e; str) { switch (e) { version (Posix) { case '/': return str[idx + 1 .. $]; } version (Windows) { case '/': case '\\': return str[idx + 1 .. $]; case ':': /* The ':' is a drive letter only if it is the second * character or the last character, * otherwise it is an ADS (Alternate Data Stream) separator. * Consider ADS separators as part of the file name. */ if (idx == 1 || idx == str.length - 1) return str[idx + 1 .. $]; break; } default: break; } } return str; } extern (C++) const(char)* name() const pure { return name(str).ptr; } unittest { assert(name("/foo/bar/object.d"[]) == "object.d"); assert(name("/foo/bar/frontend.di"[]) == "frontend.di"); } /************************************** * Return path portion of str. * Path will does not include trailing path separator. */ extern (C++) static const(char)* path(const(char)* str) { return path(str.toDString).ptr; } /// Ditto extern (D) static const(char)[] path(const(char)[] str) { const n = name(str); bool hasTrailingSlash; if (n.length < str.length) { version (Posix) { if (str[$ - n.length - 1] == '/') hasTrailingSlash = true; } else version (Windows) { if (str[$ - n.length - 1] == '\\' || str[$ - n.length - 1] == '/') hasTrailingSlash = true; } else { assert(0); } } const pathlen = str.length - n.length - (hasTrailingSlash ? 1 : 0); char* path = cast(char*)mem.xmalloc(pathlen + 1); memcpy(path, str.ptr, pathlen); path[pathlen] = 0; return path[0 .. pathlen]; } unittest { assert(path("/foo/bar"[]) == "/foo"); assert(path("foo"[]) == ""); } /************************************** * Replace filename portion of path. */ extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name) { if (absolute(name)) return name; auto n = FileName.name(path); if (n == path) return name; return combine(path[0 .. $ - n.length], name); } /** Combine a `path` and a file `name` Params: path = Path to append to name = Name to append to path Returns: The `\0` terminated string which is the combination of `path` and `name` and a valid path. */ extern (C++) static const(char)* combine(const(char)* path, const(char)* name) { if (!path) return name; return combine(path.toDString, name.toDString).ptr; } /// Ditto extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) { if (!path.length) return name; char* f = cast(char*)mem.xmalloc(path.length + 1 + name.length + 1); memcpy(f, path.ptr, path.length); bool trailingSlash = false; version (Posix) { if (path[$ - 1] != '/') { f[path.length] = '/'; trailingSlash = true; } } else version (Windows) { if (path[$ - 1] != '\\' && path[$ - 1] != '/' && path[$ - 1] != ':') { f[path.length] = '\\'; trailingSlash = true; } } else { assert(0); } const len = path.length + trailingSlash; memcpy(f + len, name.ptr, name.length); // Note: At the moment `const(char)*` are being transitioned to // `const(char)[]`. To avoid bugs crippling in, we `\0` terminate // slices, but don't include it in the slice so `.ptr` can be used. f[len + name.length] = '\0'; return f[0 .. len + name.length]; } unittest { version (Windows) assert(combine("foo"[], "bar"[]) == "foo\\bar"); else assert(combine("foo"[], "bar"[]) == "foo/bar"); assert(combine("foo/"[], "bar"[]) == "foo/bar"); } static const(char)* buildPath(const(char)* path, const(char)*[] names...) { foreach (const(char)* name; names) path = combine(path, name); return path; } // Split a path into an Array of paths extern (C++) static Strings* splitPath(const(char)* path) { char c = 0; // unnecessary initializer is for VC /W4 const(char)* p; OutBuffer buf; Strings* array; array = new Strings(); if (path) { p = path; do { char instring = 0; while (isspace(cast(char)*p)) // skip leading whitespace p++; buf.reserve(strlen(p) + 1); // guess size of path for (;; p++) { c = *p; switch (c) { case '"': instring ^= 1; // toggle inside/outside of string continue; version (OSX) { case ',': } version (Windows) { case ';': } version (Posix) { case ':': } p++; break; // note that ; cannot appear as part // of a path, quotes won't protect it case 0x1A: // ^Z means end of file case 0: break; case '\r': continue; // ignore carriage returns version (Posix) { case '~': { char* home = getenv("HOME"); if (home) buf.writestring(home); else buf.writestring("~"); continue; } } version (none) { case ' ': case '\t': // tabs in filenames? if (!instring) // if not in string break; // treat as end of path } default: buf.writeByte(c); continue; } break; } if (buf.offset) // if path is not empty { array.push(buf.extractString()); } } while (c); } return array; } /** * Add the extension `ext` to `name`, regardless of the content of `name` * * Params: * name = Path to append the extension to * ext = Extension to add (should not include '.') * * Returns: * A newly allocated string (free with `FileName.free`) */ extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) { const len = name.length + ext.length + 2; auto s = cast(char*)mem.xmalloc(len); s[0 .. name.length] = name[]; s[name.length] = '.'; s[name.length + 1 .. len - 1] = ext[]; s[len - 1] = '\0'; return s[0 .. len - 1]; } /*************************** * Free returned value with FileName::free() */ extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext) { return defaultExt(name.toDString, ext.toDString).ptr; } /// Ditto extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext) { auto e = FileName.ext(name); if (e.length) // it already has an extension return name.xarraydup; return addExt(name, ext); } unittest { assert(defaultExt("/foo/object.d"[], "d") == "/foo/object.d"); assert(defaultExt("/foo/object"[], "d") == "/foo/object.d"); assert(defaultExt("/foo/bar.d"[], "o") == "/foo/bar.d"); } /*************************** * Free returned value with FileName::free() */ extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext) { return forceExt(name.toDString, ext.toDString).ptr; } /// Ditto extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext) { if (auto e = FileName.ext(name)) return addExt(name[0 .. $ - e.length - 1], ext); return defaultExt(name, ext); // doesn't have one } unittest { assert(forceExt("/foo/object.d"[], "d") == "/foo/object.d"); assert(forceExt("/foo/object"[], "d") == "/foo/object.d"); assert(forceExt("/foo/bar.d"[], "o") == "/foo/bar.o"); } /// Returns: /// `true` if `name`'s extension is `ext` extern (C++) static bool equalsExt(const(char)* name, const(char)* ext) pure { return equalsExt(name.toDString, ext.toDString); } /// Ditto extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure { auto e = FileName.ext(name); if (!e.length && !ext.length) return true; if (!e.length || !ext.length) return false; return FileName.equals(e, ext); } unittest { assert(!equalsExt("foo.bar"[], "d")); assert(equalsExt("foo.bar"[], "bar")); assert(equalsExt("object.d"[], "d")); assert(!equalsExt("object"[], "d")); } /****************************** * Return !=0 if extensions match. */ extern (C++) bool equalsExt(const(char)* ext) const pure { return equalsExt(str, ext.toDString()); } /************************************* * Search Path for file. * Input: * cwd if true, search current directory before searching path */ extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd) { return searchPath(path, name.toDString, cwd).ptr; } extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd) { if (absolute(name)) { return exists(name) ? name : null; } if (cwd) { if (exists(name)) return name; } if (path) { foreach (p; *path) { auto n = combine(p.toDString, name); if (exists(n)) return n; } } return null; } /************************************* * Search Path for file in a safe manner. * * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory * ('Path Traversal') attacks. * http://cwe.mitre.org/data/definitions/22.html * More info: * https://www.securecoding.cert.org/confluence/display/c/FIO02-C.+Canonicalize+path+names+originating+from+tainted+sources * Returns: * NULL file not found * !=NULL mem.xmalloc'd file name */ extern (C++) static const(char)* safeSearchPath(Strings* path, const(char)* name) { version (Windows) { // don't allow leading / because it might be an absolute // path or UNC path or something we'd prefer to just not deal with if (*name == '/') { return null; } /* Disallow % \ : and .. in name characters * We allow / for compatibility with subdirectories which is allowed * on dmd/posix. With the leading / blocked above and the rest of these * conservative restrictions, we should be OK. */ for (const(char)* p = name; *p; p++) { char c = *p; if (c == '\\' || c == ':' || c == '%' || (c == '.' && p[1] == '.') || (c == '/' && p[1] == '/')) { return null; } } return FileName.searchPath(path, name, false); } else version (Posix) { /* Even with realpath(), we must check for // and disallow it */ for (const(char)* p = name; *p; p++) { char c = *p; if (c == '/' && p[1] == '/') { return null; } } if (path) { /* Each path is converted to a cannonical name and then a check is done to see * that the searched name is really a child one of the the paths searched. */ for (size_t i = 0; i < path.dim; i++) { const(char)* cname = null; const(char)* cpath = canonicalName((*path)[i]); //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", // name, (char *)path.data[i], cpath); if (cpath is null) goto cont; cname = canonicalName(combine(cpath, name)); //printf("FileName::safeSearchPath(): cname=%s\n", cname); if (cname is null) goto cont; //printf("FileName::safeSearchPath(): exists=%i " // "strncmp(cpath, cname, %i)=%i\n", exists(cname), // strlen(cpath), strncmp(cpath, cname, strlen(cpath))); // exists and name is *really* a "child" of path if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0) { .free(cast(void*)cpath); const(char)* p = mem.xstrdup(cname); .free(cast(void*)cname); return p; } cont: if (cpath) .free(cast(void*)cpath); if (cname) .free(cast(void*)cname); } } return null; } else { assert(0); } } /** Check if the file the `path` points to exists Returns: 0 if it does not exists 1 if it exists and is not a directory 2 if it exists and is a directory */ extern (C++) static int exists(const(char)* name) { return exists(name.toDString); } /// Ditto extern (D) static int exists(const(char)[] name) { if (!name.length) return 0; version (Posix) { stat_t st; if (name.toCStringThen!((v) => stat(v.ptr, &st)) < 0) return 0; if (S_ISDIR(st.st_mode)) return 2; return 1; } else version (Windows) { return name.toCStringThen!((cstr) => cstr.toWStringzThen!((wname) { const dw = GetFileAttributesW(&wname[0]); if (dw == -1) return 0; else if (dw & FILE_ATTRIBUTE_DIRECTORY) return 2; else return 1; })); } else { assert(0); } } /** Ensure that the provided path exists Accepts a path to either a file or a directory. In the former case, the basepath (path to the containing directory) will be checked for existence, and created if it does not exists. In the later case, the directory pointed to will be checked for existence and created if needed. Params: path = a path to a file or a directory Returns: `true` if the directory exists or was successfully created */ extern (C++) static bool ensurePathExists(const(char)* path) { //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); if (!path || !(*path)) return true; if (exists(path)) return true; // We were provided with a file name // We need to call ourselves recursively to ensure parent dir exist const(char)* p = FileName.path(path); if (*p) { version (Windows) { const len = strlen(path); const plen = strlen(p); // Note: Windows filename comparison should be case-insensitive, // however p is a subslice of path so we don't need it if (len == plen || (len > 2 && path[1] == ':' && path[2 .. len] == p[0 .. plen])) { mem.xfree(cast(void*)p); return true; } } const r = ensurePathExists(p); mem.xfree(cast(void*)p); if (!r) return r; } version (Windows) const r = _mkdir(path.toDString); version (Posix) { errno = 0; const r = mkdir(path, (7 << 6) | (7 << 3) | 7); } if (r == 0) return true; // Don't error out if another instance of dmd just created // this directory version (Windows) { import core.sys.windows.winerror : ERROR_ALREADY_EXISTS; if (GetLastError() == ERROR_ALREADY_EXISTS) return true; } version (Posix) { if (errno == EEXIST) return true; } return false; } /****************************************** * Return canonical version of name in a malloc'd buffer. * This code is high risk. */ extern (C++) static const(char)* canonicalName(const(char)* name) { return canonicalName(name.toDString).ptr; } /// Ditto extern (D) static const(char)[] canonicalName(const(char)[] name) { version (Posix) { // NULL destination buffer is allowed and preferred return name.toCStringThen!((n) => realpath(n.ptr, null)).toDString; } else version (Windows) { // Convert to wstring first since otherwise the Win32 APIs have a character limit return name.toWStringzThen!((wname) { /* Apparently, there is no good way to do this on Windows. * GetFullPathName isn't it, but use it anyway. */ // First find out how long the buffer has to be. auto fullPathLength = GetFullPathNameW(&wname[0], 0, null, null); if (!fullPathLength) return null; auto fullPath = new wchar[fullPathLength]; // Actually get the full path name const fullPathLengthNoTerminator = GetFullPathNameW( &wname[0], cast(uint)fullPath.length, &fullPath[0], null /*filePart*/); // Unfortunately, when the buffer is large enough the return value is the number of characters // _not_ counting the null terminator, so fullPathLengthNoTerminator should be smaller assert(fullPathLength > fullPathLengthNoTerminator); // Find out size of the converted string const retLength = WideCharToMultiByte( 0 /*codepage*/, 0 /*flags*/, &fullPath[0], fullPathLength, null, 0, null, null); auto ret = new char[retLength]; // Actually convert to char const retLength2 = WideCharToMultiByte( 0 /*codepage*/, 0 /*flags*/, &fullPath[0], cast(int)fullPath.length, &ret[0], cast(int)ret.length, null, null); assert(retLength == retLength2); return ret; }); } else { assert(0); } } /******************************** * Free memory allocated by FileName routines */ extern (C++) static void free(const(char)* str) { if (str) { assert(str[0] != cast(char)0xAB); memset(cast(void*)str, 0xAB, strlen(str) + 1); // stomp } mem.xfree(cast(void*)str); } extern (C++) const(char)* toChars() const pure nothrow @trusted { // Since we can return an empty slice (but '\0' terminated), // we don't do bounds check (as `&str[0]` does) return str.ptr; } const(char)[] toString() const pure nothrow @trusted { return str; } } version(Windows) { /**************************************************************** * The code before used the POSIX function `mkdir` on Windows. That * function is now deprecated and fails with long paths, so instead * we use the newer `CreateDirectoryW`. * * `CreateDirectoryW` is the unicode version of the generic macro * `CreateDirectory`. `CreateDirectoryA` has a file path * limitation of 248 characters, `mkdir` fails with less and might * fail due to the number of consecutive `..`s in the * path. `CreateDirectoryW` also normally has a 248 character * limit, unless the path is absolute and starts with `\\?\`. Note * that this is different from starting with the almost identical * `\\?`. * * Params: * path = The path to create. * * Returns: * 0 on success, 1 on failure. * * References: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx */ private int _mkdir(const(char)[] path) nothrow { const createRet = path.extendedPathThen!( p => CreateDirectoryW(&p[0], null /*securityAttributes*/)); // different conventions for CreateDirectory and mkdir return createRet == 0 ? 1 : 0; } /************************************** * Converts a path to one suitable to be passed to Win32 API * functions that can deal with paths longer than 248 * characters then calls the supplied function on it. * * Params: * path = The Path to call F on. * * Returns: * The result of calling F on path. * * References: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx */ package auto extendedPathThen(alias F)(const(char)[] path) { if (!path.length) return F((wchar[]).init); return path.toWStringzThen!((wpath) { // GetFullPathNameW expects a sized buffer to store the result in. Since we don't // know how large it has to be, we pass in null and get the needed buffer length // as the return code. const pathLength = GetFullPathNameW(&wpath[0], 0 /*length8*/, null /*output buffer*/, null /*filePartBuffer*/); if (pathLength == 0) { return F((wchar[]).init); } // wpath is the UTF16 version of path, but to be able to use // extended paths, we need to prefix with `\\?\` and the absolute // path. static immutable prefix = `\\?\`w; // prefix only needed for long names and non-UNC names const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\'); const prefixLength = needsPrefix ? prefix.length : 0; // +1 for the null terminator const bufferLength = pathLength + prefixLength + 1; wchar[1024] absBuf = void; wchar[] absPath = bufferLength > absBuf.length ? new wchar[bufferLength] : absBuf[0 .. bufferLength]; absPath[0 .. prefixLength] = prefix[0 .. prefixLength]; const absPathRet = GetFullPathNameW(&wpath[0], cast(uint)(absPath.length - prefixLength - 1), &absPath[prefixLength], null /*filePartBuffer*/); if (absPathRet == 0 || absPathRet > absPath.length - prefixLength) { return F((wchar[]).init); } absPath[$ - 1] = '\0'; // Strip null terminator from the slice return F(absPath[0 .. $ - 1]); }); } /********************************** * Converts a slice of UTF-8 characters to an array of wchar that's null * terminated so it can be passed to Win32 APIs then calls the supplied * function on it. * * Params: * str = The string to convert. * * Returns: * The result of calling F on the UTF16 version of str. */ private auto toWStringzThen(alias F)(const(char)[] str) nothrow { if (!str.length) return F(""w.ptr); import core.stdc.string: strlen; import core.stdc.stdlib: malloc, free; import core.sys.windows.winnls: MultiByteToWideChar; wchar[1024] buf; // first find out how long the buffer must be to store the result const length = MultiByteToWideChar(0 /*codepage*/, 0 /*flags*/, &str[0], cast(int)str.length, null, 0); if (!length) return F(""w); wchar[] ret = length >= buf.length ? (cast(wchar*)malloc(length * wchar.sizeof))[0 .. length + 1] : buf[0 .. length + 1]; scope (exit) { if (&ret[0] != &buf[0]) free(&ret[0]); } // actually do the conversion const length2 = MultiByteToWideChar( 0 /*codepage*/, 0 /*flags*/, &str[0], cast(int)str.length, &ret[0], cast(int)length); assert(str.length == length2); // should always be true according to the API // Add terminating `\0` ret[$ - 1] = '\0'; return F(ret[0 .. $ - 1]); } } version (Posix) { /** Takes a callable F and applies it to the result of converting `fileName` to an absolute file path (char*) Params: fileName = The file name to be converted to an absolute path Returns: Whatever `F` returns. */ auto absPathThen(alias F)(const(char)[] fileName) { import core.sys.posix.stdlib: realpath, free; char* absPath = fileName.toCStringThen!((fn) => realpath(&fn[0], null /* realpath allocates */)); scope(exit) free(absPath); return F(absPath.toDString()); } } else { /** Takes a callable F and applies it to the result of converting `fileName` to an absolute file path (char*) Params: fileName = The file name to be converted to an absolute path Returns: Whatever `F` returns. */ auto absPathThen(alias F)(const(char)[] fileName) { import core.sys.windows.winnls: WideCharToMultiByte; import core.stdc.stdlib: malloc, free; return fileName.extendedPathThen!((wpath) { // first find out how long the buffer must be to store the result const length = WideCharToMultiByte(0, // code page 0, // flags &wpath[0], -1, // wpath len, -1 is null terminated null, // multibyte output ptr 0, // multibyte output length null, // default char null, // if used default char ); if (!length) return F((char[]).init); char[1024] buf = void; scope multibyteBuf = length > buf.length ? (cast(char*)malloc(length * char.sizeof))[0 .. length] : buf[0 .. length]; scope (exit) { if (multibyteBuf.ptr != buf.ptr) free(multibyteBuf.ptr); } // now store the result const length2 = WideCharToMultiByte(0, // code page 0, // flags &wpath[0], -1, // wpath len, -1 is null terminated multibyteBuf.ptr, length, null, // default char null, // if used default char ); assert(length == length2); return F(multibyteBuf[0 .. length - 1]); }); } } ================================================ FILE: gcc/d/dmd/root/filename.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.h */ #pragma once #include "array.h" #include "dcompat.h" typedef Array Strings; struct FileName { private: DArray str; public: static bool equals(const char *name1, const char *name2); static bool absolute(const char *name); static const char *toAbsolute(const char *name, const char *base = NULL); static const char *ext(const char *); const char *ext(); static const char *removeExt(const char *str); static const char *name(const char *); const char *name(); static const char *path(const char *); static const char *combine(const char *path, const char *name); static Strings *splitPath(const char *path); static const char *defaultExt(const char *name, const char *ext); static const char *forceExt(const char *name, const char *ext); static bool equalsExt(const char *name, const char *ext); bool equalsExt(const char *ext); static const char *searchPath(Strings *path, const char *name, bool cwd); static const char *safeSearchPath(Strings *path, const char *name); static int exists(const char *name); static bool ensurePathExists(const char *path); static const char *canonicalName(const char *name); static void free(const char *str); const char *toChars() const; }; ================================================ FILE: gcc/d/dmd/root/hash.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d) * Documentation: https://dlang.org/phobos/dmd_root_hash.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/hash.d */ module dmd.root.hash; // MurmurHash2 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. // https://sites.google.com/site/murmurhash/ uint calcHash(const(char)* data, size_t len) pure nothrow @nogc { return calcHash(cast(const(ubyte)*)data, len); } uint calcHash(const(ubyte)* data, size_t len) pure nothrow @nogc { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. enum uint m = 0x5bd1e995; enum int r = 24; // Initialize the hash to a 'random' value uint h = cast(uint)len; // Mix 4 bytes at a time into the hash while (len >= 4) { uint k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; k *= m; k ^= k >> r; h = (h * m) ^ (k * m); data += 4; len -= 4; } // Handle the last few bytes of the input array switch (len & 3) { case 3: h ^= data[2] << 16; goto case; case 2: h ^= data[1] << 8; goto case; case 1: h ^= data[0]; h *= m; goto default; default: break; } // Do a few final mixes of the hash to ensure the last few // bytes are well-incorporated. h ^= h >> 13; h *= m; h ^= h >> 15; return h; } // combine and mix two words (boost::hash_combine) size_t mixHash(size_t h, size_t k) { return h ^ (k + 0x9e3779b9 + (h << 6) + (h >> 2)); } ================================================ FILE: gcc/d/dmd/root/longdouble.d ================================================ /* longdouble.d -- Software floating point emulation for the D frontend. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.root.longdouble; import core.stdc.config; import core.stdc.stdint; nothrow: @nogc: // Type used by the front-end for compile-time reals struct longdouble { this(T)(T r) { this.set(r); } // No constructor to be able to use this class in a union. longdouble opAssign(T)(T r) if (is (T : longdouble)) { this.realvalue = r.realvalue; return this; } longdouble opAssign(T)(T r) if (!is (T : longdouble)) { this.set(r); return this; } // Arithmetic operators. longdouble opBinary(string op, T)(T r) const if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "%") && is (T : longdouble)) { static if (op == "+") return this.add(r); else static if (op == "-") return this.sub(r); else static if (op == "*") return this.mul(r); else static if (op == "/") return this.div(r); else static if (op == "%") return this.mod(r); } longdouble opUnary(string op)() const if (op == "-") { return this.neg(); } int opCmp(longdouble r) const { return this.cmp(r); } int opEquals(longdouble r) const { return this.equals(r); } bool opCast(T : bool)() const { return this.to_bool(); } T opCast(T)() const { static if (__traits(isUnsigned, T)) return cast (T) this.to_uint(); else return cast(T) this.to_int(); } extern (C++): void set(int8_t d); void set(int16_t d); void set(int32_t d); void set(int64_t d); void set(uint8_t d); void set(uint16_t d); void set(uint32_t d); void set(uint64_t d); void set(bool d); int64_t to_int() const; uint64_t to_uint() const; bool to_bool() const; longdouble add(const ref longdouble r) const; longdouble sub(const ref longdouble r) const; longdouble mul(const ref longdouble r) const; longdouble div(const ref longdouble r) const; longdouble mod(const ref longdouble r) const; longdouble neg() const; int cmp(const ref longdouble t) const; int equals(const ref longdouble t) const; private: // Statically allocate enough space for REAL_VALUE_TYPE. enum realvalue_size = (2 + (16 + c_long.sizeof) / c_long.sizeof); c_long [realvalue_size] realvalue; } ================================================ FILE: gcc/d/dmd/root/object.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/object.h */ #pragma once #define POSIX (__linux__ || __GLIBC__ || __gnu_hurd__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun) #include "dcompat.h" #include typedef size_t hash_t; struct OutBuffer; enum DYNCAST { DYNCAST_OBJECT, DYNCAST_EXPRESSION, DYNCAST_DSYMBOL, DYNCAST_TYPE, DYNCAST_IDENTIFIER, DYNCAST_TUPLE, DYNCAST_PARAMETER, DYNCAST_STATEMENT, DYNCAST_TEMPLATEPARAMETER }; /* * Root of our class library. */ class RootObject { public: RootObject() { } virtual bool equals(RootObject *o); /** * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. * Useful for sorting Objects. */ virtual int compare(RootObject *obj); /** * Pretty-print an Object. Useful for debugging the old-fashioned way. */ virtual const char *toChars(); /// This function is `extern(D)` and should not be called from C++, /// as the ABI does not match on some platforms virtual DArray toString(); virtual void toBuffer(OutBuffer *buf); /** * Used as a replacement for dynamic_cast. Returns a unique number * defined by the library user. For Object, the return value is 0. */ virtual int dyncast() const; }; ================================================ FILE: gcc/d/dmd/root/outbuffer.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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/outbuffer.d, root/_outbuffer.d) * Documentation: https://dlang.org/phobos/dmd_root_outbuffer.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/outbuffer.d */ module dmd.root.outbuffer; import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.string; import dmd.root.rmem; import dmd.root.rootobject; struct OutBuffer { ubyte* data; size_t offset; size_t size; int level; bool doindent; private bool notlinehead; extern (C++) ~this() nothrow { mem.xfree(data); } extern (C++) char* extractData() nothrow { char* p; p = cast(char*)data; data = null; offset = 0; size = 0; return p; } extern (C++) void reserve(size_t nbytes) nothrow { //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); if (size - offset < nbytes) { /* Increase by factor of 1.5; round up to 16 bytes. * The odd formulation is so it will map onto single x86 LEA instruction. */ size = (((offset + nbytes) * 3 + 30) / 2) & ~15; data = cast(ubyte*)mem.xrealloc(data, size); } } extern (C++) void setsize(size_t size) nothrow { offset = size; } extern (C++) void reset() nothrow { offset = 0; } private void indent() nothrow { if (level) { reserve(level); data[offset .. offset + level] = '\t'; offset += level; } notlinehead = true; } extern (C++) void write(const(void)* data, size_t nbytes) nothrow { if (doindent && !notlinehead) indent(); reserve(nbytes); memcpy(this.data + offset, data, nbytes); offset += nbytes; } extern (C++) void writestring(const(char)* string) nothrow { write(string, strlen(string)); } void writestring(const(char)[] s) nothrow { write(s.ptr, s.length); } void writestring(string s) nothrow { write(s.ptr, s.length); } extern (C++) void prependstring(const(char)* string) nothrow { size_t len = strlen(string); reserve(len); memmove(data + len, data, offset); memcpy(data, string, len); offset += len; } // write newline extern (C++) void writenl() nothrow { version (Windows) { writeword(0x0A0D); // newline is CR,LF on Microsoft OS's } else { writeByte('\n'); } if (doindent) notlinehead = false; } extern (C++) void writeByte(uint b) nothrow { if (doindent && !notlinehead && b != '\n') indent(); reserve(1); this.data[offset] = cast(ubyte)b; offset++; } extern (C++) void writeUTF8(uint b) nothrow { reserve(6); if (b <= 0x7F) { this.data[offset] = cast(ubyte)b; offset++; } else if (b <= 0x7FF) { this.data[offset + 0] = cast(ubyte)((b >> 6) | 0xC0); this.data[offset + 1] = cast(ubyte)((b & 0x3F) | 0x80); offset += 2; } else if (b <= 0xFFFF) { this.data[offset + 0] = cast(ubyte)((b >> 12) | 0xE0); this.data[offset + 1] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); this.data[offset + 2] = cast(ubyte)((b & 0x3F) | 0x80); offset += 3; } else if (b <= 0x1FFFFF) { this.data[offset + 0] = cast(ubyte)((b >> 18) | 0xF0); this.data[offset + 1] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); this.data[offset + 2] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); this.data[offset + 3] = cast(ubyte)((b & 0x3F) | 0x80); offset += 4; } else if (b <= 0x3FFFFFF) { this.data[offset + 0] = cast(ubyte)((b >> 24) | 0xF8); this.data[offset + 1] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); this.data[offset + 2] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); this.data[offset + 3] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); this.data[offset + 4] = cast(ubyte)((b & 0x3F) | 0x80); offset += 5; } else if (b <= 0x7FFFFFFF) { this.data[offset + 0] = cast(ubyte)((b >> 30) | 0xFC); this.data[offset + 1] = cast(ubyte)(((b >> 24) & 0x3F) | 0x80); this.data[offset + 2] = cast(ubyte)(((b >> 18) & 0x3F) | 0x80); this.data[offset + 3] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80); this.data[offset + 4] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80); this.data[offset + 5] = cast(ubyte)((b & 0x3F) | 0x80); offset += 6; } else assert(0); } extern (C++) void prependbyte(uint b) nothrow { reserve(1); memmove(data + 1, data, offset); data[0] = cast(ubyte)b; offset++; } extern (C++) void writewchar(uint w) nothrow { version (Windows) { writeword(w); } else { write4(w); } } extern (C++) void writeword(uint w) nothrow { version (Windows) { uint newline = 0x0A0D; } else { uint newline = '\n'; } if (doindent && !notlinehead && w != newline) indent(); reserve(2); *cast(ushort*)(this.data + offset) = cast(ushort)w; offset += 2; } extern (C++) void writeUTF16(uint w) nothrow { reserve(4); if (w <= 0xFFFF) { *cast(ushort*)(this.data + offset) = cast(ushort)w; offset += 2; } else if (w <= 0x10FFFF) { *cast(ushort*)(this.data + offset) = cast(ushort)((w >> 10) + 0xD7C0); *cast(ushort*)(this.data + offset + 2) = cast(ushort)((w & 0x3FF) | 0xDC00); offset += 4; } else assert(0); } extern (C++) void write4(uint w) nothrow { version (Windows) { bool notnewline = w != 0x000A000D; } else { bool notnewline = true; } if (doindent && !notlinehead && notnewline) indent(); reserve(4); *cast(uint*)(this.data + offset) = w; offset += 4; } extern (C++) void write(const OutBuffer* buf) nothrow { if (buf) { reserve(buf.offset); memcpy(data + offset, buf.data, buf.offset); offset += buf.offset; } } extern (C++) void write(RootObject obj) /*nothrow*/ { if (obj) { writestring(obj.toChars()); } } extern (C++) void fill0(size_t nbytes) nothrow { reserve(nbytes); memset(data + offset, 0, nbytes); offset += nbytes; } extern (C++) void vprintf(const(char)* format, va_list args) nothrow { int count; if (doindent) write(null, 0); // perform indent uint psize = 128; for (;;) { reserve(psize); version (Windows) { count = _vsnprintf(cast(char*)data + offset, psize, format, args); if (count != -1) break; psize *= 2; } else version (Posix) { va_list va; va_copy(va, args); /* The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), sprintf(), snprintf(), respectively, except that they are called with a va_list instead of a variable number of arguments. These functions do not call the va_end macro. Consequently, the value of ap is undefined after the call. The application should call va_end(ap) itself afterwards. */ count = vsnprintf(cast(char*)data + offset, psize, format, va); va_end(va); if (count == -1) psize *= 2; else if (count >= psize) psize = count + 1; else break; } else { assert(0); } } offset += count; } extern (C++) void printf(const(char)* format, ...) nothrow { va_list ap; va_start(ap, format); vprintf(format, ap); va_end(ap); } /************************************** * Convert `u` to a string and append it to the buffer. * Params: * u = integral value to append */ extern (C++) void print(ulong u) nothrow { //import core.internal.string; // not available UnsignedStringBuf buf = void; writestring(unsignedToTempString(u, buf)); } extern (C++) void bracket(char left, char right) nothrow { reserve(2); memmove(data + 1, data, offset); data[0] = left; data[offset + 1] = right; offset += 2; } /****************** * Insert left at i, and right at j. * Return index just past right. */ extern (C++) size_t bracket(size_t i, const(char)* left, size_t j, const(char)* right) nothrow { size_t leftlen = strlen(left); size_t rightlen = strlen(right); reserve(leftlen + rightlen); insert(i, left, leftlen); insert(j + leftlen, right, rightlen); return j + leftlen + rightlen; } extern (C++) void spread(size_t offset, size_t nbytes) nothrow { reserve(nbytes); memmove(data + offset + nbytes, data + offset, this.offset - offset); this.offset += nbytes; } /**************************************** * Returns: offset + nbytes */ extern (C++) size_t insert(size_t offset, const(void)* p, size_t nbytes) nothrow { spread(offset, nbytes); memmove(data + offset, p, nbytes); return offset + nbytes; } size_t insert(size_t offset, const(char)[] s) nothrow { return insert(offset, s.ptr, s.length); } extern (C++) void remove(size_t offset, size_t nbytes) nothrow { memmove(data + offset, data + offset + nbytes, this.offset - (offset + nbytes)); this.offset -= nbytes; } extern (D) const(char)[] peekSlice() nothrow { return (cast(const char*)data)[0 .. offset]; } // Append terminating null if necessary and get view of internal buffer extern (C++) char* peekString() nothrow { if (!offset || data[offset - 1] != '\0') { writeByte(0); offset--; // allow appending more } return cast(char*)data; } // Append terminating null if necessary and take ownership of data extern (C++) char* extractString() nothrow { if (!offset || data[offset - 1] != '\0') writeByte(0); return extractData(); } } /****** copied from core.internal.string *************/ private: pure: nothrow: @nogc: alias UnsignedStringBuf = char[20]; char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe { size_t i = buf.length; do { if (value < radix) { ubyte x = cast(ubyte)value; buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a'); break; } else { ubyte x = cast(ubyte)(value % radix); value = value / radix; buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a'); } } while (value); return buf[i .. $]; } ================================================ FILE: gcc/d/dmd/root/outbuffer.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.h */ #pragma once #include #include #include #include #include "rmem.h" class RootObject; struct OutBuffer { unsigned char *data; size_t offset; size_t size; int level; bool doindent; private: bool notlinehead; public: OutBuffer() { data = NULL; offset = 0; size = 0; doindent = 0; level = 0; notlinehead = 0; } ~OutBuffer() { mem.xfree(data); } char *extractData(); void reserve(size_t nbytes); void setsize(size_t size); void reset(); void write(const void *data, d_size_t nbytes); void writestring(const char *string); void prependstring(const char *string); void writenl(); // write newline void writeByte(unsigned b); void writeUTF8(unsigned b); void prependbyte(unsigned b); void writewchar(unsigned w); void writeword(unsigned w); void writeUTF16(unsigned w); void write4(unsigned w); void write(OutBuffer *buf); void write(RootObject *obj); void fill0(size_t nbytes); void vprintf(const char *format, va_list args); void printf(const char *format, ...); void bracket(char left, char right); size_t bracket(size_t i, const char *left, size_t j, const char *right); void spread(size_t offset, size_t nbytes); size_t insert(size_t offset, const void *data, size_t nbytes); void remove(size_t offset, size_t nbytes); // Append terminating null if necessary and get view of internal buffer char *peekString(); // Append terminating null if necessary and take ownership of data char *extractString(); }; ================================================ FILE: gcc/d/dmd/root/port.d ================================================ /* port.d -- A mini library for doing compiler/system specific things. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.root.port; nothrow @nogc: extern (C++) struct Port { nothrow @nogc: static int memicmp(scope const char* s1, scope const char* s2, size_t n) pure; static char* strupr(char* s) pure; static bool isFloat32LiteralOutOfRange(scope const(char)* s); static bool isFloat64LiteralOutOfRange(scope const(char)* s); static void writelongLE(uint value, scope void* buffer) pure; static uint readlongLE(scope void* buffer) pure; static void writelongBE(uint value, scope void* buffer) pure; static uint readlongBE(scope void* buffer) pure; static uint readwordLE(scope void* buffer) pure; static uint readwordBE(scope void* buffer) pure; static void valcpy(scope void *dst, ulong val, size_t size) pure; } ================================================ FILE: gcc/d/dmd/root/port.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/port.h */ #pragma once // Portable wrapper around compiler/system specific things. // The idea is to minimize #ifdef's in the app code. #include #include typedef unsigned char utf8_t; struct Port { static int memicmp(const char *s1, const char *s2, size_t n); static char *strupr(char *s); static bool isFloat32LiteralOutOfRange(const char *s); static bool isFloat64LiteralOutOfRange(const char *s); static void writelongLE(unsigned value, void *buffer); static unsigned readlongLE(void *buffer); static void writelongBE(unsigned value, void *buffer); static unsigned readlongBE(void *buffer); static unsigned readwordLE(void *buffer); static unsigned readwordBE(void *buffer); static void valcpy(void *dst, uint64_t val, size_t size); }; ================================================ FILE: gcc/d/dmd/root/rmem.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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.stdc.string; version (GC) { import core.memory : GC; extern (C++) struct Mem { static char* xstrdup(const(char)* p) nothrow { return p[0 .. strlen(p) + 1].dup.ptr; } static void xfree(void* p) nothrow { return GC.free(p); } static void* xmalloc(size_t n) nothrow { return GC.malloc(n); } static void* xcalloc(size_t size, size_t n) nothrow { return GC.calloc(size * n); } static void* xrealloc(void* p, size_t size) nothrow { return GC.realloc(p, size); } static void error() nothrow { import core.stdc.stdlib : exit, EXIT_FAILURE; import core.stdc.stdio : printf; printf("Error: out of memory\n"); exit(EXIT_FAILURE); } } extern (C) void* allocmemory(size_t m_size) nothrow { return GC.malloc(m_size); } extern (C++) const __gshared Mem mem; } else { import core.stdc.stdlib; import core.stdc.stdio; extern (C++) struct Mem { static char* xstrdup(const(char)* s) nothrow { if (s) { auto p = .strdup(s); if (p) return p; error(); } return null; } static void xfree(void* p) nothrow { if (p) .free(p); } static void* xmalloc(size_t size) nothrow { if (!size) return null; auto p = .malloc(size); if (!p) error(); return p; } static void* xcalloc(size_t size, size_t n) nothrow { if (!size || !n) return null; auto p = .calloc(size, n); if (!p) error(); return p; } static void* xrealloc(void* p, size_t size) nothrow { if (!size) { if (p) .free(p); return null; } if (!p) { p = .malloc(size); if (!p) error(); return p; } p = .realloc(p, size); if (!p) error(); return p; } static void error() nothrow { printf("Error: out of memory\n"); exit(EXIT_FAILURE); } } extern (C++) const __gshared Mem mem; enum CHUNK_SIZE = (256 * 4096 - 64); __gshared size_t heapleft = 0; __gshared void* heapp; extern (C) void* allocmemory(size_t m_size) nothrow { // 16 byte alignment is better (and sometimes needed) for doubles m_size = (m_size + 15) & ~15; // The layout of the code is selected so the most common case is straight through if (m_size <= heapleft) { L1: heapleft -= m_size; auto p = heapp; heapp = cast(void*)(cast(char*)heapp + m_size); return p; } if (m_size > CHUNK_SIZE) { auto p = malloc(m_size); if (p) { return p; } printf("Error: out of memory\n"); exit(EXIT_FAILURE); } heapleft = CHUNK_SIZE; heapp = malloc(CHUNK_SIZE); if (!heapp) { printf("Error: out of memory\n"); exit(EXIT_FAILURE); } goto L1; } 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 { enum OVERRIDE_MEMALLOC = false; } static if (OVERRIDE_MEMALLOC) { extern (C) void* _d_allocmemory(size_t m_size) nothrow { return allocmemory(m_size); } extern (C) Object _d_newclass(const ClassInfo ci) nothrow { auto p = allocmemory(ci.initializer.length); p[0 .. ci.initializer.length] = cast(void[])ci.initializer[]; return cast(Object)p; } version (LDC) { extern (C) Object _d_allocclass(const ClassInfo ci) nothrow { return cast(Object)allocmemory(ci.initializer.length); } } extern (C) void* _d_newitemT(TypeInfo ti) nothrow { auto p = allocmemory(ti.tsize); (cast(ubyte*)p)[0 .. ti.initializer.length] = 0; return p; } extern (C) void* _d_newitemiT(TypeInfo ti) nothrow { auto p = allocmemory(ti.tsize); p[0 .. ti.initializer.length] = ti.initializer[]; 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; } } } /** 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) nothrow { if (!s) return null; auto p = cast(char*)mem.xmalloc(s.length + 1); char[] a = p[0 .. s.length]; a[] = s[0 .. s.length]; p[s.length] = 0; // preserve 0 terminator semantics return a; } /// 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) nothrow { if (!s) return null; const dim = s.length; auto p = (cast(T*)mem.xmalloc(T.sizeof * dim))[0 .. dim]; p[] = s; return p; } /// 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); } ================================================ FILE: gcc/d/dmd/root/rmem.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.h */ #pragma once #include // for size_t #if __APPLE__ && __i386__ /* size_t is 'unsigned long', which makes it mangle differently * than D's 'uint' */ typedef unsigned d_size_t; #else typedef size_t d_size_t; #endif struct Mem { Mem() { } static char *xstrdup(const char *s); static void *xmalloc(d_size_t size); static void *xcalloc(d_size_t size, d_size_t n); static void *xrealloc(void *p, d_size_t size); static void xfree(void *p); static void *xmallocdup(void *o, d_size_t size); static void error(); }; extern Mem mem; ================================================ FILE: gcc/d/dmd/root/root.h ================================================ /* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/root/root.h */ #pragma once #include "object.h" #include "filename.h" #include "file.h" #include "outbuffer.h" #include "array.h" ================================================ FILE: gcc/d/dmd/root/rootobject.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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/rootobject.d, root/_rootobject.d) * Documentation: https://dlang.org/phobos/dmd_root_rootobject.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rootobject.d */ module dmd.root.rootobject; import core.stdc.stdio; import dmd.root.outbuffer; /*********************************************************** */ enum DYNCAST : int { object, expression, dsymbol, type, identifier, tuple, parameter, statement, condition, templateparameter, } /*********************************************************** */ extern (C++) class RootObject { this() nothrow pure @nogc @safe { } bool equals(RootObject o) { return o is this; } int compare(RootObject) { assert(0); } const(char)* toChars() { assert(0); } /// extern(D) const(char)[] toString() { import core.stdc.string : strlen; auto p = this.toChars(); return p[0 .. strlen(p)]; } void toBuffer(OutBuffer* buf) nothrow pure @nogc @safe { assert(0); } DYNCAST dyncast() const nothrow pure @nogc @safe { return DYNCAST.object; } } ================================================ FILE: gcc/d/dmd/root/speller.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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/speller.d, root/_speller.d) * Documentation: https://dlang.org/phobos/dmd_root_speller.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/speller.d */ module dmd.root.speller; import core.stdc.limits; import core.stdc.stdlib; import core.stdc.string; alias dg_speller_t = void* delegate(const(char)*, ref int); __gshared const(char)* idchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; /************************************************** * combine a new result from the spell checker to * find the one with the closest symbol with * respect to the cost defined by the search function * Input/Output: * p best found spelling (NULL if none found yet) * cost cost of p (INT_MAX if none found yet) * Input: * np new found spelling (NULL if none found) * ncost cost of np if non-NULL * Returns: * true if the cost is less or equal 0 * false otherwise */ private bool combineSpellerResult(ref void* p, ref int cost, void* np, int ncost) { if (np && ncost < cost) { p = np; cost = ncost; if (cost <= 0) return true; } return false; } private void* spellerY(const(char)* seed, size_t seedlen, dg_speller_t dg, const(char)* charset, size_t index, int* cost) { if (!seedlen) return null; assert(seed[seedlen] == 0); char[30] tmp; char* buf; if (seedlen <= tmp.sizeof - 2) buf = tmp.ptr; else { buf = cast(char*)alloca(seedlen + 2); // leave space for extra char if (!buf) return null; // no matches } memcpy(buf, seed, index); *cost = INT_MAX; void* p = null; int ncost; /* Delete at seed[index] */ if (index < seedlen) { memcpy(buf + index, seed + index + 1, seedlen - index); assert(buf[seedlen - 1] == 0); void* np = dg(buf, ncost); if (combineSpellerResult(p, *cost, np, ncost)) return p; } if (charset && *charset) { /* Substitutions */ if (index < seedlen) { memcpy(buf, seed, seedlen + 1); for (const(char)* s = charset; *s; s++) { buf[index] = *s; //printf("sub buf = '%s'\n", buf); void* np = dg(buf, ncost); if (combineSpellerResult(p, *cost, np, ncost)) return p; } assert(buf[seedlen] == 0); } /* Insertions */ memcpy(buf + index + 1, seed + index, seedlen + 1 - index); for (const(char)* s = charset; *s; s++) { buf[index] = *s; //printf("ins buf = '%s'\n", buf); void* np = dg(buf, ncost); if (combineSpellerResult(p, *cost, np, ncost)) return p; } assert(buf[seedlen + 1] == 0); } return p; // return "best" result } private void* spellerX(const(char)* seed, size_t seedlen, dg_speller_t dg, const(char)* charset, int flag) { if (!seedlen) return null; char[30] tmp; char* buf; if (seedlen <= tmp.sizeof - 2) buf = tmp.ptr; else { buf = cast(char*)alloca(seedlen + 2); // leave space for extra char if (!buf) return null; // no matches } int cost = INT_MAX, ncost; void* p = null, np; /* Deletions */ memcpy(buf, seed + 1, seedlen); for (size_t i = 0; i < seedlen; i++) { //printf("del buf = '%s'\n", buf); if (flag) np = spellerY(buf, seedlen - 1, dg, charset, i, &ncost); else np = dg(buf, ncost); if (combineSpellerResult(p, cost, np, ncost)) return p; buf[i] = seed[i]; } /* Transpositions */ if (!flag) { memcpy(buf, seed, seedlen + 1); for (size_t i = 0; i + 1 < seedlen; i++) { // swap [i] and [i + 1] buf[i] = seed[i + 1]; buf[i + 1] = seed[i]; //printf("tra buf = '%s'\n", buf); if (combineSpellerResult(p, cost, dg(buf, ncost), ncost)) return p; buf[i] = seed[i]; } } if (charset && *charset) { /* Substitutions */ memcpy(buf, seed, seedlen + 1); for (size_t i = 0; i < seedlen; i++) { for (const(char)* s = charset; *s; s++) { buf[i] = *s; //printf("sub buf = '%s'\n", buf); if (flag) np = spellerY(buf, seedlen, dg, charset, i + 1, &ncost); else np = dg(buf, ncost); if (combineSpellerResult(p, cost, np, ncost)) return p; } buf[i] = seed[i]; } /* Insertions */ memcpy(buf + 1, seed, seedlen + 1); for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations { for (const(char)* s = charset; *s; s++) { buf[i] = *s; //printf("ins buf = '%s'\n", buf); if (flag) np = spellerY(buf, seedlen + 1, dg, charset, i + 1, &ncost); else np = dg(buf, ncost); if (combineSpellerResult(p, cost, np, ncost)) return p; } buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0 } } return p; // return "best" result } /************************************************** * Looks for correct spelling. * Currently only looks a 'distance' of one from the seed[]. * This does an exhaustive search, so can potentially be very slow. * Params: * seed = wrongly spelled word * dg = search delegate * charset = character set * Returns: * null = no correct spellings found, otherwise * the value returned by dg() for first possible correct spelling */ void* speller(const(char)* seed, scope dg_speller_t dg, const(char)* charset) { size_t seedlen = strlen(seed); size_t maxdist = seedlen < 4 ? seedlen / 2 : 2; for (int distance = 0; distance < maxdist; distance++) { void* p = spellerX(seed, seedlen, dg, charset, distance); if (p) return p; // if (seedlen > 10) // break; } return null; // didn't find it } unittest { __gshared const(char)*** cases = [ ["hello", "hell", "y"], ["hello", "hel", "y"], ["hello", "ello", "y"], ["hello", "llo", "y"], ["hello", "hellox", "y"], ["hello", "helloxy", "y"], ["hello", "xhello", "y"], ["hello", "xyhello", "y"], ["hello", "ehllo", "y"], ["hello", "helol", "y"], ["hello", "abcd", "n"], ["hello", "helxxlo", "y"], ["hello", "ehlxxlo", "n"], ["hello", "heaao", "y"], ["_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y"], [null, null, null] ]; //printf("unittest_speller()\n"); void* dgarg; void* speller_test(const(char)* s, ref int cost) { //printf("speller_test(%s, %s)\n", dgarg, s); cost = 0; if (strcmp(cast(char*)dgarg, s) == 0) return dgarg; return null; } dgarg = cast(char*)"hell"; const(void)* p = speller(cast(const(char)*)"hello", &speller_test, idchars); assert(p !is null); for (int i = 0; cases[i][0]; i++) { //printf("case [%d]\n", i); dgarg = cast(void*)cases[i][1]; void* p2 = speller(cases[i][0], &speller_test, idchars); if (p2) assert(cases[i][2][0] == 'y'); else assert(cases[i][2][0] == 'n'); } //printf("unittest_speller() success\n"); } ================================================ FILE: gcc/d/dmd/root/stringtable.d ================================================ /** * Compiler implementation of the D programming language * http://dlang.org * * Copyright: Copyright (C) 1999-2018 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; enum POOL_BITS = 12; enum POOL_SIZE = (1U << POOL_BITS); private size_t nextpow2(size_t val) pure nothrow @nogc @safe { size_t res = 1; while (res < val) res <<= 1; return res; } enum loadFactor = 0.8; 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 { void* ptrvalue; size_t length; nothrow: pure: char* lstring() { return cast(char*)(&this + 1); } size_t len() const { return length; } const(char)* toDchars() const { return cast(const(char)*)(&this + 1); } /// Returns: The content of this entry as a D slice inout(char)[] toString() inout { return (cast(inout(char)*)(&this + 1))[0 .. length]; } } struct StringTable { private: StringEntry* table; size_t tabledim; ubyte** pools; size_t npools; size_t nfill; size_t count; public: void _init(size_t size = 0) nothrow { size = nextpow2(cast(size_t)(size / loadFactor)); if (size < 32) size = 32; table = cast(StringEntry*)mem.xcalloc(size, (table[0]).sizeof); tabledim = size; pools = null; npools = nfill = 0; count = 0; } void reset(size_t size = 0) nothrow { for (size_t i = 0; i < npools; ++i) mem.xfree(pools[i]); mem.xfree(table); mem.xfree(pools); table = null; pools = null; _init(size); } ~this() nothrow { for (size_t i = 0; i < npools; ++i) mem.xfree(pools[i]); mem.xfree(table); mem.xfree(pools); table = null; pools = null; } /** 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)* lookup(const(char)* s, size_t length) inout nothrow pure { const(hash_t) hash = calcHash(s, length); const(size_t) i = findSlot(hash, s, length); // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL); return getValue(table[i].vptr); } /// ditto inout(StringValue)* lookup(const(char)[] str) inout nothrow pure { return lookup(str.ptr, str.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* insert(const(char)* s, size_t length, void* ptrvalue) nothrow { const(hash_t) hash = calcHash(s, length); size_t i = findSlot(hash, s, length); if (table[i].vptr) return null; // already in table if (++count > tabledim * loadFactor) { grow(); i = findSlot(hash, s, length); } table[i].hash = hash; table[i].vptr = allocValue(s, length, ptrvalue); // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL); return getValue(table[i].vptr); } /// ditto StringValue* insert(const(char)[] str, void* value) nothrow { return insert(str.ptr, str.length, value); } StringValue* update(const(char)* s, size_t length) nothrow { const(hash_t) hash = calcHash(s, length); size_t i = findSlot(hash, s, length); if (!table[i].vptr) { if (++count > tabledim * loadFactor) { grow(); i = findSlot(hash, s, length); } table[i].hash = hash; table[i].vptr = allocValue(s, length, null); } // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL); return getValue(table[i].vptr); } StringValue* update(const(char)[] name) nothrow { return update(name.ptr, name.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)*) fp) { foreach (const se; table[0 .. tabledim]) { if (!se.vptr) continue; const sv = getValue(se.vptr); int result = (*fp)(sv); if (result) return result; } return 0; } private: nothrow: uint allocValue(const(char)* s, size_t length, void* ptrvalue) { const(size_t) nbytes = StringValue.sizeof + length + 1; if (!npools || nfill + nbytes > POOL_SIZE) { pools = cast(ubyte**)mem.xrealloc(pools, ++npools * (pools[0]).sizeof); pools[npools - 1] = cast(ubyte*)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE); nfill = 0; } StringValue* sv = cast(StringValue*)&pools[npools - 1][nfill]; sv.ptrvalue = ptrvalue; sv.length = length; .memcpy(sv.lstring(), s, length); sv.lstring()[length] = 0; const(uint) vptr = cast(uint)(npools << POOL_BITS | nfill); nfill += nbytes + (-nbytes & 7); // align to 8 bytes return vptr; } inout(StringValue)* getValue(uint vptr) inout pure { if (!vptr) return null; const(size_t) idx = (vptr >> POOL_BITS) - 1; const(size_t) off = vptr & POOL_SIZE - 1; return cast(inout(StringValue)*)&pools[idx][off]; } size_t findSlot(hash_t hash, const(char)* s, size_t length) const pure { // quadratic probing using triangular numbers // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774 for (size_t i = hash & (tabledim - 1), j = 1;; ++j) { const(StringValue)* sv; auto vptr = table[i].vptr; if (!vptr || table[i].hash == hash && (sv = getValue(vptr)).length == length && .memcmp(s, sv.toDchars(), length) == 0) return i; i = (i + j) & (tabledim - 1); } } void grow() { const odim = tabledim; auto otab = table; tabledim *= 2; table = cast(StringEntry*)mem.xcalloc(tabledim, (table[0]).sizeof); foreach (const se; otab[0 .. odim]) { if (!se.vptr) continue; const sv = getValue(se.vptr); table[findSlot(se.hash, sv.toDchars(), sv.length)] = se; } mem.xfree(otab); } } ================================================ FILE: gcc/d/dmd/safe.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/safe.d, _safe.d) * Documentation: https://dlang.org/phobos/dmd_safe.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/safe.d */ module dmd.safe; import core.stdc.stdio; import dmd.aggregate; import dmd.dclass; import dmd.declaration; import dmd.dscope; import dmd.expression; import dmd.mtype; import dmd.target; import dmd.tokens; /************************************************************* * Check for unsafe access in @safe code: * 1. read overlapped pointers * 2. write misaligned pointers * 3. write overlapped storage classes * Print error if unsafe. * Params: * sc = scope * e = expression to check * readonly = if access is read-only * printmsg = print error message if true * Returns: * true if error */ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) { //printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg); if (e.op != TOK.dotVariable) return false; DotVarExp dve = cast(DotVarExp)e; if (VarDeclaration v = dve.var.isVarDeclaration()) { if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference()) return false; auto ad = v.toParent2().isAggregateDeclaration(); if (!ad) return false; const hasPointers = v.type.hasPointers(); if (hasPointers) { if (ad.sizeok != Sizeok.done) ad.determineSize(ad.loc); // needed to set v.overlapped if (v.overlapped && sc.func.setUnsafe()) { if (printmsg) e.error("field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad.toChars(), v.toChars()); return true; } } if (readonly || !e.type.isMutable()) return false; if (hasPointers && v.type.toBasetype().ty != Tstruct) { if ((ad.type.alignment() < Target.ptrsize || (v.offset & (Target.ptrsize - 1))) && sc.func.setUnsafe()) { if (printmsg) e.error("field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad.toChars(), v.toChars()); return true; } } if (v.overlapUnsafe && sc.func.setUnsafe()) { if (printmsg) e.error("field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes", ad.toChars(), v.toChars()); return true; } } return false; } /********************************************** * Determine if it is @safe to cast e from tfrom to tto. * Params: * e = expression to be cast * tfrom = type of e * tto = type to cast e to * Returns: * true if @safe */ bool isSafeCast(Expression e, Type tfrom, Type tto) { // Implicit conversions are always safe if (tfrom.implicitConvTo(tto)) return true; if (!tto.hasPointers()) return true; auto tfromb = tfrom.toBasetype(); auto ttob = tto.toBasetype(); if (ttob.ty == Tclass && tfromb.ty == Tclass) { ClassDeclaration cdfrom = tfromb.isClassHandle(); ClassDeclaration cdto = ttob.isClassHandle(); int offset; if (!cdfrom.isBaseOf(cdto, &offset)) return false; if (cdfrom.isCPPinterface() || cdto.isCPPinterface()) return false; if (!MODimplicitConv(tfromb.mod, ttob.mod)) return false; return true; } if (ttob.ty == Tarray && tfromb.ty == Tsarray) // https://issues.dlang.org/show_bug.cgi?id=12502 tfromb = tfromb.nextOf().arrayOf(); if (ttob.ty == Tarray && tfromb.ty == Tarray || ttob.ty == Tpointer && tfromb.ty == Tpointer) { Type ttobn = ttob.nextOf().toBasetype(); Type tfromn = tfromb.nextOf().toBasetype(); /* From void[] to anything mutable is unsafe because: * int*[] api; * void[] av = api; * int[] ai = cast(int[]) av; * ai[0] = 7; * *api[0] crash! */ if (tfromn.ty == Tvoid && ttobn.isMutable()) { if (ttob.ty == Tarray && e.op == TOK.arrayLiteral) return true; return false; } // If the struct is opaque we don't know about the struct members then the cast becomes unsafe if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members || tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members) return false; const frompointers = tfromn.hasPointers(); const topointers = ttobn.hasPointers(); if (frompointers && !topointers && ttobn.isMutable()) return false; if (!frompointers && topointers) return false; if (!topointers && ttobn.ty != Tfunction && tfromn.ty != Tfunction && (ttob.ty == Tarray || ttobn.size() <= tfromn.size()) && MODimplicitConv(tfromn.mod, ttobn.mod)) { return true; } } return false; } ================================================ FILE: gcc/d/dmd/sapply.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/sparse.d, _sparse.d) * Documentation: https://dlang.org/phobos/dmd_sapply.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sapply.d */ module dmd.sapply; import dmd.statement; import dmd.visitor; /************************************** * A Statement tree walker that will visit each Statement s in the tree, * in depth-first evaluation order, and call fp(s,param) on it. * fp() signals whether the walking continues with its return value: * Returns: * 0 continue * 1 done * It's a bit slower than using virtual functions, but more encapsulated and less brittle. * Creating an iterator for this would be much more complex. */ extern (C++) final class PostorderStatementVisitor : StoppableVisitor { alias visit = typeof(super).visit; public: StoppableVisitor v; extern (D) this(StoppableVisitor v) { this.v = v; } bool doCond(Statement s) { if (!stop && s) s.accept(this); return stop; } bool applyTo(Statement s) { s.accept(v); stop = v.stop; return true; } override void visit(Statement s) { applyTo(s); } override void visit(PeelStatement s) { doCond(s.s) || applyTo(s); } override void visit(CompoundStatement s) { for (size_t i = 0; i < s.statements.dim; i++) if (doCond((*s.statements)[i])) return; applyTo(s); } override void visit(UnrolledLoopStatement s) { for (size_t i = 0; i < s.statements.dim; i++) if (doCond((*s.statements)[i])) return; applyTo(s); } override void visit(ScopeStatement s) { doCond(s.statement) || applyTo(s); } override void visit(WhileStatement s) { doCond(s._body) || applyTo(s); } override void visit(DoStatement s) { doCond(s._body) || applyTo(s); } override void visit(ForStatement s) { doCond(s._init) || doCond(s._body) || applyTo(s); } override void visit(ForeachStatement s) { doCond(s._body) || applyTo(s); } override void visit(ForeachRangeStatement s) { doCond(s._body) || applyTo(s); } override void visit(IfStatement s) { doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s); } override void visit(PragmaStatement s) { doCond(s._body) || applyTo(s); } override void visit(SwitchStatement s) { doCond(s._body) || applyTo(s); } override void visit(CaseStatement s) { doCond(s.statement) || applyTo(s); } override void visit(DefaultStatement s) { doCond(s.statement) || applyTo(s); } override void visit(SynchronizedStatement s) { doCond(s._body) || applyTo(s); } override void visit(WithStatement s) { doCond(s._body) || applyTo(s); } override void visit(TryCatchStatement s) { if (doCond(s._body)) return; for (size_t i = 0; i < s.catches.dim; i++) if (doCond((*s.catches)[i].handler)) return; applyTo(s); } override void visit(TryFinallyStatement s) { doCond(s._body) || doCond(s.finalbody) || applyTo(s); } override void visit(OnScopeStatement s) { doCond(s.statement) || applyTo(s); } override void visit(DebugStatement s) { doCond(s.statement) || applyTo(s); } override void visit(LabelStatement s) { doCond(s.statement) || applyTo(s); } } bool walkPostorder(Statement s, StoppableVisitor v) { scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v); s.accept(pv); return v.stop; } ================================================ FILE: gcc/d/dmd/scope.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/scope.h */ #pragma once class Identifier; class Module; class Statement; class SwitchStatement; class TryFinallyStatement; class LabelStatement; class ForeachStatement; class ClassDeclaration; class AggregateDeclaration; class FuncDeclaration; class UserAttributeDeclaration; struct DocComment; struct AA; class TemplateInstance; #include "dsymbol.h" #define CSXthis_ctor 1 // called this() #define CSXsuper_ctor 2 // called super() #define CSXthis 4 // referenced this #define CSXsuper 8 // referenced super #define CSXlabel 0x10 // seen a label #define CSXreturn 0x20 // seen a return statement #define CSXany_ctor 0x40 // either this() or super() was called #define CSXhalt 0x80 // assert(0) // Flags that would not be inherited beyond scope nesting #define SCOPEctor 0x0001 // constructor type #define SCOPEcondition 0x0004 // inside static if/assert condition #define SCOPEdebug 0x0008 // inside debug conditional // Flags that would be inherited beyond scope nesting #define SCOPEnoaccesscheck 0x0002 // don't do access checks #define SCOPEconstraint 0x0010 // inside template constraint #define SCOPEinvariant 0x0020 // inside invariant code #define SCOPErequire 0x0040 // inside in contract code #define SCOPEensure 0x0060 // inside out contract code #define SCOPEcontract 0x0060 // [mask] we're inside contract code #define SCOPEctfe 0x0080 // inside a ctfe-only expression #define SCOPEcompile 0x0100 // inside __traits(compile) #define SCOPEignoresymbolvisibility 0x0200 // ignore symbol visibility (Bugzilla 15907) #define SCOPEfullinst 0x1000 // fully instantiate templates #define SCOPEfree 0x8000 // is on free list struct Scope { Scope *enclosing; // enclosing Scope Module *_module; // Root module ScopeDsymbol *scopesym; // current symbol FuncDeclaration *func; // function we are in Dsymbol *parent; // parent to use LabelStatement *slabel; // enclosing labelled statement SwitchStatement *sw; // enclosing switch statement TryFinallyStatement *tf; // enclosing try finally statement OnScopeStatement *os; // enclosing scope(xxx) statement Statement *sbreak; // enclosing statement that supports "break" Statement *scontinue; // enclosing statement that supports "continue" ForeachStatement *fes; // if nested function for ForeachStatement, this is it Scope *callsc; // used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ bool inunion; // true if processing members of a union bool nofree; // true if shouldn't free it bool inLoop; // true if inside a loop (where constructor calls aren't allowed) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope). * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint). * If minst && tinst, it's in instantiated code scope without speculation. * If !minst && tinst, it's in instantiated code scope with speculation. */ Module *minst; // root module where the instantiated templates should belong to TemplateInstance *tinst; // enclosing template instance unsigned char callSuper; // primitive flow analysis for constructors unsigned char *fieldinit; size_t fieldinit_dim; AlignDeclaration *aligndecl; // alignment for struct members LINK linkage; // linkage for external functions CPPMANGLE cppmangle; // C++ mangle type PINLINE inlining; // inlining strategy for functions Prot protection; // protection for class members int explicitProtection; // set if in an explicit protection attribute StorageClass stc; // storage class DeprecatedDeclaration *depdecl; // customized deprecation message unsigned flags; UserAttributeDeclaration *userAttribDecl; // user defined attributes DocComment *lastdc; // documentation comment for last symbol at this scope AA *anchorCounts; // lookup duplicate anchor name count Identifier *prevAnchor; // qualified symbol name of last doc anchor Scope(); Scope *copy(); Scope *push(); Scope *push(ScopeDsymbol *ss); Scope *pop(); Scope *startCTFE(); Scope *endCTFE(); void mergeCallSuper(Loc loc, unsigned cs); unsigned *saveFieldInit(); void mergeFieldInit(Loc loc, unsigned *cses); Module *instantiatingModule(); Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); Dsymbol *search_correct(Identifier *ident); Dsymbol *insert(Dsymbol *s); ClassDeclaration *getClassScope(); AggregateDeclaration *getStructClassScope(); void setNoFree(); structalign_t alignment(); bool isDeprecated(); }; ================================================ FILE: gcc/d/dmd/semantic2.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/semantic2.d, _semantic2.d) * Documentation: https://dlang.org/phobos/dmd_semantic2.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic2.d */ module dmd.semantic2; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.astcodegen; import dmd.attrib; import dmd.blockexit; import dmd.clone; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.dversion; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.hdrgen; import dmd.mtype; import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.parse; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.sideeffect; import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utf; import dmd.utils; import dmd.statement; import dmd.target; import dmd.templateparamsem; import dmd.typesem; import dmd.visitor; enum LOG = false; /************************************* * Does semantic analysis on initializers and members of aggregates. */ extern(C++) void semantic2(Dsymbol dsym, Scope* sc) { scope v = new Semantic2Visitor(sc); dsym.accept(v); } private extern(C++) final class Semantic2Visitor : Visitor { alias visit = Visitor.visit; Scope* sc; this(Scope* sc) { this.sc = sc; } override void visit(Dsymbol) {} override void visit(StaticAssert sa) { //printf("StaticAssert::semantic2() %s\n", sa.toChars()); auto sds = new ScopeDsymbol(); sc = sc.push(sds); sc.tinst = null; sc.minst = null; import dmd.staticcond; bool errors; bool result = evalStaticCondition(sc, sa.exp, sa.exp, errors); sc = sc.pop(); if (errors) { errorSupplemental(sa.loc, "while evaluating: `static assert(%s)`", sa.exp.toChars()); } else if (!result) { if (sa.msg) { sc = sc.startCTFE(); sa.msg = sa.msg.expressionSemantic(sc); sa.msg = resolveProperties(sc, sa.msg); sc = sc.endCTFE(); sa.msg = sa.msg.ctfeInterpret(); if (StringExp se = sa.msg.toStringExp()) { // same with pragma(msg) se = se.toUTF8(sc); error(sa.loc, "static assert: \"%.*s\"", cast(int)se.len, se.string); } else error(sa.loc, "static assert: %s", sa.msg.toChars()); } else error(sa.loc, "static assert: `%s` is false", sa.exp.toChars()); if (sc.tinst) sc.tinst.printInstantiationTrace(); if (!global.gag) fatal(); } } override void visit(TemplateInstance tempinst) { if (tempinst.semanticRun >= PASS.semantic2) return; tempinst.semanticRun = PASS.semantic2; static if (LOG) { printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars()); } if (!tempinst.errors && tempinst.members) { TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); sc = tempdecl._scope; assert(sc); sc = sc.push(tempinst.argsym); sc = sc.push(tempinst); sc.tinst = tempinst; sc.minst = tempinst.minst; int needGagging = (tempinst.gagged && !global.gag); uint olderrors = global.errors; int oldGaggedErrors = -1; // dead-store to prevent spurious warning if (needGagging) oldGaggedErrors = global.startGagging(); for (size_t i = 0; i < tempinst.members.dim; i++) { Dsymbol s = (*tempinst.members)[i]; static if (LOG) { printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); } s.semantic2(sc); if (tempinst.gagged && global.errors != olderrors) break; } if (global.errors != olderrors) { if (!tempinst.errors) { if (!tempdecl.literal) tempinst.error(tempinst.loc, "error instantiating"); if (tempinst.tinst) tempinst.tinst.printInstantiationTrace(); } tempinst.errors = true; } if (needGagging) global.endGagging(oldGaggedErrors); sc = sc.pop(); sc.pop(); } static if (LOG) { printf("-TemplateInstance.semantic2('%s')\n", tempinst.toChars()); } } override void visit(TemplateMixin tmix) { if (tmix.semanticRun >= PASS.semantic2) return; tmix.semanticRun = PASS.semantic2; static if (LOG) { printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars()); } if (tmix.members) { assert(sc); sc = sc.push(tmix.argsym); sc = sc.push(tmix); for (size_t i = 0; i < tmix.members.dim; i++) { Dsymbol s = (*tmix.members)[i]; static if (LOG) { printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); } s.semantic2(sc); } sc = sc.pop(); sc.pop(); } static if (LOG) { printf("-TemplateMixin.semantic2('%s')\n", tmix.toChars()); } } override void visit(VarDeclaration vd) { if (vd.semanticRun < PASS.semanticdone && vd.inuse) return; //printf("VarDeclaration::semantic2('%s')\n", toChars()); if (vd.aliassym) // if it's a tuple { vd.aliassym.accept(this); vd.semanticRun = PASS.semantic2done; return; } if (vd._init && !vd.toParent().isFuncDeclaration()) { vd.inuse++; // https://issues.dlang.org/show_bug.cgi?id=14166 // Don't run CTFE for the temporary variables inside typeof vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); vd.inuse--; } if (vd._init && vd.storage_class & STC.manifest) { /* Cannot initializer enums with CTFE classreferences and addresses of struct literals. * Scan initializer looking for them. Issue error if found. */ if (ExpInitializer ei = vd._init.isExpInitializer()) { static bool hasInvalidEnumInitializer(Expression e) { static bool arrayHasInvalidEnumInitializer(Expressions* elems) { foreach (e; *elems) { if (e && hasInvalidEnumInitializer(e)) return true; } return false; } if (e.op == TOK.classReference) return true; if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral) return true; if (e.op == TOK.arrayLiteral) return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements); if (e.op == TOK.structLiteral) return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); if (e.op == TOK.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; return arrayHasInvalidEnumInitializer(ae.values) || arrayHasInvalidEnumInitializer(ae.keys); } return false; } if (hasInvalidEnumInitializer(ei.exp)) vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); } } else if (vd._init && vd.isThreadlocal()) { // Cannot initialize a thread-local class or pointer to struct variable with a literal // that itself is a thread-local reference and would need dynamic initialization also. if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared()) { ExpInitializer ei = vd._init.isExpInitializer(); if (ei && ei.exp.op == TOK.classReference) vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead."); } else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared()) { ExpInitializer ei = vd._init.isExpInitializer(); if (ei && ei.exp.op == TOK.address && (cast(AddrExp)ei.exp).e1.op == TOK.structLiteral) vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead."); } } vd.semanticRun = PASS.semantic2done; } override void visit(Module mod) { //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call return; mod.semanticRun = PASS.semantic2; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope* sc = Scope.createGlobal(mod); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 2 semantic routines: do initializers and function bodies for (size_t i = 0; i < mod.members.dim; i++) { Dsymbol s = (*mod.members)[i]; s.semantic2(sc); } if (mod.userAttribDecl) { mod.userAttribDecl.semantic2(sc); } sc = sc.pop(); sc.pop(); mod.semanticRun = PASS.semantic2done; //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); } override void visit(FuncDeclaration fd) { import dmd.dmangle : mangleToFuncSignature; if (fd.semanticRun >= PASS.semantic2done) return; assert(fd.semanticRun <= PASS.semantic2); fd.semanticRun = PASS.semantic2; //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars()); // https://issues.dlang.org/show_bug.cgi?id=18385 // Disable for 2.079, s.t. a deprecation cycle can be started with 2.080 if (0) if (fd.overnext && !fd.errors) { OutBuffer buf1; OutBuffer buf2; // Always starts the lookup from 'this', because the conflicts with // previous overloads are already reported. auto f1 = fd; mangleToFuncSignature(buf1, f1); overloadApply(f1, (Dsymbol s) { auto f2 = s.isFuncDeclaration(); if (!f2 || f1 == f2 || f2.errors) return 0; // Don't have to check conflict between declaration and definition. if ((f1.fbody !is null) != (f2.fbody !is null)) return 0; /* Check for overload merging with base class member functions. * * class B { void foo() {} } * class D : B { * override void foo() {} // B.foo appears as f2 * alias foo = B.foo; * } */ if (f1.overrides(f2)) return 0; // extern (C) functions always conflict each other. if (f1.ident == f2.ident && f1.toParent2() == f2.toParent2() && (f1.linkage != LINK.d && f1.linkage != LINK.cpp) && (f2.linkage != LINK.d && f2.linkage != LINK.cpp)) { /* Allow the hack that is actually used in druntime, * to ignore function attributes for extern (C) functions. * TODO: Must be reconsidered in the future. * BUG: https://issues.dlang.org/show_bug.cgi?id=18206 * * extern(C): * alias sigfn_t = void function(int); * alias sigfn_t2 = void function(int) nothrow @nogc; * sigfn_t bsd_signal(int sig, sigfn_t func); * sigfn_t2 bsd_signal(int sig, sigfn_t2 func) nothrow @nogc; // no error */ if (f1.fbody is null || f2.fbody is null) return 0; auto tf1 = cast(TypeFunction)f1.type; auto tf2 = cast(TypeFunction)f2.type; error(f2.loc, "%s `%s%s` cannot be overloaded with %s`extern(%s)` function at %s", f2.kind(), f2.toPrettyChars(), parametersTypeToChars(tf2.parameters, tf2.varargs), (f1.linkage == f2.linkage ? "another " : "").ptr, linkageToChars(f1.linkage), f1.loc.toChars()); f2.type = Type.terror; f2.errors = true; return 0; } buf2.reset(); mangleToFuncSignature(buf2, f2); auto s1 = buf1.peekString(); auto s2 = buf2.peekString(); //printf("+%s\n\ts1 = %s\n\ts2 = %s @ [%s]\n", toChars(), s1, s2, f2.loc.toChars()); if (strcmp(s1, s2) == 0) { auto tf2 = cast(TypeFunction)f2.type; error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s", f2.kind(), f2.toPrettyChars(), parametersTypeToChars(tf2.parameters, tf2.varargs), f1.loc.toChars()); f2.type = Type.terror; f2.errors = true; } return 0; }); } objc.setSelector(fd, sc); objc.validateSelector(fd); if (ClassDeclaration cd = fd.parent.isClassDeclaration()) { objc.checkLinkage(fd); } if (!fd.type || fd.type.ty != Tfunction) return; TypeFunction f = cast(TypeFunction) fd.type; if (!f.parameters) return; size_t nparams = Parameter.dim(f.parameters); //semantic for parameters' UDAs foreach (i; 0..nparams) { Parameter param = Parameter.getNth(f.parameters, i); if (param && param.userAttribDecl) param.userAttribDecl.semantic2(sc); } } override void visit(Import i) { //printf("Import::semantic2('%s')\n", toChars()); if (i.mod) { i.mod.semantic2(null); if (i.mod.needmoduleinfo) { //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars()); if (sc) sc._module.needmoduleinfo = 1; } } } override void visit(Nspace ns) { if (ns.semanticRun >= PASS.semantic2) return; ns.semanticRun = PASS.semantic2; static if (LOG) { printf("+Nspace::semantic2('%s')\n", ns.toChars()); } if (ns.members) { assert(sc); sc = sc.push(ns); sc.linkage = LINK.cpp; foreach (s; *ns.members) { static if (LOG) { printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); } s.semantic2(sc); } sc.pop(); } static if (LOG) { printf("-Nspace::semantic2('%s')\n", ns.toChars()); } } override void visit(AttribDeclaration ad) { Dsymbols* d = ad.include(sc); if (d) { Scope* sc2 = ad.newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.semantic2(sc2); } if (sc2 != sc) sc2.pop(); } } /** * Run the DeprecatedDeclaration's semantic2 phase then its members. * * The message set via a `DeprecatedDeclaration` can be either of: * - a string literal * - an enum * - a static immutable * So we need to call ctfe to resolve it. * Afterward forwards to the members' semantic2. */ override void visit(DeprecatedDeclaration dd) { getMessage(dd); visit(cast(AttribDeclaration)dd); } override void visit(AlignDeclaration ad) { ad.getAlignment(sc); visit(cast(AttribDeclaration)ad); } override void visit(UserAttributeDeclaration uad) { if (uad.decl && uad.atts && uad.atts.dim && uad._scope) { static void eval(Scope* sc, Expressions* exps) { foreach (ref Expression e; *exps) { if (e) { e = e.expressionSemantic(sc); if (definitelyValueParameter(e)) e = e.ctfeInterpret(); if (e.op == TOK.tuple) { TupleExp te = cast(TupleExp)e; eval(sc, te.exps); } } } } uad._scope = null; eval(sc, uad.atts); } visit(cast(AttribDeclaration)uad); } override void visit(AggregateDeclaration ad) { //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors); if (!ad.members) return; if (ad._scope) { ad.error("has forward references"); return; } auto sc2 = ad.newScope(sc); ad.determineSize(ad.loc); for (size_t i = 0; i < ad.members.dim; i++) { Dsymbol s = (*ad.members)[i]; //printf("\t[%d] %s\n", i, s.toChars()); s.semantic2(sc2); } sc2.pop(); } } ================================================ FILE: gcc/d/dmd/semantic3.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/semantic3.d, _semantic3.d) * Documentation: https://dlang.org/phobos/dmd_semantic3.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic3.d */ module dmd.semantic3; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.aliasthis; import dmd.arraytypes; import dmd.astcodegen; import dmd.attrib; import dmd.blockexit; import dmd.clone; import dmd.ctorflow; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.dversion; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.initsem; import dmd.hdrgen; import dmd.mtype; import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; import dmd.parse; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; import dmd.sideeffect; import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utf; import dmd.utils; import dmd.semantic2; import dmd.statement; import dmd.target; import dmd.templateparamsem; import dmd.typesem; import dmd.visitor; enum LOG = false; /************************************* * Does semantic analysis on function bodies. */ extern(C++) void semantic3(Dsymbol dsym, Scope* sc) { scope v = new Semantic3Visitor(sc); dsym.accept(v); } private extern(C++) final class Semantic3Visitor : Visitor { alias visit = Visitor.visit; Scope* sc; this(Scope* sc) { this.sc = sc; } override void visit(Dsymbol) {} override void visit(TemplateInstance tempinst) { static if (LOG) { printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", tempinst.toChars(), tempinst.semanticRun); } //if (toChars()[0] == 'D') *(char*)0=0; if (tempinst.semanticRun >= PASS.semantic3) return; tempinst.semanticRun = PASS.semantic3; if (!tempinst.errors && tempinst.members) { TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); sc = tempdecl._scope; sc = sc.push(tempinst.argsym); sc = sc.push(tempinst); sc.tinst = tempinst; sc.minst = tempinst.minst; int needGagging = (tempinst.gagged && !global.gag); uint olderrors = global.errors; int oldGaggedErrors = -1; // dead-store to prevent spurious warning /* If this is a gagged instantiation, gag errors. * Future optimisation: If the results are actually needed, errors * would already be gagged, so we don't really need to run semantic * on the members. */ if (needGagging) oldGaggedErrors = global.startGagging(); for (size_t i = 0; i < tempinst.members.dim; i++) { Dsymbol s = (*tempinst.members)[i]; s.semantic3(sc); if (tempinst.gagged && global.errors != olderrors) break; } if (global.errors != olderrors) { if (!tempinst.errors) { if (!tempdecl.literal) tempinst.error(tempinst.loc, "error instantiating"); if (tempinst.tinst) tempinst.tinst.printInstantiationTrace(); } tempinst.errors = true; } if (needGagging) global.endGagging(oldGaggedErrors); sc = sc.pop(); sc.pop(); } } override void visit(TemplateMixin tmix) { if (tmix.semanticRun >= PASS.semantic3) return; tmix.semanticRun = PASS.semantic3; static if (LOG) { printf("TemplateMixin.semantic3('%s')\n", tmix.toChars()); } if (tmix.members) { sc = sc.push(tmix.argsym); sc = sc.push(tmix); for (size_t i = 0; i < tmix.members.dim; i++) { Dsymbol s = (*tmix.members)[i]; s.semantic3(sc); } sc = sc.pop(); sc.pop(); } } override void visit(Module mod) { //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); if (mod.semanticRun != PASS.semantic2done) return; mod.semanticRun = PASS.semantic3; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope* sc = Scope.createGlobal(mod); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 3 semantic routines: do initializers and function bodies for (size_t i = 0; i < mod.members.dim; i++) { Dsymbol s = (*mod.members)[i]; //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars()); s.semantic3(sc); mod.runDeferredSemantic2(); } if (mod.userAttribDecl) { mod.userAttribDecl.semantic3(sc); } sc = sc.pop(); sc.pop(); mod.semanticRun = PASS.semantic3done; } override void visit(FuncDeclaration funcdecl) { /* Determine if function should add `return 0;` */ bool addReturn0() { TypeFunction f = cast(TypeFunction)funcdecl.type; return f.next.ty == Tvoid && (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain()); } VarDeclaration _arguments = null; if (!funcdecl.parent) { if (global.errors) return; //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); assert(0); } if (funcdecl.errors || isError(funcdecl.parent)) { funcdecl.errors = true; return; } //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), funcdecl, sc, funcdecl.loc.toChars()); //fflush(stdout); //printf("storage class = x%x %x\n", sc.stc, storage_class); //{ static int x; if (++x == 2) *(char*)0=0; } //printf("\tlinkage = %d\n", sc.linkage); if (funcdecl.ident == Id.assign && !funcdecl.inuse) { if (funcdecl.storage_class & STC.inference) { /* https://issues.dlang.org/show_bug.cgi?id=15044 * For generated opAssign function, any errors * from its body need to be gagged. */ uint oldErrors = global.startGagging(); ++funcdecl.inuse; funcdecl.semantic3(sc); --funcdecl.inuse; if (global.endGagging(oldErrors)) // if errors happened { // Disable generated opAssign, because some members forbid identity assignment. funcdecl.storage_class |= STC.disable; funcdecl.fbody = null; // remove fbody which contains the error funcdecl.semantic3Errors = false; } return; } } //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract)); if (funcdecl.semanticRun >= PASS.semantic3) return; funcdecl.semanticRun = PASS.semantic3; funcdecl.semantic3Errors = false; if (!funcdecl.type || funcdecl.type.ty != Tfunction) return; TypeFunction f = cast(TypeFunction)funcdecl.type; if (!funcdecl.inferRetType && f.next.ty == Terror) return; if (!funcdecl.fbody && funcdecl.inferRetType && !f.next) { funcdecl.error("has no function body with return type inference"); return; } uint oldErrors = global.errors; auto fds = FuncDeclSem3(funcdecl,sc); fds.checkInContractOverrides(); // Remember whether we need to generate an 'out' contract. immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl); if (funcdecl.fbody || funcdecl.frequires || needEnsure) { /* Symbol table into which we place parameters and nested functions, * solely to diagnose name collisions. */ funcdecl.localsymtab = new DsymbolTable(); // Establish function scope auto ss = new ScopeDsymbol(); // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes for (auto scx = sc; ; scx = scx.enclosing) { if (scx.scopesym) { ss.parent = scx.scopesym; break; } } ss.loc = funcdecl.loc; ss.endlinnum = funcdecl.endloc.linnum; Scope* sc2 = sc.push(ss); sc2.func = funcdecl; sc2.parent = funcdecl; sc2.ctorflow.callSuper = CSX.none; sc2.sbreak = null; sc2.scontinue = null; sc2.sw = null; sc2.fes = funcdecl.fes; sc2.linkage = LINK.d; sc2.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.abstract_ | STC.deprecated_ | STC.override_ | STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property | STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system); sc2.protection = Prot(Prot.Kind.public_); sc2.explicitProtection = 0; sc2.aligndecl = null; if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure) sc2.flags = sc.flags & ~SCOPE.contract; sc2.flags &= ~SCOPE.compile; sc2.tf = null; sc2.os = null; sc2.inLoop = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; sc2.ctorflow.fieldinit = null; /* Note: When a lambda is defined immediately under aggregate member * scope, it should be contextless due to prevent interior pointers. * e.g. * // dg points 'this' - it's interior pointer * class C { int x; void delegate() dg = (){ this.x = 1; }; } * * However, lambdas could be used inside typeof, in order to check * some expressions validity at compile time. For such case the lambda * body can access aggregate instance members. * e.g. * class C { int x; static assert(is(typeof({ this.x = 1; }))); } * * To properly accept it, mark these lambdas as member functions. */ if (auto fld = funcdecl.isFuncLiteralDeclaration()) { if (auto ad = funcdecl.isMember2()) { if (!sc.intypeof) { if (fld.tok == TOK.delegate_) funcdecl.error("cannot be %s members", ad.kind()); else fld.tok = TOK.function_; } else { if (fld.tok != TOK.function_) fld.tok = TOK.delegate_; } } } // Declare 'this' auto ad = funcdecl.isThis(); funcdecl.vthis = funcdecl.declareThis(sc2, ad); //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis); //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars()); // Declare hidden variable _arguments[] and _argptr if (f.varargs == 1) { if (f.linkage == LINK.d) { // Declare _arguments[] funcdecl.v_arguments = new VarDeclaration(Loc.initial, Type.typeinfotypelist.type, Id._arguments_typeinfo, null); funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter; funcdecl.v_arguments.dsymbolSemantic(sc2); sc2.insert(funcdecl.v_arguments); funcdecl.v_arguments.parent = funcdecl; //Type *t = Type::typeinfo.type.constOf().arrayOf(); Type t = Type.dtypeinfo.type.arrayOf(); _arguments = new VarDeclaration(Loc.initial, t, Id._arguments, null); _arguments.storage_class |= STC.temp; _arguments.dsymbolSemantic(sc2); sc2.insert(_arguments); _arguments.parent = funcdecl; } if (f.linkage == LINK.d || (f.parameters && Parameter.dim(f.parameters))) { // Declare _argptr Type t = Type.tvalist; // Init is handled in FuncDeclaration_toObjFile funcdecl.v_argptr = new VarDeclaration(Loc.initial, t, Id._argptr, new VoidInitializer(funcdecl.loc)); funcdecl.v_argptr.storage_class |= STC.temp; funcdecl.v_argptr.dsymbolSemantic(sc2); sc2.insert(funcdecl.v_argptr); funcdecl.v_argptr.parent = funcdecl; } } /* Declare all the function parameters as variables * and install them in parameters[] */ size_t nparams = Parameter.dim(f.parameters); if (nparams) { /* parameters[] has all the tuples removed, as the back end * doesn't know about tuples */ funcdecl.parameters = new VarDeclarations(); funcdecl.parameters.reserve(nparams); for (size_t i = 0; i < nparams; i++) { Parameter fparam = Parameter.getNth(f.parameters, i); Identifier id = fparam.ident; StorageClass stc = 0; if (!id) { /* Generate identifier for un-named parameter, * because we need it later on. */ fparam.ident = id = Identifier.generateId("_param_", i); stc |= STC.temp; } Type vtype = fparam.type; auto v = new VarDeclaration(funcdecl.loc, vtype, id, null); //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars()); stc |= STC.parameter; if (f.varargs == 2 && i + 1 == nparams) { stc |= STC.variadic; auto vtypeb = vtype.toBasetype(); if (vtypeb.ty == Tarray) { /* Since it'll be pointing into the stack for the array * contents, it needs to be `scope` */ stc |= STC.scope_; } } if (funcdecl.flags & FUNCFLAG.inferScope && !(fparam.storageClass & STC.scope_)) stc |= STC.maybescope; stc |= fparam.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); v.storage_class = stc; v.dsymbolSemantic(sc2); if (!sc2.insert(v)) { funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars()); funcdecl.errors = true; } else funcdecl.parameters.push(v); funcdecl.localsymtab.insert(v); v.parent = funcdecl; if (fparam.userAttribDecl) v.userAttribDecl = fparam.userAttribDecl; } } // Declare the tuple symbols and put them in the symbol table, // but not in parameters[]. if (f.parameters) { for (size_t i = 0; i < f.parameters.dim; i++) { Parameter fparam = (*f.parameters)[i]; if (!fparam.ident) continue; // never used, so ignore if (fparam.type.ty == Ttuple) { TypeTuple t = cast(TypeTuple)fparam.type; size_t dim = Parameter.dim(t.arguments); auto exps = new Objects(dim); for (size_t j = 0; j < dim; j++) { Parameter narg = Parameter.getNth(t.arguments, j); assert(narg.ident); VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration(); assert(v); Expression e = new VarExp(v.loc, v); (*exps)[j] = e; } assert(fparam.ident); auto v = new TupleDeclaration(funcdecl.loc, fparam.ident, exps); //printf("declaring tuple %s\n", v.toChars()); v.isexp = true; if (!sc2.insert(v)) funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars()); funcdecl.localsymtab.insert(v); v.parent = funcdecl; } } } // Precondition invariant Statement fpreinv = null; if (funcdecl.addPreInvariant()) { Expression e = addInvariant(funcdecl.loc, sc, ad, funcdecl.vthis); if (e) fpreinv = new ExpStatement(Loc.initial, e); } // Postcondition invariant Statement fpostinv = null; if (funcdecl.addPostInvariant()) { Expression e = addInvariant(funcdecl.loc, sc, ad, funcdecl.vthis); if (e) fpostinv = new ExpStatement(Loc.initial, e); } // Pre/Postcondition contract if (!funcdecl.fbody) funcdecl.buildEnsureRequire(); Scope* scout = null; if (needEnsure || funcdecl.addPostInvariant()) { /* https://issues.dlang.org/show_bug.cgi?id=3657 * Set the correct end line number for fensure scope. */ uint fensure_endlin = funcdecl.endloc.linnum; if (funcdecl.fensure) if (auto s = funcdecl.fensure.isScopeStatement()) fensure_endlin = s.endloc.linnum; if ((needEnsure && global.params.useOut) || fpostinv) { funcdecl.returnLabel = new LabelDsymbol(Id.returnLabel); } // scope of out contract (need for vresult.semantic) auto sym = new ScopeDsymbol(); sym.parent = sc2.scopesym; sym.loc = funcdecl.loc; sym.endlinnum = fensure_endlin; scout = sc2.push(sym); } if (funcdecl.fbody) { auto sym = new ScopeDsymbol(); sym.parent = sc2.scopesym; sym.loc = funcdecl.loc; sym.endlinnum = funcdecl.endloc.linnum; sc2 = sc2.push(sym); auto ad2 = funcdecl.isMember2(); /* If this is a class constructor */ if (ad2 && funcdecl.isCtorDeclaration()) { sc2.ctorflow.allocFieldinit(ad2.fields.dim); foreach (v; ad2.fields) { v.ctorinit = 0; } } if (!funcdecl.inferRetType && !Target.isReturnOnStack(f, funcdecl.needThis())) funcdecl.nrvo_can = 0; bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_)); funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2); if (!funcdecl.fbody) funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements()); if (funcdecl.naked) { fpreinv = null; // can't accommodate with no stack frame fpostinv = null; } assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref)); f = cast(TypeFunction)funcdecl.type; if (funcdecl.inferRetType) { // If no return type inferred yet, then infer a void if (!f.next) f.next = Type.tvoid; if (f.checkRetType(funcdecl.loc)) funcdecl.fbody = new ErrorStatement(); } if (global.params.vcomplex && f.next !is null) f.next.checkComplexTransition(funcdecl.loc, sc); if (funcdecl.returns && !funcdecl.fbody.isErrorStatement()) { for (size_t i = 0; i < funcdecl.returns.dim;) { Expression exp = (*funcdecl.returns)[i].exp; if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult) { if (addReturn0()) exp.type = Type.tint32; else exp.type = f.next; // Remove `return vresult;` from returns funcdecl.returns.remove(i); continue; } if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336 f.isref = false; i++; } } if (f.isref) // Function returns a reference { if (funcdecl.storage_class & STC.auto_) funcdecl.storage_class &= ~STC.auto_; } if (!Target.isReturnOnStack(f, funcdecl.needThis())) funcdecl.nrvo_can = 0; if (funcdecl.fbody.isErrorStatement()) { } else if (funcdecl.isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all * ctor consts were initialized. */ ScopeDsymbol pd = funcdecl.toParent().isScopeDsymbol(); for (size_t i = 0; i < pd.members.dim; i++) { Dsymbol s = (*pd.members)[i]; s.checkCtorConstInit(); } } else if (ad2 && funcdecl.isCtorDeclaration()) { ClassDeclaration cd = ad2.isClassDeclaration(); // Verify that all the ctorinit fields got initialized if (!(sc2.ctorflow.callSuper & CSX.this_ctor)) { foreach (i, v; ad2.fields) { if (v.isThisDeclaration()) continue; if (v.ctorinit == 0) { /* Current bugs in the flow analysis: * 1. union members should not produce error messages even if * not assigned to * 2. structs should recognize delegating opAssign calls as well * as delegating calls to other constructors */ if (v.isCtorinit() && !v.type.isMutable() && cd) funcdecl.error("missing initializer for %s field `%s`", MODtoChars(v.type.mod), v.toChars()); else if (v.storage_class & STC.nodefaultctor) error(funcdecl.loc, "field `%s` must be initialized in constructor", v.toChars()); else if (v.type.needsNested()) error(funcdecl.loc, "field `%s` must be initialized in constructor, because it is nested struct", v.toChars()); } else { bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); if (mustInit && !(sc2.ctorflow.fieldinit[i].csx & CSX.this_ctor)) { funcdecl.error("field `%s` must be initialized but skipped", v.toChars()); } } } } sc2.ctorflow.freeFieldinit(); if (cd && !(sc2.ctorflow.callSuper & CSX.any_ctor) && cd.baseClass && cd.baseClass.ctor) { sc2.ctorflow.callSuper = CSX.none; // Insert implicit super() at start of fbody FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, funcdecl.vthis.type, null, 1); if (!fd) { funcdecl.error("no match for implicit `super()` call in constructor"); } else if (fd.storage_class & STC.disable) { funcdecl.error("cannot call `super()` implicitly because it is annotated with `@disable`"); } else { Expression e1 = new SuperExp(Loc.initial); Expression e = new CallExp(Loc.initial, e1); e = e.expressionSemantic(sc2); Statement s = new ExpStatement(Loc.initial, e); funcdecl.fbody = new CompoundStatement(Loc.initial, s, funcdecl.fbody); } } //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper); } /* https://issues.dlang.org/show_bug.cgi?id=17502 * Wait until after the return type has been inferred before * generating the contracts for this function, and merging contracts * from overrides. * * https://issues.dlang.org/show_bug.cgi?id=17893 * However should take care to generate this before inferered * function attributes are applied, such as 'nothrow'. * * This was originally at the end of the first semantic pass, but * required a fix-up to be done here for the '__result' variable * type of __ensure() inside auto functions, but this didn't work * if the out parameter was implicit. */ funcdecl.buildEnsureRequire(); // Check for errors related to 'nothrow'. const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow); if (f.isnothrow && blockexit & BE.throw_) error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars()); if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches)) { /* Disable optimization on Win32 due to * https://issues.dlang.org/show_bug.cgi?id=17997 */ // if (!global.params.isWindows || global.params.is64bit) funcdecl.eh_none = true; // don't generate unwind tables for this function } if (funcdecl.flags & FUNCFLAG.nothrowInprocess) { if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.isnothrow = !(blockexit & BE.throw_); } if (funcdecl.fbody.isErrorStatement()) { } else if (ad2 && funcdecl.isCtorDeclaration()) { /* Append: * return this; * to function body */ if (blockexit & BE.fallthru) { Statement s = new ReturnStatement(funcdecl.loc, null); s = s.statementSemantic(sc2); funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s); funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1); } } else if (funcdecl.fes) { // For foreach(){} body, append a return 0; if (blockexit & BE.fallthru) { Expression e = new IntegerExp(0); Statement s = new ReturnStatement(Loc.initial, e); funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s); funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1); } assert(!funcdecl.returnLabel); } else { const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0; if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm) { Expression e; if (!funcdecl.hasReturnExp) funcdecl.error("has no `return` statement, but is expected to return a value of type `%s`", f.next.toChars()); else funcdecl.error("no `return exp;` or `assert(0);` at end of function"); if (global.params.useAssert == CHECKENABLE.on && !global.params.useInline) { /* Add an assert(0, msg); where the missing return * should be. */ e = new AssertExp(funcdecl.endloc, new IntegerExp(0), new StringExp(funcdecl.loc, cast(char*)"missing return expression")); } else e = new HaltExp(funcdecl.endloc); e = new CommaExp(Loc.initial, e, f.next.defaultInit(Loc.initial)); e = e.expressionSemantic(sc2); Statement s = new ExpStatement(Loc.initial, e); funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s); } } if (funcdecl.returns) { bool implicit0 = addReturn0(); Type tret = implicit0 ? Type.tint32 : f.next; assert(tret.ty != Tvoid); if (funcdecl.vresult || funcdecl.returnLabel) funcdecl.buildResultVar(scout ? scout : sc2, tret); /* Cannot move this loop into NrvoWalker, because * returns[i] may be in the nested delegate for foreach-body. */ for (size_t i = 0; i < funcdecl.returns.dim; i++) { ReturnStatement rs = (*funcdecl.returns)[i]; Expression exp = rs.exp; if (exp.op == TOK.error) continue; if (tret.ty == Terror) { // https://issues.dlang.org/show_bug.cgi?id=13702 exp = checkGC(sc2, exp); continue; } if (!exp.implicitConvTo(tret) && funcdecl.isTypeIsolated(exp.type)) { if (exp.type.immutableOf().implicitConvTo(tret)) exp = exp.castTo(sc2, exp.type.immutableOf()); else if (exp.type.wildOf().implicitConvTo(tret)) exp = exp.castTo(sc2, exp.type.wildOf()); } exp = exp.implicitCastTo(sc2, tret); if (f.isref) { // Function returns a reference exp = exp.toLvalue(sc2, exp); checkReturnEscapeRef(sc2, exp, false); } else { exp = exp.optimize(WANTvalue); /* https://issues.dlang.org/show_bug.cgi?id=10789 * If NRVO is not possible, all returned lvalues should call their postblits. */ if (!funcdecl.nrvo_can) exp = doCopyOrMove(sc2, exp); if (tret.hasPointers()) checkReturnEscape(sc2, exp, false); } exp = checkGC(sc2, exp); if (funcdecl.vresult) { // Create: return vresult = exp; exp = new BlitExp(rs.loc, funcdecl.vresult, exp); exp.type = funcdecl.vresult.type; if (rs.caseDim) exp = Expression.combine(exp, new IntegerExp(rs.caseDim)); } else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf())) { exp = exp.implicitCastTo(sc2, funcdecl.tintro.nextOf()); } rs.exp = exp; } } if (funcdecl.nrvo_var || funcdecl.returnLabel) { scope NrvoWalker nw = new NrvoWalker(); nw.fd = funcdecl; nw.sc = sc2; nw.visitStmt(funcdecl.fbody); } sc2 = sc2.pop(); } funcdecl.frequire = funcdecl.mergeFrequire(funcdecl.frequire); funcdecl.fensure = funcdecl.mergeFensure(funcdecl.fensure, Id.result); Statement freq = funcdecl.frequire; Statement fens = funcdecl.fensure; /* Do the semantic analysis on the [in] preconditions and * [out] postconditions. */ if (freq) { /* frequire is composed of the [in] contracts */ auto sym = new ScopeDsymbol(); sym.parent = sc2.scopesym; sym.loc = funcdecl.loc; sym.endlinnum = funcdecl.endloc.linnum; sc2 = sc2.push(sym); sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require; // BUG: need to error if accessing out parameters // BUG: need to disallow returns and throws // BUG: verify that all in and ref parameters are read freq = freq.statementSemantic(sc2); freq.blockExit(funcdecl, false); funcdecl.eh_none = false; sc2 = sc2.pop(); if (!global.params.useIn) freq = null; } if (fens) { /* fensure is composed of the [out] contracts */ if (f.next.ty == Tvoid && funcdecl.fensures) { foreach (e; *funcdecl.fensures) { if (e.id) { funcdecl.error(e.ensure.loc, "`void` functions have no result"); //fens = null; } } } sc2 = scout; //push sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure; // BUG: need to disallow returns and throws if (funcdecl.fensure && f.next.ty != Tvoid) funcdecl.buildResultVar(scout, f.next); fens = fens.statementSemantic(sc2); fens.blockExit(funcdecl, false); funcdecl.eh_none = false; sc2 = sc2.pop(); if (!global.params.useOut) fens = null; } if (funcdecl.fbody && funcdecl.fbody.isErrorStatement()) { } else { auto a = new Statements(); // Merge in initialization of 'out' parameters if (funcdecl.parameters) { for (size_t i = 0; i < funcdecl.parameters.dim; i++) { VarDeclaration v = (*funcdecl.parameters)[i]; if (v.storage_class & STC.out_) { if (!v._init) { v.error("Zero-length `out` parameters are not allowed."); return; } ExpInitializer ie = v._init.isExpInitializer(); assert(ie); if (ie.exp.op == TOK.construct) ie.exp.op = TOK.assign; // construction occurred in parameter processing a.push(new ExpStatement(Loc.initial, ie.exp)); } } } if (_arguments) { /* Advance to elements[] member of TypeInfo_Tuple with: * _arguments = v_arguments.elements; */ Expression e = new VarExp(Loc.initial, funcdecl.v_arguments); e = new DotIdExp(Loc.initial, e, Id.elements); e = new ConstructExp(Loc.initial, _arguments, e); e = e.expressionSemantic(sc2); _arguments._init = new ExpInitializer(Loc.initial, e); auto de = new DeclarationExp(Loc.initial, _arguments); a.push(new ExpStatement(Loc.initial, de)); } // Merge contracts together with body into one compound statement if (freq || fpreinv) { if (!freq) freq = fpreinv; else if (fpreinv) freq = new CompoundStatement(Loc.initial, freq, fpreinv); a.push(freq); } if (funcdecl.fbody) a.push(funcdecl.fbody); if (fens || fpostinv) { if (!fens) fens = fpostinv; else if (fpostinv) fens = new CompoundStatement(Loc.initial, fpostinv, fens); auto ls = new LabelStatement(Loc.initial, Id.returnLabel, fens); funcdecl.returnLabel.statement = ls; a.push(funcdecl.returnLabel.statement); if (f.next.ty != Tvoid && funcdecl.vresult) { // Create: return vresult; Expression e = new VarExp(Loc.initial, funcdecl.vresult); if (funcdecl.tintro) { e = e.implicitCastTo(sc, funcdecl.tintro.nextOf()); e = e.expressionSemantic(sc); } auto s = new ReturnStatement(Loc.initial, e); a.push(s); } } if (addReturn0()) { // Add a return 0; statement Statement s = new ReturnStatement(Loc.initial, new IntegerExp(0)); a.push(s); } Statement sbody = new CompoundStatement(Loc.initial, a); /* Append destructor calls for parameters as finally blocks. */ if (funcdecl.parameters) { foreach (v; *funcdecl.parameters) { if (v.storage_class & (STC.ref_ | STC.out_ | STC.lazy_)) continue; if (v.needsScopeDtor()) { // same with ExpStatement.scopeCode() Statement s = new DtorExpStatement(Loc.initial, v.edtor, v); v.storage_class |= STC.nodtor; s = s.statementSemantic(sc2); bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess); const blockexit = s.blockExit(funcdecl, isnothrow); if (blockexit & BE.throw_) funcdecl.eh_none = false; if (f.isnothrow && isnothrow && blockexit & BE.throw_) error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars()); if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_) f.isnothrow = false; if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru) sbody = new CompoundStatement(Loc.initial, sbody, s); else sbody = new TryFinallyStatement(Loc.initial, sbody, s); } } } // from this point on all possible 'throwers' are checked funcdecl.flags &= ~FUNCFLAG.nothrowInprocess; if (funcdecl.isSynchronized()) { /* Wrap the entire function body in a synchronized statement */ ClassDeclaration cd = funcdecl.isThis() ? funcdecl.isThis().isClassDeclaration() : funcdecl.parent.isClassDeclaration(); if (cd) { if (!global.params.is64bit && global.params.isWindows && !funcdecl.isStatic() && !sbody.usesEH() && !global.params.trace) { /* The back end uses the "jmonitor" hack for syncing; * no need to do the sync at this level. */ } else { Expression vsync; if (funcdecl.isStatic()) { // The monitor is in the ClassInfo vsync = new DotIdExp(funcdecl.loc, resolve(funcdecl.loc, sc2, cd, false), Id.classinfo); } else { // 'this' is the monitor vsync = new VarExp(funcdecl.loc, funcdecl.vthis); } sbody = new PeelStatement(sbody); // don't redo semantic() sbody = new SynchronizedStatement(funcdecl.loc, vsync, sbody); sbody = sbody.statementSemantic(sc2); } } else { funcdecl.error("synchronized function `%s` must be a member of a class", funcdecl.toChars()); } } // If declaration has no body, don't set sbody to prevent incorrect codegen. if (funcdecl.fbody || funcdecl.allowsContractWithoutBody()) funcdecl.fbody = sbody; } // Fix up forward-referenced gotos if (funcdecl.gotos) { for (size_t i = 0; i < funcdecl.gotos.dim; ++i) { (*funcdecl.gotos)[i].checkLabel(); } } if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires)) funcdecl.error("naked assembly functions with contracts are not supported"); sc2.ctorflow.callSuper = CSX.none; sc2.pop(); } if (funcdecl.checkClosure()) { // We should be setting errors here instead of relying on the global error count. //errors = true; } /* If function survived being marked as impure, then it is pure */ if (funcdecl.flags & FUNCFLAG.purityInprocess) { funcdecl.flags &= ~FUNCFLAG.purityInprocess; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.purity = PURE.fwdref; } if (funcdecl.flags & FUNCFLAG.safetyInprocess) { funcdecl.flags &= ~FUNCFLAG.safetyInprocess; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.trust = TRUST.safe; } if (funcdecl.flags & FUNCFLAG.nogcInprocess) { funcdecl.flags &= ~FUNCFLAG.nogcInprocess; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.isnogc = true; } if (funcdecl.flags & FUNCFLAG.returnInprocess) { funcdecl.flags &= ~FUNCFLAG.returnInprocess; if (funcdecl.storage_class & STC.return_) { if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.isreturn = true; } } funcdecl.flags &= ~FUNCFLAG.inferScope; // Eliminate maybescope's { // Create and fill array[] with maybe candidates from the `this` and the parameters VarDeclaration[] array = void; VarDeclaration[10] tmp = void; size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0); if (dim <= tmp.length) array = tmp[0 .. dim]; else { auto ptr = cast(VarDeclaration*)mem.xmalloc(dim * VarDeclaration.sizeof); array = ptr[0 .. dim]; } size_t n = 0; if (funcdecl.vthis) array[n++] = funcdecl.vthis; if (funcdecl.parameters) { foreach (v; *funcdecl.parameters) { array[n++] = v; } } eliminateMaybeScopes(array[0 .. n]); if (dim > tmp.length) mem.xfree(array.ptr); } // Infer STC.scope_ if (funcdecl.parameters && !funcdecl.errors) { size_t nfparams = Parameter.dim(f.parameters); assert(nfparams == funcdecl.parameters.dim); foreach (u, v; *funcdecl.parameters) { if (v.storage_class & STC.maybescope) { //printf("Inferring scope for %s\n", v.toChars()); Parameter p = Parameter.getNth(f.parameters, u); notMaybeScope(v); v.storage_class |= STC.scope_ | STC.scopeinferred; p.storageClass |= STC.scope_ | STC.scopeinferred; assert(!(p.storageClass & STC.maybescope)); } } } if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope) { notMaybeScope(funcdecl.vthis); funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred; f.isscope = true; f.isscopeinferred = true; } // reset deco to apply inference result to mangled name if (f != funcdecl.type) f.deco = null; // Do semantic type AFTER pure/nothrow inference. if (!f.deco && funcdecl.ident != Id.xopEquals && funcdecl.ident != Id.xopCmp) { sc = sc.push(); if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665 sc.flags |= SCOPE.ctor; sc.stc = 0; sc.linkage = funcdecl.linkage; // https://issues.dlang.org/show_bug.cgi?id=8496 funcdecl.type = f.typeSemantic(funcdecl.loc, sc); sc = sc.pop(); } /* If this function had instantiated with gagging, error reproduction will be * done by TemplateInstance::semantic. * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. */ funcdecl.semanticRun = PASS.semantic3done; funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()); if (funcdecl.type.ty == Terror) funcdecl.errors = true; //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); //fflush(stdout); } override void visit(CtorDeclaration ctor) { //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars()); if (ctor.semanticRun >= PASS.semantic3) return; /* If any of the fields of the aggregate have a destructor, add * scope (failure) { this.fieldDtor(); } * as the first statement. It is not necessary to add it after * each initialization of a field, because destruction of .init constructed * structs should be benign. * https://issues.dlang.org/show_bug.cgi?id=14246 */ AggregateDeclaration ad = ctor.toParent2().isAggregateDeclaration(); if (ad && ad.fieldDtor && global.params.dtorFields) { /* Generate: * this.fieldDtor() */ Expression e = new ThisExp(ctor.loc); e.type = ad.type.mutableOf(); e = new DotVarExp(ctor.loc, e, ad.fieldDtor, false); e = new CallExp(ctor.loc, e); auto sexp = new ExpStatement(ctor.loc, e); auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc); version (all) { /* Generate: * try { ctor.fbody; } * catch (Exception __o) * { this.fieldDtor(); throw __o; } * This differs from the alternate scope(failure) version in that an Exception * is caught rather than a Throwable. This enables the optimization whereby * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only * applies to Exception.) */ Identifier id = Identifier.generateId("__o"); auto ts = new ThrowStatement(ctor.loc, new IdentifierExp(ctor.loc, id)); auto handler = new CompoundStatement(ctor.loc, ss, ts); auto catches = new Catches(); auto ctch = new Catch(ctor.loc, getException(), id, handler); catches.push(ctch); ctor.fbody = new TryCatchStatement(ctor.loc, ctor.fbody, catches); } else { /* Generate: * scope (failure) { this.fieldDtor(); } * Hopefully we can use this version someday when scope(failure) catches * Exception instead of Throwable. */ auto s = new OnScopeStatement(ctor.loc, TOK.onScopeFailure, ss); ctor.fbody = new CompoundStatement(ctor.loc, s, ctor.fbody); } } visit(cast(FuncDeclaration)ctor); } override void visit(Nspace ns) { if (ns.semanticRun >= PASS.semantic3) return; ns.semanticRun = PASS.semantic3; static if (LOG) { printf("Nspace::semantic3('%s')\n", ns.toChars()); } if (ns.members) { sc = sc.push(ns); sc.linkage = LINK.cpp; foreach (s; *ns.members) { s.semantic3(sc); } sc.pop(); } } override void visit(AttribDeclaration ad) { Dsymbols* d = ad.include(sc); if (d) { Scope* sc2 = ad.newScope(sc); for (size_t i = 0; i < d.dim; i++) { Dsymbol s = (*d)[i]; s.semantic3(sc2); } if (sc2 != sc) sc2.pop(); } } override void visit(AggregateDeclaration ad) { //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors); if (!ad.members) return; StructDeclaration sd = ad.isStructDeclaration(); if (!sc) // from runDeferredSemantic3 for TypeInfo generation { assert(sd); sd.semanticTypeInfoMembers(); return; } auto sc2 = ad.newScope(sc); for (size_t i = 0; i < ad.members.dim; i++) { Dsymbol s = (*ad.members)[i]; s.semantic3(sc2); } sc2.pop(); // don't do it for unused deprecated types // or error ypes if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != Diagnostic.error) && (ad.type && ad.type.ty != Terror)) { // Evaluate: RTinfo!type auto tiargs = new Objects(); tiargs.push(ad.type); auto ti = new TemplateInstance(ad.loc, Type.rtinfo, tiargs); Scope* sc3 = ti.tempdecl._scope.startCTFE(); sc3.tinst = sc.tinst; sc3.minst = sc.minst; if (ad.isDeprecated()) sc3.stc |= STC.deprecated_; ti.dsymbolSemantic(sc3); ti.semantic2(sc3); ti.semantic3(sc3); auto e = resolve(Loc.initial, sc3, ti.toAlias(), false); sc3.endCTFE(); e = e.ctfeInterpret(); ad.getRTInfo = e; } if (sd) sd.semanticTypeInfoMembers(); ad.semanticRun = PASS.semantic3done; } } private struct FuncDeclSem3 { // The FuncDeclaration subject to Semantic analysis FuncDeclaration funcdecl; // Scope of analysis Scope* sc; this(FuncDeclaration fd,Scope* s) { funcdecl = fd; sc = s; } /* Checks that the overriden functions (if any) have in contracts if * funcdecl has an in contract. */ void checkInContractOverrides() { if (funcdecl.frequires) { for (size_t i = 0; i < funcdecl.foverrides.dim; i++) { FuncDeclaration fdv = funcdecl.foverrides[i]; if (fdv.fbody && !fdv.frequires) { funcdecl.error("cannot have an in contract when overridden function `%s` does not have an in contract", fdv.toPrettyChars()); break; } } } } } ================================================ FILE: gcc/d/dmd/sideeffect.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/sideeffect.d, _sideeffect.d) * Documentation: https://dlang.org/phobos/dmd_sideeffect.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sideeffect.d */ module dmd.sideeffect; import dmd.apply; import dmd.declaration; import dmd.dscope; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.tokens; import dmd.visitor; /************************************************** * Front-end expression rewriting should create temporary variables for * non trivial sub-expressions in order to: * 1. save evaluation order * 2. prevent sharing of sub-expression in AST */ extern (C++) bool isTrivialExp(Expression e) { extern (C++) final class IsTrivialExp : StoppableVisitor { alias visit = typeof(super).visit; public: extern (D) this() { } override void visit(Expression e) { /* https://issues.dlang.org/show_bug.cgi?id=11201 * CallExp is always non trivial expression, * especially for inlining. */ if (e.op == TOK.call) { stop = true; return; } // stop walking if we determine this expression has side effects stop = lambdaHasSideEffect(e); } } scope IsTrivialExp v = new IsTrivialExp(); return walkPostorder(e, v) == false; } /******************************************** * Determine if Expression has any side effects. */ extern (C++) bool hasSideEffect(Expression e) { extern (C++) final class LambdaHasSideEffect : StoppableVisitor { alias visit = typeof(super).visit; public: extern (D) this() { } override void visit(Expression e) { // stop walking if we determine this expression has side effects stop = lambdaHasSideEffect(e); } } scope LambdaHasSideEffect v = new LambdaHasSideEffect(); return walkPostorder(e, v); } /******************************************** * Determine if the call of f, or function type or delegate type t1, has any side effects. * Returns: * 0 has any side effects * 1 nothrow + constant purity * 2 nothrow + strong purity */ int callSideEffectLevel(FuncDeclaration f) { /* https://issues.dlang.org/show_bug.cgi?id=12760 * ctor call always has side effects. */ if (f.isCtorDeclaration()) return 0; assert(f.type.ty == Tfunction); TypeFunction tf = cast(TypeFunction)f.type; if (tf.isnothrow) { PURE purity = f.isPure(); if (purity == PURE.strong) return 2; if (purity == PURE.const_) return 1; } return 0; } int callSideEffectLevel(Type t) { t = t.toBasetype(); TypeFunction tf; if (t.ty == Tdelegate) tf = cast(TypeFunction)(cast(TypeDelegate)t).next; else { assert(t.ty == Tfunction); tf = cast(TypeFunction)t; } if (!tf.isnothrow) // function can throw return 0; tf.purityLevel(); PURE purity = tf.purity; if (t.ty == Tdelegate && purity > PURE.weak) { if (tf.isMutable()) purity = PURE.weak; else if (!tf.isImmutable()) purity = PURE.const_; } if (purity == PURE.strong) return 2; if (purity == PURE.const_) return 1; return 0; } private bool lambdaHasSideEffect(Expression e) { switch (e.op) { // Sort the cases by most frequently used first case TOK.assign: case TOK.plusPlus: case TOK.minusMinus: case TOK.declaration: case TOK.construct: case TOK.blit: case TOK.addAssign: case TOK.minAssign: case TOK.concatenateAssign: case TOK.concatenateElemAssign: case TOK.concatenateDcharAssign: case TOK.mulAssign: case TOK.divAssign: case TOK.modAssign: case TOK.leftShiftAssign: case TOK.rightShiftAssign: case TOK.unsignedRightShiftAssign: case TOK.andAssign: case TOK.orAssign: case TOK.xorAssign: case TOK.powAssign: case TOK.in_: case TOK.remove: case TOK.assert_: case TOK.halt: case TOK.delete_: case TOK.new_: case TOK.newAnonymousClass: return true; case TOK.call: { CallExp ce = cast(CallExp)e; /* Calling a function or delegate that is pure nothrow * has no side effects. */ if (ce.e1.type) { Type t = ce.e1.type.toBasetype(); if (t.ty == Tdelegate) t = (cast(TypeDelegate)t).next; if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0) { } else return true; } break; } case TOK.cast_: { CastExp ce = cast(CastExp)e; /* if: * cast(classtype)func() // because it may throw */ if (ce.to.ty == Tclass && ce.e1.op == TOK.call && ce.e1.type.ty == Tclass) return true; break; } default: break; } return false; } /*********************************** * The result of this expression will be discarded. * Print error messages if the operation has no side effects (and hence is meaningless). * Returns: * true if expression has no side effects */ bool discardValue(Expression e) { if (lambdaHasSideEffect(e)) // check side-effect shallowly return false; switch (e.op) { case TOK.cast_: { CastExp ce = cast(CastExp)e; if (ce.to.equals(Type.tvoid)) { /* * Don't complain about an expression with no effect if it was cast to void */ return false; } break; // complain } case TOK.error: return false; case TOK.variable: { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && (v.storage_class & STC.temp)) { // https://issues.dlang.org/show_bug.cgi?id=5810 // Don't complain about an internal generated variable. return false; } break; } case TOK.call: /* Issue 3882: */ if (global.params.warnings != Diagnostic.off && !global.gag) { CallExp ce = cast(CallExp)e; if (e.type.ty == Tvoid) { /* Don't complain about calling void-returning functions with no side-effect, * because purity and nothrow are inferred, and because some of the * runtime library depends on it. Needs more investigation. * * One possible solution is to restrict this message to only be called in hierarchies that * never call assert (and or not called from inside unittest blocks) */ } else if (ce.e1.type) { Type t = ce.e1.type.toBasetype(); if (t.ty == Tdelegate) t = (cast(TypeDelegate)t).next; if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0) { const(char)* s; if (ce.f) s = ce.f.toPrettyChars(); else if (ce.e1.op == TOK.star) { // print 'fp' if ce.e1 is (*fp) s = (cast(PtrExp)ce.e1).e1.toChars(); } else s = ce.e1.toChars(); e.warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional", s, e.type.toChars()); } } } return false; case TOK.andAnd: case TOK.orOr: { LogicalExp aae = cast(LogicalExp)e; return discardValue(aae.e2); } case TOK.question: { CondExp ce = cast(CondExp)e; /* https://issues.dlang.org/show_bug.cgi?id=6178 * https://issues.dlang.org/show_bug.cgi?id=14089 * Either CondExp::e1 or e2 may have * redundant expression to make those types common. For example: * * struct S { this(int n); int v; alias v this; } * S[int] aa; * aa[1] = 0; * * The last assignment statement will be rewitten to: * * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value; * * The last DotVarExp is necessary to take assigned value. * * int value = (aa[1] = 0); // value = aa[1].value * * To avoid false error, discardValue() should be called only when * the both tops of e1 and e2 have actually no side effects. */ if (!lambdaHasSideEffect(ce.e1) && !lambdaHasSideEffect(ce.e2)) { return discardValue(ce.e1) | discardValue(ce.e2); } return false; } case TOK.comma: { CommaExp ce = cast(CommaExp)e; /* Check for compiler-generated code of the form auto __tmp, e, __tmp; * In such cases, only check e for side effect (it's OK for __tmp to have * no side effect). * See https://issues.dlang.org/show_bug.cgi?id=4231 for discussion */ auto fc = firstComma(ce); if (fc.op == TOK.declaration && ce.e2.op == TOK.variable && (cast(DeclarationExp)fc).declaration == (cast(VarExp)ce.e2).var) { return false; } // Don't check e1 until we cast(void) the a,b code generation //discardValue(ce.e1); return discardValue(ce.e2); } case TOK.tuple: /* Pass without complaint if any of the tuple elements have side effects. * Ideally any tuple elements with no side effects should raise an error, * this needs more investigation as to what is the right thing to do. */ if (!hasSideEffect(e)) break; return false; default: break; } e.error("`%s` has no effect", e.toChars()); return true; } /************************************************** * Build a temporary variable to copy the value of e into. * Params: * stc = storage classes will be added to the made temporary variable * name = name for temporary variable * e = original expression * Returns: * Newly created temporary variable. */ VarDeclaration copyToTemp(StorageClass stc, const char* name, Expression e) { assert(name[0] == '_' && name[1] == '_'); auto vd = new VarDeclaration(e.loc, e.type, Identifier.generateId(name), new ExpInitializer(e.loc, e)); vd.storage_class = stc | STC.temp | STC.ctfe; // temporary is always CTFEable return vd; } /************************************************** * Build a temporary variable to extract e's evaluation, if e is not trivial. * Params: * sc = scope * name = name for temporary variable * e0 = a new side effect part will be appended to it. * e = original expression * alwaysCopy = if true, build new temporary variable even if e is trivial. * Returns: * When e is trivial and alwaysCopy == false, e itself is returned. * Otherwise, a new VarExp is returned. * Note: * e's lvalue-ness will be handled well by STC.ref_ or STC.rvalue. */ Expression extractSideEffect(Scope* sc, const char* name, ref Expression e0, Expression e, bool alwaysCopy = false) { if (!alwaysCopy && isTrivialExp(e)) return e; auto vd = copyToTemp(0, name, e); vd.storage_class |= e.isLvalue() ? STC.ref_ : STC.rvalue; e0 = Expression.combine(e0, new DeclarationExp(vd.loc, vd) .expressionSemantic(sc)); return new VarExp(vd.loc, vd) .expressionSemantic(sc); } ================================================ FILE: gcc/d/dmd/statement.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/statement.d, _statement.d) * Documentation: https://dlang.org/phobos/dmd_statement.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d */ module dmd.statement; import core.stdc.stdarg; import core.stdc.stdio; import dmd.aggregate; import dmd.arraytypes; import dmd.attrib; import dmd.astcodegen; import dmd.gluelayer; import dmd.canthrow; import dmd.cond; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.dinterpret; import dmd.mtype; import dmd.parse; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.sapply; import dmd.sideeffect; import dmd.staticassert; import dmd.tokens; import dmd.visitor; /** * Returns: * `TypeIdentifier` corresponding to `object.Throwable` */ TypeIdentifier getThrowable() { auto tid = new TypeIdentifier(Loc.initial, Id.empty); tid.addIdent(Id.object); tid.addIdent(Id.Throwable); return tid; } /** * Returns: * TypeIdentifier corresponding to `object.Exception` */ TypeIdentifier getException() { auto tid = new TypeIdentifier(Loc.initial, Id.empty); tid.addIdent(Id.object); tid.addIdent(Id.Exception); return tid; } /*********************************************************** * Specification: http://dlang.org/spec/statement.html */ extern (C++) abstract class Statement : RootObject { Loc loc; override final DYNCAST dyncast() const { return DYNCAST.statement; } final extern (D) this(const ref Loc loc) { this.loc = loc; // If this is an in{} contract scope statement (skip for determining // inlineStatus of a function body for header content) } Statement syntaxCopy() { assert(0); } /************************************* * Do syntax copy of an array of Statement's. */ static Statements* arraySyntaxCopy(Statements* a) { Statements* b = null; if (a) { b = a.copy(); foreach (i, s; *a) { (*b)[i] = s ? s.syntaxCopy() : null; } } return b; } override final const(char)* toChars() { HdrGenState hgs; OutBuffer buf; .toCBuffer(this, &buf, &hgs); return buf.extractString(); } final void error(const(char)* format, ...) { va_list ap; va_start(ap, format); .verror(loc, format, ap); va_end(ap); } final void warning(const(char)* format, ...) { va_list ap; va_start(ap, format); .vwarning(loc, format, ap); va_end(ap); } final void deprecation(const(char)* format, ...) { va_list ap; va_start(ap, format); .vdeprecation(loc, format, ap); va_end(ap); } Statement getRelatedLabeled() { return this; } /**************************** * Determine if an enclosed `break` would apply to this * statement, such as if it is a loop or switch statement. * Returns: * `true` if it does */ bool hasBreak() { //printf("Statement::hasBreak()\n"); return false; } /**************************** * Determine if an enclosed `continue` would apply to this * statement, such as if it is a loop statement. * Returns: * `true` if it does */ bool hasContinue() { return false; } /********************************** * Returns: * `true` if statement uses exception handling */ final bool usesEH() { extern (C++) final class UsesEH : StoppableVisitor { alias visit = typeof(super).visit; public: override void visit(Statement s) { } override void visit(TryCatchStatement s) { stop = true; } override void visit(TryFinallyStatement s) { stop = true; } override void visit(OnScopeStatement s) { stop = true; } override void visit(SynchronizedStatement s) { stop = true; } } scope UsesEH ueh = new UsesEH(); return walkPostorder(this, ueh); } /********************************** * Returns: * `true` if statement 'comes from' somewhere else, like a goto */ final bool comeFrom() { extern (C++) final class ComeFrom : StoppableVisitor { alias visit = typeof(super).visit; public: override void visit(Statement s) { } override void visit(CaseStatement s) { stop = true; } override void visit(DefaultStatement s) { stop = true; } override void visit(LabelStatement s) { stop = true; } override void visit(AsmStatement s) { stop = true; } } scope ComeFrom cf = new ComeFrom(); return walkPostorder(this, cf); } /********************************** * Returns: * `true` if statement has executable code. */ final bool hasCode() { extern (C++) final class HasCode : StoppableVisitor { alias visit = typeof(super).visit; public: override void visit(Statement s) { stop = true; } override void visit(ExpStatement s) { if (s.exp !is null) { stop = s.exp.hasCode(); } } override void visit(CompoundStatement s) { } override void visit(ScopeStatement s) { } override void visit(ImportStatement s) { } } scope HasCode hc = new HasCode(); return walkPostorder(this, hc); } /**************************************** * If this statement has code that needs to run in a finally clause * at the end of the current scope, return that code in the form of * a Statement. * Params: * sc = context * sentry = set to code executed upon entry to the scope * sexception = set to code executed upon exit from the scope via exception * sfinally = set to code executed in finally block * Returns: * code to be run in the finally clause */ Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) { //printf("Statement::scopeCode()\n"); *sentry = null; *sexception = null; *sfinally = null; return this; } /********************************* * Flatten out the scope by presenting the statement * as an array of statements. * Params: * sc = context * Returns: * The array of `Statements`, or `null` if no flattening necessary */ Statements* flatten(Scope* sc) { return null; } /******************************* * Find last statement in a sequence of statements. * Returns: * the last statement, or `null` if there isn't one */ inout(Statement) last() inout nothrow pure { return this; } /******************** * A cheaper method of doing downcasting of Statements. * Returns: * the downcast statement if it can be downcasted, otherwise `null` */ ErrorStatement isErrorStatement() { return null; } /// ditto inout(ScopeStatement) isScopeStatement() inout nothrow pure { return null; } /// ditto ExpStatement isExpStatement() { return null; } /// ditto inout(CompoundStatement) isCompoundStatement() inout nothrow pure { return null; } /// ditto inout(ReturnStatement) isReturnStatement() inout nothrow pure { return null; } /// ditto IfStatement isIfStatement() { return null; } /// ditto CaseStatement isCaseStatement() { return null; } /// ditto DefaultStatement isDefaultStatement() { return null; } /// ditto LabelStatement isLabelStatement() { return null; } /// ditto GotoDefaultStatement isGotoDefaultStatement() pure { return null; } /// ditto GotoCaseStatement isGotoCaseStatement() pure { return null; } /// ditto inout(BreakStatement) isBreakStatement() inout nothrow pure { return null; } /// ditto DtorExpStatement isDtorExpStatement() { return null; } /// ditto ForwardingStatement isForwardingStatement() { return null; } /************************** * Support Visitor Pattern * Params: * v = visitor */ void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Any Statement that fails semantic() or has a component that is an ErrorExp or * a TypeError should return an ErrorStatement from semantic(). */ extern (C++) final class ErrorStatement : Statement { extern (D) this() { super(Loc.initial); assert(global.gaggedErrors || global.errors); } override Statement syntaxCopy() { return this; } override ErrorStatement isErrorStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PeelStatement : Statement { Statement s; extern (D) this(Statement s) { super(s.loc); this.s = s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Convert TemplateMixin members (== Dsymbols) to Statements. */ private Statement toStatement(Dsymbol s) { extern (C++) final class ToStmt : Visitor { alias visit = Visitor.visit; public: Statement result; Statement visitMembers(Loc loc, Dsymbols* a) { if (!a) return null; auto statements = new Statements(); foreach (s; *a) { statements.push(toStatement(s)); } return new CompoundStatement(loc, statements); } override void visit(Dsymbol s) { .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); result = new ErrorStatement(); } override void visit(TemplateMixin tm) { auto a = new Statements(); foreach (m; *tm.members) { Statement s = toStatement(m); if (s) a.push(s); } result = new CompoundStatement(tm.loc, a); } /* An actual declaration symbol will be converted to DeclarationExp * with ExpStatement. */ Statement declStmt(Dsymbol s) { auto de = new DeclarationExp(s.loc, s); de.type = Type.tvoid; // avoid repeated semantic return new ExpStatement(s.loc, de); } override void visit(VarDeclaration d) { result = declStmt(d); } override void visit(AggregateDeclaration d) { result = declStmt(d); } override void visit(FuncDeclaration d) { result = declStmt(d); } override void visit(EnumDeclaration d) { result = declStmt(d); } override void visit(AliasDeclaration d) { result = declStmt(d); } override void visit(TemplateDeclaration d) { result = declStmt(d); } /* All attributes have been already picked by the semantic analysis of * 'bottom' declarations (function, struct, class, etc). * So we don't have to copy them. */ override void visit(StorageClassDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(DeprecatedDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(LinkDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(ProtDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(AlignDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(UserAttributeDeclaration d) { result = visitMembers(d.loc, d.decl); } override void visit(StaticAssert s) { } override void visit(Import s) { } override void visit(PragmaDeclaration d) { } override void visit(ConditionalDeclaration d) { result = visitMembers(d.loc, d.include(null)); } override void visit(StaticForeachDeclaration d) { assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe); (d.sfe.aggrfe ? d.sfe.aggrfe._body : d.sfe.rangefe._body) = visitMembers(d.loc, d.decl); result = new StaticForeachStatement(d.loc, d.sfe); } override void visit(CompileDeclaration d) { result = visitMembers(d.loc, d.include(null)); } } if (!s) return null; scope ToStmt v = new ToStmt(); s.accept(v); return v.result; } /*********************************************************** */ extern (C++) class ExpStatement : Statement { Expression exp; final extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } final extern (D) this(const ref Loc loc, Dsymbol declaration) { super(loc); this.exp = new DeclarationExp(loc, declaration); } static ExpStatement create(Loc loc, Expression exp) { return new ExpStatement(loc, exp); } override Statement syntaxCopy() { return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); } override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) { //printf("ExpStatement::scopeCode()\n"); *sentry = null; *sexception = null; *sfinally = null; if (exp && exp.op == TOK.declaration) { auto de = cast(DeclarationExp)exp; auto v = de.declaration.isVarDeclaration(); if (v && !v.isDataseg()) { if (v.needsScopeDtor()) { *sfinally = new DtorExpStatement(loc, v.edtor, v); v.storage_class |= STC.nodtor; // don't add in dtor again } } } return this; } override final Statements* flatten(Scope* sc) { /* https://issues.dlang.org/show_bug.cgi?id=14243 * expand template mixin in statement scope * to handle variable destructors. */ if (exp && exp.op == TOK.declaration) { Dsymbol d = (cast(DeclarationExp)exp).declaration; if (TemplateMixin tm = d.isTemplateMixin()) { Expression e = exp.expressionSemantic(sc); if (e.op == TOK.error || tm.errors) { auto a = new Statements(); a.push(new ErrorStatement()); return a; } assert(tm.members); Statement s = toStatement(tm); version (none) { OutBuffer buf; buf.doindent = 1; HdrGenState hgs; hgs.hdrgen = true; toCBuffer(s, &buf, &hgs); printf("tm ==> s = %s\n", buf.peekString()); } auto a = new Statements(); a.push(s); return a; } } return null; } override final ExpStatement isExpStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DtorExpStatement : ExpStatement { // Wraps an expression that is the destruction of 'var' VarDeclaration var; extern (D) this(const ref Loc loc, Expression exp, VarDeclaration v) { super(loc, exp); this.var = v; } override Statement syntaxCopy() { return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); } override void accept(Visitor v) { v.visit(this); } override DtorExpStatement isDtorExpStatement() { return this; } } /*********************************************************** * https://dlang.org/spec/statement.html#mixin-statement */ extern (C++) final class CompileStatement : Statement { Expressions* exps; extern (D) this(const ref Loc loc, Expression exp) { Expressions* exps = new Expressions(); exps.push(exp); this(loc, exps); } extern (D) this(const ref Loc loc, Expressions* exps) { super(loc); this.exps = exps; } override Statement syntaxCopy() { return new CompileStatement(loc, Expression.arraySyntaxCopy(exps)); } private Statements* compileIt(Scope* sc) { //printf("CompileStatement::compileIt() %s\n", exp.toChars()); auto errorStatements() { auto a = new Statements(); a.push(new ErrorStatement()); return a; } OutBuffer buf; if (exps) { foreach (ex; *exps) { sc = sc.startCTFE(); auto e = ex.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); // allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); if (e.op == TOK.error) { //errorSupplemental(exp.loc, "while evaluating `mixin(%s)`", ex.toChars()); return errorStatements(); } StringExp se = e.toStringExp(); if (se) { se = se.toUTF8(sc); buf.printf("%.*s", cast(int)se.len, se.string); } else buf.printf("%s", e.toChars()); } } const errors = global.errors; const len = buf.offset; const str = buf.extractString()[0 .. len]; scope p = new Parser!ASTCodegen(loc, sc._module, str, false); p.nextToken(); auto a = new Statements(); while (p.token.value != TOK.endOfFile) { Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); if (!s || p.errors) { assert(!p.errors || global.errors != errors); // make sure we caught all the cases return errorStatements(); } a.push(s); } return a; } override Statements* flatten(Scope* sc) { //printf("CompileStatement::flatten() %s\n", exp.toChars()); return compileIt(sc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class CompoundStatement : Statement { Statements* statements; /** * Construct a `CompoundStatement` using an already existing * array of `Statement`s * * Params: * loc = Instantiation information * s = An array of `Statement`s, that will referenced by this class */ final extern (D) this(const ref Loc loc, Statements* s) { super(loc); statements = s; } /** * Construct a `CompoundStatement` from an array of `Statement`s * * Params: * loc = Instantiation information * sts = A variadic array of `Statement`s, that will copied in this class * The entries themselves will not be copied. */ final extern (D) this(const ref Loc loc, Statement[] sts...) { super(loc); statements = new Statements(); statements.reserve(sts.length); foreach (s; sts) statements.push(s); } static CompoundStatement create(Loc loc, Statement s1, Statement s2) { return new CompoundStatement(loc, s1, s2); } override Statement syntaxCopy() { return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements)); } override Statements* flatten(Scope* sc) { return statements; } override final inout(ReturnStatement) isReturnStatement() inout nothrow pure { ReturnStatement rs = null; foreach (s; *statements) { if (s) { rs = cast(ReturnStatement)s.isReturnStatement(); if (rs) break; } } return cast(inout)rs; } override final inout(Statement) last() inout nothrow pure { Statement s = null; for (size_t i = statements.dim; i; --i) { s = cast(Statement)(*statements)[i - 1]; if (s) { s = cast(Statement)s.last(); if (s) break; } } return cast(inout)s; } override final inout(CompoundStatement) isCompoundStatement() inout nothrow pure { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CompoundDeclarationStatement : CompoundStatement { extern (D) this(const ref Loc loc, Statements* s) { super(loc, s); statements = s; } override Statement syntaxCopy() { auto a = new Statements(statements.dim); foreach (i, s; *statements) { (*a)[i] = s ? s.syntaxCopy() : null; } return new CompoundDeclarationStatement(loc, a); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * The purpose of this is so that continue will go to the next * of the statements, and break will go to the end of the statements. */ extern (C++) final class UnrolledLoopStatement : Statement { Statements* statements; extern (D) this(const ref Loc loc, Statements* s) { super(loc); statements = s; } override Statement syntaxCopy() { auto a = new Statements(statements.dim); foreach (i, s; *statements) { (*a)[i] = s ? s.syntaxCopy() : null; } return new UnrolledLoopStatement(loc, a); } override bool hasBreak() { return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class ScopeStatement : Statement { Statement statement; Loc endloc; // location of closing curly bracket extern (D) this(const ref Loc loc, Statement s, Loc endloc) { super(loc); this.statement = s; this.endloc = endloc; } override Statement syntaxCopy() { return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); } override inout(ScopeStatement) isScopeStatement() inout nothrow pure { return this; } override inout(ReturnStatement) isReturnStatement() inout nothrow pure { if (statement) return statement.isReturnStatement(); return null; } override bool hasBreak() { //printf("ScopeStatement::hasBreak() %s\n", toChars()); return statement ? statement.hasBreak() : false; } override bool hasContinue() { return statement ? statement.hasContinue() : false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Statement whose symbol table contains foreach index variables in a * local scope and forwards other members to the parent scope. This * wraps a statement. * * Also see: `dmd.attrib.ForwardingAttribDeclaration` */ extern (C++) final class ForwardingStatement : Statement { /// The symbol containing the `static foreach` variables. ForwardingScopeDsymbol sym = null; /// The wrapped statement. Statement statement; extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement s) { super(loc); this.sym = sym; assert(s); statement = s; } extern (D) this(const ref Loc loc, Statement s) { auto sym = new ForwardingScopeDsymbol(null); sym.symtab = new DsymbolTable(); this(loc, sym, s); } override Statement syntaxCopy() { return new ForwardingStatement(loc, statement.syntaxCopy()); } /*********************** * ForwardingStatements are distributed over the flattened * sequence of statements. This prevents flattening to be * "blocked" by a ForwardingStatement and is necessary, for * example, to support generating scope guards with `static * foreach`: * * static foreach(i; 0 .. 10) scope(exit) writeln(i); * writeln("this is printed first"); * // then, it prints 10, 9, 8, 7, ... */ override Statements* flatten(Scope* sc) { if (!statement) { return null; } sc = sc.push(sym); auto a = statement.flatten(sc); sc = sc.pop(); if (!a) { return a; } auto b = new Statements(a.dim); foreach (i, s; *a) { (*b)[i] = s ? new ForwardingStatement(s.loc, sym, s) : null; } return b; } override ForwardingStatement isForwardingStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class WhileStatement : Statement { Expression condition; Statement _body; Loc endloc; // location of closing curly bracket extern (D) this(const ref Loc loc, Expression c, Statement b, Loc endloc) { super(loc); condition = c; _body = b; this.endloc = endloc; } override Statement syntaxCopy() { return new WhileStatement(loc, condition.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); } override bool hasBreak() { return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DoStatement : Statement { Statement _body; Expression condition; Loc endloc; // location of ';' after while extern (D) this(const ref Loc loc, Statement b, Expression c, Loc endloc) { super(loc); _body = b; condition = c; this.endloc = endloc; } override Statement syntaxCopy() { return new DoStatement(loc, _body ? _body.syntaxCopy() : null, condition.syntaxCopy(), endloc); } override bool hasBreak() { return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ForStatement : Statement { Statement _init; Expression condition; Expression increment; Statement _body; Loc endloc; // location of closing curly bracket // When wrapped in try/finally clauses, this points to the outermost one, // which may have an associated label. Internal break/continue statements // treat that label as referring to this loop. Statement relatedLabeled; extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) { super(loc); this._init = _init; this.condition = condition; this.increment = increment; this._body = _body; this.endloc = endloc; } override Statement syntaxCopy() { return new ForStatement(loc, _init ? _init.syntaxCopy() : null, condition ? condition.syntaxCopy() : null, increment ? increment.syntaxCopy() : null, _body.syntaxCopy(), endloc); } override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) { //printf("ForStatement::scopeCode()\n"); Statement.scopeCode(sc, sentry, sexception, sfinally); return this; } override Statement getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; } override bool hasBreak() { //printf("ForStatement::hasBreak()\n"); return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * https://dlang.org/spec/statement.html#foreach-statement */ extern (C++) final class ForeachStatement : Statement { TOK op; // TOK.foreach_ or TOK.foreach_reverse_ Parameters* parameters; // array of Parameters, one for each ForeachType Expression aggr; // ForeachAggregate Statement _body; // NoScopeNonEmptyStatement Loc endloc; // location of closing curly bracket VarDeclaration key; VarDeclaration value; FuncDeclaration func; // function we're lexically in Statements* cases; // put breaks, continues, gotos and returns here ScopeStatements* gotos; // forward referenced goto's go here extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) { super(loc); this.op = op; this.parameters = parameters; this.aggr = aggr; this._body = _body; this.endloc = endloc; } override Statement syntaxCopy() { return new ForeachStatement(loc, op, Parameter.arraySyntaxCopy(parameters), aggr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); } override bool hasBreak() { return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ForeachRangeStatement : Statement { TOK op; // TOK.foreach_ or TOK.foreach_reverse_ Parameter prm; // loop index variable Expression lwr; Expression upr; Statement _body; Loc endloc; // location of closing curly bracket VarDeclaration key; extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) { super(loc); this.op = op; this.prm = prm; this.lwr = lwr; this.upr = upr; this._body = _body; this.endloc = endloc; } override Statement syntaxCopy() { return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); } override bool hasBreak() { return true; } override bool hasContinue() { return true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class IfStatement : Statement { Parameter prm; Expression condition; Statement ifbody; Statement elsebody; VarDeclaration match; // for MatchExpression results Loc endloc; // location of closing curly bracket extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) { super(loc); this.prm = prm; this.condition = condition; this.ifbody = ifbody; this.elsebody = elsebody; this.endloc = endloc; } override Statement syntaxCopy() { return new IfStatement(loc, prm ? prm.syntaxCopy() : null, condition.syntaxCopy(), ifbody ? ifbody.syntaxCopy() : null, elsebody ? elsebody.syntaxCopy() : null, endloc); } override IfStatement isIfStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ConditionalStatement : Statement { Condition condition; Statement ifbody; Statement elsebody; extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) { super(loc); this.condition = condition; this.ifbody = ifbody; this.elsebody = elsebody; } override Statement syntaxCopy() { return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); } override Statements* flatten(Scope* sc) { Statement s; //printf("ConditionalStatement::flatten()\n"); if (condition.include(sc)) { DebugCondition dc = condition.isDebugCondition(); if (dc) s = new DebugStatement(loc, ifbody); else s = ifbody; } else s = elsebody; auto a = new Statements(); a.push(s); return a; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * Static foreach statements, like: * void main() * { * static foreach(i; 0 .. 10) * { * pragma(msg, i); * } * } */ extern (C++) final class StaticForeachStatement : Statement { StaticForeach sfe; extern (D) this(const ref Loc loc, StaticForeach sfe) { super(loc); this.sfe = sfe; } override Statement syntaxCopy() { return new StaticForeachStatement(loc,sfe.syntaxCopy()); } override Statements* flatten(Scope* sc) { sfe.prepare(sc); if (sfe.ready()) { import dmd.statementsem; auto s = makeTupleForeach!(true,false)(sc, sfe.aggrfe,sfe.needExpansion); auto result = s.flatten(sc); if (result) { return result; } result = new Statements(); result.push(s); return result; } else { auto result = new Statements(); result.push(new ErrorStatement()); return result; } } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class PragmaStatement : Statement { Identifier ident; Expressions* args; // array of Expression's Statement _body; extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Statement _body) { super(loc); this.ident = ident; this.args = args; this._body = _body; } override Statement syntaxCopy() { return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class StaticAssertStatement : Statement { StaticAssert sa; extern (D) this(StaticAssert sa) { super(sa.loc); this.sa = sa; } override Statement syntaxCopy() { return new StaticAssertStatement(cast(StaticAssert)sa.syntaxCopy(null)); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class SwitchStatement : Statement { Expression condition; /// switch(condition) Statement _body; /// bool isFinal; /// DefaultStatement sdefault; /// default: TryFinallyStatement tf; /// GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's CaseStatements* cases; /// array of CaseStatement's int hasNoDefault; /// !=0 if no default statement int hasVars; /// !=0 if has variable case values VarDeclaration lastVar; /// last observed variable declaration in this statement extern (D) this(const ref Loc loc, Expression c, Statement b, bool isFinal) { super(loc); this.condition = c; this._body = b; this.isFinal = isFinal; } override Statement syntaxCopy() { return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal); } override bool hasBreak() { return true; } /************************************ * Returns: * true if error */ extern (D) bool checkLabel() { /* * Checks the scope of a label for existing variable declaration. * Params: * vd = last variable declared before this case/default label * Returns: `true` if the variables declared in this label would be skipped. */ bool checkVar(VarDeclaration vd) { for (auto v = vd; v && v != lastVar; v = v.lastVar) { if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp)) || v._init.isVoidInitializer()) continue; if (vd.ident == Id.withSym) error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars()); else error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars()); return true; } return false; } enum error = true; if (sdefault && checkVar(sdefault.lastVar)) return !error; // return error once fully deprecated foreach (scase; *cases) { if (scase && checkVar(scase.lastVar)) return !error; // return error once fully deprecated } return !error; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CaseStatement : Statement { Expression exp; Statement statement; int index; // which case it is (since we sort this) VarDeclaration lastVar; extern (D) this(const ref Loc loc, Expression exp, Statement s) { super(loc); this.exp = exp; this.statement = s; } override Statement syntaxCopy() { return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); } override int compare(RootObject obj) { // Sort cases so we can do an efficient lookup CaseStatement cs2 = cast(CaseStatement)obj; return exp.compare(cs2.exp); } override CaseStatement isCaseStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class CaseRangeStatement : Statement { Expression first; Expression last; Statement statement; extern (D) this(const ref Loc loc, Expression first, Expression last, Statement s) { super(loc); this.first = first; this.last = last; this.statement = s; } override Statement syntaxCopy() { return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DefaultStatement : Statement { Statement statement; VarDeclaration lastVar; extern (D) this(const ref Loc loc, Statement s) { super(loc); this.statement = s; } override Statement syntaxCopy() { return new DefaultStatement(loc, statement.syntaxCopy()); } override DefaultStatement isDefaultStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class GotoDefaultStatement : Statement { SwitchStatement sw; extern (D) this(const ref Loc loc) { super(loc); } override Statement syntaxCopy() { return new GotoDefaultStatement(loc); } override GotoDefaultStatement isGotoDefaultStatement() pure { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class GotoCaseStatement : Statement { Expression exp; // null, or which case to goto CaseStatement cs; // case statement it resolves to extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } override Statement syntaxCopy() { return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); } override GotoCaseStatement isGotoCaseStatement() pure { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class SwitchErrorStatement : Statement { Expression exp; extern (D) this(const ref Loc loc) { super(loc); } final extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ReturnStatement : Statement { Expression exp; size_t caseDim; extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } override Statement syntaxCopy() { return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); } override inout(ReturnStatement) isReturnStatement() inout nothrow pure { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class BreakStatement : Statement { Identifier ident; extern (D) this(const ref Loc loc, Identifier ident) { super(loc); this.ident = ident; } override Statement syntaxCopy() { return new BreakStatement(loc, ident); } override inout(BreakStatement) isBreakStatement() inout nothrow pure { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ContinueStatement : Statement { Identifier ident; extern (D) this(const ref Loc loc, Identifier ident) { super(loc); this.ident = ident; } override Statement syntaxCopy() { return new ContinueStatement(loc, ident); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class SynchronizedStatement : Statement { Expression exp; Statement _body; extern (D) this(const ref Loc loc, Expression exp, Statement _body) { super(loc); this.exp = exp; this._body = _body; } override Statement syntaxCopy() { return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); } override bool hasBreak() { return false; //true; } override bool hasContinue() { return false; //true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class WithStatement : Statement { Expression exp; Statement _body; VarDeclaration wthis; Loc endloc; extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc) { super(loc); this.exp = exp; this._body = _body; this.endloc = endloc; } override Statement syntaxCopy() { return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class TryCatchStatement : Statement { Statement _body; Catches* catches; extern (D) this(const ref Loc loc, Statement _body, Catches* catches) { super(loc); this._body = _body; this.catches = catches; } override Statement syntaxCopy() { auto a = new Catches(catches.dim); foreach (i, c; *catches) { (*a)[i] = c.syntaxCopy(); } return new TryCatchStatement(loc, _body.syntaxCopy(), a); } override bool hasBreak() { return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class Catch : RootObject { Loc loc; Type type; Identifier ident; VarDeclaration var; Statement handler; bool errors; // set if semantic processing errors // was generated by the compiler, wasn't present in source code bool internalCatch; extern (D) this(const ref Loc loc, Type t, Identifier id, Statement handler) { //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); this.loc = loc; this.type = t; this.ident = id; this.handler = handler; } Catch syntaxCopy() { auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); c.internalCatch = internalCatch; return c; } } /*********************************************************** */ extern (C++) final class TryFinallyStatement : Statement { Statement _body; Statement finalbody; bool bodyFallsThru; // true if _body falls through to finally extern (D) this(const ref Loc loc, Statement _body, Statement finalbody) { super(loc); this._body = _body; this.finalbody = finalbody; this.bodyFallsThru = true; // assume true until statementSemantic() } static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody) { return new TryFinallyStatement(loc, _body, finalbody); } override Statement syntaxCopy() { return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); } override bool hasBreak() { return false; //true; } override bool hasContinue() { return false; //true; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class OnScopeStatement : Statement { TOK tok; Statement statement; extern (D) this(const ref Loc loc, TOK tok, Statement statement) { super(loc); this.tok = tok; this.statement = statement; } override Statement syntaxCopy() { return new OnScopeStatement(loc, tok, statement.syntaxCopy()); } override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) { //printf("OnScopeStatement::scopeCode()\n"); *sentry = null; *sexception = null; *sfinally = null; Statement s = new PeelStatement(statement); switch (tok) { case TOK.onScopeExit: *sfinally = s; break; case TOK.onScopeFailure: *sexception = s; break; case TOK.onScopeSuccess: { /* Create: * sentry: bool x = false; * sexception: x = true; * sfinally: if (!x) statement; */ auto v = copyToTemp(0, "__os", new IntegerExp(Loc.initial, 0, Type.tbool)); v.dsymbolSemantic(sc); *sentry = new ExpStatement(loc, v); Expression e = new IntegerExp(Loc.initial, 1, Type.tbool); e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e); *sexception = new ExpStatement(Loc.initial, e); e = new VarExp(Loc.initial, v); e = new NotExp(Loc.initial, e); *sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial); break; } default: assert(0); } return null; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ThrowStatement : Statement { Expression exp; // was generated by the compiler, wasn't present in source code bool internalThrow; extern (D) this(const ref Loc loc, Expression exp) { super(loc); this.exp = exp; } override Statement syntaxCopy() { auto s = new ThrowStatement(loc, exp.syntaxCopy()); s.internalThrow = internalThrow; return s; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class DebugStatement : Statement { Statement statement; extern (D) this(const ref Loc loc, Statement statement) { super(loc); this.statement = statement; } override Statement syntaxCopy() { return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); } override Statements* flatten(Scope* sc) { Statements* a = statement ? statement.flatten(sc) : null; if (a) { foreach (ref s; *a) { s = new DebugStatement(loc, s); } } return a; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class GotoStatement : Statement { Identifier ident; LabelDsymbol label; TryFinallyStatement tf; OnScopeStatement os; VarDeclaration lastVar; extern (D) this(const ref Loc loc, Identifier ident) { super(loc); this.ident = ident; } override Statement syntaxCopy() { return new GotoStatement(loc, ident); } extern (D) bool checkLabel() { if (!label.statement) { error("label `%s` is undefined", label.toChars()); return true; } if (label.statement.os != os) { if (os && os.tok == TOK.onScopeFailure && !label.statement.os) { // Jump out from scope(failure) block is allowed. } else { if (label.statement.os) error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); else error("cannot `goto` out of `%s` block", Token.toChars(os.tok)); return true; } } if (label.statement.tf != tf) { error("cannot `goto` in or out of `finally` block"); return true; } VarDeclaration vd = label.statement.lastVar; if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest)) return false; VarDeclaration last = lastVar; while (last && last != vd) last = last.lastVar; if (last == vd) { // All good, the label's scope has no variables } else if (vd.storage_class & STC.exptemp) { // Lifetime ends at end of expression, so no issue with skipping the statement } else if (vd.ident == Id.withSym) { error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars()); return true; } else { error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars()); return true; } return false; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class LabelStatement : Statement { Identifier ident; Statement statement; TryFinallyStatement tf; OnScopeStatement os; VarDeclaration lastVar; Statement gotoTarget; // interpret bool breaks; // someone did a 'break ident' extern (D) this(const ref Loc loc, Identifier ident, Statement statement) { super(loc); this.ident = ident; this.statement = statement; } override Statement syntaxCopy() { return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); } override Statements* flatten(Scope* sc) { Statements* a = null; if (statement) { a = statement.flatten(sc); if (a) { if (!a.dim) { a.push(new ExpStatement(loc, cast(Expression)null)); } // reuse 'this' LabelStatement this.statement = (*a)[0]; (*a)[0] = this; } } return a; } override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexit, Statement* sfinally) { //printf("LabelStatement::scopeCode()\n"); if (statement) statement = statement.scopeCode(sc, sentry, sexit, sfinally); else { *sentry = null; *sexit = null; *sfinally = null; } return this; } override LabelStatement isLabelStatement() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class LabelDsymbol : Dsymbol { LabelStatement statement; extern (D) this(Identifier ident) { super(ident); } static LabelDsymbol create(Identifier ident) { return new LabelDsymbol(ident); } // is this a LabelDsymbol()? override LabelDsymbol isLabel() { return this; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) class AsmStatement : Statement { Token* tokens; extern (D) this(const ref Loc loc, Token* tokens) { super(loc); this.tokens = tokens; } override Statement syntaxCopy() { return new AsmStatement(loc, tokens); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * https://dlang.org/spec/iasm.html */ extern (C++) final class InlineAsmStatement : AsmStatement { code* asmcode; uint asmalign; // alignment of this statement uint regs; // mask of registers modified (must match regm_t in back end) bool refparam; // true if function parameter is referenced bool naked; // true if function is to be naked extern (D) this(const ref Loc loc, Token* tokens) { super(loc, tokens); } override Statement syntaxCopy() { return new InlineAsmStatement(loc, tokens); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html * Assembler instructions with D expression operands. */ extern (C++) final class GccAsmStatement : AsmStatement { StorageClass stc; // attributes of the asm {} block Expression insn; // string expression that is the template for assembler code Expressions* args; // input and output operands of the statement uint outputargs; // of the operands in 'args', the number of output operands Identifiers* names; // list of symbolic names for the operands Expressions* constraints; // list of string constants specifying constraints on operands Expressions* clobbers; // list of string constants specifying clobbers and scratch registers Identifiers* labels; // list of goto labels GotoStatements* gotos; // of the goto labels, the equivalent statements they represent extern (D) this(const ref Loc loc, Token* tokens) { super(loc, tokens); } override Statement syntaxCopy() { return new GccAsmStatement(loc, tokens); } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** * a complete asm {} block */ extern (C++) final class CompoundAsmStatement : CompoundStatement { StorageClass stc; // postfix attributes like nothrow/pure/@trusted extern (D) this(const ref Loc loc, Statements* s, StorageClass stc) { super(loc, s); this.stc = stc; } override CompoundAsmStatement syntaxCopy() { auto a = new Statements(statements.dim); foreach (i, s; *statements) { (*a)[i] = s ? s.syntaxCopy() : null; } return new CompoundAsmStatement(loc, a, stc); } override Statements* flatten(Scope* sc) { return null; } override void accept(Visitor v) { v.visit(this); } } /*********************************************************** */ extern (C++) final class ImportStatement : Statement { Dsymbols* imports; // Array of Import's extern (D) this(const ref Loc loc, Dsymbols* imports) { super(loc); this.imports = imports; } override Statement syntaxCopy() { auto m = new Dsymbols(imports.dim); foreach (i, s; *imports) { (*m)[i] = s.syntaxCopy(null); } return new ImportStatement(loc, m); } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/statement.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/statement.h */ #pragma once #include "arraytypes.h" #include "dsymbol.h" #include "visitor.h" #include "tokens.h" struct Scope; class Expression; class LabelDsymbol; class Identifier; class IfStatement; class ExpStatement; class DefaultStatement; class VarDeclaration; class Condition; class ErrorStatement; class ReturnStatement; class CompoundStatement; class Parameter; class StaticAssert; class AsmStatement; class GotoStatement; class ScopeStatement; class TryCatchStatement; class TryFinallyStatement; class CaseStatement; class DefaultStatement; class LabelStatement; class StaticForeach; // Back end struct code; bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply); bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply); /* How a statement exits; this is returned by blockExit() */ enum BE { BEnone = 0, BEfallthru = 1, BEthrow = 2, BEreturn = 4, BEgoto = 8, BEhalt = 0x10, BEbreak = 0x20, BEcontinue = 0x40, BEerrthrow = 0x80, BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt) }; class Statement : public RootObject { public: Loc loc; virtual Statement *syntaxCopy(); const char *toChars(); void error(const char *format, ...); void warning(const char *format, ...); void deprecation(const char *format, ...); virtual Statement *getRelatedLabeled() { return this; } virtual bool hasBreak(); virtual bool hasContinue(); bool usesEH(); bool comeFrom(); bool hasCode(); virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); virtual Statements *flatten(Scope *sc); virtual Statement *last(); // Avoid dynamic_cast virtual ErrorStatement *isErrorStatement() { return NULL; } virtual ScopeStatement *isScopeStatement() { return NULL; } virtual ExpStatement *isExpStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } virtual IfStatement *isIfStatement() { return NULL; } virtual CaseStatement *isCaseStatement() { return NULL; } virtual DefaultStatement *isDefaultStatement() { return NULL; } virtual LabelStatement *isLabelStatement() { return NULL; } virtual GotoDefaultStatement *isGotoDefaultStatement() { return NULL; } virtual GotoCaseStatement *isGotoCaseStatement() { return NULL; } virtual BreakStatement *isBreakStatement() { return NULL; } virtual DtorExpStatement *isDtorExpStatement() { return NULL; } virtual ForwardingStatement *isForwardingStatement() { return NULL; } virtual void accept(Visitor *v) { v->visit(this); } }; /** Any Statement that fails semantic() or has a component that is an ErrorExp or * a TypeError should return an ErrorStatement from semantic(). */ class ErrorStatement : public Statement { public: Statement *syntaxCopy(); ErrorStatement *isErrorStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class PeelStatement : public Statement { public: Statement *s; void accept(Visitor *v) { v->visit(this); } }; class ExpStatement : public Statement { public: Expression *exp; static ExpStatement *create(Loc loc, Expression *exp); Statement *syntaxCopy(); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); Statements *flatten(Scope *sc); ExpStatement *isExpStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class DtorExpStatement : public ExpStatement { public: /* Wraps an expression that is the destruction of 'var' */ VarDeclaration *var; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } DtorExpStatement *isDtorExpStatement() { return this; } }; class CompileStatement : public Statement { public: Expressions *exps; Statement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class CompoundStatement : public Statement { public: Statements *statements; static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2); Statement *syntaxCopy(); Statements *flatten(Scope *sc); ReturnStatement *isReturnStatement(); Statement *last(); CompoundStatement *isCompoundStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class CompoundDeclarationStatement : public CompoundStatement { public: Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; /* The purpose of this is so that continue will go to the next * of the statements, and break will go to the end of the statements. */ class UnrolledLoopStatement : public Statement { public: Statements *statements; Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class ScopeStatement : public Statement { public: Statement *statement; Loc endloc; // location of closing curly bracket Statement *syntaxCopy(); ScopeStatement *isScopeStatement() { return this; } ReturnStatement *isReturnStatement(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class ForwardingStatement : public Statement { ForwardingScopeDsymbol *sym; Statement *statement; Statement *syntaxCopy(); Statements *flatten(Scope *sc); ForwardingStatement *isForwardingStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class WhileStatement : public Statement { public: Expression *condition; Statement *_body; Loc endloc; // location of closing curly bracket Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class DoStatement : public Statement { public: Statement *_body; Expression *condition; Loc endloc; // location of ';' after while Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class ForStatement : public Statement { public: Statement *_init; Expression *condition; Expression *increment; Statement *_body; Loc endloc; // location of closing curly bracket // When wrapped in try/finally clauses, this points to the outermost one, // which may have an associated label. Internal break/continue statements // treat that label as referring to this loop. Statement *relatedLabeled; Statement *syntaxCopy(); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; } bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class ForeachStatement : public Statement { public: TOK op; // TOKforeach or TOKforeach_reverse Parameters *parameters; // array of Parameter*'s Expression *aggr; Statement *_body; Loc endloc; // location of closing curly bracket VarDeclaration *key; VarDeclaration *value; FuncDeclaration *func; // function we're lexically in Statements *cases; // put breaks, continues, gotos and returns here ScopeStatements *gotos; // forward referenced goto's go here Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class ForeachRangeStatement : public Statement { public: TOK op; // TOKforeach or TOKforeach_reverse Parameter *prm; // loop index variable Expression *lwr; Expression *upr; Statement *_body; Loc endloc; // location of closing curly bracket VarDeclaration *key; Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class IfStatement : public Statement { public: Parameter *prm; Expression *condition; Statement *ifbody; Statement *elsebody; VarDeclaration *match; // for MatchExpression results Loc endloc; // location of closing curly bracket Statement *syntaxCopy(); IfStatement *isIfStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class ConditionalStatement : public Statement { public: Condition *condition; Statement *ifbody; Statement *elsebody; Statement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class StaticForeachStatement : public Statement { public: StaticForeach *sfe; Statement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class PragmaStatement : public Statement { public: Identifier *ident; Expressions *args; // array of Expression's Statement *_body; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class StaticAssertStatement : public Statement { public: StaticAssert *sa; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class SwitchStatement : public Statement { public: Expression *condition; Statement *_body; bool isFinal; DefaultStatement *sdefault; TryFinallyStatement *tf; GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's CaseStatements *cases; // array of CaseStatement's int hasNoDefault; // !=0 if no default statement int hasVars; // !=0 if has variable case values VarDeclaration *lastVar; Statement *syntaxCopy(); bool hasBreak(); void accept(Visitor *v) { v->visit(this); } }; class CaseStatement : public Statement { public: Expression *exp; Statement *statement; int index; // which case it is (since we sort this) VarDeclaration *lastVar; Statement *syntaxCopy(); int compare(RootObject *obj); CaseStatement *isCaseStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class CaseRangeStatement : public Statement { public: Expression *first; Expression *last; Statement *statement; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class DefaultStatement : public Statement { public: Statement *statement; VarDeclaration *lastVar; Statement *syntaxCopy(); DefaultStatement *isDefaultStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class GotoDefaultStatement : public Statement { public: SwitchStatement *sw; Statement *syntaxCopy(); GotoDefaultStatement *isGotoDefaultStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class GotoCaseStatement : public Statement { public: Expression *exp; // NULL, or which case to goto CaseStatement *cs; // case statement it resolves to Statement *syntaxCopy(); GotoCaseStatement *isGotoCaseStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class SwitchErrorStatement : public Statement { public: Expression *exp; void accept(Visitor *v) { v->visit(this); } }; class ReturnStatement : public Statement { public: Expression *exp; size_t caseDim; Statement *syntaxCopy(); ReturnStatement *isReturnStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class BreakStatement : public Statement { public: Identifier *ident; Statement *syntaxCopy(); BreakStatement *isBreakStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class ContinueStatement : public Statement { public: Identifier *ident; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class SynchronizedStatement : public Statement { public: Expression *exp; Statement *_body; Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class WithStatement : public Statement { public: Expression *exp; Statement *_body; VarDeclaration *wthis; Loc endloc; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class TryCatchStatement : public Statement { public: Statement *_body; Catches *catches; Statement *syntaxCopy(); bool hasBreak(); void accept(Visitor *v) { v->visit(this); } }; class Catch : public RootObject { public: Loc loc; Type *type; Identifier *ident; VarDeclaration *var; Statement *handler; // set if semantic processing errors bool errors; // was generated by the compiler, // wasn't present in source code bool internalCatch; Catch *syntaxCopy(); }; class TryFinallyStatement : public Statement { public: Statement *_body; Statement *finalbody; bool bodyFallsThru; // true if _body falls through to finally static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody); Statement *syntaxCopy(); bool hasBreak(); bool hasContinue(); void accept(Visitor *v) { v->visit(this); } }; class OnScopeStatement : public Statement { public: TOK tok; Statement *statement; Statement *syntaxCopy(); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); void accept(Visitor *v) { v->visit(this); } }; class ThrowStatement : public Statement { public: Expression *exp; // was generated by the compiler, // wasn't present in source code bool internalThrow; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class DebugStatement : public Statement { public: Statement *statement; Statement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class GotoStatement : public Statement { public: Identifier *ident; LabelDsymbol *label; TryFinallyStatement *tf; OnScopeStatement *os; VarDeclaration *lastVar; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class LabelStatement : public Statement { public: Identifier *ident; Statement *statement; TryFinallyStatement *tf; OnScopeStatement *os; VarDeclaration *lastVar; Statement *gotoTarget; // interpret bool breaks; // someone did a 'break ident' Statement *syntaxCopy(); Statements *flatten(Scope *sc); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); LabelStatement *isLabelStatement() { return this; } void accept(Visitor *v) { v->visit(this); } }; class LabelDsymbol : public Dsymbol { public: LabelStatement *statement; static LabelDsymbol *create(Identifier *ident); LabelDsymbol *isLabel(); void accept(Visitor *v) { v->visit(this); } }; Statement* asmSemantic(AsmStatement *s, Scope *sc); class AsmStatement : public Statement { public: Token *tokens; Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; class InlineAsmStatement : public AsmStatement { public: code *asmcode; unsigned asmalign; // alignment of this statement unsigned regs; // mask of registers modified (must match regm_t in back end) bool refparam; // true if function parameter is referenced bool naked; // true if function is to be naked Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; // A GCC asm statement - assembler instructions with D expression operands class GccAsmStatement : public AsmStatement { public: StorageClass stc; // attributes of the asm {} block Expression *insn; // string expression that is the template for assembler code Expressions *args; // input and output operands of the statement unsigned outputargs; // of the operands in 'args', the number of output operands Identifiers *names; // list of symbolic names for the operands Expressions *constraints; // list of string constants specifying constraints on operands Expressions *clobbers; // list of string constants specifying clobbers and scratch registers Identifiers *labels; // list of goto labels GotoStatements *gotos; // of the goto labels, the equivalent statements they represent Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; // a complete asm {} block class CompoundAsmStatement : public CompoundStatement { public: StorageClass stc; // postfix attributes like nothrow/pure/@trusted CompoundAsmStatement *syntaxCopy(); Statements *flatten(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; class ImportStatement : public Statement { public: Dsymbols *imports; // Array of Import's Statement *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; ================================================ FILE: gcc/d/dmd/statement_rewrite_walker.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/statement_rewrite_walker.d, _statement_rewrite_walker.d) * Documentation: https://dlang.org/phobos/dmd_statement_rewrite_walker.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement_rewrite_walker.d */ module dmd.statement_rewrite_walker; import core.stdc.stdio; import dmd.statement; import dmd.visitor; /** A visitor to walk entire statements and provides ability to replace any sub-statements. */ extern (C++) class StatementRewriteWalker : SemanticTimePermissiveVisitor { alias visit = SemanticTimePermissiveVisitor.visit; /* Point the currently visited statement. * By using replaceCurrent() method, you can replace AST during walking. */ Statement* ps; public: final void visitStmt(ref Statement s) { ps = &s; s.accept(this); } final void replaceCurrent(Statement s) { *ps = s; } override void visit(PeelStatement s) { if (s.s) visitStmt(s.s); } override void visit(CompoundStatement s) { if (s.statements && s.statements.dim) { for (size_t i = 0; i < s.statements.dim; i++) { if ((*s.statements)[i]) visitStmt((*s.statements)[i]); } } } override void visit(CompoundDeclarationStatement s) { visit(cast(CompoundStatement)s); } override void visit(UnrolledLoopStatement s) { if (s.statements && s.statements.dim) { for (size_t i = 0; i < s.statements.dim; i++) { if ((*s.statements)[i]) visitStmt((*s.statements)[i]); } } } override void visit(ScopeStatement s) { if (s.statement) visitStmt(s.statement); } override void visit(WhileStatement s) { if (s._body) visitStmt(s._body); } override void visit(DoStatement s) { if (s._body) visitStmt(s._body); } override void visit(ForStatement s) { if (s._init) visitStmt(s._init); if (s._body) visitStmt(s._body); } override void visit(ForeachStatement s) { if (s._body) visitStmt(s._body); } override void visit(ForeachRangeStatement s) { if (s._body) visitStmt(s._body); } override void visit(IfStatement s) { if (s.ifbody) visitStmt(s.ifbody); if (s.elsebody) visitStmt(s.elsebody); } override void visit(SwitchStatement s) { if (s._body) visitStmt(s._body); } override void visit(CaseStatement s) { if (s.statement) visitStmt(s.statement); } override void visit(CaseRangeStatement s) { if (s.statement) visitStmt(s.statement); } override void visit(DefaultStatement s) { if (s.statement) visitStmt(s.statement); } override void visit(SynchronizedStatement s) { if (s._body) visitStmt(s._body); } override void visit(WithStatement s) { if (s._body) visitStmt(s._body); } override void visit(TryCatchStatement s) { if (s._body) visitStmt(s._body); if (s.catches && s.catches.dim) { for (size_t i = 0; i < s.catches.dim; i++) { Catch c = (*s.catches)[i]; if (c && c.handler) visitStmt(c.handler); } } } override void visit(TryFinallyStatement s) { if (s._body) visitStmt(s._body); if (s.finalbody) visitStmt(s.finalbody); } override void visit(DebugStatement s) { if (s.statement) visitStmt(s.statement); } override void visit(LabelStatement s) { if (s.statement) visitStmt(s.statement); } } ================================================ FILE: gcc/d/dmd/statementsem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/statementsem.d, _statementsem.d) * Documentation: https://dlang.org/phobos/dmd_statementsem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statementsem.d */ module dmd.statementsem; import core.stdc.stdio; import dmd.aggregate; import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.blockexit; import dmd.clone; import dmd.cond; import dmd.ctorflow; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.gluelayer; import dmd.id; import dmd.identifier; import dmd.init; import dmd.intrange; import dmd.mtype; import dmd.nogc; import dmd.opover; import dmd.root.outbuffer; import dmd.semantic2; import dmd.sideeffect; import dmd.statement; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; /***************************************** * CTFE requires FuncDeclaration::labtab for the interpretation. * So fixing the label name inside in/out contracts is necessary * for the uniqueness in labtab. * Params: * sc = context * ident = statement label name to be adjusted * Returns: * adjusted label name */ private Identifier fixupLabelName(Scope* sc, Identifier ident) { uint flags = (sc.flags & SCOPE.contract); const id = ident.toString(); if (flags && flags != SCOPE.invariant_ && !(id.length >= 2 && id[0] == '_' && id[1] == '_')) // does not start with "__" { OutBuffer buf; buf.writestring(flags == SCOPE.require ? "__in_" : "__out_"); buf.writestring(ident.toString()); ident = Identifier.idPool(buf.peekSlice()); } return ident; } /******************************************* * Check to see if statement is the innermost labeled statement. * Params: * sc = context * statement = Statement to check * Returns: * if `true`, then the `LabelStatement`, otherwise `null` */ private LabelStatement checkLabeledLoop(Scope* sc, Statement statement) { if (sc.slabel && sc.slabel.statement == statement) { return sc.slabel; } return null; } /*********************************************************** * Check an assignment is used as a condition. * Intended to be use before the `semantic` call on `e`. * Params: * e = condition expression which is not yet run semantic analysis. * Returns: * `e` or ErrorExp. */ private Expression checkAssignmentAsCondition(Expression e) { auto ec = lastComma(e); if (ec.op == TOK.assign) { ec.error("assignment cannot be used as a condition, perhaps `==` was meant?"); return new ErrorExp(); } return e; } // Performs semantic analysis in Statement AST nodes extern(C++) Statement statementSemantic(Statement s, Scope* sc) { scope v = new StatementSemanticVisitor(sc); s.accept(v); return v.result; } private extern (C++) final class StatementSemanticVisitor : Visitor { alias visit = Visitor.visit; Statement result; Scope* sc; this(Scope* sc) { this.sc = sc; } private void setError() { result = new ErrorStatement(); } override void visit(Statement s) { result = s; } override void visit(ErrorStatement s) { result = s; } override void visit(PeelStatement s) { /* "peel" off this wrapper, and don't run semantic() * on the result. */ result = s.s; } override void visit(ExpStatement s) { /* https://dlang.org/spec/statement.html#expression-statement */ if (s.exp) { //printf("ExpStatement::semantic() %s\n", exp.toChars()); // Allow CommaExp in ExpStatement because return isn't used CommaExp.allow(s.exp); s.exp = s.exp.expressionSemantic(sc); s.exp = resolveProperties(sc, s.exp); s.exp = s.exp.addDtorHook(sc); if (checkNonAssignmentArrayOp(s.exp)) s.exp = new ErrorExp(); if (auto f = isFuncAddress(s.exp)) { if (f.checkForwardRef(s.exp.loc)) s.exp = new ErrorExp(); } if (discardValue(s.exp)) s.exp = new ErrorExp(); s.exp = s.exp.optimize(WANTvalue); s.exp = checkGC(sc, s.exp); if (s.exp.op == TOK.error) return setError(); } result = s; } override void visit(CompileStatement cs) { /* https://dlang.org/spec/statement.html#mixin-statement */ //printf("CompileStatement::semantic() %s\n", exp.toChars()); Statements* a = cs.flatten(sc); if (!a) return; Statement s = new CompoundStatement(cs.loc, a); result = s.statementSemantic(sc); } override void visit(CompoundStatement cs) { //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc); version (none) { foreach (i, s; cs.statements) { if (s) printf("[%d]: %s", i, s.toChars()); } } for (size_t i = 0; i < cs.statements.dim;) { Statement s = (*cs.statements)[i]; if (s) { Statements* flt = s.flatten(sc); if (flt) { cs.statements.remove(i); cs.statements.insert(i, flt); continue; } s = s.statementSemantic(sc); (*cs.statements)[i] = s; if (s) { Statement sentry; Statement sexception; Statement sfinally; (*cs.statements)[i] = s.scopeCode(sc, &sentry, &sexception, &sfinally); if (sentry) { sentry = sentry.statementSemantic(sc); cs.statements.insert(i, sentry); i++; } if (sexception) sexception = sexception.statementSemantic(sc); if (sexception) { /* Returns: true if statements[] are empty statements */ static bool isEmpty(const Statement[] statements) { foreach (s; statements) { if (const cs = s.isCompoundStatement()) { if (!isEmpty((*cs.statements)[])) return false; } else return false; } return true; } if (!sfinally && isEmpty((*cs.statements)[i + 1 .. cs.statements.dim])) { } else { /* Rewrite: * s; s1; s2; * As: * s; * try { s1; s2; } * catch (Throwable __o) * { sexception; throw __o; } */ auto a = new Statements(); foreach (j; i + 1 .. cs.statements.dim) { a.push((*cs.statements)[j]); } Statement _body = new CompoundStatement(Loc.initial, a); _body = new ScopeStatement(Loc.initial, _body, Loc.initial); Identifier id = Identifier.generateId("__o"); Statement handler = new PeelStatement(sexception); if (sexception.blockExit(sc.func, false) & BE.fallthru) { auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); ts.internalThrow = true; handler = new CompoundStatement(Loc.initial, handler, ts); } auto catches = new Catches(); auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); ctch.internalCatch = true; catches.push(ctch); s = new TryCatchStatement(Loc.initial, _body, catches); if (sfinally) s = new TryFinallyStatement(Loc.initial, s, sfinally); s = s.statementSemantic(sc); cs.statements.setDim(i + 1); cs.statements.push(s); break; } } else if (sfinally) { if (0 && i + 1 == cs.statements.dim) { cs.statements.push(sfinally); } else { /* Rewrite: * s; s1; s2; * As: * s; try { s1; s2; } finally { sfinally; } */ auto a = new Statements(); foreach (j; i + 1 .. cs.statements.dim) { a.push((*cs.statements)[j]); } Statement _body = new CompoundStatement(Loc.initial, a); s = new TryFinallyStatement(Loc.initial, _body, sfinally); s = s.statementSemantic(sc); cs.statements.setDim(i + 1); cs.statements.push(s); break; } } } else { /* Remove NULL statements from the list. */ cs.statements.remove(i); continue; } } i++; } foreach (i; 0 .. cs.statements.dim) { Lagain: Statement s = (*cs.statements)[i]; if (!s) continue; Statement se = s.isErrorStatement(); if (se) { result = se; return; } /* https://issues.dlang.org/show_bug.cgi?id=11653 * 'semantic' may return another CompoundStatement * (eg. CaseRangeStatement), so flatten it here. */ Statements* flt = s.flatten(sc); if (flt) { cs.statements.remove(i); cs.statements.insert(i, flt); if (cs.statements.dim <= i) break; goto Lagain; } } if (cs.statements.dim == 1) { result = (*cs.statements)[0]; return; } result = cs; } override void visit(UnrolledLoopStatement uls) { //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc); Scope* scd = sc.push(); scd.sbreak = uls; scd.scontinue = uls; Statement serror = null; foreach (i, ref s; *uls.statements) { if (s) { //printf("[%d]: %s\n", i, s.toChars()); s = s.statementSemantic(scd); if (s && !serror) serror = s.isErrorStatement(); } } scd.pop(); result = serror ? serror : uls; } override void visit(ScopeStatement ss) { //printf("ScopeStatement::semantic(sc = %p)\n", sc); if (ss.statement) { ScopeDsymbol sym = new ScopeDsymbol(); sym.parent = sc.scopesym; sym.endlinnum = ss.endloc.linnum; sc = sc.push(sym); Statements* a = ss.statement.flatten(sc); if (a) { ss.statement = new CompoundStatement(ss.loc, a); } ss.statement = ss.statement.statementSemantic(sc); if (ss.statement) { if (ss.statement.isErrorStatement()) { sc.pop(); result = ss.statement; return; } Statement sentry; Statement sexception; Statement sfinally; ss.statement = ss.statement.scopeCode(sc, &sentry, &sexception, &sfinally); assert(!sentry); assert(!sexception); if (sfinally) { //printf("adding sfinally\n"); sfinally = sfinally.statementSemantic(sc); ss.statement = new CompoundStatement(ss.loc, ss.statement, sfinally); } } sc.pop(); } result = ss; } override void visit(ForwardingStatement ss) { assert(ss.sym); for (Scope* csc = sc; !ss.sym.forward; csc = csc.enclosing) { assert(csc); ss.sym.forward = csc.scopesym; } sc = sc.push(ss.sym); sc.sbreak = ss; sc.scontinue = ss; ss.statement = ss.statement.statementSemantic(sc); sc = sc.pop(); result = ss.statement; } override void visit(WhileStatement ws) { /* Rewrite as a for(;condition;) loop * https://dlang.org/spec/statement.html#while-statement */ Statement s = new ForStatement(ws.loc, null, ws.condition, null, ws._body, ws.endloc); s = s.statementSemantic(sc); result = s; } override void visit(DoStatement ds) { /* https://dlang.org/spec/statement.html#do-statement */ const inLoopSave = sc.inLoop; sc.inLoop = true; if (ds._body) ds._body = ds._body.semanticScope(sc, ds, ds); sc.inLoop = inLoopSave; if (ds.condition.op == TOK.dotIdentifier) (cast(DotIdExp)ds.condition).noderef = true; // check in syntax level ds.condition = checkAssignmentAsCondition(ds.condition); ds.condition = ds.condition.expressionSemantic(sc); ds.condition = resolveProperties(sc, ds.condition); if (checkNonAssignmentArrayOp(ds.condition)) ds.condition = new ErrorExp(); ds.condition = ds.condition.optimize(WANTvalue); ds.condition = checkGC(sc, ds.condition); ds.condition = ds.condition.toBoolean(sc); if (ds.condition.op == TOK.error) return setError(); if (ds._body && ds._body.isErrorStatement()) { result = ds._body; return; } result = ds; } override void visit(ForStatement fs) { /* https://dlang.org/spec/statement.html#for-statement */ //printf("ForStatement::semantic %s\n", fs.toChars()); if (fs._init) { /* Rewrite: * for (auto v1 = i1, v2 = i2; condition; increment) { ... } * to: * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } } * then lowered to: * auto v1 = i1; * try { * auto v2 = i2; * try { * for (; condition; increment) { ... } * } finally { v2.~this(); } * } finally { v1.~this(); } */ auto ainit = new Statements(); ainit.push(fs._init); fs._init = null; ainit.push(fs); Statement s = new CompoundStatement(fs.loc, ainit); s = new ScopeStatement(fs.loc, s, fs.endloc); s = s.statementSemantic(sc); if (!s.isErrorStatement()) { if (LabelStatement ls = checkLabeledLoop(sc, fs)) ls.gotoTarget = fs; fs.relatedLabeled = s; } result = s; return; } assert(fs._init is null); auto sym = new ScopeDsymbol(); sym.parent = sc.scopesym; sym.endlinnum = fs.endloc.linnum; sc = sc.push(sym); sc.inLoop = true; if (fs.condition) { if (fs.condition.op == TOK.dotIdentifier) (cast(DotIdExp)fs.condition).noderef = true; // check in syntax level fs.condition = checkAssignmentAsCondition(fs.condition); fs.condition = fs.condition.expressionSemantic(sc); fs.condition = resolveProperties(sc, fs.condition); if (checkNonAssignmentArrayOp(fs.condition)) fs.condition = new ErrorExp(); fs.condition = fs.condition.optimize(WANTvalue); fs.condition = checkGC(sc, fs.condition); fs.condition = fs.condition.toBoolean(sc); } if (fs.increment) { CommaExp.allow(fs.increment); fs.increment = fs.increment.expressionSemantic(sc); fs.increment = resolveProperties(sc, fs.increment); if (checkNonAssignmentArrayOp(fs.increment)) fs.increment = new ErrorExp(); fs.increment = fs.increment.optimize(WANTvalue); fs.increment = checkGC(sc, fs.increment); } sc.sbreak = fs; sc.scontinue = fs; if (fs._body) fs._body = fs._body.semanticNoScope(sc); sc.pop(); if (fs.condition && fs.condition.op == TOK.error || fs.increment && fs.increment.op == TOK.error || fs._body && fs._body.isErrorStatement()) return setError(); result = fs; } /******************* * Determines the return type of makeTupleForeach. */ private static template MakeTupleForeachRet(bool isDecl) { static if(isDecl) { alias MakeTupleForeachRet = Dsymbols*; } else { alias MakeTupleForeachRet = void; } } /******************* * Type check and unroll `foreach` over an expression tuple as well * as `static foreach` statements and `static foreach` * declarations. For `static foreach` statements and `static * foreach` declarations, the visitor interface is used (and the * result is written into the `result` field.) For `static * foreach` declarations, the resulting Dsymbols* are returned * directly. * * The unrolled body is wrapped into a * - UnrolledLoopStatement, for `foreach` over an expression tuple. * - ForwardingStatement, for `static foreach` statements. * - ForwardingAttribDeclaration, for `static foreach` declarations. * * `static foreach` variables are declared as `STC.local`, such * that they are inserted into the local symbol tables of the * forwarding constructs instead of forwarded. For `static * foreach` with multiple foreach loop variables whose aggregate * has been lowered into a sequence of tuples, this function * expands the tuples into multiple `STC.local` `static foreach` * variables. */ MakeTupleForeachRet!isDecl makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args) { auto returnEarly() { static if (isDecl) { return null; } else { result = new ErrorStatement(); return; } } static if(isDecl) { static assert(isStatic); auto dbody = args[0]; } static if(isStatic) { auto needExpansion = args[$-1]; assert(sc); auto previous = sc.scopesym; } alias s = fs; auto loc = fs.loc; size_t dim = fs.parameters.dim; static if(isStatic) bool skipCheck = needExpansion; else enum skipCheck = false; if (!skipCheck && (dim < 1 || dim > 2)) { fs.error("only one (value) or two (key,value) arguments for tuple `foreach`"); setError(); return returnEarly(); } Type paramtype = (*fs.parameters)[dim - 1].type; if (paramtype) { paramtype = paramtype.typeSemantic(loc, sc); if (paramtype.ty == Terror) { setError(); return returnEarly(); } } Type tab = fs.aggr.type.toBasetype(); TypeTuple tuple = cast(TypeTuple)tab; static if(!isDecl) { auto statements = new Statements(); } else { auto declarations = new Dsymbols(); } //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars()); size_t n; TupleExp te = null; if (fs.aggr.op == TOK.tuple) // expression tuple { te = cast(TupleExp)fs.aggr; n = te.exps.dim; } else if (fs.aggr.op == TOK.type) // type tuple { n = Parameter.dim(tuple.arguments); } else assert(0); foreach (j; 0 .. n) { size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j; Expression e = null; Type t = null; if (te) e = (*te.exps)[k]; else t = Parameter.getNth(tuple.arguments, k).type; Parameter p = (*fs.parameters)[0]; static if(!isDecl) { auto st = new Statements(); } else { auto st = new Dsymbols(); } static if(isStatic) bool skip = needExpansion; else enum skip = false; if (!skip && dim == 2) { // Declare key if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_)) { fs.error("no storage class for key `%s`", p.ident.toChars()); setError(); return returnEarly(); } static if(isStatic) { if(!p.type) { p.type = Type.tsize_t; } } p.type = p.type.typeSemantic(loc, sc); TY keyty = p.type.ty; if (keyty != Tint32 && keyty != Tuns32) { if (global.params.isLP64) { if (keyty != Tint64 && keyty != Tuns64) { fs.error("`foreach`: key type must be `int` or `uint`, `long` or `ulong`, not `%s`", p.type.toChars()); setError(); return returnEarly(); } } else { fs.error("`foreach`: key type must be `int` or `uint`, not `%s`", p.type.toChars()); setError(); return returnEarly(); } } Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k)); auto var = new VarDeclaration(loc, p.type, p.ident, ie); var.storage_class |= STC.manifest; static if(isStatic) var.storage_class |= STC.local; static if(!isDecl) { st.push(new ExpStatement(loc, var)); } else { st.push(var); } p = (*fs.parameters)[1]; // value } /*********************** * Declares a unrolled `foreach` loop variable or a `static foreach` variable. * * Params: * storageClass = The storage class of the variable. * type = The declared type of the variable. * ident = The name of the variable. * e = The initializer of the variable (i.e. the current element of the looped over aggregate). * t = The type of the initializer. * Returns: * `true` iff the declaration was successful. */ bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t) { if (storageClass & (STC.out_ | STC.lazy_) || storageClass & STC.ref_ && !te) { fs.error("no storage class for value `%s`", ident.toChars()); setError(); return false; } Declaration var; if (e) { Type tb = e.type.toBasetype(); Dsymbol ds = null; if (!(storageClass & STC.manifest)) { if ((isStatic || tb.ty == Tfunction || tb.ty == Tsarray || storageClass&STC.alias_) && e.op == TOK.variable) ds = (cast(VarExp)e).var; else if (e.op == TOK.template_) ds = (cast(TemplateExp)e).td; else if (e.op == TOK.scope_) ds = (cast(ScopeExp)e).sds; else if (e.op == TOK.function_) { auto fe = cast(FuncExp)e; ds = fe.td ? cast(Dsymbol)fe.td : fe.fd; } else if (e.op == TOK.overloadSet) ds = (cast(OverExp)e).vars; } else if (storageClass & STC.alias_) { fs.error("`foreach` loop variable cannot be both `enum` and `alias`"); setError(); return false; } if (ds) { var = new AliasDeclaration(loc, ident, ds); if (storageClass & STC.ref_) { fs.error("symbol `%s` cannot be `ref`", ds.toChars()); setError(); return false; } if (paramtype) { fs.error("cannot specify element type for symbol `%s`", ds.toChars()); setError(); return false; } } else if (e.op == TOK.type) { var = new AliasDeclaration(loc, ident, e.type); if (paramtype) { fs.error("cannot specify element type for type `%s`", e.type.toChars()); setError(); return false; } } else { e = resolveProperties(sc, e); type = e.type; if (paramtype) type = paramtype; Initializer ie = new ExpInitializer(Loc.initial, e); auto v = new VarDeclaration(loc, type, ident, ie); if (storageClass & STC.ref_) v.storage_class |= STC.ref_ | STC.foreach_; if (isStatic || storageClass&STC.manifest || e.isConst() || e.op == TOK.string_ || e.op == TOK.structLiteral || e.op == TOK.arrayLiteral) { if (v.storage_class & STC.ref_) { static if (!isStatic) { fs.error("constant value `%s` cannot be `ref`", ie.toChars()); } else { if (!needExpansion) { fs.error("constant value `%s` cannot be `ref`", ie.toChars()); } else { fs.error("constant value `%s` cannot be `ref`", ident.toChars()); } } setError(); return false; } else v.storage_class |= STC.manifest; } var = v; } } else { var = new AliasDeclaration(loc, ident, t); if (paramtype) { fs.error("cannot specify element type for symbol `%s`", s.toChars()); setError(); return false; } } static if (isStatic) { var.storage_class |= STC.local; } static if (!isDecl) { st.push(new ExpStatement(loc, var)); } else { st.push(var); } return true; } static if (!isStatic) { // Declare value if (!declareVariable(p.storageClass, p.type, p.ident, e, t)) { return returnEarly(); } } else { if (!needExpansion) { // Declare value if (!declareVariable(p.storageClass, p.type, p.ident, e, t)) { return returnEarly(); } } else { // expand tuples into multiple `static foreach` variables. assert(e && !t); auto ident = Identifier.generateId("__value"); declareVariable(0, e.type, ident, e, null); import dmd.cond: StaticForeach; auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length); Expression access = new DotIdExp(loc, e, field); access = expressionSemantic(access, sc); if (!tuple) return returnEarly(); //printf("%s\n",tuple.toChars()); foreach (l; 0 .. dim) { auto cp = (*fs.parameters)[l]; Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t)); init_ = init_.expressionSemantic(sc); assert(init_.type); declareVariable(p.storageClass, init_.type, cp.ident, init_, null); } } } static if (!isDecl) { if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646 st.push(fs._body.syntaxCopy()); Statement res = new CompoundStatement(loc, st); } else { st.append(Dsymbol.arraySyntaxCopy(dbody)); } static if (!isStatic) { res = new ScopeStatement(loc, res, fs.endloc); } else static if (!isDecl) { auto fwd = new ForwardingStatement(loc, res); previous = fwd.sym; res = fwd; } else { import dmd.attrib: ForwardingAttribDeclaration; auto res = new ForwardingAttribDeclaration(st); previous = res.sym; } static if (!isDecl) { statements.push(res); } else { declarations.push(res); } } static if (!isStatic) { Statement res = new UnrolledLoopStatement(loc, statements); if (LabelStatement ls = checkLabeledLoop(sc, fs)) ls.gotoTarget = res; if (te && te.e0) res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res); } else static if (!isDecl) { Statement res = new CompoundStatement(loc, statements); } else { auto res = declarations; } static if (!isDecl) { result = res; } else { return res; } } override void visit(ForeachStatement fs) { /* https://dlang.org/spec/statement.html#foreach-statement */ //printf("ForeachStatement::semantic() %p\n", fs); /****** * Issue error if any of the ForeachTypes were not supplied and could not be inferred. * Returns: * true if error issued */ static bool checkForArgTypes(ForeachStatement fs) { bool result = false; foreach (p; *fs.parameters) { if (!p.type) { fs.error("cannot infer type for `foreach` variable `%s`, perhaps set it explicitly", p.ident.toChars()); p.type = Type.terror; result = true; } } return result; } const loc = fs.loc; const dim = fs.parameters.dim; TypeAArray taa = null; Type tn = null; Type tnv = null; fs.func = sc.func; if (fs.func.fes) fs.func = fs.func.fes.func; VarDeclaration vinit = null; fs.aggr = fs.aggr.expressionSemantic(sc); fs.aggr = resolveProperties(sc, fs.aggr); fs.aggr = fs.aggr.optimize(WANTvalue); if (fs.aggr.op == TOK.error) return setError(); Expression oaggr = fs.aggr; if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct && (cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor && fs.aggr.op != TOK.type && !fs.aggr.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=14653 // Extend the life of rvalue aggregate till the end of foreach. vinit = copyToTemp(STC.rvalue, "__aggr", fs.aggr); vinit.endlinnum = fs.endloc.linnum; vinit.dsymbolSemantic(sc); fs.aggr = new VarExp(fs.aggr.loc, vinit); } Dsymbol sapply = null; // the inferred opApply() or front() function if (!inferForeachAggregate(sc, fs.op == TOK.foreach_, fs.aggr, sapply)) { const(char)* msg = ""; if (fs.aggr.type && isAggregate(fs.aggr.type)) { msg = ", define `opApply()`, range primitives, or use `.tupleof`"; } fs.error("invalid `foreach` aggregate `%s`%s", oaggr.toChars(), msg); return setError(); } Dsymbol sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors /* Check for inference errors */ if (!inferApplyArgTypes(fs, sc, sapply)) { /** Try and extract the parameter count of the opApply callback function, e.g.: int opApply(int delegate(int, float)) => 2 args */ bool foundMismatch = false; size_t foreachParamCount = 0; if (sapplyOld) { if (FuncDeclaration fd = sapplyOld.isFuncDeclaration()) { int fvarargs; // ignored (opApply shouldn't take variadics) Parameters* fparameters = fd.getParameters(&fvarargs); if (Parameter.dim(fparameters) == 1) { // first param should be the callback function Parameter fparam = Parameter.getNth(fparameters, 0); if ((fparam.type.ty == Tpointer || fparam.type.ty == Tdelegate) && fparam.type.nextOf().ty == Tfunction) { TypeFunction tf = cast(TypeFunction)fparam.type.nextOf(); foreachParamCount = Parameter.dim(tf.parameters); foundMismatch = true; } } } } //printf("dim = %d, parameters.dim = %d\n", dim, parameters.dim); if (foundMismatch && dim != foreachParamCount) { const(char)* plural = foreachParamCount > 1 ? "s" : ""; fs.error("cannot infer argument types, expected %d argument%s, not %d", foreachParamCount, plural, dim); } else fs.error("cannot uniquely infer `foreach` argument types"); return setError(); } Type tab = fs.aggr.type.toBasetype(); if (tab.ty == Ttuple) // don't generate new scope for tuple loops { makeTupleForeach!(false,false)(fs); if (vinit) result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result); result = result.statementSemantic(sc); return; } auto sym = new ScopeDsymbol(); sym.parent = sc.scopesym; sym.endlinnum = fs.endloc.linnum; auto sc2 = sc.push(sym); sc2.inLoop = true; foreach (Parameter p; *fs.parameters) { if (p.storageClass & STC.manifest) { fs.error("cannot declare `enum` loop variables for non-unrolled foreach"); } if (p.storageClass & STC.alias_) { fs.error("cannot declare `alias` loop variables for non-unrolled foreach"); } } Statement s = fs; switch (tab.ty) { case Tarray: case Tsarray: { if (checkForArgTypes(fs)) goto case Terror; if (dim < 1 || dim > 2) { fs.error("only one or two arguments for array `foreach`"); goto case Terror; } /* Look for special case of parsing char types out of char type * array. */ tn = tab.nextOf().toBasetype(); if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar) { int i = (dim == 1) ? 0 : 1; // index of value Parameter p = (*fs.parameters)[i]; p.type = p.type.typeSemantic(loc, sc2); p.type = p.type.addStorageClass(p.storageClass); tnv = p.type.toBasetype(); if (tnv.ty != tn.ty && (tnv.ty == Tchar || tnv.ty == Twchar || tnv.ty == Tdchar)) { if (p.storageClass & STC.ref_) { fs.error("`foreach`: value of UTF conversion cannot be `ref`"); goto case Terror; } if (dim == 2) { p = (*fs.parameters)[0]; if (p.storageClass & STC.ref_) { fs.error("`foreach`: key cannot be `ref`"); goto case Terror; } } goto Lapply; } } foreach (i; 0 .. dim) { // Declare parameters Parameter p = (*fs.parameters)[i]; p.type = p.type.typeSemantic(loc, sc2); p.type = p.type.addStorageClass(p.storageClass); VarDeclaration var; if (dim == 2 && i == 0) { var = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null); var.storage_class |= STC.temp | STC.foreach_; if (var.storage_class & (STC.ref_ | STC.out_)) var.storage_class |= STC.nodtor; fs.key = var; if (p.storageClass & STC.ref_) { if (var.type.constConv(p.type) <= MATCH.nomatch) { fs.error("key type mismatch, `%s` to `ref %s`", var.type.toChars(), p.type.toChars()); goto case Terror; } } if (tab.ty == Tsarray) { TypeSArray ta = cast(TypeSArray)tab; IntRange dimrange = getIntRange(ta.dim); if (!IntRange.fromType(var.type).contains(dimrange)) { fs.error("index type `%s` cannot cover index range 0..%llu", p.type.toChars(), ta.dim.toInteger()); goto case Terror; } fs.key.range = new IntRange(SignExtendedNumber(0), dimrange.imax); } } else { var = new VarDeclaration(loc, p.type, p.ident, null); var.storage_class |= STC.foreach_; var.storage_class |= p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.TYPECTOR); if (var.storage_class & (STC.ref_ | STC.out_)) var.storage_class |= STC.nodtor; fs.value = var; if (var.storage_class & STC.ref_) { if (fs.aggr.checkModifiable(sc2, 1) == 2) var.storage_class |= STC.ctorinit; Type t = tab.nextOf(); if (t.constConv(p.type) <= MATCH.nomatch) { fs.error("argument type mismatch, `%s` to `ref %s`", t.toChars(), p.type.toChars()); goto case Terror; } } } } /* Convert to a ForStatement * foreach (key, value; a) body => * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) * { T value = tmp[k]; body } * * foreach_reverse (key, value; a) body => * for (T[] tmp = a[], size_t key = tmp.length; key--; ) * { T value = tmp[k]; body } */ auto id = Identifier.generateId("__r"); auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null)); VarDeclaration tmp; if (fs.aggr.op == TOK.arrayLiteral && !((*fs.parameters)[dim - 1].storageClass & STC.ref_)) { auto ale = cast(ArrayLiteralExp)fs.aggr; size_t edim = ale.elements ? ale.elements.dim : 0; auto telem = (*fs.parameters)[dim - 1].type; // https://issues.dlang.org/show_bug.cgi?id=12936 // if telem has been specified explicitly, // converting array literal elements to telem might make it @nogc. fs.aggr = fs.aggr.implicitCastTo(sc, telem.sarrayOf(edim)); if (fs.aggr.op == TOK.error) goto case Terror; // for (T[edim] tmp = a, ...) tmp = new VarDeclaration(loc, fs.aggr.type, id, ie); } else tmp = new VarDeclaration(loc, tab.nextOf().arrayOf(), id, ie); tmp.storage_class |= STC.temp; Expression tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id.length); if (!fs.key) { Identifier idkey = Identifier.generateId("__key"); fs.key = new VarDeclaration(loc, Type.tsize_t, idkey, null); fs.key.storage_class |= STC.temp; } if (fs.op == TOK.foreach_reverse_) fs.key._init = new ExpInitializer(loc, tmp_length); else fs.key._init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs.key.type)); auto cs = new Statements(); if (vinit) cs.push(new ExpStatement(loc, vinit)); cs.push(new ExpStatement(loc, tmp)); cs.push(new ExpStatement(loc, fs.key)); Statement forinit = new CompoundDeclarationStatement(loc, cs); Expression cond; if (fs.op == TOK.foreach_reverse_) { // key-- cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key)); } else { // key < tmp.length cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), tmp_length); } Expression increment = null; if (fs.op == TOK.foreach_) { // key += 1 increment = new AddAssignExp(loc, new VarExp(loc, fs.key), new IntegerExp(loc, 1, fs.key.type)); } // T value = tmp[key]; IndexExp indexExp = new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs.key)); indexExp.indexIsInBounds = true; // disabling bounds checking in foreach statements. fs.value._init = new ExpInitializer(loc, indexExp); Statement ds = new ExpStatement(loc, fs.value); if (dim == 2) { Parameter p = (*fs.parameters)[0]; if ((p.storageClass & STC.ref_) && p.type.equals(fs.key.type)) { fs.key.range = null; auto v = new AliasDeclaration(loc, p.ident, fs.key); fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body); } else { auto ei = new ExpInitializer(loc, new IdentifierExp(loc, fs.key.ident)); auto v = new VarDeclaration(loc, p.type, p.ident, ei); v.storage_class |= STC.foreach_ | (p.storageClass & STC.ref_); fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body); if (fs.key.range && !p.type.isMutable()) { /* Limit the range of the key to the specified range */ v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1)); } } } fs._body = new CompoundStatement(loc, ds, fs._body); s = new ForStatement(loc, forinit, cond, increment, fs._body, fs.endloc); if (auto ls = checkLabeledLoop(sc, fs)) // https://issues.dlang.org/show_bug.cgi?id=15450 // don't use sc2 ls.gotoTarget = s; s = s.statementSemantic(sc2); break; } case Taarray: if (fs.op == TOK.foreach_reverse_) fs.warning("cannot use `foreach_reverse` with an associative array"); if (checkForArgTypes(fs)) goto case Terror; taa = cast(TypeAArray)tab; if (dim < 1 || dim > 2) { fs.error("only one or two arguments for associative array `foreach`"); goto case Terror; } goto Lapply; case Tclass: case Tstruct: /* Prefer using opApply, if it exists */ if (sapply) goto Lapply; { /* Look for range iteration, i.e. the properties * .empty, .popFront, .popBack, .front and .back * foreach (e; aggr) { ... } * translates to: * for (auto __r = aggr[]; !__r.empty; __r.popFront()) { * auto e = __r.front; * ... * } */ auto ad = (tab.ty == Tclass) ? cast(AggregateDeclaration)(cast(TypeClass)tab).sym : cast(AggregateDeclaration)(cast(TypeStruct)tab).sym; Identifier idfront; Identifier idpopFront; if (fs.op == TOK.foreach_) { idfront = Id.Ffront; idpopFront = Id.FpopFront; } else { idfront = Id.Fback; idpopFront = Id.FpopBack; } auto sfront = ad.search(Loc.initial, idfront); if (!sfront) goto Lapply; /* Generate a temporary __r and initialize it with the aggregate. */ VarDeclaration r; Statement _init; if (vinit && fs.aggr.op == TOK.variable && (cast(VarExp)fs.aggr).var == vinit) { r = vinit; _init = new ExpStatement(loc, vinit); } else { r = copyToTemp(0, "__r", fs.aggr); r.dsymbolSemantic(sc); _init = new ExpStatement(loc, r); if (vinit) _init = new CompoundStatement(loc, new ExpStatement(loc, vinit), _init); } // !__r.empty Expression e = new VarExp(loc, r); e = new DotIdExp(loc, e, Id.Fempty); Expression condition = new NotExp(loc, e); // __r.idpopFront() e = new VarExp(loc, r); Expression increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront)); /* Declaration statement for e: * auto e = __r.idfront; */ e = new VarExp(loc, r); Expression einit = new DotIdExp(loc, e, idfront); Statement makeargs, forbody; if (dim == 1) { auto p = (*fs.parameters)[0]; auto ve = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, einit)); ve.storage_class |= STC.foreach_; ve.storage_class |= p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.TYPECTOR); makeargs = new ExpStatement(loc, ve); } else { auto vd = copyToTemp(STC.ref_, "__front", einit); vd.dsymbolSemantic(sc); makeargs = new ExpStatement(loc, vd); Type tfront; if (auto fd = sfront.isFuncDeclaration()) { if (!fd.functionSemantic()) goto Lrangeerr; tfront = fd.type; } else if (auto td = sfront.isTemplateDeclaration()) { Expressions a; if (auto f = resolveFuncCall(loc, sc, td, null, tab, &a, 1)) tfront = f.type; } else if (auto d = sfront.isDeclaration()) { tfront = d.type; } if (!tfront || tfront.ty == Terror) goto Lrangeerr; if (tfront.toBasetype().ty == Tfunction) tfront = tfront.toBasetype().nextOf(); if (tfront.ty == Tvoid) { fs.error("`%s.front` is `void` and has no value", oaggr.toChars()); goto case Terror; } // Resolve inout qualifier of front type tfront = tfront.substWildTo(tab.mod); Expression ve = new VarExp(loc, vd); ve.type = tfront; auto exps = new Expressions(); exps.push(ve); int pos = 0; while (exps.dim < dim) { pos = expandAliasThisTuples(exps, pos); if (pos == -1) break; } if (exps.dim != dim) { const(char)* plural = exps.dim > 1 ? "s" : ""; fs.error("cannot infer argument types, expected %d argument%s, not %d", exps.dim, plural, dim); goto case Terror; } foreach (i; 0 .. dim) { auto p = (*fs.parameters)[i]; auto exp = (*exps)[i]; version (none) { printf("[%d] p = %s %s, exp = %s %s\n", i, p.type ? p.type.toChars() : "?", p.ident.toChars(), exp.type.toChars(), exp.toChars()); } if (!p.type) p.type = exp.type; p.type = p.type.addStorageClass(p.storageClass).typeSemantic(loc, sc2); if (!exp.implicitConvTo(p.type)) goto Lrangeerr; auto var = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, exp)); var.storage_class |= STC.ctfe | STC.ref_ | STC.foreach_; makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var)); } } forbody = new CompoundStatement(loc, makeargs, fs._body); s = new ForStatement(loc, _init, condition, increment, forbody, fs.endloc); if (auto ls = checkLabeledLoop(sc, fs)) ls.gotoTarget = s; version (none) { printf("init: %s\n", _init.toChars()); printf("condition: %s\n", condition.toChars()); printf("increment: %s\n", increment.toChars()); printf("body: %s\n", forbody.toChars()); } s = s.statementSemantic(sc2); break; Lrangeerr: fs.error("cannot infer argument types"); goto case Terror; } case Tdelegate: if (fs.op == TOK.foreach_reverse_) fs.deprecation("cannot use `foreach_reverse` with a delegate"); Lapply: { if (checkForArgTypes(fs)) goto case Terror; TypeFunction tfld = null; if (sapply) { FuncDeclaration fdapply = sapply.isFuncDeclaration(); if (fdapply) { assert(fdapply.type && fdapply.type.ty == Tfunction); tfld = cast(TypeFunction)fdapply.type.typeSemantic(loc, sc2); goto Lget; } else if (tab.ty == Tdelegate) { tfld = cast(TypeFunction)tab.nextOf(); Lget: //printf("tfld = %s\n", tfld.toChars()); if (tfld.parameters.dim == 1) { Parameter p = Parameter.getNth(tfld.parameters, 0); if (p.type && p.type.ty == Tdelegate) { auto t = p.type.typeSemantic(loc, sc2); assert(t.ty == Tdelegate); tfld = cast(TypeFunction)t.nextOf(); } //printf("tfld = %s\n", tfld.toChars()); } } } FuncExp flde = foreachBodyToFunction(sc2, fs, tfld); if (!flde) goto case Terror; // Resolve any forward referenced goto's foreach (i; 0 .. fs.gotos.dim) { GotoStatement gs = cast(GotoStatement)(*fs.gotos)[i].statement; if (!gs.label.statement) { // 'Promote' it to this scope, and replace with a return fs.cases.push(gs); s = new ReturnStatement(Loc.initial, new IntegerExp(fs.cases.dim + 1)); (*fs.gotos)[i].statement = s; } } Expression e = null; Expression ec; if (vinit) { e = new DeclarationExp(loc, vinit); e = e.expressionSemantic(sc2); if (e.op == TOK.error) goto case Terror; } if (taa) { // Check types Parameter p = (*fs.parameters)[0]; bool isRef = (p.storageClass & STC.ref_) != 0; Type ta = p.type; if (dim == 2) { Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index); if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta)) { fs.error("`foreach`: index must be type `%s`, not `%s`", ti.toChars(), ta.toChars()); goto case Terror; } p = (*fs.parameters)[1]; isRef = (p.storageClass & STC.ref_) != 0; ta = p.type; } Type taav = taa.nextOf(); if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta)) { fs.error("`foreach`: value must be type `%s`, not `%s`", taav.toChars(), ta.toChars()); goto case Terror; } /* Call: * extern(C) int _aaApply(void*, in size_t, int delegate(void*)) * _aaApply(aggr, keysize, flde) * * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*)) * _aaApply2(aggr, keysize, flde) */ __gshared const(char)** name = ["_aaApply", "_aaApply2"]; __gshared FuncDeclaration* fdapply = [null, null]; __gshared TypeDelegate* fldeTy = [null, null]; ubyte i = (dim == 2 ? 1 : 0); if (!fdapply[i]) { auto params = new Parameters(); params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null)); params.push(new Parameter(STC.in_, Type.tsize_t, null, null, null)); auto dgparams = new Parameters(); dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); if (dim == 2) dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); fldeTy[i] = new TypeDelegate(new TypeFunction(dgparams, Type.tint32, 0, LINK.d)); params.push(new Parameter(0, fldeTy[i], null, null, null)); fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, name[i]); } auto exps = new Expressions(); exps.push(fs.aggr); auto keysize = taa.index.size(); if (keysize == SIZE_INVALID) goto case Terror; assert(keysize < keysize.max - Target.ptrsize); keysize = (keysize + (Target.ptrsize - 1)) & ~(Target.ptrsize - 1); // paint delegate argument to the type runtime expects Expression fexp = flde; if (!fldeTy[i].equals(flde.type)) { fexp = new CastExp(loc, flde, flde.type); fexp.type = fldeTy[i]; } exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t)); exps.push(fexp); ec = new VarExp(Loc.initial, fdapply[i], false); ec = new CallExp(loc, ec, exps); ec.type = Type.tint32; // don't run semantic() on ec } else if (tab.ty == Tarray || tab.ty == Tsarray) { /* Call: * _aApply(aggr, flde) */ __gshared const(char)** fntab = [ "cc", "cw", "cd", "wc", "cc", "wd", "dc", "dw", "dd" ]; const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1; char[BUFFER_LEN] fdname; int flag; switch (tn.ty) { case Tchar: flag = 0; break; case Twchar: flag = 3; break; case Tdchar: flag = 6; break; default: assert(0); } switch (tnv.ty) { case Tchar: flag += 0; break; case Twchar: flag += 1; break; case Tdchar: flag += 2; break; default: assert(0); } const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim); assert(j < BUFFER_LEN); FuncDeclaration fdapply; TypeDelegate dgty; auto params = new Parameters(); params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null)); auto dgparams = new Parameters(); dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); if (dim == 2) dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); dgty = new TypeDelegate(new TypeFunction(dgparams, Type.tint32, 0, LINK.d)); params.push(new Parameter(0, dgty, null, null, null)); fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr); if (tab.ty == Tsarray) fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf()); // paint delegate argument to the type runtime expects Expression fexp = flde; if (!dgty.equals(flde.type)) { fexp = new CastExp(loc, flde, flde.type); fexp.type = dgty; } ec = new VarExp(Loc.initial, fdapply, false); ec = new CallExp(loc, ec, fs.aggr, fexp); ec.type = Type.tint32; // don't run semantic() on ec } else if (tab.ty == Tdelegate) { /* Call: * aggr(flde) */ if (fs.aggr.op == TOK.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested()) { // https://issues.dlang.org/show_bug.cgi?id=3560 fs.aggr = (cast(DelegateExp)fs.aggr).e1; } ec = new CallExp(loc, fs.aggr, flde); ec = ec.expressionSemantic(sc2); if (ec.op == TOK.error) goto case Terror; if (ec.type != Type.tint32) { fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); goto case Terror; } } else { version (none) { if (global.params.vsafe) { message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); } flde.fd.tookAddressOf = 1; } else { if (global.params.vsafe) ++flde.fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); assert(sapply); /* Call: * aggr.apply(flde) */ ec = new DotIdExp(loc, fs.aggr, sapply.ident); ec = new CallExp(loc, ec, flde); ec = ec.expressionSemantic(sc2); if (ec.op == TOK.error) goto case Terror; if (ec.type != Type.tint32) { fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); goto case Terror; } } e = Expression.combine(e, ec); if (!fs.cases.dim) { // Easy case, a clean exit from the loop e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899 s = new ExpStatement(loc, e); } else { // Construct a switch statement around the return value // of the apply function. auto a = new Statements(); // default: break; takes care of cases 0 and 1 s = new BreakStatement(Loc.initial, null); s = new DefaultStatement(Loc.initial, s); a.push(s); // cases 2... foreach (i, c; *fs.cases) { s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c); a.push(s); } s = new CompoundStatement(loc, a); s = new SwitchStatement(loc, e, s, false); } s = s.statementSemantic(sc2); break; } assert(0); case Terror: s = new ErrorStatement(); break; default: fs.error("`foreach`: `%s` is not an aggregate type", fs.aggr.type.toChars()); goto case Terror; } sc2.pop(); result = s; } /************************************* * Turn foreach body into the function literal: * int delegate(ref T param) { body } * Params: * sc = context * fs = ForeachStatement * tfld = type of function literal to be created, can be null * Returns: * Function literal created, as an expression * null if error. */ static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld) { auto params = new Parameters(); foreach (i; 0 .. fs.parameters.dim) { Parameter p = (*fs.parameters)[i]; StorageClass stc = STC.ref_; Identifier id; p.type = p.type.typeSemantic(fs.loc, sc); p.type = p.type.addStorageClass(p.storageClass); if (tfld) { Parameter prm = Parameter.getNth(tfld.parameters, i); //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars()); stc = prm.storageClass & STC.ref_; id = p.ident; // argument copy is not need. if ((p.storageClass & STC.ref_) != stc) { if (!stc) { fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars()); return null; } goto LcopyArg; } } else if (p.storageClass & STC.ref_) { // default delegate parameters are marked as ref, then // argument copy is not need. id = p.ident; } else { // Make a copy of the ref argument so it isn't // a reference. LcopyArg: id = Identifier.generateId("__applyArg", cast(int)i); Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id)); auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie); v.storage_class |= STC.temp; Statement s = new ExpStatement(fs.loc, v); fs._body = new CompoundStatement(fs.loc, s, fs._body); } params.push(new Parameter(stc, p.type, id, null, null)); } // https://issues.dlang.org/show_bug.cgi?id=13840 // Throwable nested function inside nothrow function is acceptable. StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func); auto tf = new TypeFunction(params, Type.tint32, 0, LINK.d, stc); fs.cases = new Statements(); fs.gotos = new ScopeStatements(); auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs); fld.fbody = fs._body; Expression flde = new FuncExp(fs.loc, fld); flde = flde.expressionSemantic(sc); fld.tookAddressOf = 0; if (flde.op == TOK.error) return null; return cast(FuncExp)flde; } override void visit(ForeachRangeStatement fs) { /* https://dlang.org/spec/statement.html#foreach-range-statement */ //printf("ForeachRangeStatement::semantic() %p\n", fs); auto loc = fs.loc; fs.lwr = fs.lwr.expressionSemantic(sc); fs.lwr = resolveProperties(sc, fs.lwr); fs.lwr = fs.lwr.optimize(WANTvalue); if (!fs.lwr.type) { fs.error("invalid range lower bound `%s`", fs.lwr.toChars()); return setError(); } fs.upr = fs.upr.expressionSemantic(sc); fs.upr = resolveProperties(sc, fs.upr); fs.upr = fs.upr.optimize(WANTvalue); if (!fs.upr.type) { fs.error("invalid range upper bound `%s`", fs.upr.toChars()); return setError(); } if (fs.prm.type) { fs.prm.type = fs.prm.type.typeSemantic(loc, sc); fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass); fs.lwr = fs.lwr.implicitCastTo(sc, fs.prm.type); if (fs.upr.implicitConvTo(fs.prm.type) || (fs.prm.storageClass & STC.ref_)) { fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type); } else { // See if upr-1 fits in prm.type Expression limit = new MinExp(loc, fs.upr, new IntegerExp(1)); limit = limit.expressionSemantic(sc); limit = limit.optimize(WANTvalue); if (!limit.implicitConvTo(fs.prm.type)) { fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type); } } } else { /* Must infer types from lwr and upr */ Type tlwr = fs.lwr.type.toBasetype(); if (tlwr.ty == Tstruct || tlwr.ty == Tclass) { /* Just picking the first really isn't good enough. */ fs.prm.type = fs.lwr.type; } else if (fs.lwr.type == fs.upr.type) { /* Same logic as CondExp ?lwr:upr */ fs.prm.type = fs.lwr.type; } else { scope AddExp ea = new AddExp(loc, fs.lwr, fs.upr); if (typeCombine(ea, sc)) return setError(); fs.prm.type = ea.type; fs.lwr = ea.e1; fs.upr = ea.e2; } fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass); } if (fs.prm.type.ty == Terror || fs.lwr.op == TOK.error || fs.upr.op == TOK.error) { return setError(); } /* Convert to a for loop: * foreach (key; lwr .. upr) => * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) * * foreach_reverse (key; lwr .. upr) => * for (auto tmp = lwr, auto key = upr; key-- > tmp;) */ auto ie = new ExpInitializer(loc, (fs.op == TOK.foreach_) ? fs.lwr : fs.upr); fs.key = new VarDeclaration(loc, fs.upr.type.mutableOf(), Identifier.generateId("__key"), ie); fs.key.storage_class |= STC.temp; SignExtendedNumber lower = getIntRange(fs.lwr).imin; SignExtendedNumber upper = getIntRange(fs.upr).imax; if (lower <= upper) { fs.key.range = new IntRange(lower, upper); } Identifier id = Identifier.generateId("__limit"); ie = new ExpInitializer(loc, (fs.op == TOK.foreach_) ? fs.upr : fs.lwr); auto tmp = new VarDeclaration(loc, fs.upr.type, id, ie); tmp.storage_class |= STC.temp; auto cs = new Statements(); // Keep order of evaluation as lwr, then upr if (fs.op == TOK.foreach_) { cs.push(new ExpStatement(loc, fs.key)); cs.push(new ExpStatement(loc, tmp)); } else { cs.push(new ExpStatement(loc, tmp)); cs.push(new ExpStatement(loc, fs.key)); } Statement forinit = new CompoundDeclarationStatement(loc, cs); Expression cond; if (fs.op == TOK.foreach_reverse_) { cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key)); if (fs.prm.type.isscalar()) { // key-- > tmp cond = new CmpExp(TOK.greaterThan, loc, cond, new VarExp(loc, tmp)); } else { // key-- != tmp cond = new EqualExp(TOK.notEqual, loc, cond, new VarExp(loc, tmp)); } } else { if (fs.prm.type.isscalar()) { // key < tmp cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp)); } else { // key != tmp cond = new EqualExp(TOK.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp)); } } Expression increment = null; if (fs.op == TOK.foreach_) { // key += 1 //increment = new AddAssignExp(loc, new VarExp(loc, fs.key), new IntegerExp(1)); increment = new PreExp(TOK.prePlusPlus, loc, new VarExp(loc, fs.key)); } if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type)) { fs.key.range = null; auto v = new AliasDeclaration(loc, fs.prm.ident, fs.key); fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body); } else { ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.prm.type)); auto v = new VarDeclaration(loc, fs.prm.type, fs.prm.ident, ie); v.storage_class |= STC.temp | STC.foreach_ | (fs.prm.storageClass & STC.ref_); fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body); if (fs.key.range && !fs.prm.type.isMutable()) { /* Limit the range of the key to the specified range */ v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1)); } } if (fs.prm.storageClass & STC.ref_) { if (fs.key.type.constConv(fs.prm.type) <= MATCH.nomatch) { fs.error("argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars()); return setError(); } } auto s = new ForStatement(loc, forinit, cond, increment, fs._body, fs.endloc); if (LabelStatement ls = checkLabeledLoop(sc, fs)) ls.gotoTarget = s; result = s.statementSemantic(sc); } override void visit(IfStatement ifs) { /* https://dlang.org/spec/statement.html#IfStatement */ // check in syntax level ifs.condition = checkAssignmentAsCondition(ifs.condition); auto sym = new ScopeDsymbol(); sym.parent = sc.scopesym; sym.endlinnum = ifs.endloc.linnum; Scope* scd = sc.push(sym); if (ifs.prm) { /* Declare prm, which we will set to be the * result of condition. */ auto ei = new ExpInitializer(ifs.loc, ifs.condition); ifs.match = new VarDeclaration(ifs.loc, ifs.prm.type, ifs.prm.ident, ei); ifs.match.parent = scd.func; ifs.match.storage_class |= ifs.prm.storageClass; ifs.match.dsymbolSemantic(scd); auto de = new DeclarationExp(ifs.loc, ifs.match); auto ve = new VarExp(ifs.loc, ifs.match); ifs.condition = new CommaExp(ifs.loc, de, ve); ifs.condition = ifs.condition.expressionSemantic(scd); if (ifs.match.edtor) { Statement sdtor = new DtorExpStatement(ifs.loc, ifs.match.edtor, ifs.match); sdtor = new OnScopeStatement(ifs.loc, TOK.onScopeExit, sdtor); ifs.ifbody = new CompoundStatement(ifs.loc, sdtor, ifs.ifbody); ifs.match.storage_class |= STC.nodtor; } } else { if (ifs.condition.op == TOK.dotIdentifier) (cast(DotIdExp)ifs.condition).noderef = true; ifs.condition = ifs.condition.expressionSemantic(scd); ifs.condition = resolveProperties(scd, ifs.condition); ifs.condition = ifs.condition.addDtorHook(scd); } if (checkNonAssignmentArrayOp(ifs.condition)) ifs.condition = new ErrorExp(); ifs.condition = checkGC(scd, ifs.condition); // Convert to boolean after declaring prm so this works: // if (S prm = S()) {} // where S is a struct that defines opCast!bool. ifs.condition = ifs.condition.toBoolean(scd); // If we can short-circuit evaluate the if statement, don't do the // semantic analysis of the skipped code. // This feature allows a limited form of conditional compilation. ifs.condition = ifs.condition.optimize(WANTvalue); // Save 'root' of two branches (then and else) at the point where it forks CtorFlow ctorflow_root = scd.ctorflow.clone(); ifs.ifbody = ifs.ifbody.semanticNoScope(scd); scd.pop(); CtorFlow ctorflow_then = sc.ctorflow; // move flow results sc.ctorflow = ctorflow_root; // reset flow analysis back to root if (ifs.elsebody) ifs.elsebody = ifs.elsebody.semanticScope(sc, null, null); // Merge 'then' results into 'else' results sc.merge(ifs.loc, ctorflow_then); ctorflow_then.freeFieldinit(); // free extra copy of the data if (ifs.condition.op == TOK.error || (ifs.ifbody && ifs.ifbody.isErrorStatement()) || (ifs.elsebody && ifs.elsebody.isErrorStatement())) { return setError(); } result = ifs; } override void visit(ConditionalStatement cs) { //printf("ConditionalStatement::semantic()\n"); // If we can short-circuit evaluate the if statement, don't do the // semantic analysis of the skipped code. // This feature allows a limited form of conditional compilation. if (cs.condition.include(sc)) { DebugCondition dc = cs.condition.isDebugCondition(); if (dc) { sc = sc.push(); sc.flags |= SCOPE.debug_; cs.ifbody = cs.ifbody.statementSemantic(sc); sc.pop(); } else cs.ifbody = cs.ifbody.statementSemantic(sc); result = cs.ifbody; } else { if (cs.elsebody) cs.elsebody = cs.elsebody.statementSemantic(sc); result = cs.elsebody; } } override void visit(PragmaStatement ps) { /* https://dlang.org/spec/statement.html#pragma-statement */ // Should be merged with PragmaDeclaration //printf("PragmaStatement::semantic() %s\n", ps.toChars()); //printf("body = %p\n", ps._body); if (ps.ident == Id.msg) { if (ps.args) { foreach (arg; *ps.args) { sc = sc.startCTFE(); auto e = arg.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); // pragma(msg) is allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); if (e.op == TOK.error) { errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); return setError(); } StringExp se = e.toStringExp(); if (se) { se = se.toUTF8(sc); fprintf(stderr, "%.*s", cast(int)se.len, se.string); } else fprintf(stderr, "%s", e.toChars()); } fprintf(stderr, "\n"); } } else if (ps.ident == Id.lib) { version (all) { /* Should this be allowed? */ ps.error("`pragma(lib)` not allowed as statement"); return setError(); } else { if (!ps.args || ps.args.dim != 1) { ps.error("`string` expected for library name"); return setError(); } else { auto se = semanticString(sc, (*ps.args)[0], "library name"); if (!se) return setError(); if (global.params.verbose) { message("library %.*s", cast(int)se.len, se.string); } } } } else if (ps.ident == Id.linkerDirective) { /* Should this be allowed? */ ps.error("`pragma(linkerDirective)` not allowed as statement"); return setError(); } else if (ps.ident == Id.startaddress) { if (!ps.args || ps.args.dim != 1) ps.error("function name expected for start address"); else { Expression e = (*ps.args)[0]; sc = sc.startCTFE(); e = e.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); e = e.ctfeInterpret(); (*ps.args)[0] = e; Dsymbol sa = getDsymbol(e); if (!sa || !sa.isFuncDeclaration()) { ps.error("function name expected for start address, not `%s`", e.toChars()); return setError(); } if (ps._body) { ps._body = ps._body.statementSemantic(sc); if (ps._body.isErrorStatement()) { result = ps._body; return; } } result = ps; return; } } else if (ps.ident == Id.Pinline) { PINLINE inlining = PINLINE.default_; if (!ps.args || ps.args.dim == 0) inlining = PINLINE.default_; else if (!ps.args || ps.args.dim != 1) { ps.error("boolean expression expected for `pragma(inline)`"); return setError(); } else { Expression e = (*ps.args)[0]; if (e.op != TOK.int64 || !e.type.equals(Type.tbool)) { ps.error("pragma(inline, true or false) expected, not `%s`", e.toChars()); return setError(); } if (e.isBool(true)) inlining = PINLINE.always; else if (e.isBool(false)) inlining = PINLINE.never; FuncDeclaration fd = sc.func; if (!fd) { ps.error("`pragma(inline)` is not inside a function"); return setError(); } fd.inlining = inlining; } } else if (!global.params.ignoreUnsupportedPragmas) { ps.error("unrecognized `pragma(%s)`", ps.ident.toChars()); return setError(); } if (ps._body) { if (ps.ident == Id.msg || ps.ident == Id.startaddress) { ps.error("`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); return setError(); } ps._body = ps._body.statementSemantic(sc); } result = ps._body; } override void visit(StaticAssertStatement s) { s.sa.semantic2(sc); } override void visit(SwitchStatement ss) { /* https://dlang.org/spec/statement.html#switch-statement */ //printf("SwitchStatement::semantic(%p)\n", ss); ss.tf = sc.tf; if (ss.cases) { result = ss; // already run return; } bool conditionError = false; ss.condition = ss.condition.expressionSemantic(sc); ss.condition = resolveProperties(sc, ss.condition); Type att = null; TypeEnum te = null; while (ss.condition.op != TOK.error) { // preserve enum type for final switches if (ss.condition.type.ty == Tenum) te = cast(TypeEnum)ss.condition.type; if (ss.condition.type.isString()) { // If it's not an array, cast it to one if (ss.condition.type.ty != Tarray) { ss.condition = ss.condition.implicitCastTo(sc, ss.condition.type.nextOf().arrayOf()); } ss.condition.type = ss.condition.type.constOf(); break; } ss.condition = integralPromotions(ss.condition, sc); if (ss.condition.op != TOK.error && ss.condition.type.isintegral()) break; auto ad = isAggregate(ss.condition.type); if (ad && ad.aliasthis && ss.condition.type != att) { if (!att && ss.condition.type.checkAliasThisRec()) att = ss.condition.type; if (auto e = resolveAliasThis(sc, ss.condition, true)) { ss.condition = e; continue; } } if (ss.condition.op != TOK.error) { ss.error("`%s` must be of integral or string type, it is a `%s`", ss.condition.toChars(), ss.condition.type.toChars()); conditionError = true; break; } } if (checkNonAssignmentArrayOp(ss.condition)) ss.condition = new ErrorExp(); ss.condition = ss.condition.optimize(WANTvalue); ss.condition = checkGC(sc, ss.condition); if (ss.condition.op == TOK.error) conditionError = true; bool needswitcherror = false; ss.lastVar = sc.lastVar; sc = sc.push(); sc.sbreak = ss; sc.sw = ss; ss.cases = new CaseStatements(); const inLoopSave = sc.inLoop; sc.inLoop = true; // BUG: should use Scope::mergeCallSuper() for each case instead ss._body = ss._body.statementSemantic(sc); sc.inLoop = inLoopSave; if (conditionError || ss._body.isErrorStatement()) { sc.pop(); return setError(); } // Resolve any goto case's with exp Lgotocase: foreach (gcs; ss.gotoCases) { if (!gcs.exp) { gcs.error("no `case` statement following `goto case;`"); sc.pop(); return setError(); } for (Scope* scx = sc; scx; scx = scx.enclosing) { if (!scx.sw) continue; foreach (cs; *scx.sw.cases) { if (cs.exp.equals(gcs.exp)) { gcs.cs = cs; continue Lgotocase; } } } gcs.error("`case %s` not found", gcs.exp.toChars()); sc.pop(); return setError(); } if (ss.isFinal) { Type t = ss.condition.type; Dsymbol ds; EnumDeclaration ed = null; if (t && ((ds = t.toDsymbol(sc)) !is null)) ed = ds.isEnumDeclaration(); // typedef'ed enum if (!ed && te && ((ds = te.toDsymbol(sc)) !is null)) ed = ds.isEnumDeclaration(); if (ed) { Lmembers: foreach (es; *ed.members) { EnumMember em = es.isEnumMember(); if (em) { foreach (cs; *ss.cases) { if (cs.exp.equals(em.value) || (!cs.exp.type.isString() && !em.value.type.isString() && cs.exp.toInteger() == em.value.toInteger())) continue Lmembers; } ss.error("`enum` member `%s` not represented in `final switch`", em.toChars()); sc.pop(); return setError(); } } } else needswitcherror = true; } if (!sc.sw.sdefault && (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on)) { ss.hasNoDefault = 1; if (!ss.isFinal && !ss._body.isErrorStatement()) ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`"); // Generate runtime error if the default is hit auto a = new Statements(); CompoundStatement cs; Statement s; if (global.params.useSwitchError == CHECKENABLE.on && global.params.checkAction != CHECKACTION.halt) { if (global.params.checkAction == CHECKACTION.C) { /* Rewrite as an assert(0) and let e2ir generate * the call to the C assert failure function */ s = new ExpStatement(ss.loc, new AssertExp(ss.loc, new IntegerExp(ss.loc, 0, Type.tint32))); } else { Expression sl = new IdentifierExp(ss.loc, Id.empty); sl = new DotIdExp(ss.loc, sl, Id.object); sl = new DotIdExp(ss.loc, sl, Id.__switch_error); Expressions* args = new Expressions(); args.push(new StringExp(ss.loc, cast(char*) ss.loc.filename)); args.push(new IntegerExp(ss.loc.linnum)); sl = new CallExp(ss.loc, sl, args); sl.expressionSemantic(sc); s = new SwitchErrorStatement(ss.loc, sl); } } else s = new ExpStatement(ss.loc, new HaltExp(ss.loc)); a.reserve(2); sc.sw.sdefault = new DefaultStatement(ss.loc, s); a.push(ss._body); if (ss._body.blockExit(sc.func, false) & BE.fallthru) a.push(new BreakStatement(Loc.initial, null)); a.push(sc.sw.sdefault); cs = new CompoundStatement(ss.loc, a); ss._body = cs; } if (ss.checkLabel()) { sc.pop(); return setError(); } if (ss.condition.type.isString()) { // Transform a switch with string labels into a switch with integer labels. // The integer value of each case corresponds to the index of each label // string in the sorted array of label strings. // The value of the integer condition is obtained by calling the druntime template // switch(object.__switch(cond, options...)) {0: {...}, 1: {...}, ...} // We sort a copy of the array of labels because we want to do a binary search in object.__switch, // without modifying the order of the case blocks here in the compiler. size_t numcases = 0; if (ss.cases) numcases = ss.cases.dim; for (size_t i = 0; i < numcases; i++) { CaseStatement cs = (*ss.cases)[i]; cs.index = cast(int)i; } // Make a copy of all the cases so that qsort doesn't scramble the actual // data we pass to codegen (the order of the cases in the switch). CaseStatements *csCopy = (*ss.cases).copy(); extern (C) static int sort_compare(const(void*) x, const(void*) y) @trusted { CaseStatement ox = *cast(CaseStatement *)x; CaseStatement oy = *cast(CaseStatement*)y; return ox.compare(oy); } if (numcases) { import core.stdc.stdlib; qsort(csCopy.data, numcases, CaseStatement.sizeof, cast(_compare_fp_t)&sort_compare); } // The actual lowering auto arguments = new Expressions(); arguments.push(ss.condition); auto compileTimeArgs = new Objects(); // The type & label no. compileTimeArgs.push(new TypeExp(ss.loc, ss.condition.type.nextOf())); // The switch labels foreach (caseString; *csCopy) { compileTimeArgs.push(caseString.exp); } Expression sl = new IdentifierExp(ss.loc, Id.empty); sl = new DotIdExp(ss.loc, sl, Id.object); sl = new DotTemplateInstanceExp(ss.loc, sl, Id.__switch, compileTimeArgs); sl = new CallExp(ss.loc, sl, arguments); sl.expressionSemantic(sc); ss.condition = sl; auto i = 0; foreach (c; *csCopy) { (*ss.cases)[c.index].exp = new IntegerExp(i++); } //printf("%s\n", ss._body.toChars()); ss.statementSemantic(sc); } sc.pop(); result = ss; } override void visit(CaseStatement cs) { SwitchStatement sw = sc.sw; bool errors = false; //printf("CaseStatement::semantic() %s\n", toChars()); sc = sc.startCTFE(); cs.exp = cs.exp.expressionSemantic(sc); cs.exp = resolveProperties(sc, cs.exp); sc = sc.endCTFE(); if (sw) { cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type); cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); Expression e = cs.exp; // Remove all the casts the user and/or implicitCastTo may introduce // otherwise we'd sometimes fail the check below. while (e.op == TOK.cast_) e = (cast(CastExp)e).e1; /* This is where variables are allowed as case expressions. */ if (e.op == TOK.variable) { VarExp ve = cast(VarExp)e; VarDeclaration v = ve.var.isVarDeclaration(); Type t = cs.exp.type.toBasetype(); if (v && (t.isintegral() || t.ty == Tclass)) { /* Flag that we need to do special code generation * for this, i.e. generate a sequence of if-then-else */ sw.hasVars = 1; /* TODO check if v can be uninitialized at that point. */ if (!v.isConst() && !v.isImmutable()) { cs.deprecation("`case` variables have to be `const` or `immutable`"); } if (sw.isFinal) { cs.error("`case` variables not allowed in `final switch` statements"); errors = true; } /* Find the outermost scope `scx` that set `sw`. * Then search scope `scx` for a declaration of `v`. */ for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx.enclosing && scx.enclosing.sw == sw) continue; assert(scx.sw == sw); if (!scx.search(cs.exp.loc, v.ident, null)) { cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", v.toChars(), v.loc.toChars()); errors = true; } break; } goto L1; } } else cs.exp = cs.exp.ctfeInterpret(); if (StringExp se = cs.exp.toStringExp()) cs.exp = se; else if (cs.exp.op != TOK.int64 && cs.exp.op != TOK.error) { cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars()); errors = true; } L1: foreach (cs2; *sw.cases) { //printf("comparing '%s' with '%s'\n", exp.toChars(), cs.exp.toChars()); if (cs2.exp.equals(cs.exp)) { cs.error("duplicate `case %s` in `switch` statement", cs.exp.toChars()); errors = true; break; } } sw.cases.push(cs); // Resolve any goto case's with no exp to this case statement for (size_t i = 0; i < sw.gotoCases.dim;) { GotoCaseStatement gcs = sw.gotoCases[i]; if (!gcs.exp) { gcs.cs = cs; sw.gotoCases.remove(i); // remove from array continue; } i++; } if (sc.sw.tf != sc.tf) { cs.error("`switch` and `case` are in different `finally` blocks"); errors = true; } } else { cs.error("`case` not in `switch` statement"); errors = true; } sc.ctorflow.orCSX(CSX.label); cs.statement = cs.statement.statementSemantic(sc); if (cs.statement.isErrorStatement()) { result = cs.statement; return; } if (errors || cs.exp.op == TOK.error) return setError(); cs.lastVar = sc.lastVar; result = cs; } override void visit(CaseRangeStatement crs) { SwitchStatement sw = sc.sw; if (sw is null) { crs.error("case range not in `switch` statement"); return setError(); } //printf("CaseRangeStatement::semantic() %s\n", toChars()); bool errors = false; if (sw.isFinal) { crs.error("case ranges not allowed in `final switch`"); errors = true; } sc = sc.startCTFE(); crs.first = crs.first.expressionSemantic(sc); crs.first = resolveProperties(sc, crs.first); sc = sc.endCTFE(); crs.first = crs.first.implicitCastTo(sc, sw.condition.type); crs.first = crs.first.ctfeInterpret(); sc = sc.startCTFE(); crs.last = crs.last.expressionSemantic(sc); crs.last = resolveProperties(sc, crs.last); sc = sc.endCTFE(); crs.last = crs.last.implicitCastTo(sc, sw.condition.type); crs.last = crs.last.ctfeInterpret(); if (crs.first.op == TOK.error || crs.last.op == TOK.error || errors) { if (crs.statement) crs.statement.statementSemantic(sc); return setError(); } uinteger_t fval = crs.first.toInteger(); uinteger_t lval = crs.last.toInteger(); if ((crs.first.type.isunsigned() && fval > lval) || (!crs.first.type.isunsigned() && cast(sinteger_t)fval > cast(sinteger_t)lval)) { crs.error("first `case %s` is greater than last `case %s`", crs.first.toChars(), crs.last.toChars()); errors = true; lval = fval; } if (lval - fval > 256) { crs.error("had %llu cases which is more than 256 cases in case range", lval - fval); errors = true; lval = fval + 256; } if (errors) return setError(); /* This works by replacing the CaseRange with an array of Case's. * * case a: .. case b: s; * => * case a: * [...] * case b: * s; */ auto statements = new Statements(); for (uinteger_t i = fval; i != lval + 1; i++) { Statement s = crs.statement; if (i != lval) // if not last case s = new ExpStatement(crs.loc, cast(Expression)null); Expression e = new IntegerExp(crs.loc, i, crs.first.type); Statement cs = new CaseStatement(crs.loc, e, s); statements.push(cs); } Statement s = new CompoundStatement(crs.loc, statements); sc.ctorflow.orCSX(CSX.label); s = s.statementSemantic(sc); result = s; } override void visit(DefaultStatement ds) { //printf("DefaultStatement::semantic()\n"); bool errors = false; if (sc.sw) { if (sc.sw.sdefault) { ds.error("`switch` statement already has a default"); errors = true; } sc.sw.sdefault = ds; if (sc.sw.tf != sc.tf) { ds.error("`switch` and `default` are in different `finally` blocks"); errors = true; } if (sc.sw.isFinal) { ds.error("`default` statement not allowed in `final switch` statement"); errors = true; } } else { ds.error("`default` not in `switch` statement"); errors = true; } sc.ctorflow.orCSX(CSX.label); ds.statement = ds.statement.statementSemantic(sc); if (errors || ds.statement.isErrorStatement()) return setError(); ds.lastVar = sc.lastVar; result = ds; } override void visit(GotoDefaultStatement gds) { /* https://dlang.org/spec/statement.html#goto-statement */ gds.sw = sc.sw; if (!gds.sw) { gds.error("`goto default` not in `switch` statement"); return setError(); } if (gds.sw.isFinal) { gds.error("`goto default` not allowed in `final switch` statement"); return setError(); } result = gds; } override void visit(GotoCaseStatement gcs) { /* https://dlang.org/spec/statement.html#goto-statement */ if (!sc.sw) { gcs.error("`goto case` not in `switch` statement"); return setError(); } if (gcs.exp) { gcs.exp = gcs.exp.expressionSemantic(sc); gcs.exp = gcs.exp.implicitCastTo(sc, sc.sw.condition.type); gcs.exp = gcs.exp.optimize(WANTvalue); if (gcs.exp.op == TOK.error) return setError(); } sc.sw.gotoCases.push(gcs); result = gcs; } override void visit(ReturnStatement rs) { /* https://dlang.org/spec/statement.html#return-statement */ //printf("ReturnStatement.dsymbolSemantic() %p, %s\n", rs, rs.toChars()); FuncDeclaration fd = sc.parent.isFuncDeclaration(); if (fd.fes) fd = fd.fes.func; // fd is now function enclosing foreach TypeFunction tf = cast(TypeFunction)fd.type; assert(tf.ty == Tfunction); if (rs.exp && rs.exp.op == TOK.variable && (cast(VarExp)rs.exp).var == fd.vresult) { // return vresult; if (sc.fes) { assert(rs.caseDim == 0); sc.fes.cases.push(rs); result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1)); return; } if (fd.returnLabel) { auto gs = new GotoStatement(rs.loc, Id.returnLabel); gs.label = fd.returnLabel; result = gs; return; } if (!fd.returns) fd.returns = new ReturnStatements(); fd.returns.push(rs); result = rs; return; } Type tret = tf.next; Type tbret = tret ? tret.toBasetype() : null; bool inferRef = (tf.isref && (fd.storage_class & STC.auto_)); Expression e0 = null; bool errors = false; if (sc.flags & SCOPE.contract) { rs.error("`return` statements cannot be in contracts"); errors = true; } if (sc.os && sc.os.tok != TOK.onScopeFailure) { rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); errors = true; } if (sc.tf) { rs.error("`return` statements cannot be in `finally` bodies"); errors = true; } if (fd.isCtorDeclaration()) { if (rs.exp) { rs.error("cannot return expression from constructor"); errors = true; } // Constructors implicitly do: // return this; rs.exp = new ThisExp(Loc.initial); rs.exp.type = tret; } else if (rs.exp) { fd.hasReturnExp |= (fd.hasReturnExp & 1 ? 16 : 1); FuncLiteralDeclaration fld = fd.isFuncLiteralDeclaration(); if (tret) rs.exp = inferType(rs.exp, tret); else if (fld && fld.treq) rs.exp = inferType(rs.exp, fld.treq.nextOf().nextOf()); rs.exp = rs.exp.expressionSemantic(sc); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 if (rs.exp.op == TOK.type) rs.exp = resolveAliasThis(sc, rs.exp); rs.exp = resolveProperties(sc, rs.exp); if (rs.exp.checkType()) rs.exp = new ErrorExp(); if (auto f = isFuncAddress(rs.exp)) { if (fd.inferRetType && f.checkForwardRef(rs.exp.loc)) rs.exp = new ErrorExp(); } if (checkNonAssignmentArrayOp(rs.exp)) rs.exp = new ErrorExp(); // Extract side-effect part rs.exp = Expression.extractLast(rs.exp, e0); if (rs.exp.op == TOK.call) rs.exp = valueNoDtor(rs.exp); if (e0) e0 = e0.optimize(WANTvalue); /* Void-return function can have void typed expression * on return statement. */ if (tbret && tbret.ty == Tvoid || rs.exp.type.ty == Tvoid) { if (rs.exp.type.ty != Tvoid) { rs.error("cannot return non-void from `void` function"); errors = true; rs.exp = new CastExp(rs.loc, rs.exp, Type.tvoid); rs.exp = rs.exp.expressionSemantic(sc); } /* Replace: * return exp; * with: * exp; return; */ e0 = Expression.combine(e0, rs.exp); rs.exp = null; } if (e0) e0 = checkGC(sc, e0); } if (rs.exp) { if (fd.inferRetType) // infer return type { if (!tret) { tf.next = rs.exp.type; } else if (tret.ty != Terror && !rs.exp.type.equals(tret)) { int m1 = rs.exp.type.implicitConvTo(tret); int m2 = tret.implicitConvTo(rs.exp.type); //printf("exp.type = %s m2<-->m1 tret %s\n", exp.type.toChars(), tret.toChars()); //printf("m1 = %d, m2 = %d\n", m1, m2); if (m1 && m2) { } else if (!m1 && m2) tf.next = rs.exp.type; else if (m1 && !m2) { } else if (rs.exp.op != TOK.error) { rs.error("mismatched function return type inference of `%s` and `%s`", rs.exp.type.toChars(), tret.toChars()); errors = true; tf.next = Type.terror; } } tret = tf.next; tbret = tret.toBasetype(); } if (inferRef) // deduce 'auto ref' { /* Determine "refness" of function return: * if it's an lvalue, return by ref, else return by value * https://dlang.org/spec/function.html#auto-ref-functions */ void turnOffRef() { tf.isref = false; // return by value tf.isreturn = false; // ignore 'return' attribute, whether explicit or inferred fd.storage_class &= ~STC.return_; } if (rs.exp.isLvalue()) { /* May return by ref */ if (checkReturnEscapeRef(sc, rs.exp, true)) turnOffRef(); else if (!rs.exp.type.constConv(tf.next)) turnOffRef(); } else turnOffRef(); /* The "refness" is determined by all of return statements. * This means: * return 3; return x; // ok, x can be a value * return x; return 3; // ok, x can be a value */ } // handle NRVO if (fd.nrvo_can && rs.exp.op == TOK.variable) { VarExp ve = cast(VarExp)rs.exp; VarDeclaration v = ve.var.isVarDeclaration(); if (tf.isref) { // Function returns a reference if (!inferRef) fd.nrvo_can = 0; } else if (!v || v.isOut() || v.isRef()) fd.nrvo_can = 0; else if (fd.nrvo_var is null) { if (!v.isDataseg() && !v.isParameter() && v.toParent2() == fd) { //printf("Setting nrvo to %s\n", v.toChars()); fd.nrvo_var = v; } else fd.nrvo_can = 0; } else if (fd.nrvo_var != v) fd.nrvo_can = 0; } else //if (!exp.isLvalue()) // keep NRVO-ability fd.nrvo_can = 0; } else { // handle NRVO fd.nrvo_can = 0; // infer return type if (fd.inferRetType) { if (tf.next && tf.next.ty != Tvoid) { if (tf.next.ty != Terror) { rs.error("mismatched function return type inference of `void` and `%s`", tf.next.toChars()); } errors = true; tf.next = Type.terror; } else tf.next = Type.tvoid; tret = tf.next; tbret = tret.toBasetype(); } if (inferRef) // deduce 'auto ref' tf.isref = false; if (tbret.ty != Tvoid) // if non-void return { if (tbret.ty != Terror) rs.error("`return` expression expected"); errors = true; } else if (fd.isMain()) { // main() returns 0, even if it returns void rs.exp = new IntegerExp(0); } } // If any branches have called a ctor, but this branch hasn't, it's an error if (sc.ctorflow.callSuper & CSX.any_ctor && !(sc.ctorflow.callSuper & (CSX.this_ctor | CSX.super_ctor))) { rs.error("`return` without calling constructor"); errors = true; } if (sc.ctorflow.fieldinit.length) // if aggregate fields are being constructed { auto ad = fd.isMember2(); assert(ad); foreach (i, v; ad.fields) { bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested()); if (mustInit && !(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) { rs.error("an earlier `return` statement skips field `%s` initialization", v.toChars()); errors = true; } } } sc.ctorflow.orCSX(CSX.return_); if (errors) return setError(); if (sc.fes) { if (!rs.exp) { // Send out "case receiver" statement to the foreach. // return exp; Statement s = new ReturnStatement(Loc.initial, rs.exp); sc.fes.cases.push(s); // Immediately rewrite "this" return statement as: // return cases.dim+1; rs.exp = new IntegerExp(sc.fes.cases.dim + 1); if (e0) { result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs); return; } result = rs; return; } else { fd.buildResultVar(null, rs.exp.type); bool r = fd.vresult.checkNestedReference(sc, Loc.initial); assert(!r); // vresult should be always accessible // Send out "case receiver" statement to the foreach. // return vresult; Statement s = new ReturnStatement(Loc.initial, new VarExp(Loc.initial, fd.vresult)); sc.fes.cases.push(s); // Save receiver index for the later rewriting from: // return exp; // to: // vresult = exp; retrun caseDim; rs.caseDim = sc.fes.cases.dim + 1; } } if (rs.exp) { if (!fd.returns) fd.returns = new ReturnStatements(); fd.returns.push(rs); } if (e0) { result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs); return; } result = rs; } override void visit(BreakStatement bs) { /* https://dlang.org/spec/statement.html#break-statement */ //printf("BreakStatement::semantic()\n"); // If: // break Identifier; if (bs.ident) { bs.ident = fixupLabelName(sc, bs.ident); FuncDeclaration thisfunc = sc.func; for (Scope* scx = sc; scx; scx = scx.enclosing) { if (scx.func != thisfunc) // if in enclosing function { if (sc.fes) // if this is the body of a foreach { /* Post this statement to the fes, and replace * it with a return value that caller will put into * a switch. Caller will figure out where the break * label actually is. * Case numbers start with 2, not 0, as 0 is continue * and 1 is break. */ sc.fes.cases.push(bs); result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1)); return; } break; // can't break to it } LabelStatement ls = scx.slabel; if (ls && ls.ident == bs.ident) { Statement s = ls.statement; if (!s || !s.hasBreak()) bs.error("label `%s` has no `break`", bs.ident.toChars()); else if (ls.tf != sc.tf) bs.error("cannot break out of `finally` block"); else { ls.breaks = true; result = bs; return; } return setError(); } } bs.error("enclosing label `%s` for `break` not found", bs.ident.toChars()); return setError(); } else if (!sc.sbreak) { if (sc.os && sc.os.tok != TOK.onScopeFailure) { bs.error("`break` is not inside `%s` bodies", Token.toChars(sc.os.tok)); } else if (sc.fes) { // Replace break; with return 1; result = new ReturnStatement(Loc.initial, new IntegerExp(1)); return; } else bs.error("`break` is not inside a loop or `switch`"); return setError(); } else if (sc.sbreak.isForwardingStatement()) { bs.error("must use labeled `break` within `static foreach`"); } result = bs; } override void visit(ContinueStatement cs) { /* https://dlang.org/spec/statement.html#continue-statement */ //printf("ContinueStatement::semantic() %p\n", cs); if (cs.ident) { cs.ident = fixupLabelName(sc, cs.ident); Scope* scx; FuncDeclaration thisfunc = sc.func; for (scx = sc; scx; scx = scx.enclosing) { LabelStatement ls; if (scx.func != thisfunc) // if in enclosing function { if (sc.fes) // if this is the body of a foreach { for (; scx; scx = scx.enclosing) { ls = scx.slabel; if (ls && ls.ident == cs.ident && ls.statement == sc.fes) { // Replace continue ident; with return 0; result = new ReturnStatement(Loc.initial, new IntegerExp(0)); return; } } /* Post this statement to the fes, and replace * it with a return value that caller will put into * a switch. Caller will figure out where the break * label actually is. * Case numbers start with 2, not 0, as 0 is continue * and 1 is break. */ sc.fes.cases.push(cs); result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1)); return; } break; // can't continue to it } ls = scx.slabel; if (ls && ls.ident == cs.ident) { Statement s = ls.statement; if (!s || !s.hasContinue()) cs.error("label `%s` has no `continue`", cs.ident.toChars()); else if (ls.tf != sc.tf) cs.error("cannot continue out of `finally` block"); else { result = cs; return; } return setError(); } } cs.error("enclosing label `%s` for `continue` not found", cs.ident.toChars()); return setError(); } else if (!sc.scontinue) { if (sc.os && sc.os.tok != TOK.onScopeFailure) { cs.error("`continue` is not inside `%s` bodies", Token.toChars(sc.os.tok)); } else if (sc.fes) { // Replace continue; with return 0; result = new ReturnStatement(Loc.initial, new IntegerExp(0)); return; } else cs.error("`continue` is not inside a loop"); return setError(); } else if (sc.scontinue.isForwardingStatement()) { cs.error("must use labeled `continue` within `static foreach`"); } result = cs; } override void visit(SynchronizedStatement ss) { /* https://dlang.org/spec/statement.html#synchronized-statement */ if (ss.exp) { ss.exp = ss.exp.expressionSemantic(sc); ss.exp = resolveProperties(sc, ss.exp); ss.exp = ss.exp.optimize(WANTvalue); ss.exp = checkGC(sc, ss.exp); if (ss.exp.op == TOK.error) { if (ss._body) ss._body = ss._body.statementSemantic(sc); return setError(); } ClassDeclaration cd = ss.exp.type.isClassHandle(); if (!cd) { ss.error("can only `synchronize` on class objects, not `%s`", ss.exp.type.toChars()); return setError(); } else if (cd.isInterfaceDeclaration()) { /* Cast the interface to an object, as the object has the monitor, * not the interface. */ if (!ClassDeclaration.object) { ss.error("missing or corrupt object.d"); fatal(); } Type t = ClassDeclaration.object.type; t = t.typeSemantic(Loc.initial, sc).toBasetype(); assert(t.ty == Tclass); ss.exp = new CastExp(ss.loc, ss.exp, t); ss.exp = ss.exp.expressionSemantic(sc); } version (all) { /* Rewrite as: * auto tmp = exp; * _d_monitorenter(tmp); * try { body } finally { _d_monitorexit(tmp); } */ auto tmp = copyToTemp(0, "__sync", ss.exp); tmp.dsymbolSemantic(sc); auto cs = new Statements(); cs.push(new ExpStatement(ss.loc, tmp)); auto args = new Parameters(); args.push(new Parameter(0, ClassDeclaration.object.type, null, null, null)); FuncDeclaration fdenter = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorenter); Expression e = new CallExp(ss.loc, fdenter, new VarExp(ss.loc, tmp)); e.type = Type.tvoid; // do not run semantic on e cs.push(new ExpStatement(ss.loc, e)); FuncDeclaration fdexit = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorexit); e = new CallExp(ss.loc, fdexit, new VarExp(ss.loc, tmp)); e.type = Type.tvoid; // do not run semantic on e Statement s = new ExpStatement(ss.loc, e); s = new TryFinallyStatement(ss.loc, ss._body, s); cs.push(s); s = new CompoundStatement(ss.loc, cs); result = s.statementSemantic(sc); } } else { /* Generate our own critical section, then rewrite as: * static shared align(D_CRITICAL_SECTION.alignof) byte[D_CRITICAL_SECTION.sizeof] __critsec; * _d_criticalenter(&__critsec[0]); * try { body } finally { _d_criticalexit(&__critsec[0]); } */ auto id = Identifier.generateId("__critsec"); auto t = Type.tint8.sarrayOf(Target.ptrsize + Target.critsecsize()); auto tmp = new VarDeclaration(ss.loc, t, id, null); tmp.storage_class |= STC.temp | STC.shared_ | STC.static_; Expression tmpExp = new VarExp(ss.loc, tmp); auto cs = new Statements(); cs.push(new ExpStatement(ss.loc, tmp)); /* This is just a dummy variable for "goto skips declaration" error. * Backend optimizer could remove this unused variable. */ auto v = new VarDeclaration(ss.loc, Type.tvoidptr, Identifier.generateId("__sync"), null); v.dsymbolSemantic(sc); cs.push(new ExpStatement(ss.loc, v)); auto args = new Parameters(); args.push(new Parameter(0, t.pointerTo(), null, null, null)); FuncDeclaration fdenter = FuncDeclaration.genCfunc(args, Type.tvoid, Id.criticalenter, STC.nothrow_); Expression int0 = new IntegerExp(ss.loc, dinteger_t(0), Type.tint8); Expression e = new AddrExp(ss.loc, new IndexExp(ss.loc, tmpExp, int0)); e = e.expressionSemantic(sc); e = new CallExp(ss.loc, fdenter, e); e.type = Type.tvoid; // do not run semantic on e cs.push(new ExpStatement(ss.loc, e)); FuncDeclaration fdexit = FuncDeclaration.genCfunc(args, Type.tvoid, Id.criticalexit, STC.nothrow_); e = new AddrExp(ss.loc, new IndexExp(ss.loc, tmpExp, int0)); e = e.expressionSemantic(sc); e = new CallExp(ss.loc, fdexit, e); e.type = Type.tvoid; // do not run semantic on e Statement s = new ExpStatement(ss.loc, e); s = new TryFinallyStatement(ss.loc, ss._body, s); cs.push(s); s = new CompoundStatement(ss.loc, cs); result = s.statementSemantic(sc); // set the explicit __critsec alignment after semantic() tmp.alignment = Target.ptrsize; } } override void visit(WithStatement ws) { /* https://dlang.org/spec/statement.html#with-statement */ ScopeDsymbol sym; Initializer _init; //printf("WithStatement::semantic()\n"); ws.exp = ws.exp.expressionSemantic(sc); ws.exp = resolveProperties(sc, ws.exp); ws.exp = ws.exp.optimize(WANTvalue); ws.exp = checkGC(sc, ws.exp); if (ws.exp.op == TOK.error) return setError(); if (ws.exp.op == TOK.scope_) { sym = new WithScopeSymbol(ws); sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } else if (ws.exp.op == TOK.type) { Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) { ws.error("`with` type `%s` has no members", ws.exp.toChars()); return setError(); } sym = new WithScopeSymbol(ws); sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } else { Type t = ws.exp.type.toBasetype(); Expression olde = ws.exp; if (t.ty == Tpointer) { ws.exp = new PtrExp(ws.loc, ws.exp); ws.exp = ws.exp.expressionSemantic(sc); t = ws.exp.type.toBasetype(); } assert(t); t = t.toBasetype(); if (t.isClassHandle()) { _init = new ExpInitializer(ws.loc, ws.exp); ws.wthis = new VarDeclaration(ws.loc, ws.exp.type, Id.withSym, _init); ws.wthis.dsymbolSemantic(sc); sym = new WithScopeSymbol(ws); sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } else if (t.ty == Tstruct) { if (!ws.exp.isLvalue()) { /* Re-write to * { * auto __withtmp = exp * with(__withtmp) * { * ... * } * } */ auto tmp = copyToTemp(0, "__withtmp", ws.exp); tmp.dsymbolSemantic(sc); auto es = new ExpStatement(ws.loc, tmp); ws.exp = new VarExp(ws.loc, tmp); Statement ss = new ScopeStatement(ws.loc, new CompoundStatement(ws.loc, es, ws), ws.endloc); result = ss.statementSemantic(sc); return; } Expression e = ws.exp.addressOf(); _init = new ExpInitializer(ws.loc, e); ws.wthis = new VarDeclaration(ws.loc, e.type, Id.withSym, _init); ws.wthis.dsymbolSemantic(sc); sym = new WithScopeSymbol(ws); // Need to set the scope to make use of resolveAliasThis sym.setScope(sc); sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } else { ws.error("`with` expressions must be aggregate types or pointers to them, not `%s`", olde.type.toChars()); return setError(); } } if (ws._body) { sym._scope = sc; sc = sc.push(sym); sc.insert(sym); ws._body = ws._body.statementSemantic(sc); sc.pop(); if (ws._body && ws._body.isErrorStatement()) { result = ws._body; return; } } result = ws; } // https://dlang.org/spec/statement.html#TryStatement override void visit(TryCatchStatement tcs) { //printf("TryCatchStatement.semantic()\n"); if (!global.params.useExceptions) { tcs.error("Cannot use try-catch statements with -betterC"); return setError(); } if (!ClassDeclaration.throwable) { tcs.error("Cannot use try-catch statements because `object.Throwable` was not declared"); return setError(); } uint flags; enum FLAGcpp = 1; enum FLAGd = 2; tcs._body = tcs._body.semanticScope(sc, null, null); assert(tcs._body); /* Even if body is empty, still do semantic analysis on catches */ bool catchErrors = false; foreach (i, c; *tcs.catches) { c.catchSemantic(sc); if (c.errors) { catchErrors = true; continue; } auto cd = c.type.toBasetype().isClassHandle(); flags |= cd.isCPPclass() ? FLAGcpp : FLAGd; // Determine if current catch 'hides' any previous catches foreach (j; 0 .. i) { Catch cj = (*tcs.catches)[j]; const si = c.loc.toChars(); const sj = cj.loc.toChars(); if (c.type.toBasetype().implicitConvTo(cj.type.toBasetype())) { tcs.error("`catch` at %s hides `catch` at %s", sj, si); catchErrors = true; } } } if (sc.func) { sc.func.flags |= FUNCFLAG.hasCatches; if (flags == (FLAGcpp | FLAGd)) { tcs.error("cannot mix catching D and C++ exceptions in the same try-catch"); catchErrors = true; } } if (catchErrors) return setError(); if (tcs._body.isErrorStatement()) { result = tcs._body; return; } /* If the try body never throws, we can eliminate any catches * of recoverable exceptions. */ if (!(tcs._body.blockExit(sc.func, false) & BE.throw_) && ClassDeclaration.exception) { foreach_reverse (i; 0 .. tcs.catches.dim) { Catch c = (*tcs.catches)[i]; /* If catch exception type is derived from Exception */ if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) && (!c.handler || !c.handler.comeFrom())) { // Remove c from the array of catches tcs.catches.remove(i); } } } if (tcs.catches.dim == 0) { result = tcs._body.hasCode() ? tcs._body : null; return; } result = tcs; } override void visit(TryFinallyStatement tfs) { //printf("TryFinallyStatement::semantic()\n"); tfs._body = tfs._body.statementSemantic(sc); sc = sc.push(); sc.tf = tfs; sc.sbreak = null; sc.scontinue = null; // no break or continue out of finally block tfs.finalbody = tfs.finalbody.semanticNoScope(sc); sc.pop(); if (!tfs._body) { result = tfs.finalbody; return; } if (!tfs.finalbody) { result = tfs._body; return; } auto blockexit = tfs._body.blockExit(sc.func, false); // if not worrying about exceptions if (!(global.params.useExceptions && ClassDeclaration.throwable)) blockexit &= ~BE.throw_; // don't worry about paths that otherwise may throw // Don't care about paths that halt, either if ((blockexit & ~BE.halt) == BE.fallthru) { result = new CompoundStatement(tfs.loc, tfs._body, tfs.finalbody); return; } tfs.bodyFallsThru = (blockexit & BE.fallthru) != 0; result = tfs; } override void visit(OnScopeStatement oss) { /* https://dlang.org/spec/statement.html#scope-guard-statement */ if (oss.tok != TOK.onScopeExit) { // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement, // so the generated catch block cannot be placed in finally block. // See also Catch::semantic. if (sc.os && sc.os.tok != TOK.onScopeFailure) { // If enclosing is scope(success) or scope(exit), this will be placed in finally block. oss.error("cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.os.tok)); return setError(); } if (sc.tf) { oss.error("cannot put `%s` statement inside `finally` block", Token.toChars(oss.tok)); return setError(); } } sc = sc.push(); sc.tf = null; sc.os = oss; if (oss.tok != TOK.onScopeFailure) { // Jump out from scope(failure) block is allowed. sc.sbreak = null; sc.scontinue = null; } oss.statement = oss.statement.semanticNoScope(sc); sc.pop(); if (!oss.statement || oss.statement.isErrorStatement()) { result = oss.statement; return; } result = oss; } override void visit(ThrowStatement ts) { /* https://dlang.org/spec/statement.html#throw-statement */ //printf("ThrowStatement::semantic()\n"); if (!global.params.useExceptions) { ts.error("Cannot use `throw` statements with -betterC"); return setError(); } if (!ClassDeclaration.throwable) { ts.error("Cannot use `throw` statements because `object.Throwable` was not declared"); return setError(); } FuncDeclaration fd = sc.parent.isFuncDeclaration(); fd.hasReturnExp |= 2; if (ts.exp.op == TOK.new_) { NewExp ne = cast(NewExp)ts.exp; ne.thrownew = true; } ts.exp = ts.exp.expressionSemantic(sc); ts.exp = resolveProperties(sc, ts.exp); ts.exp = checkGC(sc, ts.exp); if (ts.exp.op == TOK.error) return setError(); checkThrowEscape(sc, ts.exp, false); ClassDeclaration cd = ts.exp.type.toBasetype().isClassHandle(); if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null))) { ts.error("can only throw class objects derived from `Throwable`, not type `%s`", ts.exp.type.toChars()); return setError(); } result = ts; } override void visit(DebugStatement ds) { if (ds.statement) { sc = sc.push(); sc.flags |= SCOPE.debug_; ds.statement = ds.statement.statementSemantic(sc); sc.pop(); } result = ds.statement; } override void visit(GotoStatement gs) { /* https://dlang.org/spec/statement.html#goto-statement */ //printf("GotoStatement::semantic()\n"); FuncDeclaration fd = sc.func; gs.ident = fixupLabelName(sc, gs.ident); gs.label = fd.searchLabel(gs.ident); gs.tf = sc.tf; gs.os = sc.os; gs.lastVar = sc.lastVar; if (!gs.label.statement && sc.fes) { /* Either the goto label is forward referenced or it * is in the function that the enclosing foreach is in. * Can't know yet, so wrap the goto in a scope statement * so we can patch it later, and add it to a 'look at this later' * list. */ auto ss = new ScopeStatement(gs.loc, gs, gs.loc); sc.fes.gotos.push(ss); // 'look at this later' list result = ss; return; } // Add to fwdref list to check later if (!gs.label.statement) { if (!fd.gotos) fd.gotos = new GotoStatements(); fd.gotos.push(gs); } else if (gs.checkLabel()) return setError(); result = gs; } override void visit(LabelStatement ls) { //printf("LabelStatement::semantic()\n"); FuncDeclaration fd = sc.parent.isFuncDeclaration(); ls.ident = fixupLabelName(sc, ls.ident); ls.tf = sc.tf; ls.os = sc.os; ls.lastVar = sc.lastVar; LabelDsymbol ls2 = fd.searchLabel(ls.ident); if (ls2.statement) { ls.error("label `%s` already defined", ls2.toChars()); return setError(); } else ls2.statement = ls; sc = sc.push(); sc.scopesym = sc.enclosing.scopesym; sc.ctorflow.orCSX(CSX.label); sc.slabel = ls; if (ls.statement) ls.statement = ls.statement.statementSemantic(sc); sc.pop(); result = ls; } override void visit(AsmStatement s) { /* https://dlang.org/spec/statement.html#asm */ result = asmSemantic(s, sc); } override void visit(CompoundAsmStatement cas) { // Apply postfix attributes of the asm block to each statement. sc = sc.push(); sc.stc |= cas.stc; foreach (ref s; *cas.statements) { s = s ? s.statementSemantic(sc) : null; } assert(sc.func); // use setImpure/setGC when the deprecation cycle is over PURE purity; if (!(cas.stc & STC.pure_) && (purity = sc.func.isPureBypassingInference()) != PURE.impure && purity != PURE.fwdref) cas.deprecation("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.isNogcBypassingInference()) cas.deprecation("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); if (!(cas.stc & (STC.trusted | STC.safe)) && sc.func.setUnsafe()) cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); sc.pop(); result = cas; } override void visit(ImportStatement imps) { /* https://dlang.org/spec/module.html#ImportDeclaration */ foreach (i; 0 .. imps.imports.dim) { Import s = (*imps.imports)[i].isImport(); assert(!s.aliasdecls.dim); foreach (j, name; s.names) { Identifier _alias = s.aliases[j]; if (!_alias) _alias = name; auto tname = new TypeIdentifier(s.loc, name); auto ad = new AliasDeclaration(s.loc, _alias, tname); ad._import = s; s.aliasdecls.push(ad); } s.dsymbolSemantic(sc); Module.addDeferredSemantic2(s); // https://issues.dlang.org/show_bug.cgi?id=14666 sc.insert(s); foreach (aliasdecl; s.aliasdecls) { sc.insert(aliasdecl); } } result = imps; } } void catchSemantic(Catch c, Scope* sc) { //printf("Catch::semantic(%s)\n", ident.toChars()); if (sc.os && sc.os.tok != TOK.onScopeFailure) { // If enclosing is scope(success) or scope(exit), this will be placed in finally block. error(c.loc, "cannot put `catch` statement inside `%s`", Token.toChars(sc.os.tok)); c.errors = true; } if (sc.tf) { /* This is because the _d_local_unwind() gets the stack munged * up on this. The workaround is to place any try-catches into * a separate function, and call that. * To fix, have the compiler automatically convert the finally * body into a nested function. */ error(c.loc, "cannot put `catch` statement inside `finally` block"); c.errors = true; } auto sym = new ScopeDsymbol(); sym.parent = sc.scopesym; sc = sc.push(sym); if (!c.type) { error(c.loc, "`catch` statement without an exception specification is deprecated"); errorSupplemental(c.loc, "use `catch(Throwable)` for old behavior"); c.errors = true; // reference .object.Throwable c.type = getThrowable(); } c.type = c.type.typeSemantic(c.loc, sc); if (c.type == Type.terror) c.errors = true; else { StorageClass stc; auto cd = c.type.toBasetype().isClassHandle(); if (!cd) { error(c.loc, "can only catch class objects, not `%s`", c.type.toChars()); c.errors = true; } else if (cd.isCPPclass()) { if (!Target.cppExceptions) { error(c.loc, "catching C++ class objects not supported for this target"); c.errors = true; } if (sc.func && !sc.intypeof && !c.internalCatch && sc.func.setUnsafe()) { error(c.loc, "cannot catch C++ class objects in `@safe` code"); c.errors = true; } } else if (cd != ClassDeclaration.throwable && !ClassDeclaration.throwable.isBaseOf(cd, null)) { error(c.loc, "can only catch class objects derived from `Throwable`, not `%s`", c.type.toChars()); c.errors = true; } else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception && cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) && sc.func.setUnsafe()) { error(c.loc, "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type.toChars()); c.errors = true; } else if (global.params.ehnogc) { stc |= STC.scope_; } if (c.ident) { c.var = new VarDeclaration(c.loc, c.type, c.ident, null, stc); c.var.iscatchvar = true; c.var.dsymbolSemantic(sc); sc.insert(c.var); if (global.params.ehnogc && stc & STC.scope_) { /* Add a destructor for c.var * try { handler } finally { if (!__ctfe) _d_delThrowable(var); } */ assert(!c.var.edtor); // ensure we didn't create one in callScopeDtor() Loc loc = c.loc; Expression e = new VarExp(loc, c.var); e = new CallExp(loc, new IdentifierExp(loc, Id._d_delThrowable), e); Expression ec = new IdentifierExp(loc, Id.ctfe); ec = new NotExp(loc, ec); Statement s = new IfStatement(loc, null, ec, new ExpStatement(loc, e), null, loc); c.handler = new TryFinallyStatement(loc, c.handler, s); } } c.handler = c.handler.statementSemantic(sc); if (c.handler && c.handler.isErrorStatement()) c.errors = true; } sc.pop(); } Statement semanticNoScope(Statement s, Scope* sc) { //printf("Statement::semanticNoScope() %s\n", toChars()); if (!s.isCompoundStatement() && !s.isScopeStatement()) { s = new CompoundStatement(s.loc, s); // so scopeCode() gets called } s = s.statementSemantic(sc); return s; } // Same as semanticNoScope(), but do create a new scope Statement semanticScope(Statement s, Scope* sc, Statement sbreak, Statement scontinue) { auto sym = new ScopeDsymbol(); sym.parent = sc.scopesym; Scope* scd = sc.push(sym); if (sbreak) scd.sbreak = sbreak; if (scontinue) scd.scontinue = scontinue; s = s.semanticNoScope(scd); scd.pop(); return s; } /******************* * Determines additional argument types for makeTupleForeach. */ static template TupleForeachArgs(bool isStatic, bool isDecl) { alias Seq(T...)=T; static if(isStatic) alias T = Seq!(bool); else alias T = Seq!(); static if(!isDecl) alias TupleForeachArgs = T; else alias TupleForeachArgs = Seq!(Dsymbols*,T); } /******************* * Determines the return type of makeTupleForeach. */ static template TupleForeachRet(bool isStatic, bool isDecl) { alias Seq(T...)=T; static if(!isDecl) alias TupleForeachRet = Statement; else alias TupleForeachRet = Dsymbols*; } /******************* * See StatementSemanticVisitor.makeTupleForeach. This is a simple * wrapper that returns the generated statements/declarations. */ TupleForeachRet!(isStatic, isDecl) makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args) { scope v = new StatementSemanticVisitor(sc); static if(!isDecl) { v.makeTupleForeach!(isStatic, isDecl)(fs, args); return v.result; } else { return v.makeTupleForeach!(isStatic, isDecl)(fs, args); } } ================================================ FILE: gcc/d/dmd/staticassert.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/staticassert.d, _staticassert.d) * Documentation: https://dlang.org/phobos/dmd_staticassert.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticassert.d */ module dmd.staticassert; import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.visitor; /*********************************************************** */ extern (C++) final class StaticAssert : Dsymbol { Expression exp; Expression msg; extern (D) this(const ref Loc loc, Expression exp, Expression msg) { super(Id.empty); this.loc = loc; this.exp = exp; this.msg = msg; } override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); return new StaticAssert(loc, exp.syntaxCopy(), msg ? msg.syntaxCopy() : null); } override void addMember(Scope* sc, ScopeDsymbol sds) { // we didn't add anything } override bool oneMember(Dsymbol* ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); *ps = null; return true; } override const(char)* kind() const { return "static assert"; } override void accept(Visitor v) { v.visit(this); } } ================================================ FILE: gcc/d/dmd/staticcond.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/staticcond.d, _staticcond.d) * Documentation: https://dlang.org/phobos/dmd_staticcond.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticcond.d */ module dmd.staticcond; import dmd.aliasthis; import dmd.arraytypes; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.globals; import dmd.identifier; import dmd.mtype; import dmd.tokens; import dmd.utils; /******************************************** * Semantically analyze and then evaluate a static condition at compile time. * This is special because short circuit operators &&, || and ?: at the top * level are not semantically analyzed if the result of the expression is not * necessary. * Params: * sc = instantiating scope * exp = original expression, for error messages * e = resulting expression * errors = set to `true` if errors occurred * Returns: * true if evaluates to true */ bool evalStaticCondition(Scope* sc, Expression exp, Expression e, ref bool errors) { if (e.op == TOK.andAnd || e.op == TOK.orOr) { LogicalExp aae = cast(LogicalExp)e; bool result = evalStaticCondition(sc, exp, aae.e1, errors); if (errors) return false; if (e.op == TOK.andAnd) { if (!result) return false; } else { if (result) return true; } result = evalStaticCondition(sc, exp, aae.e2, errors); return !errors && result; } if (e.op == TOK.question) { CondExp ce = cast(CondExp)e; bool result = evalStaticCondition(sc, exp, ce.econd, errors); if (errors) return false; Expression leg = result ? ce.e1 : ce.e2; result = evalStaticCondition(sc, exp, leg, errors); return !errors && result; } uint nerrors = global.errors; sc = sc.startCTFE(); sc.flags |= SCOPE.condition; e = e.expressionSemantic(sc); e = resolveProperties(sc, e); sc = sc.endCTFE(); e = e.optimize(WANTvalue); if (nerrors != global.errors || e.op == TOK.error || e.type.toBasetype() == Type.terror) { errors = true; return false; } e = resolveAliasThis(sc, e); if (!e.type.isBoolean()) { exp.error("expression `%s` of type `%s` does not have a boolean value", exp.toChars(), e.type.toChars()); errors = true; return false; } e = e.ctfeInterpret(); if (e.isBool(true)) return true; else if (e.isBool(false)) return false; e.error("expression `%s` is not constant", e.toChars()); errors = true; return false; } ================================================ FILE: gcc/d/dmd/target.d ================================================ /* target.d -- Target interface for the D front end. * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.target; import dmd.argtypes; import dmd.dclass; import dmd.dsymbol; import dmd.expression; import dmd.globals; import dmd.mtype; import dmd.tokens : TOK; import dmd.root.ctfloat; import dmd.root.outbuffer; /** * Describes a back-end target. At present it is incomplete, but in the future * it should grow to contain most or all target machine and target O/S specific * information. * * In many cases, calls to sizeof() can't be used directly for getting data type * sizes since cross compiling is supported and would end up using the host * sizes rather than the target sizes. */ struct Target { extern (C++) __gshared { // D ABI uint ptrsize; /// size of a pointer in bytes uint realsize; /// size a real consumes in memory uint realpad; /// padding added to the CPU real size to bring it up to realsize uint realalignsize; /// alignment for reals uint classinfosize; /// size of `ClassInfo` ulong maxStaticDataSize; /// maximum size of static data // C ABI uint c_longsize; /// size of a C `long` or `unsigned long` type uint c_long_doublesize; /// size of a C `long double` // C++ ABI bool reverseCppOverloads; /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl) bool cppExceptions; /// set if catching C++ exceptions is supported bool twoDtorInVtable; /// target C++ ABI puts deleting and non-deleting destructor into vtable } /** * Values representing all properties for floating point types */ extern (C++) struct FPTypeProperties(T) { __gshared { real_t max; /// largest representable value that's not infinity real_t min_normal; /// smallest representable normalized value that's not 0 real_t nan; /// NaN value real_t snan; /// signalling NaN value real_t infinity; /// infinity value real_t epsilon; /// smallest increment to the value 1 d_int64 dig; /// number of decimal digits of precision d_int64 mant_dig; /// number of bits in mantissa d_int64 max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable d_int64 min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value d_int64 max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable) d_int64 min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value } } /// alias FloatProperties = FPTypeProperties!float; /// alias DoubleProperties = FPTypeProperties!double; /// alias RealProperties = FPTypeProperties!real_t; /** * Initialize the Target */ extern (C++) static void _init(); /** * Requested target memory alignment size of the given type. * Params: * type = type to inspect * Returns: * alignment in bytes */ extern (C++) static uint alignsize(Type type); /** * Requested target field alignment size of the given type. * Params: * type = type to inspect * Returns: * alignment in bytes */ extern (C++) static uint fieldalign(Type type); /** * Size of the target OS critical section. * Returns: * size in bytes */ extern (C++) static uint critsecsize(); /** * Type for the `va_list` type for the target. * NOTE: For Posix/x86_64 this returns the type which will really * be used for passing an argument of type va_list. * Returns: * `Type` that represents `va_list`. */ extern (C++) static Type va_listType(); /** * Checks whether the target supports a vector type. * Params: * sz = vector type size in bytes * type = vector element type * Returns: * 0 vector type is supported, * 1 vector type is not supported on the target at all * 2 vector element type is not supported * 3 vector size is not supported */ extern (C++) static int isVectorTypeSupported(int sz, Type type); /** * Checks whether the target supports the given operation for vectors. * Params: * type = target type of operation * op = the unary or binary op being done on the `type` * t2 = type of second operand if `op` is a binary operation * Returns: * true if the operation is supported or type is not a vector */ extern (C++) static bool isVectorOpSupported(Type type, TOK op, Type t2 = null); /** * Mangle the given symbol for C++ ABI. * Params: * s = declaration with C++ linkage * Returns: * string mangling of symbol */ extern (C++) static const(char)* toCppMangle(Dsymbol s); /** * Get RTTI mangling of the given class declaration for C++ ABI. * Params: * cd = class with C++ linkage * Returns: * string mangling of C++ typeinfo */ extern (C++) static const(char)* cppTypeInfoMangle(ClassDeclaration cd); /** * Gets vendor-specific type mangling for C++ ABI. * Params: * t = type to inspect * Returns: * string if type is mangled specially on target * null if unhandled */ extern (C++) static const(char)* cppTypeMangle(Type t); /** * Get the type that will really be used for passing the given argument * to an `extern(C++)` function. * Params: * p = parameter to be passed. * Returns: * `Type` to use for parameter `p`. */ extern (C++) static Type cppParameterType(Parameter p); /** * Default system linkage for the target. * Returns: * `LINK` to use for `extern(System)` */ extern (C++) static LINK systemLinkage(); /** * Describes how an argument type is passed to a function on target. * Params: * t = type to break down * Returns: * tuple of types if type is passed in one or more registers * empty tuple if type is always passed on the stack */ extern (C++) static TypeTuple toArgTypes(Type t) { return .toArgTypes(t); } /** * Determine return style of function - whether in registers or * through a hidden pointer to the caller's stack. * Params: * tf = function type to check * needsThis = true if the function type is for a non-static member function * Returns: * true if return value from function is on the stack */ extern (C++) static bool isReturnOnStack(TypeFunction tf, bool needsThis); /*** * Determine the size a value of type `t` will be when it * is passed on the function parameter stack. * Params: * loc = location to use for error messages * t = type of parameter * Returns: * size used on parameter stack */ extern (C++) static ulong parameterSize(const ref Loc loc, Type t); /** * Get targetInfo by key * Params: * name = name of targetInfo to get * loc = location to use for error messages * Returns: * Expression for the requested targetInfo */ extern (C++) static Expression getTargetInfo(const(char)* name, const ref Loc loc); } ================================================ FILE: gcc/d/dmd/target.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 2013-2018 by The D Language Foundation, All Rights Reserved * written by Iain Buclaw * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/target.h */ #pragma once // This file contains a data structure that describes a back-end target. // At present it is incomplete, but in future it should grow to contain // most or all target machine and target O/S specific information. #include "globals.h" #include "tokens.h" class ClassDeclaration; class Dsymbol; class Expression; class Parameter; class Type; class TypeTuple; class TypeFunction; struct Target { // D ABI static unsigned ptrsize; static unsigned realsize; // size a real consumes in memory static unsigned realpad; // 'padding' added to the CPU real size to bring it up to realsize static unsigned realalignsize; // alignment for reals static unsigned classinfosize; // size of 'ClassInfo' static unsigned long long maxStaticDataSize; // maximum size of static data // C ABI static unsigned c_longsize; // size of a C 'long' or 'unsigned long' type static unsigned c_long_doublesize; // size of a C 'long double' // C++ ABI static bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order static bool cppExceptions; // set if catching C++ exceptions is supported static bool twoDtorInVtable; // target C++ ABI puts deleting and non-deleting destructor into vtable template struct FPTypeProperties { static real_t max; static real_t min_normal; static real_t nan; static real_t snan; static real_t infinity; static real_t epsilon; static d_int64 dig; static d_int64 mant_dig; static d_int64 max_exp; static d_int64 min_exp; static d_int64 max_10_exp; static d_int64 min_10_exp; }; typedef FPTypeProperties FloatProperties; typedef FPTypeProperties DoubleProperties; typedef FPTypeProperties RealProperties; static void _init(); // Type sizes and support. static unsigned alignsize(Type *type); static unsigned fieldalign(Type *type); static unsigned critsecsize(); static Type *va_listType(); // get type of va_list static int isVectorTypeSupported(int sz, Type *type); static bool isVectorOpSupported(Type *type, TOK op, Type *t2 = NULL); // ABI and backend. static const char *toCppMangle(Dsymbol *s); static const char *cppTypeInfoMangle(ClassDeclaration *cd); static const char *cppTypeMangle(Type *t); static Type *cppParameterType(Parameter *p); static LINK systemLinkage(); static TypeTuple *toArgTypes(Type *t); static bool isReturnOnStack(TypeFunction *tf, bool needsThis); static d_uns64 parameterSize(const Loc& loc, Type *t); static Expression *getTargetInfo(const char* name, const Loc& loc); }; ================================================ FILE: gcc/d/dmd/template.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/template.h */ #pragma once #include "arraytypes.h" #include "dsymbol.h" class Identifier; class TemplateInstance; class TemplateParameter; class TemplateTypeParameter; class TemplateThisParameter; class TemplateValueParameter; class TemplateAliasParameter; class TemplateTupleParameter; class Type; class TypeQualified; struct Scope; class Expression; class FuncDeclaration; class Parameter; class Tuple : public RootObject { public: Objects objects; // kludge for template.isType() int dyncast() const { return DYNCAST_TUPLE; } const char *toChars() { return objects.toChars(); } }; struct TemplatePrevious { TemplatePrevious *prev; Scope *sc; Objects *dedargs; }; class TemplateDeclaration : public ScopeDsymbol { public: TemplateParameters *parameters; // array of TemplateParameter's TemplateParameters *origParameters; // originals for Ddoc Expression *constraint; // Hash table to look up TemplateInstance's of this TemplateDeclaration void *instances; TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list FuncDeclaration *funcroot; // first function in unified overload list Dsymbol *onemember; // if !=NULL then one member of this template bool literal; // this template declaration is a literal bool ismixin; // template declaration is only to be used as a mixin bool isstatic; // this is static template declaration Prot protection; int inuse; // for recursive expansion detection TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack Dsymbol *syntaxCopy(Dsymbol *); bool overloadInsert(Dsymbol *s); bool hasStaticCtorOrDtor(); const char *kind() const; const char *toChars(); Prot prot(); MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); TemplateDeclaration *isTemplateDeclaration() { return this; } TemplateTupleParameter *isVariadic(); bool isOverloadable(); void accept(Visitor *v) { v->visit(this); } }; /* For type-parameter: * template Foo(ident) // specType is set to NULL * template Foo(ident : specType) * For value-parameter: * template Foo(valType ident) // specValue is set to NULL * template Foo(valType ident : specValue) * For alias-parameter: * template Foo(alias ident) * For this-parameter: * template Foo(this ident) */ class TemplateParameter : public RootObject { public: Loc loc; Identifier *ident; /* True if this is a part of precedent parameter specialization pattern. * * template A(T : X!TL, alias X, TL...) {} * // X and TL are dependent template parameter * * A dependent template parameter should return MATCHexact in matchArg() * to respect the match level of the corresponding precedent parameter. */ bool dependent; virtual TemplateTypeParameter *isTemplateTypeParameter(); virtual TemplateValueParameter *isTemplateValueParameter(); virtual TemplateAliasParameter *isTemplateAliasParameter(); virtual TemplateThisParameter *isTemplateThisParameter(); virtual TemplateTupleParameter *isTemplateTupleParameter(); virtual TemplateParameter *syntaxCopy() = 0; virtual bool declareParameter(Scope *sc) = 0; virtual void print(RootObject *oarg, RootObject *oded) = 0; virtual RootObject *specialization() = 0; virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0; virtual bool hasDefaultArg() = 0; /* Match actual argument against parameter. */ virtual MATCH matchArg(Loc instLoc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; /* Create dummy argument based on parameter. */ virtual void *dummyArg() = 0; virtual void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * ident : specType = defaultType */ class TemplateTypeParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *specType; // type parameter: if !=NULL, this is the type specialization Type *defaultType; TemplateTypeParameter *isTemplateTypeParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * this ident : specType = defaultType */ class TemplateThisParameter : public TemplateTypeParameter { public: TemplateThisParameter *isTemplateThisParameter(); TemplateParameter *syntaxCopy(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * valType ident : specValue = defaultValue */ class TemplateValueParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *valType; Expression *specValue; Expression *defaultValue; TemplateValueParameter *isTemplateValueParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * specType ident : specAlias = defaultAlias */ class TemplateAliasParameter : public TemplateParameter { using TemplateParameter::matchArg; public: Type *specType; RootObject *specAlias; RootObject *defaultAlias; TemplateAliasParameter *isTemplateAliasParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Syntax: * ident ... */ class TemplateTupleParameter : public TemplateParameter { public: TemplateTupleParameter *isTemplateTupleParameter(); TemplateParameter *syntaxCopy(); bool declareParameter(Scope *sc); void print(RootObject *oarg, RootObject *oded); RootObject *specialization(); RootObject *defaultArg(Loc instLoc, Scope *sc); bool hasDefaultArg(); MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); void accept(Visitor *v) { v->visit(this); } }; /* Given: * foo!(args) => * name = foo * tiargs = args */ class TemplateInstance : public ScopeDsymbol { public: Identifier *name; // Array of Types/Expressions of template // instance arguments [int*, char, 10*10] Objects *tiargs; // Array of Types/Expressions corresponding // to TemplateDeclaration.parameters // [int, char, 100] Objects tdtypes; Dsymbol *tempdecl; // referenced by foo.bar.abc Dsymbol *enclosing; // if referencing local symbols, this is the context Dsymbol *aliasdecl; // !=NULL if instance is an alias for its sole member TemplateInstance *inst; // refer to existing instance ScopeDsymbol *argsym; // argument symbol table int inuse; // for recursive expansion detection int nest; // for recursive pretty printing detection bool semantictiargsdone; // has semanticTiargs() been done? bool havetempdecl; // if used second constructor bool gagged; // if the instantiation is done with error gagging hash_t hash; // cached result of toHash() Expressions *fargs; // for function template, these are the function arguments TemplateInstances* deferred; Module *memberOf; // if !null, then this TemplateInstance appears in memberOf.members[] // Used to determine the instance needs code generation. // Note that these are inaccurate until semantic analysis phase completed. TemplateInstance *tinst; // enclosing template instance TemplateInstance *tnext; // non-first instantiated instances Module *minst; // the top module that instantiated this instance Dsymbol *syntaxCopy(Dsymbol *); Dsymbol *toAlias(); // resolve real symbol const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); const char *toChars(); const char* toPrettyCharsHelper(); void printInstantiationTrace(); Identifier *getIdent(); int compare(RootObject *o); hash_t toHash(); bool needsCodegen(); TemplateInstance *isTemplateInstance() { return this; } void accept(Visitor *v) { v->visit(this); } }; class TemplateMixin : public TemplateInstance { public: TypeQualified *tqual; Dsymbol *syntaxCopy(Dsymbol *s); const char *kind() const; bool oneMember(Dsymbol **ps, Identifier *ident); int apply(Dsymbol_apply_ft_t fp, void *param); bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *toChars(); TemplateMixin *isTemplateMixin() { return this; } void accept(Visitor *v) { v->visit(this); } }; Expression *isExpression(RootObject *o); Dsymbol *isDsymbol(RootObject *o); Type *isType(RootObject *o); Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool arrayObjectIsError(const Objects *args); bool isError(const RootObject *const o); Type *getType(RootObject *o); Dsymbol *getDsymbol(RootObject *o); RootObject *objectSyntaxCopy(RootObject *o); ================================================ FILE: gcc/d/dmd/templateparamsem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Template implementation. * * Copyright: Copyright (C) 1999-2018 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/templateparamsem.d, _templateparamsem.d) * Documentation: https://dlang.org/phobos/dmd_templateparamsem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templateparamsem.d */ module dmd.templateparamsem; import dmd.arraytypes; import dmd.dsymbol; import dmd.dscope; import dmd.dtemplate; import dmd.globals; import dmd.expression; import dmd.expressionsem; import dmd.root.rootobject; import dmd.mtype; import dmd.typesem; import dmd.visitor; /************************************************ * Performs semantic on TemplateParameter AST nodes. * * Params: * tp = element of `parameters` to be semantically analyzed * sc = context * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` * Returns: * `true` if no errors */ extern(C++) bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters) { scope v = new TemplateParameterSemanticVisitor(sc, parameters); tp.accept(v); return v.result; } private extern (C++) final class TemplateParameterSemanticVisitor : Visitor { alias visit = Visitor.visit; Scope* sc; TemplateParameters* parameters; bool result; this(Scope* sc, TemplateParameters* parameters) { this.sc = sc; this.parameters = parameters; } override void visit(TemplateTypeParameter ttp) { //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars()); if (ttp.specType && !reliesOnTident(ttp.specType, parameters)) { ttp.specType = ttp.specType.typeSemantic(ttp.loc, sc); } version (none) { // Don't do semantic() until instantiation if (ttp.defaultType) { ttp.defaultType = ttp.defaultType.typeSemantic(ttp.loc, sc); } } result = !(ttp.specType && isError(ttp.specType)); } override void visit(TemplateValueParameter tvp) { tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc); version (none) { // defer semantic analysis to arg match if (tvp.specValue) { Expression e = tvp.specValue; sc = sc.startCTFE(); e = e.semantic(sc); sc = sc.endCTFE(); e = e.implicitCastTo(sc, tvp.valType); e = e.ctfeInterpret(); if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.complex80 || e.op == TOK.null_ || e.op == TOK.string_) tvp.specValue = e; } if (tvp.defaultValue) { Expression e = defaultValue; sc = sc.startCTFE(); e = e.semantic(sc); sc = sc.endCTFE(); e = e.implicitCastTo(sc, tvp.valType); e = e.ctfeInterpret(); if (e.op == TOK.int64) tvp.defaultValue = e; } } result = !isError(tvp.valType); } override void visit(TemplateAliasParameter tap) { if (tap.specType && !reliesOnTident(tap.specType, parameters)) { tap.specType = tap.specType.typeSemantic(tap.loc, sc); } tap.specAlias = aliasParameterSemantic(tap.loc, sc, tap.specAlias, parameters); version (none) { // Don't do semantic() until instantiation if (tap.defaultAlias) tap.defaultAlias = tap.defaultAlias.semantic(tap.loc, sc); } result = !(tap.specType && isError(tap.specType)) && !(tap.specAlias && isError(tap.specAlias)); } override void visit(TemplateTupleParameter ttp) { result = true; } } /*********************************************** * Support function for performing semantic analysis on `TemplateAliasParameter`. * * Params: * loc = location (for error messages) * sc = context * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias` * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` * Returns: * object resulting from running `semantic` on `o` */ RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplateParameters* parameters) { if (o) { Expression ea = isExpression(o); Type ta = isType(o); if (ta && (!parameters || !reliesOnTident(ta, parameters))) { Dsymbol s = ta.toDsymbol(sc); if (s) o = s; else o = ta.typeSemantic(loc, sc); } else if (ea) { sc = sc.startCTFE(); ea = ea.expressionSemantic(sc); sc = sc.endCTFE(); o = ea.ctfeInterpret(); } } return o; } ================================================ FILE: gcc/d/dmd/tokens.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/tokens.d, _tokens.d) * Documentation: https://dlang.org/phobos/dmd_tokens.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tokens.d */ module dmd.tokens; import core.stdc.ctype; import core.stdc.stdio; import core.stdc.string; import dmd.globals; import dmd.identifier; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.utf; enum TOK : int { reserved, // Other leftParentheses, rightParentheses, leftBracket, rightBracket, leftCurly, rightCurly, colon, negate, semicolon, dotDotDot, endOfFile, cast_, null_, assert_, true_, false_, array, call, address, type, throw_, new_, delete_, star, symbolOffset, variable, dotVariable, dotIdentifier, dotTemplateInstance, dotType, slice, arrayLength, version_, module_, dollar, template_, dotTemplateDeclaration, declaration, typeof_, pragma_, dSymbol, typeid_, uadd, remove, newAnonymousClass, comment, arrayLiteral, assocArrayLiteral, structLiteral, classReference, thrownException, delegatePointer, delegateFunctionPointer, // Operators lessThan = 54, greaterThan, lessOrEqual, greaterOrEqual, equal, notEqual, identity, notIdentity, index, is_, leftShift = 64, rightShift, leftShiftAssign, rightShiftAssign, unsignedRightShift, unsignedRightShiftAssign, concatenate, concatenateAssign, // ~= concatenateElemAssign, concatenateDcharAssign, add, min, addAssign, minAssign, mul, div, mod, mulAssign, divAssign, modAssign, and, or, xor, andAssign, orAssign, xorAssign, assign, not, tilde, plusPlus, minusMinus, construct, blit, dot, arrow, comma, question, andAnd, orOr, prePlusPlus, preMinusMinus, // Numeric literals int32Literal = 105, uns32Literal, int64Literal, uns64Literal, int128Literal, uns128Literal, float32Literal, float64Literal, float80Literal, imaginary32Literal, imaginary64Literal, imaginary80Literal, // Char constants charLiteral = 117, wcharLiteral, dcharLiteral, // Leaf operators identifier = 120, string_, hexadecimalString, this_, super_, halt, tuple, error, // Basic types void_ = 128, int8, uns8, int16, uns16, int32, uns32, int64, uns64, int128, uns128, float32, float64, float80, imaginary32, imaginary64, imaginary80, complex32, complex64, complex80, char_, wchar_, dchar_, bool_, // Aggregates struct_ = 152, class_, interface_, union_, enum_, import_, alias_, override_, delegate_, function_, mixin_, align_, extern_, private_, protected_, public_, export_, static_, final_, const_, abstract_, debug_, deprecated_, in_, out_, inout_, lazy_, auto_, package_, manifest, immutable_, // Statements if_ = 183, else_, while_, for_, do_, switch_, case_, default_, break_, continue_, with_, synchronized_, return_, goto_, try_, catch_, finally_, asm_, foreach_, foreach_reverse_, scope_, onScopeExit, onScopeFailure, onScopeSuccess, // Contracts invariant_ = 207, // Testing unittest_, // Added after 1.0 argumentTypes, ref_, macro_, parameters = 212, traits, overloadSet, pure_, nothrow_, gshared, line, file, fileFullPath, moduleString, functionString, prettyFunction, shared_, at, pow, powAssign, goesTo, vector, pound, interval = 231, voidExpression, cantExpression, showCtfeContext, objcClassReference, max_, } // Assert that all token enum members have consecutive values and // that none of them overlap static assert(() { foreach (idx, enumName; __traits(allMembers, TOK)) { static if (idx != __traits(getMember, TOK, enumName)) { pragma(msg, "Error: Expected TOK.", enumName, " to be ", idx, " but is ", __traits(getMember, TOK, enumName)); static assert(0); } } return true; }()); /**************************************** */ private immutable TOK[] keywords = [ TOK.this_, TOK.super_, TOK.assert_, TOK.null_, TOK.true_, TOK.false_, TOK.cast_, TOK.new_, TOK.delete_, TOK.throw_, TOK.module_, TOK.pragma_, TOK.typeof_, TOK.typeid_, TOK.template_, TOK.void_, TOK.int8, TOK.uns8, TOK.int16, TOK.uns16, TOK.int32, TOK.uns32, TOK.int64, TOK.uns64, TOK.int128, TOK.uns128, TOK.float32, TOK.float64, TOK.float80, TOK.bool_, TOK.char_, TOK.wchar_, TOK.dchar_, TOK.imaginary32, TOK.imaginary64, TOK.imaginary80, TOK.complex32, TOK.complex64, TOK.complex80, TOK.delegate_, TOK.function_, TOK.is_, TOK.if_, TOK.else_, TOK.while_, TOK.for_, TOK.do_, TOK.switch_, TOK.case_, TOK.default_, TOK.break_, TOK.continue_, TOK.synchronized_, TOK.return_, TOK.goto_, TOK.try_, TOK.catch_, TOK.finally_, TOK.with_, TOK.asm_, TOK.foreach_, TOK.foreach_reverse_, TOK.scope_, TOK.struct_, TOK.class_, TOK.interface_, TOK.union_, TOK.enum_, TOK.import_, TOK.mixin_, TOK.static_, TOK.final_, TOK.const_, TOK.alias_, TOK.override_, TOK.abstract_, TOK.debug_, TOK.deprecated_, TOK.in_, TOK.out_, TOK.inout_, TOK.lazy_, TOK.auto_, TOK.align_, TOK.extern_, TOK.private_, TOK.package_, TOK.protected_, TOK.public_, TOK.export_, TOK.invariant_, TOK.unittest_, TOK.version_, TOK.argumentTypes, TOK.parameters, TOK.ref_, TOK.macro_, TOK.pure_, TOK.nothrow_, TOK.gshared, TOK.traits, TOK.vector, TOK.overloadSet, TOK.file, TOK.fileFullPath, TOK.line, TOK.moduleString, TOK.functionString, TOK.prettyFunction, TOK.shared_, TOK.immutable_, ]; /*********************************************************** */ extern (C++) struct Token { Token* next; Loc loc; const(char)* ptr; // pointer to first character of this token within buffer TOK value; const(char)* blockComment; // doc comment string prior to this token const(char)* lineComment; // doc comment for previous token union { // Integers sinteger_t intvalue; uinteger_t unsvalue; // Floats real_t floatvalue; struct { const(char)* ustring; // UTF8 string uint len; ubyte postfix; // 'c', 'w', 'd' } Identifier ident; } extern (D) private __gshared immutable string[TOK.max_] tochars = [ // Keywords TOK.this_: "this", TOK.super_: "super", TOK.assert_: "assert", TOK.null_: "null", TOK.true_: "true", TOK.false_: "false", TOK.cast_: "cast", TOK.new_: "new", TOK.delete_: "delete", TOK.throw_: "throw", TOK.module_: "module", TOK.pragma_: "pragma", TOK.typeof_: "typeof", TOK.typeid_: "typeid", TOK.template_: "template", TOK.void_: "void", TOK.int8: "byte", TOK.uns8: "ubyte", TOK.int16: "short", TOK.uns16: "ushort", TOK.int32: "int", TOK.uns32: "uint", TOK.int64: "long", TOK.uns64: "ulong", TOK.int128: "cent", TOK.uns128: "ucent", TOK.float32: "float", TOK.float64: "double", TOK.float80: "real", TOK.bool_: "bool", TOK.char_: "char", TOK.wchar_: "wchar", TOK.dchar_: "dchar", TOK.imaginary32: "ifloat", TOK.imaginary64: "idouble", TOK.imaginary80: "ireal", TOK.complex32: "cfloat", TOK.complex64: "cdouble", TOK.complex80: "creal", TOK.delegate_: "delegate", TOK.function_: "function", TOK.is_: "is", TOK.if_: "if", TOK.else_: "else", TOK.while_: "while", TOK.for_: "for", TOK.do_: "do", TOK.switch_: "switch", TOK.case_: "case", TOK.default_: "default", TOK.break_: "break", TOK.continue_: "continue", TOK.synchronized_: "synchronized", TOK.return_: "return", TOK.goto_: "goto", TOK.try_: "try", TOK.catch_: "catch", TOK.finally_: "finally", TOK.with_: "with", TOK.asm_: "asm", TOK.foreach_: "foreach", TOK.foreach_reverse_: "foreach_reverse", TOK.scope_: "scope", TOK.struct_: "struct", TOK.class_: "class", TOK.interface_: "interface", TOK.union_: "union", TOK.enum_: "enum", TOK.import_: "import", TOK.mixin_: "mixin", TOK.static_: "static", TOK.final_: "final", TOK.const_: "const", TOK.alias_: "alias", TOK.override_: "override", TOK.abstract_: "abstract", TOK.debug_: "debug", TOK.deprecated_: "deprecated", TOK.in_: "in", TOK.out_: "out", TOK.inout_: "inout", TOK.lazy_: "lazy", TOK.auto_: "auto", TOK.align_: "align", TOK.extern_: "extern", TOK.private_: "private", TOK.package_: "package", TOK.protected_: "protected", TOK.public_: "public", TOK.export_: "export", TOK.invariant_: "invariant", TOK.unittest_: "unittest", TOK.version_: "version", TOK.argumentTypes: "__argTypes", TOK.parameters: "__parameters", TOK.ref_: "ref", TOK.macro_: "macro", TOK.pure_: "pure", TOK.nothrow_: "nothrow", TOK.gshared: "__gshared", TOK.traits: "__traits", TOK.vector: "__vector", TOK.overloadSet: "__overloadset", TOK.file: "__FILE__", TOK.fileFullPath: "__FILE_FULL_PATH__", TOK.line: "__LINE__", TOK.moduleString: "__MODULE__", TOK.functionString: "__FUNCTION__", TOK.prettyFunction: "__PRETTY_FUNCTION__", TOK.shared_: "shared", TOK.immutable_: "immutable", TOK.endOfFile: "End of File", TOK.leftCurly: "{", TOK.rightCurly: "}", TOK.leftParentheses: "(", TOK.rightParentheses: ")", TOK.leftBracket: "[", TOK.rightBracket: "]", TOK.semicolon: ";", TOK.colon: ":", TOK.comma: ",", TOK.dot: ".", TOK.xor: "^", TOK.xorAssign: "^=", TOK.assign: "=", TOK.construct: "=", TOK.blit: "=", TOK.lessThan: "<", TOK.greaterThan: ">", TOK.lessOrEqual: "<=", TOK.greaterOrEqual: ">=", TOK.equal: "==", TOK.notEqual: "!=", TOK.not: "!", TOK.leftShift: "<<", TOK.rightShift: ">>", TOK.unsignedRightShift: ">>>", TOK.add: "+", TOK.min: "-", TOK.mul: "*", TOK.div: "/", TOK.mod: "%", TOK.slice: "..", TOK.dotDotDot: "...", TOK.and: "&", TOK.andAnd: "&&", TOK.or: "|", TOK.orOr: "||", TOK.array: "[]", TOK.index: "[i]", TOK.address: "&", TOK.star: "*", TOK.tilde: "~", TOK.dollar: "$", TOK.plusPlus: "++", TOK.minusMinus: "--", TOK.prePlusPlus: "++", TOK.preMinusMinus: "--", TOK.type: "type", TOK.question: "?", TOK.negate: "-", TOK.uadd: "+", TOK.variable: "var", TOK.addAssign: "+=", TOK.minAssign: "-=", TOK.mulAssign: "*=", TOK.divAssign: "/=", TOK.modAssign: "%=", TOK.leftShiftAssign: "<<=", TOK.rightShiftAssign: ">>=", TOK.unsignedRightShiftAssign: ">>>=", TOK.andAssign: "&=", TOK.orAssign: "|=", TOK.concatenateAssign: "~=", TOK.concatenateElemAssign: "~=", TOK.concatenateDcharAssign: "~=", TOK.concatenate: "~", TOK.call: "call", TOK.identity: "is", TOK.notIdentity: "!is", TOK.identifier: "identifier", TOK.at: "@", TOK.pow: "^^", TOK.powAssign: "^^=", TOK.goesTo: "=>", TOK.pound: "#", // For debugging TOK.error: "error", TOK.dotIdentifier: "dotid", TOK.dotTemplateDeclaration: "dottd", TOK.dotTemplateInstance: "dotti", TOK.dotVariable: "dotvar", TOK.dotType: "dottype", TOK.symbolOffset: "symoff", TOK.arrayLength: "arraylength", TOK.arrayLiteral: "arrayliteral", TOK.assocArrayLiteral: "assocarrayliteral", TOK.structLiteral: "structliteral", TOK.string_: "string", TOK.dSymbol: "symbol", TOK.tuple: "tuple", TOK.declaration: "declaration", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", TOK.delegatePointer: "delegateptr", // Finish up TOK.reserved: "reserved", TOK.remove: "remove", TOK.newAnonymousClass: "newanonclass", TOK.comment: "comment", TOK.classReference: "classreference", TOK.thrownException: "thrownexception", TOK.delegateFunctionPointer: "delegatefuncptr", TOK.arrow: "arrow", TOK.int32Literal: "int32v", TOK.uns32Literal: "uns32v", TOK.int64Literal: "int64v", TOK.uns64Literal: "uns64v", TOK.int128Literal: "int128v", TOK.uns128Literal: "uns128v", TOK.float32Literal: "float32v", TOK.float64Literal: "float64v", TOK.float80Literal: "float80v", TOK.imaginary32Literal: "imaginary32v", TOK.imaginary64Literal: "imaginary64v", TOK.imaginary80Literal: "imaginary80v", TOK.charLiteral: "charv", TOK.wcharLiteral: "wcharv", TOK.dcharLiteral: "dcharv", TOK.halt: "halt", TOK.hexadecimalString: "xstring", TOK.manifest: "manifest", TOK.interval: "interval", TOK.voidExpression: "voidexp", TOK.cantExpression: "cantexp", TOK.showCtfeContext : "showCtfeContext", TOK.objcClassReference: "class", ]; static assert(() { foreach (s; tochars) assert(s.length); return true; }()); shared static this() { Identifier.initTable(); foreach (kw; keywords) { //printf("keyword[%d] = '%s'\n",kw, tochars[kw].ptr); Identifier.idPool(tochars[kw].ptr, tochars[kw].length, cast(uint)kw); } } extern (D) private __gshared Token* freelist = null; extern (D) static Token* alloc() { if (Token.freelist) { Token* t = freelist; freelist = t.next; t.next = null; return t; } return new Token(); } void free() { next = freelist; freelist = &this; } int isKeyword() const { foreach (kw; keywords) { if (kw == value) return 1; } return 0; } /**** * Set to contents of ptr[0..length] * Params: * ptr = pointer to string * length = length of string */ void setString(const(char)* ptr, size_t length) { auto s = cast(char*)mem.xmalloc(length + 1); memcpy(s, ptr, length); s[length] = 0; ustring = s; len = cast(uint)length; postfix = 0; } /**** * Set to contents of buf * Params: * buf = string (not zero terminated) */ void setString(const ref OutBuffer buf) { setString(cast(const(char)*)buf.data, buf.offset); } /**** * Set to empty string */ void setString() { ustring = ""; len = 0; postfix = 0; } extern (C++) const(char)* toChars() const { __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer; const(char)* p = &buffer[0]; switch (value) { case TOK.int32Literal: sprintf(&buffer[0], "%d", cast(d_int32)intvalue); break; case TOK.uns32Literal: case TOK.charLiteral: case TOK.wcharLiteral: case TOK.dcharLiteral: sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue); break; case TOK.int64Literal: sprintf(&buffer[0], "%lldL", cast(long)intvalue); break; case TOK.uns64Literal: sprintf(&buffer[0], "%lluUL", cast(ulong)unsvalue); break; case TOK.float32Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); strcat(&buffer[0], "f"); break; case TOK.float64Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); break; case TOK.float80Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); strcat(&buffer[0], "L"); break; case TOK.imaginary32Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); strcat(&buffer[0], "fi"); break; case TOK.imaginary64Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); strcat(&buffer[0], "i"); break; case TOK.imaginary80Literal: CTFloat.sprint(&buffer[0], 'g', floatvalue); strcat(&buffer[0], "Li"); break; case TOK.string_: { OutBuffer buf; buf.writeByte('"'); for (size_t i = 0; i < len;) { dchar c; utf_decodeChar(ustring, len, i, c); switch (c) { case 0: break; case '"': case '\\': buf.writeByte('\\'); goto default; default: if (c <= 0x7F) { if (isprint(c)) buf.writeByte(c); else buf.printf("\\x%02x", c); } else if (c <= 0xFFFF) buf.printf("\\u%04x", c); else buf.printf("\\U%08x", c); continue; } break; } buf.writeByte('"'); if (postfix) buf.writeByte(postfix); p = buf.extractString(); } break; case TOK.hexadecimalString: { OutBuffer buf; buf.writeByte('x'); buf.writeByte('"'); foreach (size_t i; 0 .. len) { if (i) buf.writeByte(' '); buf.printf("%02x", ustring[i]); } buf.writeByte('"'); if (postfix) buf.writeByte(postfix); buf.writeByte(0); p = buf.extractData(); break; } case TOK.identifier: case TOK.enum_: case TOK.struct_: case TOK.import_: case TOK.wchar_: case TOK.dchar_: case TOK.bool_: case TOK.char_: case TOK.int8: case TOK.uns8: case TOK.int16: case TOK.uns16: case TOK.int32: case TOK.uns32: case TOK.int64: case TOK.uns64: case TOK.int128: case TOK.uns128: case TOK.float32: case TOK.float64: case TOK.float80: case TOK.imaginary32: case TOK.imaginary64: case TOK.imaginary80: case TOK.complex32: case TOK.complex64: case TOK.complex80: case TOK.void_: p = ident.toChars(); break; default: p = toChars(value); break; } return p; } extern (D) static const(char)* toChars(TOK value) { return toString(value).ptr; } extern (D) static string toString(TOK value) pure nothrow @nogc @safe { return tochars[value]; } } ================================================ FILE: gcc/d/dmd/tokens.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/tokens.h */ #pragma once #include "root/port.h" #include "globals.h" class Identifier; /* Tokens: ( ) [ ] { } < > <= >= == != === !== << >> <<= >>= >>> >>>= + - += -= * / % *= /= %= & | ^ &= |= ^= = ! ~ @ ^^ ^^= ++ -- . -> : , => ? && || */ enum TOK { TOKreserved, // Other TOKlparen, TOKrparen, TOKlbracket, TOKrbracket, TOKlcurly, TOKrcurly, TOKcolon, TOKneg, TOKsemicolon, TOKdotdotdot, TOKeof, TOKcast, TOKnull, TOKassert, TOKtrue, TOKfalse, TOKarray, TOKcall, TOKaddress, TOKtype, TOKthrow, TOKnew, TOKdelete, TOKstar, TOKsymoff, TOKvar, TOKdotvar, TOKdotid, TOKdotti, TOKdottype, TOKslice, TOKarraylength, TOKversion, TOKmodule, TOKdollar, TOKtemplate, TOKdottd, TOKdeclaration, TOKtypeof, TOKpragma, TOKdsymbol, TOKtypeid, TOKuadd, TOKremove, TOKnewanonclass, TOKcomment, TOKarrayliteral, TOKassocarrayliteral, TOKstructliteral, TOKclassreference, TOKthrownexception, TOKdelegateptr, TOKdelegatefuncptr, // 54 // Operators TOKlt, TOKgt, TOKle, TOKge, TOKequal, TOKnotequal, TOKidentity, TOKnotidentity, TOKindex, TOKis, // 64 TOKshl, TOKshr, TOKshlass, TOKshrass, TOKushr, TOKushrass, TOKcat, TOKcatass, TOKcatelemass, TOKcatdcharass, // ~ ~= TOKadd, TOKmin, TOKaddass, TOKminass, TOKmul, TOKdiv, TOKmod, TOKmulass, TOKdivass, TOKmodass, TOKand, TOKor, TOKxor, TOKandass, TOKorass, TOKxorass, TOKassign, TOKnot, TOKtilde, TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, TOKdot, TOKarrow, TOKcomma, TOKquestion, TOKandand, TOKoror, TOKpreplusplus, TOKpreminusminus, // 105 // Numeric literals TOKint32v, TOKuns32v, TOKint64v, TOKuns64v, TOKint128v, TOKuns128v, TOKfloat32v, TOKfloat64v, TOKfloat80v, TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, // Char constants TOKcharv, TOKwcharv, TOKdcharv, // Leaf operators TOKidentifier, TOKstring, TOKxstring, TOKthis, TOKsuper, TOKhalt, TOKtuple, TOKerror, // Basic types TOKvoid, TOKint8, TOKuns8, TOKint16, TOKuns16, TOKint32, TOKuns32, TOKint64, TOKuns64, TOKint128, TOKuns128, TOKfloat32, TOKfloat64, TOKfloat80, TOKimaginary32, TOKimaginary64, TOKimaginary80, TOKcomplex32, TOKcomplex64, TOKcomplex80, TOKchar, TOKwchar, TOKdchar, TOKbool, // 152 // Aggregates TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, TOKalias, TOKoverride, TOKdelegate, TOKfunction, TOKmixin, TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, TOKstatic, TOKfinal, TOKconst, TOKabstract, TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, TOKauto, TOKpackage, TOKmanifest, TOKimmutable, // 183 // Statements TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, TOKasm, TOKforeach, TOKforeach_reverse, TOKscope, TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, // 207 // Contracts TOKinvariant, // Testing TOKunittest, // Added after 1.0 TOKargTypes, TOKref, TOKmacro, // 212 TOKparameters, TOKtraits, TOKoverloadset, TOKpure, TOKnothrow, TOKgshared, TOKline, TOKfile, TOKfilefullpath, TOKmodulestring, TOKfuncstring, TOKprettyfunc, TOKshared, TOKat, TOKpow, TOKpowass, TOKgoesto, TOKvector, TOKpound, // 231 TOKinterval, TOKvoidexp, TOKcantexp, TOKshowctfecontext, TOKobjc_class_reference, TOKMAX }; #define TOKwild TOKinout // Token has an anonymous struct, which is not strict ISO C++. #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif struct Token { Token *next; Loc loc; const utf8_t *ptr; // pointer to first character of this token within buffer TOK value; const utf8_t *blockComment; // doc comment string prior to this token const utf8_t *lineComment; // doc comment for previous token union { // Integers sinteger_t intvalue; uinteger_t unsvalue; // Floats real_t floatvalue; struct { utf8_t *ustring; // UTF8 string unsigned len; unsigned char postfix; // 'c', 'w', 'd' }; Identifier *ident; }; void free(); Token() : next(NULL) {} int isKeyword(); const char *toChars() const; }; #if defined(__GNUC__) #pragma GCC diagnostic pop #endif ================================================ FILE: gcc/d/dmd/traits.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/traits.d, _traits.d) * Documentation: https://dlang.org/phobos/dmd_traits.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/traits.d */ module dmd.traits; import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.attrib; import dmd.canthrow; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.mtype; import dmd.nogc; import dmd.root.array; import dmd.root.speller; import dmd.root.stringtable; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.visitor; import dmd.root.rootobject; enum LOGSEMANTIC = false; /************************ TraitsExp ************************************/ // callback for TypeFunction::attributesApply struct PushAttributes { Expressions* mods; extern (D) static int fp(void* param, string str) { PushAttributes* p = cast(PushAttributes*)param; p.mods.push(new StringExp(Loc.initial, cast(char*)str.ptr, str.length)); return 0; } } /************************************** * Convert `Expression` or `Type` to corresponding `Dsymbol`, additionally * stripping off expression contexts. * * Some symbol related `__traits` ignore arguments expression contexts. * For example: * ---- * struct S { void f() {} } * S s; * pragma(msg, __traits(isNested, s.f)); * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`. * ---- * * This is used for that common `__traits` behavior. * * Input: * oarg object to get the symbol for * Returns: * Dsymbol the corresponding symbol for oarg */ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) { if (auto e = isExpression(oarg)) { if (e.op == TOK.dotVariable) return (cast(DotVarExp)e).var; if (e.op == TOK.dotTemplateDeclaration) return (cast(DotTemplateExp)e).td; } return getDsymbol(oarg); } private __gshared StringTable traitsStringTable; shared static this() { static immutable string[] names = [ "isAbstractClass", "isArithmetic", "isAssociativeArray", "isDisabled", "isDeprecated", "isFuture", "isFinalClass", "isPOD", "isNested", "isFloating", "isIntegral", "isScalar", "isStaticArray", "isUnsigned", "isVirtualFunction", "isVirtualMethod", "isAbstractFunction", "isFinalFunction", "isOverrideFunction", "isStaticFunction", "isRef", "isOut", "isLazy", "isReturnOnStack", "hasMember", "identifier", "getProtection", "parent", "getLinkage", "getMember", "getOverloads", "getVirtualFunctions", "getVirtualMethods", "classInstanceSize", "allMembers", "derivedMembers", "isSame", "compiles", "parameters", "getAliasThis", "getAttributes", "getFunctionAttributes", "getFunctionVariadicStyle", "getParameterStorageClasses", "getUnitTests", "getVirtualIndex", "getPointerBitmap", "isZeroInit", "getTargetInfo" ]; traitsStringTable._init(48); foreach (s; names) { auto sv = traitsStringTable.insert(s.ptr, s.length, cast(void*)s.ptr); assert(sv); } } /** * get an array of size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument * Returns: the size of the type in bytes, d_uns64.max on error */ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) { d_uns64 sz; if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration()) sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc); else sz = t.size(loc); if (sz == SIZE_INVALID) return d_uns64.max; const sz_size_t = Type.tsize_t.size(loc); if (sz > sz.max - sz_size_t) { error(loc, "size overflow for type `%s`", t.toChars()); return d_uns64.max; } d_uns64 bitsPerWord = sz_size_t * 8; d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t; d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; data.setDim(cast(size_t)cntdata); data.zero(); extern (C++) final class PointerBitmapVisitor : Visitor { alias visit = Visitor.visit; public: extern (D) this(Array!(d_uns64)* _data, d_uns64 _sz_size_t) { this.data = _data; this.sz_size_t = _sz_size_t; } void setpointer(d_uns64 off) { d_uns64 ptroff = off / sz_size_t; (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); } override void visit(Type t) { Type tb = t.toBasetype(); if (tb != t) tb.accept(this); } override void visit(TypeError t) { visit(cast(Type)t); } override void visit(TypeNext t) { assert(0); } override void visit(TypeBasic t) { if (t.ty == Tvoid) setpointer(offset); } override void visit(TypeVector t) { } override void visit(TypeArray t) { assert(0); } override void visit(TypeSArray t) { d_uns64 arrayoff = offset; d_uns64 nextsize = t.next.size(); if (nextsize == SIZE_INVALID) error = true; d_uns64 dim = t.dim.toInteger(); for (d_uns64 i = 0; i < dim; i++) { offset = arrayoff + i * nextsize; t.next.accept(this); } offset = arrayoff; } override void visit(TypeDArray t) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr} override void visit(TypeAArray t) { setpointer(offset); } override void visit(TypePointer t) { if (t.nextOf().ty != Tfunction) // don't mark function pointers setpointer(offset); } override void visit(TypeReference t) { setpointer(offset); } override void visit(TypeClass t) { setpointer(offset); } override void visit(TypeFunction t) { } override void visit(TypeDelegate t) { setpointer(offset); } // delegate is {context, function} override void visit(TypeQualified t) { assert(0); } // assume resolved override void visit(TypeIdentifier t) { assert(0); } override void visit(TypeInstance t) { assert(0); } override void visit(TypeTypeof t) { assert(0); } override void visit(TypeReturn t) { assert(0); } override void visit(TypeEnum t) { visit(cast(Type)t); } override void visit(TypeTuple t) { visit(cast(Type)t); } override void visit(TypeSlice t) { assert(0); } override void visit(TypeNull t) { // always a null pointer } override void visit(TypeStruct t) { d_uns64 structoff = offset; foreach (v; t.sym.fields) { offset = structoff + v.offset; if (v.type.ty == Tclass) setpointer(offset); else v.type.accept(this); } offset = structoff; } // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references void visitClass(TypeClass t) { d_uns64 classoff = offset; // skip vtable-ptr and monitor if (t.sym.baseClass) visitClass(cast(TypeClass)t.sym.baseClass.type); foreach (v; t.sym.fields) { offset = classoff + v.offset; v.type.accept(this); } offset = classoff; } Array!(d_uns64)* data; d_uns64 offset; d_uns64 sz_size_t; bool error; } scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t); if (t.ty == Tclass) pbv.visitClass(cast(TypeClass)t); else t.accept(pbv); return pbv.error ? d_uns64.max : sz; } /** * get an array of size_t values that indicate possible pointer words in memory * if interpreted as the type given as argument * the first array element is the size of the type for independent interpretation * of the array * following elements bits represent one word (4/8 bytes depending on the target * architecture). If set the corresponding memory might contain a pointer/reference. * * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] */ private Expression pointerBitmap(TraitsExp e) { if (!e.args || e.args.dim != 1) { error(e.loc, "a single type expected for trait pointerBitmap"); return new ErrorExp(); } Type t = getType((*e.args)[0]); if (!t) { error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); return new ErrorExp(); } Array!(d_uns64) data; d_uns64 sz = getTypePointerBitmap(e.loc, t, &data); if (sz == d_uns64.max) return new ErrorExp(); auto exps = new Expressions(); exps.push(new IntegerExp(e.loc, sz, Type.tsize_t)); foreach (d_uns64 i; 0 .. data.dim) exps.push(new IntegerExp(e.loc, data[cast(size_t)i], Type.tsize_t)); auto ale = new ArrayLiteralExp(e.loc, Type.tsize_t.sarrayOf(data.dim + 1), exps); return ale; } Expression semanticTraits(TraitsExp e, Scope* sc) { static if (LOGSEMANTIC) { printf("TraitsExp::semantic() %s\n", e.toChars()); } if (e.ident != Id.compiles && e.ident != Id.isSame && e.ident != Id.identifier && e.ident != Id.getProtection && e.ident != Id.getAttributes) { if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1)) return new ErrorExp(); } size_t dim = e.args ? e.args.dim : 0; Expression dimError(int expected) { e.error("expected %d arguments for `%s` but had %d", expected, e.ident.toChars(), cast(int)dim); return new ErrorExp(); } IntegerExp True() { return new IntegerExp(e.loc, true, Type.tbool); } IntegerExp False() { return new IntegerExp(e.loc, false, Type.tbool); } /******** * Gets the function type from a given AST node * if the node is a function of some sort. * Params: * o = an AST node to check for a `TypeFunction` * fdp = if `o` is a FuncDeclaration then fdp is set to that, otherwise `null` * Returns: * a type node if `o` is a declaration of * a delegate, function, function-pointer or a variable of the former. * Otherwise, `null`. */ static TypeFunction toTypeFunction(RootObject o, out FuncDeclaration fdp) { Type t; if (auto s = getDsymbolWithoutExpCtx(o)) { if (auto fd = s.isFuncDeclaration()) { t = fd.type; fdp = fd; } else if (auto vd = s.isVarDeclaration()) t = vd.type; else t = isType(o); } else t = isType(o); if (t) { if (t.ty == Tfunction) return cast(TypeFunction)t; else if (t.ty == Tdelegate) return cast(TypeFunction)t.nextOf(); else if (t.ty == Tpointer && t.nextOf().ty == Tfunction) return cast(TypeFunction)t.nextOf(); } return null; } IntegerExp isX(T)(bool function(T) fp) { if (!dim) return False(); foreach (o; *e.args) { static if (is(T == Type)) auto y = getType(o); static if (is(T : Dsymbol)) { auto s = getDsymbolWithoutExpCtx(o); if (!s) return False(); } static if (is(T == Dsymbol)) alias y = s; static if (is(T == Declaration)) auto y = s.isDeclaration(); static if (is(T == FuncDeclaration)) auto y = s.isFuncDeclaration(); static if (is(T == EnumMember)) auto y = s.isEnumMember(); if (!y || !fp(y)) return False(); } return True(); } alias isTypeX = isX!Type; alias isDsymX = isX!Dsymbol; alias isDeclX = isX!Declaration; alias isFuncX = isX!FuncDeclaration; alias isEnumMemX = isX!EnumMember; if (e.ident == Id.isArithmetic) { return isTypeX(t => t.isintegral() || t.isfloating()); } if (e.ident == Id.isFloating) { return isTypeX(t => t.isfloating()); } if (e.ident == Id.isIntegral) { return isTypeX(t => t.isintegral()); } if (e.ident == Id.isScalar) { return isTypeX(t => t.isscalar()); } if (e.ident == Id.isUnsigned) { return isTypeX(t => t.isunsigned()); } if (e.ident == Id.isAssociativeArray) { return isTypeX(t => t.toBasetype().ty == Taarray); } if (e.ident == Id.isDeprecated) { if (global.params.vcomplex) { if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true)) return True(); } return isDsymX(t => t.isDeprecated()); } if (e.ident == Id.isFuture) { return isDeclX(t => t.isFuture()); } if (e.ident == Id.isStaticArray) { return isTypeX(t => t.toBasetype().ty == Tsarray); } if (e.ident == Id.isAbstractClass) { return isTypeX(t => t.toBasetype().ty == Tclass && (cast(TypeClass)t.toBasetype()).sym.isAbstract()); } if (e.ident == Id.isFinalClass) { return isTypeX(t => t.toBasetype().ty == Tclass && ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0); } if (e.ident == Id.isTemplate) { if (dim != 1) return dimError(1); return isDsymX((s) { if (!s.toAlias().isOverloadable()) return false; return overloadApply(s, sm => sm.isTemplateDeclaration() !is null) != 0; }); } if (e.ident == Id.isPOD) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto t = isType(o); if (!t) { e.error("type expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), o.toChars()); return new ErrorExp(); } Type tb = t.baseElemOf(); if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) { return sd.isPOD() ? True() : False(); } return True(); } if (e.ident == Id.isNested) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbolWithoutExpCtx(o); if (!s) { } else if (auto ad = s.isAggregateDeclaration()) { return ad.isNested() ? True() : False(); } else if (auto fd = s.isFuncDeclaration()) { return fd.isNested() ? True() : False(); } e.error("aggregate or function expected instead of `%s`", o.toChars()); return new ErrorExp(); } if (e.ident == Id.isDisabled) { if (dim != 1) return dimError(1); return isDeclX(f => f.isDisabled()); } if (e.ident == Id.isAbstractFunction) { if (dim != 1) return dimError(1); return isFuncX(f => f.isAbstract()); } if (e.ident == Id.isVirtualFunction) { if (dim != 1) return dimError(1); return isFuncX(f => f.isVirtual()); } if (e.ident == Id.isVirtualMethod) { if (dim != 1) return dimError(1); return isFuncX(f => f.isVirtualMethod()); } if (e.ident == Id.isFinalFunction) { if (dim != 1) return dimError(1); return isFuncX(f => f.isFinalFunc()); } if (e.ident == Id.isOverrideFunction) { if (dim != 1) return dimError(1); return isFuncX(f => f.isOverride()); } if (e.ident == Id.isStaticFunction) { if (dim != 1) return dimError(1); return isFuncX(f => !f.needThis() && !f.isNested()); } if (e.ident == Id.isRef) { if (dim != 1) return dimError(1); return isDeclX(d => d.isRef()); } if (e.ident == Id.isOut) { if (dim != 1) return dimError(1); return isDeclX(d => d.isOut()); } if (e.ident == Id.isLazy) { if (dim != 1) return dimError(1); return isDeclX(d => (d.storage_class & STC.lazy_) != 0); } if (e.ident == Id.identifier) { // Get identifier for symbol as a string literal /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 2)) return new ErrorExp(); if (dim != 1) return dimError(1); auto o = (*e.args)[0]; Identifier id; if (auto po = isParameter(o)) { if (!po.ident) { e.error("argument `%s` has no identifier", po.type.toChars()); return new ErrorExp(); } id = po.ident; } else { Dsymbol s = getDsymbolWithoutExpCtx(o); if (!s || !s.ident) { e.error("argument `%s` has no identifier", o.toChars()); return new ErrorExp(); } id = s.ident; } auto se = new StringExp(e.loc, cast(char*)id.toChars()); return se.expressionSemantic(sc); } if (e.ident == Id.getProtection) { if (dim != 1) return dimError(1); Scope* sc2 = sc.push(); sc2.flags = sc.flags | SCOPE.noaccesscheck; bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1); sc2.pop(); if (!ok) return new ErrorExp(); auto o = (*e.args)[0]; auto s = getDsymbolWithoutExpCtx(o); if (!s) { if (!isError(o)) e.error("argument `%s` has no protection", o.toChars()); return new ErrorExp(); } if (s.semanticRun == PASS.init) s.dsymbolSemantic(null); auto protName = protectionToChars(s.prot().kind); // TODO: How about package(names) assert(protName); auto se = new StringExp(e.loc, cast(char*)protName); return se.expressionSemantic(sc); } if (e.ident == Id.parent) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbolWithoutExpCtx(o); if (s) { // https://issues.dlang.org/show_bug.cgi?id=12496 // Consider: // class T1 // { // class C(uint value) { } // } // __traits(parent, T1.C!2) if (auto ad = s.isAggregateDeclaration()) // `s` is `C` { if (ad.isNested()) // `C` is nested { if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not { if (p.isTemplateInstance()) // `C!2` is a template instance s = p; // `C!2`'s parent is `T1` } } } if (auto fd = s.isFuncDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=8943 s = fd.toAliasFunc(); if (!s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=8922 s = s.toParent(); } if (!s || s.isImport()) { e.error("argument `%s` has no parent", o.toChars()); return new ErrorExp(); } if (auto f = s.isFuncDeclaration()) { if (auto td = getFuncTemplateDecl(f)) { if (td.overroot) // if not start of overloaded list of TemplateDeclaration's td = td.overroot; // then get the start Expression ex = new TemplateExp(e.loc, td, f); ex = ex.expressionSemantic(sc); return ex; } if (auto fld = f.isFuncLiteralDeclaration()) { // Directly translate to VarExp instead of FuncExp Expression ex = new VarExp(e.loc, fld, true); return ex.expressionSemantic(sc); } } return resolve(e.loc, sc, s, false); } if (e.ident == Id.hasMember || e.ident == Id.getMember || e.ident == Id.getOverloads || e.ident == Id.getVirtualMethods || e.ident == Id.getVirtualFunctions) { if (dim != 2 && !(dim == 3 && e.ident == Id.getOverloads)) return dimError(2); auto o = (*e.args)[0]; auto ex = isExpression((*e.args)[1]); if (!ex) { e.error("expression expected as second argument of __traits `%s`", e.ident.toChars()); return new ErrorExp(); } ex = ex.ctfeInterpret(); bool includeTemplates = false; if (dim == 3 && e.ident == Id.getOverloads) { auto b = isExpression((*e.args)[2]); b = b.ctfeInterpret(); if (!b.type.equals(Type.tbool)) { e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars()); return new ErrorExp(); } includeTemplates = b.isBool(true); } StringExp se = ex.toStringExp(); if (!se || se.len == 0) { e.error("string expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); return new ErrorExp(); } se = se.toUTF8(sc); if (se.sz != 1) { e.error("string must be chars"); return new ErrorExp(); } auto id = Identifier.idPool(se.peekSlice()); /* Prefer dsymbol, because it might need some runtime contexts. */ Dsymbol sym = getDsymbol(o); if (sym) { if (e.ident == Id.hasMember) { if (auto sm = sym.search(e.loc, id)) return True(); } ex = new DsymbolExp(e.loc, sym); ex = new DotIdExp(e.loc, ex, id); } else if (auto t = isType(o)) ex = typeDotIdExp(e.loc, t, id); else if (auto ex2 = isExpression(o)) ex = new DotIdExp(e.loc, ex2, id); else { e.error("invalid first argument"); return new ErrorExp(); } // ignore symbol visibility for these traits, should disable access checks as well Scope* scx = sc.push(); scx.flags |= SCOPE.ignoresymbolvisibility; scope (exit) scx.pop(); if (e.ident == Id.hasMember) { /* Take any errors as meaning it wasn't found */ ex = ex.trySemantic(scx); return ex ? True() : False(); } else if (e.ident == Id.getMember) { if (ex.op == TOK.dotIdentifier) // Prevent semantic() from replacing Symbol with its initializer (cast(DotIdExp)ex).wantsym = true; ex = ex.expressionSemantic(scx); return ex; } else if (e.ident == Id.getVirtualFunctions || e.ident == Id.getVirtualMethods || e.ident == Id.getOverloads) { uint errors = global.errors; Expression eorig = ex; ex = ex.expressionSemantic(scx); if (errors < global.errors) e.error("`%s` cannot be resolved", eorig.toChars()); /* Create tuple of functions of ex */ auto exps = new Expressions(); Dsymbol f; if (ex.op == TOK.variable) { VarExp ve = cast(VarExp)ex; f = ve.var.isFuncDeclaration(); ex = null; } else if (ex.op == TOK.dotVariable) { DotVarExp dve = cast(DotVarExp)ex; f = dve.var.isFuncDeclaration(); if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_) ex = null; else ex = dve.e1; } else if (ex.op == TOK.template_) { VarExp ve = cast(VarExp)ex; auto td = ve.var.isTemplateDeclaration(); f = td; if (td && td.funcroot) f = td.funcroot; ex = null; } bool[string] funcTypeHash; /* Compute the function signature and insert it in the * hashtable, if not present. This is needed so that * traits(getOverlods, F3, "visit") does not count `int visit(int)` * twice in the following example: * * ============================================= * interface F1 { int visit(int);} * interface F2 { int visit(int); void visit(); } * interface F3 : F2, F1 {} *============================================== */ void insertInterfaceInheritedFunction(FuncDeclaration fd, Expression e) { auto funcType = fd.type.toChars(); auto len = strlen(funcType); string signature = funcType[0 .. len].idup; //printf("%s - %s\n", fd.toChars, signature); if (signature !in funcTypeHash) { funcTypeHash[signature] = true; exps.push(e); } } int dg(Dsymbol s) { if (includeTemplates) { exps.push(new DsymbolExp(Loc.initial, s, false)); return 0; } auto fd = s.isFuncDeclaration(); if (!fd) return 0; if (e.ident == Id.getVirtualFunctions && !fd.isVirtual()) return 0; if (e.ident == Id.getVirtualMethods && !fd.isVirtualMethod()) return 0; auto fa = new FuncAliasDeclaration(fd.ident, fd, false); fa.protection = fd.protection; auto e = ex ? new DotVarExp(Loc.initial, ex, fa, false) : new DsymbolExp(Loc.initial, fa, false); // if the parent is an interface declaration // we must check for functions with the same signature // in different inherited interfaces if (sym && sym.isInterfaceDeclaration()) insertInterfaceInheritedFunction(fd, e); else exps.push(e); return 0; } InterfaceDeclaration ifd = null; if (sym) ifd = sym.isInterfaceDeclaration(); // If the symbol passed as a parameter is an // interface that inherits other interfaces overloadApply(f, &dg); if (ifd && ifd.interfaces && f) { // check the overloads of each inherited interface individually foreach (bc; ifd.interfaces) { if (auto fd = bc.sym.search(e.loc, f.ident)) overloadApply(fd, &dg); } } auto tup = new TupleExp(e.loc, exps); return tup.expressionSemantic(scx); } else assert(0); } if (e.ident == Id.classInstanceSize) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbol(o); auto cd = s ? s.isClassDeclaration() : null; if (!cd) { e.error("first argument is not a class"); return new ErrorExp(); } if (cd.sizeok != Sizeok.done) { cd.size(e.loc); } if (cd.sizeok != Sizeok.done) { e.error("%s `%s` is forward referenced", cd.kind(), cd.toChars()); return new ErrorExp(); } return new IntegerExp(e.loc, cd.structsize, Type.tsize_t); } if (e.ident == Id.getAliasThis) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbol(o); auto ad = s ? s.isAggregateDeclaration() : null; if (!ad) { e.error("argument is not an aggregate type"); return new ErrorExp(); } auto exps = new Expressions(); if (ad.aliasthis) exps.push(new StringExp(e.loc, cast(char*)ad.aliasthis.ident.toChars())); Expression ex = new TupleExp(e.loc, exps); ex = ex.expressionSemantic(sc); return ex; } if (e.ident == Id.getAttributes) { /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that * a symbol should not be folded to a constant. * Bit 1 means don't convert Parameter to Type if Parameter has an identifier */ if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 3)) return new ErrorExp(); if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto po = isParameter(o); auto s = getDsymbolWithoutExpCtx(o); UserAttributeDeclaration udad = null; if (po) { udad = po.userAttribDecl; } else if (s) { if (s.isImport()) { s = s.isImport().mod; } //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope); udad = s.userAttribDecl; } else { version (none) { Expression x = isExpression(o); Type t = isType(o); if (x) printf("e = %s %s\n", Token.toChars(x.op), x.toChars()); if (t) printf("t = %d %s\n", t.ty, t.toChars()); } e.error("first argument is not a symbol"); return new ErrorExp(); } auto exps = udad ? udad.getAttributes() : new Expressions(); auto tup = new TupleExp(e.loc, exps); return tup.expressionSemantic(sc); } if (e.ident == Id.getFunctionAttributes) { /* Extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. * https://dlang.org/spec/traits.html#getFunctionAttributes */ if (dim != 1) return dimError(1); FuncDeclaration fd; TypeFunction tf = toTypeFunction((*e.args)[0], fd); if (!tf) { e.error("first argument is not a function"); return new ErrorExp(); } auto mods = new Expressions(); PushAttributes pa; pa.mods = mods; tf.modifiersApply(&pa, &PushAttributes.fp); tf.attributesApply(&pa, &PushAttributes.fp, TRUSTformatSystem); auto tup = new TupleExp(e.loc, mods); return tup.expressionSemantic(sc); } if (e.ident == Id.isReturnOnStack) { /* Extract as a boolean if function return value is on the stack * https://dlang.org/spec/traits.html#isReturnOnStack */ if (dim != 1) return dimError(1); RootObject o = (*e.args)[0]; FuncDeclaration fd; TypeFunction tf = toTypeFunction(o, fd); if (!tf) { e.error("argument to `__traits(isReturnOnStack, %s)` is not a function", o.toChars()); return new ErrorExp(); } bool value = Target.isReturnOnStack(tf, fd && fd.needThis()); return new IntegerExp(e.loc, value, Type.tbool); } if (e.ident == Id.getFunctionVariadicStyle) { /* Accept a symbol or a type. Returns one of the following: * "none" not a variadic function * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments` * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg * "typesafe" void typesafe(T[] ...) */ // get symbol linkage as a string if (dim != 1) return dimError(1); LINK link; int varargs; auto o = (*e.args)[0]; FuncDeclaration fd; TypeFunction tf = toTypeFunction(o, fd); if (tf) { link = tf.linkage; varargs = tf.varargs; } else { if (!fd) { e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars()); return new ErrorExp(); } link = fd.linkage; fd.getParameters(&varargs); } string style; switch (varargs) { case 0: style = "none"; break; case 1: style = (link == LINK.d) ? "argptr" : "stdarg"; break; case 2: style = "typesafe"; break; default: assert(0); } auto se = new StringExp(e.loc, cast(char*)style); return se.expressionSemantic(sc); } if (e.ident == Id.getParameterStorageClasses) { /* Accept a function symbol or a type, followed by a parameter index. * Returns a tuple of strings of the parameter's storage classes. */ // get symbol linkage as a string if (dim != 2) return dimError(2); auto o = (*e.args)[0]; auto o1 = (*e.args)[1]; FuncDeclaration fd; TypeFunction tf = toTypeFunction(o, fd); Parameters* fparams; if (tf) { fparams = tf.parameters; } else { if (!fd) { e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", o.toChars(), o1.toChars()); return new ErrorExp(); } fparams = fd.getParameters(null); } StorageClass stc; // Set stc to storage class of the ith parameter auto ex = isExpression((*e.args)[1]); if (!ex) { e.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`", o.toChars(), o1.toChars()); return new ErrorExp(); } ex = ex.ctfeInterpret(); auto ii = ex.toUInteger(); if (ii >= Parameter.dim(fparams)) { e.error("parameter index must be in range 0..%u not %s", cast(uint)Parameter.dim(fparams), ex.toChars()); return new ErrorExp(); } uint n = cast(uint)ii; Parameter p = Parameter.getNth(fparams, n); stc = p.storageClass; // This mirrors hdrgen.visit(Parameter p) if (p.type && p.type.mod & MODFlags.shared_) stc &= ~STC.shared_; auto exps = new Expressions; void push(string s) { exps.push(new StringExp(e.loc, cast(char*)s.ptr, cast(uint)s.length)); } if (stc & STC.auto_) push("auto"); if (stc & STC.return_) push("return"); if (stc & STC.out_) push("out"); else if (stc & STC.ref_) push("ref"); else if (stc & STC.in_) push("in"); else if (stc & STC.lazy_) push("lazy"); else if (stc & STC.alias_) push("alias"); if (stc & STC.const_) push("const"); if (stc & STC.immutable_) push("immutable"); if (stc & STC.wild) push("inout"); if (stc & STC.shared_) push("shared"); if (stc & STC.scope_ && !(stc & STC.scopeinferred)) push("scope"); auto tup = new TupleExp(e.loc, exps); return tup.expressionSemantic(sc); } if (e.ident == Id.getLinkage) { // get symbol linkage as a string if (dim != 1) return dimError(1); LINK link; auto o = (*e.args)[0]; FuncDeclaration fd; TypeFunction tf = toTypeFunction(o, fd); if (tf) link = tf.linkage; else { auto s = getDsymbol(o); Declaration d; AggregateDeclaration agg; if (!s || ((d = s.isDeclaration()) is null && (agg = s.isAggregateDeclaration()) is null)) { e.error("argument to `__traits(getLinkage, %s)` is not a declaration", o.toChars()); return new ErrorExp(); } if (d !is null) link = d.linkage; else final switch (agg.classKind) { case ClassKind.d: link = LINK.d; break; case ClassKind.cpp: link = LINK.cpp; break; case ClassKind.objc: link = LINK.objc; break; } } auto linkage = linkageToChars(link); auto se = new StringExp(e.loc, cast(char*)linkage); return se.expressionSemantic(sc); } if (e.ident == Id.allMembers || e.ident == Id.derivedMembers) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbol(o); if (!s) { e.error("argument has no members"); return new ErrorExp(); } if (auto imp = s.isImport()) { // https://issues.dlang.org/show_bug.cgi?id=9692 s = imp.mod; } auto sds = s.isScopeDsymbol(); if (!sds || sds.isTemplateDeclaration()) { e.error("%s `%s` has no members", s.kind(), s.toChars()); return new ErrorExp(); } auto idents = new Identifiers(); int pushIdentsDg(size_t n, Dsymbol sm) { if (!sm) return 1; // skip local symbols, such as static foreach loop variables if (auto decl = sm.isDeclaration()) { if (decl.storage_class & STC.local) { return 0; } } //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars()); if (sm.ident) { const idx = sm.ident.toChars(); if (idx[0] == '_' && idx[1] == '_' && sm.ident != Id.ctor && sm.ident != Id.dtor && sm.ident != Id.__xdtor && sm.ident != Id.postblit && sm.ident != Id.__xpostblit) { return 0; } if (sm.ident == Id.empty) { return 0; } if (sm.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177 return 0; if (!sds.isModule() && sm.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057 return 0; //printf("\t%s\n", sm.ident.toChars()); /* Skip if already present in idents[] */ foreach (id; *idents) { if (id == sm.ident) return 0; // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. debug assert(strcmp(id.toChars(), sm.ident.toChars()) != 0); } idents.push(sm.ident); } else if (auto ed = sm.isEnumDeclaration()) { ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg); } return 0; } ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg); auto cd = sds.isClassDeclaration(); if (cd && e.ident == Id.allMembers) { if (cd.semanticRun < PASS.semanticdone) cd.dsymbolSemantic(null); // https://issues.dlang.org/show_bug.cgi?id=13668 // Try to resolve forward reference void pushBaseMembersDg(ClassDeclaration cd) { for (size_t i = 0; i < cd.baseclasses.dim; i++) { auto cb = (*cd.baseclasses)[i].sym; assert(cb); ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg); if (cb.baseclasses.dim) pushBaseMembersDg(cb); } } pushBaseMembersDg(cd); } // Turn Identifiers into StringExps reusing the allocated array assert(Expressions.sizeof == Identifiers.sizeof); auto exps = cast(Expressions*)idents; foreach (i, id; *idents) { auto se = new StringExp(e.loc, cast(char*)id.toChars()); (*exps)[i] = se; } /* Making this a tuple is more flexible, as it can be statically unrolled. * To make an array literal, enclose __traits in [ ]: * [ __traits(allMembers, ...) ] */ Expression ex = new TupleExp(e.loc, exps); ex = ex.expressionSemantic(sc); return ex; } if (e.ident == Id.compiles) { /* Determine if all the objects - types, expressions, or symbols - * compile without error */ if (!dim) return False(); foreach (o; *e.args) { uint errors = global.startGagging(); Scope* sc2 = sc.push(); sc2.tinst = null; sc2.minst = null; sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst; bool err = false; auto t = isType(o); auto ex = t ? t.typeToExpression() : isExpression(o); if (!ex && t) { Dsymbol s; t.resolve(e.loc, sc2, &ex, &t, &s); if (t) { t.typeSemantic(e.loc, sc2); if (t.ty == Terror) err = true; } else if (s && s.errors) err = true; } if (ex) { ex = ex.expressionSemantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex.optimize(WANTvalue); if (sc2.func && sc2.func.type.ty == Tfunction) { const tf = cast(TypeFunction)sc2.func.type; err |= tf.isnothrow && canThrow(ex, sc2.func, false); } ex = checkGC(sc2, ex); if (ex.op == TOK.error) err = true; } // Carefully detach the scope from the parent and throw it away as // we only need it to evaluate the expression // https://issues.dlang.org/show_bug.cgi?id=15428 sc2.detach(); if (global.endGagging(errors) || err) { return False(); } } return True(); } if (e.ident == Id.isSame) { /* Determine if two symbols are the same */ if (dim != 2) return dimError(2); if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 0)) return new ErrorExp(); auto o1 = (*e.args)[0]; auto o2 = (*e.args)[1]; static FuncLiteralDeclaration isLambda(RootObject oarg) { if (auto t = isDsymbol(oarg)) { if (auto td = t.isTemplateDeclaration()) { if (td.members && td.members.dim == 1) { if (auto fd = (*td.members)[0].isFuncLiteralDeclaration()) return fd; } } } else if (auto ea = isExpression(oarg)) { if (ea.op == TOK.function_) { if (auto fe = cast(FuncExp)ea) return fe.fd; } } return null; } auto l1 = isLambda(o1); auto l2 = isLambda(o2); if (l1 && l2) { import dmd.lambdacomp : isSameFuncLiteral; if (isSameFuncLiteral(l1, l2, sc)) return True(); } auto s1 = getDsymbol(o1); auto s2 = getDsymbol(o2); //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars()); version (none) { printf("o1: %p\n", o1); printf("o2: %p\n", o2); if (!s1) { if (auto ea = isExpression(o1)) printf("%s\n", ea.toChars()); if (auto ta = isType(o1)) printf("%s\n", ta.toChars()); return False(); } else printf("%s %s\n", s1.kind(), s1.toChars()); } if (!s1 && !s2) { auto ea1 = isExpression(o1); auto ea2 = isExpression(o2); if (ea1 && ea2) { if (ea1.equals(ea2)) return True(); } } if (!s1 || !s2) return False(); s1 = s1.toAlias(); s2 = s2.toAlias(); if (auto fa1 = s1.isFuncAliasDeclaration()) s1 = fa1.toAliasFunc(); if (auto fa2 = s2.isFuncAliasDeclaration()) s2 = fa2.toAliasFunc(); // https://issues.dlang.org/show_bug.cgi?id=11259 // compare import symbol to a package symbol static bool cmp(Dsymbol s1, Dsymbol s2) { auto imp = s1.isImport(); return imp && imp.pkg && imp.pkg == s2.isPackage(); } if (cmp(s1,s2) || cmp(s2,s1)) return True(); if (s1 == s2) return True(); // https://issues.dlang.org/show_bug.cgi?id=18771 // OverloadSets are equal if they contain the same functions auto overSet1 = s1.isOverloadSet(); if (!overSet1) return False(); auto overSet2 = s2.isOverloadSet(); if (!overSet2) return False(); if (overSet1.a.dim != overSet2.a.dim) return False(); // OverloadSets contain array of Dsymbols => O(n*n) // to compare for equality as the order of overloads // might not be the same Lnext: foreach(overload1; overSet1.a) { foreach(overload2; overSet2.a) { if (overload1 == overload2) continue Lnext; } return False(); } return True(); } if (e.ident == Id.getUnitTests) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbolWithoutExpCtx(o); if (!s) { e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate", o.toChars()); return new ErrorExp(); } if (auto imp = s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990 s = imp.mod; auto sds = s.isScopeDsymbol(); if (!sds) { e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate, not a %s", s.toChars(), s.kind()); return new ErrorExp(); } auto exps = new Expressions(); if (global.params.useUnitTests) { bool[void*] uniqueUnitTests; void collectUnitTests(Dsymbols* a) { if (!a) return; foreach (s; *a) { if (auto atd = s.isAttribDeclaration()) { collectUnitTests(atd.include(null)); continue; } if (auto ud = s.isUnitTestDeclaration()) { if (cast(void*)ud in uniqueUnitTests) continue; auto ad = new FuncAliasDeclaration(ud.ident, ud, false); ad.protection = ud.protection; auto e = new DsymbolExp(Loc.initial, ad, false); exps.push(e); uniqueUnitTests[cast(void*)ud] = true; } } } collectUnitTests(sds.members); } auto te = new TupleExp(e.loc, exps); return te.expressionSemantic(sc); } if (e.ident == Id.getVirtualIndex) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; auto s = getDsymbolWithoutExpCtx(o); auto fd = s ? s.isFuncDeclaration() : null; if (!fd) { e.error("first argument to __traits(getVirtualIndex) must be a function"); return new ErrorExp(); } fd = fd.toAliasFunc(); // Necessary to support multiple overloads. return new IntegerExp(e.loc, fd.vtblIndex, Type.tptrdiff_t); } if (e.ident == Id.getPointerBitmap) { return pointerBitmap(e); } if (e.ident == Id.isZeroInit) { if (dim != 1) return dimError(1); auto o = (*e.args)[0]; Type t = isType(o); if (!t) { e.error("type expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), o.toChars()); return new ErrorExp(); } Type tb = t.baseElemOf(); return tb.isZeroInit(e.loc) ? True() : False(); } if (e.ident == Id.getTargetInfo) { if (dim != 1) return dimError(1); auto ex = isExpression((*e.args)[0]); StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null; if (!ex || !se || se.len == 0) { e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); return new ErrorExp(); } se = se.toUTF8(sc); Expression r = Target.getTargetInfo(se.toPtr(), e.loc); if (!r) { e.error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se.toPtr()); return new ErrorExp(); } return r.expressionSemantic(sc); } extern (D) void* trait_search_fp(const(char)* seed, ref int cost) { //printf("trait_search_fp('%s')\n", seed); size_t len = strlen(seed); if (!len) return null; cost = 0; StringValue* sv = traitsStringTable.lookup(seed, len); return sv ? sv.ptrvalue : null; } if (auto sub = cast(const(char)*)speller(e.ident.toChars(), &trait_search_fp, idchars)) e.error("unrecognized trait `%s`, did you mean `%s`?", e.ident.toChars(), sub); else e.error("unrecognized trait `%s`", e.ident.toChars()); return new ErrorExp(); } ================================================ FILE: gcc/d/dmd/transitivevisitor.d ================================================ /** * Documentation: https://dlang.org/phobos/dmd_transitivevisitor.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/transitivevisitor.d */ module dmd.transitivevisitor; import dmd.permissivevisitor; import dmd.tokens; import dmd.root.rootobject; import core.stdc.stdio; /** Visitor that implements the AST traversal logic. The nodes just accept their children. */ extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST { alias visit = PermissiveVisitor!AST.visit; mixin ParseVisitMethods!AST; } /* This mixin implements the AST traversal logic for parse time AST nodes. The same code * is used for semantic time AST node traversal, so in order to not duplicate the code, * the template mixin is used. */ package mixin template ParseVisitMethods(AST) { // Statement Nodes //=========================================================== override void visit(AST.ExpStatement s) { //printf("Visiting ExpStatement\n"); if (s.exp && s.exp.op == TOK.declaration) { (cast(AST.DeclarationExp)s.exp).declaration.accept(this); return; } if (s.exp) s.exp.accept(this); } override void visit(AST.CompileStatement s) { //printf("Visiting CompileStatement\n"); visitArgs(s.exps); } override void visit(AST.CompoundStatement s) { //printf("Visiting CompoundStatement\n"); foreach (sx; *s.statements) { if (sx) sx.accept(this); } } void visitVarDecl(AST.VarDeclaration v) { //printf("Visiting VarDeclaration\n"); if (v.type) visitType(v.type); if (v._init) { auto ie = v._init.isExpInitializer(); if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) (cast(AST.AssignExp)ie.exp).e2.accept(this); else v._init.accept(this); } } override void visit(AST.CompoundDeclarationStatement s) { //printf("Visiting CompoundDeclarationStatement\n"); foreach (sx; *s.statements) { auto ds = sx ? sx.isExpStatement() : null; if (ds && ds.exp.op == TOK.declaration) { auto d = (cast(AST.DeclarationExp)ds.exp).declaration; assert(d.isDeclaration()); if (auto v = d.isVarDeclaration()) visitVarDecl(v); else d.accept(this); } } } override void visit(AST.ScopeStatement s) { //printf("Visiting ScopeStatement\n"); if (s.statement) s.statement.accept(this); } override void visit(AST.WhileStatement s) { //printf("Visiting WhileStatement\n"); s.condition.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.DoStatement s) { //printf("Visiting DoStatement\n"); if (s._body) s._body.accept(this); s.condition.accept(this); } override void visit(AST.ForStatement s) { //printf("Visiting ForStatement\n"); if (s._init) s._init.accept(this); if (s.condition) s.condition.accept(this); if (s.increment) s.increment.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.ForeachStatement s) { //printf("Visiting ForeachStatement\n"); foreach (p; *s.parameters) if (p.type) visitType(p.type); s.aggr.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.ForeachRangeStatement s) { //printf("Visiting ForeachRangeStatement\n"); if (s.prm.type) visitType(s.prm.type); s.lwr.accept(this); s.upr.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.IfStatement s) { //printf("Visiting IfStatement\n"); if (s.prm && s.prm.type) visitType(s.prm.type); s.condition.accept(this); s.ifbody.accept(this); if (s.elsebody) s.elsebody.accept(this); } override void visit(AST.ConditionalStatement s) { //printf("Visiting ConditionalStatement\n"); s.condition.accept(this); if (s.ifbody) s.ifbody.accept(this); if (s.elsebody) s.elsebody.accept(this); } void visitArgs(AST.Expressions* expressions, AST.Expression basis = null) { if (!expressions || !expressions.dim) return; foreach (el; *expressions) { if (!el) el = basis; if (el) el.accept(this); } } override void visit(AST.PragmaStatement s) { //printf("Visiting PragmaStatement\n"); if (s.args && s.args.dim) visitArgs(s.args); if (s._body) s._body.accept(this); } override void visit(AST.StaticAssertStatement s) { //printf("Visiting StaticAssertStatement\n"); s.sa.accept(this); } override void visit(AST.SwitchStatement s) { //printf("Visiting SwitchStatement\n"); s.condition.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.CaseStatement s) { //printf("Visiting CaseStatement\n"); s.exp.accept(this); s.statement.accept(this); } override void visit(AST.CaseRangeStatement s) { //printf("Visiting CaseRangeStatement\n"); s.first.accept(this); s.last.accept(this); s.statement.accept(this); } override void visit(AST.DefaultStatement s) { //printf("Visiting DefaultStatement\n"); s.statement.accept(this); } override void visit(AST.GotoCaseStatement s) { //printf("Visiting GotoCaseStatement\n"); if (s.exp) s.exp.accept(this); } override void visit(AST.ReturnStatement s) { //printf("Visiting ReturnStatement\n"); if (s.exp) s.exp.accept(this); } override void visit(AST.SynchronizedStatement s) { //printf("Visiting SynchronizedStatement\n"); if (s.exp) s.exp.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.WithStatement s) { //printf("Visiting WithStatement\n"); s.exp.accept(this); if (s._body) s._body.accept(this); } override void visit(AST.TryCatchStatement s) { //printf("Visiting TryCatchStatement\n"); if (s._body) s._body.accept(this); foreach (c; *s.catches) visit(c); } override void visit(AST.TryFinallyStatement s) { //printf("Visiting TryFinallyStatement\n"); s._body.accept(this); s.finalbody.accept(this); } override void visit(AST.OnScopeStatement s) { //printf("Visiting OnScopeStatement\n"); s.statement.accept(this); } override void visit(AST.ThrowStatement s) { //printf("Visiting ThrowStatement\n"); s.exp.accept(this); } override void visit(AST.LabelStatement s) { //printf("Visiting LabelStatement\n"); if (s.statement) s.statement.accept(this); } override void visit(AST.ImportStatement s) { //printf("Visiting ImportStatement\n"); foreach (imp; *s.imports) imp.accept(this); } void visit(AST.Catch c) { //printf("Visiting Catch\n"); if (c.type) visitType(c.type); if (c.handler) c.handler.accept(this); } // Type Nodes //============================================================ void visitType(AST.Type t) { //printf("Visiting Type\n"); if (!t) return; if (t.ty == AST.Tfunction) { visitFunctionType(cast(AST.TypeFunction)t, null); return; } else t.accept(this); } void visitFunctionType(AST.TypeFunction t, AST.TemplateDeclaration td) { if (t.next) visitType(t.next); if (td) { foreach (p; *td.origParameters) p.accept(this); } visitParameters(t.parameters); } void visitParameters(AST.Parameters* parameters) { if (parameters) { size_t dim = AST.Parameter.dim(parameters); foreach(i; 0..dim) { AST.Parameter fparam = AST.Parameter.getNth(parameters, i); fparam.accept(this); } } } override void visit(AST.TypeVector t) { //printf("Visiting TypeVector\n"); if (!t.basetype) return; t.basetype.accept(this); } override void visit(AST.TypeSArray t) { //printf("Visiting TypeSArray\n"); t.next.accept(this); } override void visit(AST.TypeDArray t) { //printf("Visiting TypeDArray\n"); t.next.accept(this); } override void visit(AST.TypeAArray t) { //printf("Visiting TypeAArray\n"); t.next.accept(this); t.index.accept(this); } override void visit(AST.TypePointer t) { //printf("Visiting TypePointer\n"); if (t.next.ty == AST.Tfunction) { visitFunctionType(cast(AST.TypeFunction)t.next, null); } else t.next.accept(this); } override void visit(AST.TypeReference t) { //printf("Visiting TypeReference\n"); t.next.accept(this); } override void visit(AST.TypeFunction t) { //printf("Visiting TypeFunction\n"); visitFunctionType(t, null); } override void visit(AST.TypeDelegate t) { //printf("Visiting TypeDelegate\n"); visitFunctionType(cast(AST.TypeFunction)t.next, null); } void visitTypeQualified(AST.TypeQualified t) { //printf("Visiting TypeQualified\n"); foreach (id; t.idents) { if (id.dyncast() == DYNCAST.dsymbol) (cast(AST.TemplateInstance)id).accept(this); else if (id.dyncast() == DYNCAST.expression) (cast(AST.Expression)id).accept(this); else if (id.dyncast() == DYNCAST.type) (cast(AST.Type)id).accept(this); } } override void visit(AST.TypeIdentifier t) { //printf("Visiting TypeIdentifier\n"); visitTypeQualified(t); } override void visit(AST.TypeInstance t) { //printf("Visiting TypeInstance\n"); t.tempinst.accept(this); visitTypeQualified(t); } override void visit(AST.TypeTypeof t) { //printf("Visiting TypeTypeof\n"); t.exp.accept(this); visitTypeQualified(t); } override void visit(AST.TypeReturn t) { //printf("Visiting TypeReturn\n"); visitTypeQualified(t); } override void visit(AST.TypeTuple t) { //printf("Visiting TypeTuple\n"); visitParameters(t.arguments); } override void visit(AST.TypeSlice t) { //printf("Visiting TypeSlice\n"); t.next.accept(this); t.lwr.accept(this); t.upr.accept(this); } // Miscellaneous //======================================================== override void visit(AST.StaticAssert s) { //printf("Visiting StaticAssert\n"); s.exp.accept(this); if (s.msg) s.msg.accept(this); } override void visit(AST.EnumMember em) { //printf("Visiting EnumMember\n"); if (em.type) visitType(em.type); if (em.value) em.value.accept(this); } // Declarations //========================================================= void visitAttribDeclaration(AST.AttribDeclaration d) { if (d.decl) foreach (de; *d.decl) de.accept(this); } override void visit(AST.AttribDeclaration d) { //printf("Visiting AttribDeclaration\n"); visitAttribDeclaration(d); } override void visit(AST.StorageClassDeclaration d) { //printf("Visiting StorageClassDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.DeprecatedDeclaration d) { //printf("Visiting DeprecatedDeclaration\n"); d.msg.accept(this); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.LinkDeclaration d) { //printf("Visiting LinkDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.CPPMangleDeclaration d) { //printf("Visiting CPPMangleDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.ProtDeclaration d) { //printf("Visiting ProtDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.AlignDeclaration d) { //printf("Visiting AlignDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.AnonDeclaration d) { //printf("Visiting AnonDeclaration\n"); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.PragmaDeclaration d) { //printf("Visiting PragmaDeclaration\n"); if (d.args && d.args.dim) visitArgs(d.args); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } override void visit(AST.ConditionalDeclaration d) { //printf("Visiting ConditionalDeclaration\n"); d.condition.accept(this); if (d.decl) foreach (de; *d.decl) de.accept(this); if (d.elsedecl) foreach (de; *d.elsedecl) de.accept(this); } override void visit(AST.CompileDeclaration d) { //printf("Visiting compileDeclaration\n"); visitArgs(d.exps); } override void visit(AST.UserAttributeDeclaration d) { //printf("Visiting UserAttributeDeclaration\n"); visitArgs(d.atts); visitAttribDeclaration(cast(AST.AttribDeclaration)d); } void visitFuncBody(AST.FuncDeclaration f) { //printf("Visiting funcBody\n"); if (f.frequires) { foreach (frequire; *f.frequires) { frequire.accept(this); } } if (f.fensures) { foreach (fensure; *f.fensures) { fensure.ensure.accept(this); } } if (f.fbody) { f.fbody.accept(this); } } void visitBaseClasses(AST.ClassDeclaration d) { //printf("Visiting ClassDeclaration\n"); if (!d || !d.baseclasses.dim) return; foreach (b; *d.baseclasses) visitType(b.type); } bool visitEponymousMember(AST.TemplateDeclaration d) { //printf("Visiting EponymousMember\n"); if (!d.members || d.members.dim != 1) return false; AST.Dsymbol onemember = (*d.members)[0]; if (onemember.ident != d.ident) return false; if (AST.FuncDeclaration fd = onemember.isFuncDeclaration()) { assert(fd.type); visitFunctionType(cast(AST.TypeFunction)fd.type, d); if (d.constraint) d.constraint.accept(this); visitFuncBody(fd); return true; } if (AST.AggregateDeclaration ad = onemember.isAggregateDeclaration()) { visitTemplateParameters(d.parameters); if (d.constraint) d.constraint.accept(this); visitBaseClasses(ad.isClassDeclaration()); if (ad.members) foreach (s; *ad.members) s.accept(this); return true; } if (AST.VarDeclaration vd = onemember.isVarDeclaration()) { if (d.constraint) return false; if (vd.type) visitType(vd.type); visitTemplateParameters(d.parameters); if (vd._init) { AST.ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) (cast(AST.AssignExp)ie.exp).e2.accept(this); else vd._init.accept(this); return true; } } return false; } void visitTemplateParameters(AST.TemplateParameters* parameters) { if (!parameters || !parameters.dim) return; foreach (p; *parameters) p.accept(this); } override void visit(AST.TemplateDeclaration d) { //printf("Visiting TemplateDeclaration\n"); if (visitEponymousMember(d)) return; visitTemplateParameters(d.parameters); if (d.constraint) d.constraint.accept(this); foreach (s; *d.members) s.accept(this); } void visitObject(RootObject oarg) { if (auto t = AST.isType(oarg)) { visitType(t); } else if (auto e = AST.isExpression(oarg)) { e.accept(this); } else if (auto v = AST.isTuple(oarg)) { auto args = &v.objects; foreach (arg; *args) visitObject(arg); } } void visitTiargs(AST.TemplateInstance ti) { //printf("Visiting tiargs\n"); if (!ti.tiargs) return; foreach (arg; *ti.tiargs) { visitObject(arg); } } override void visit(AST.TemplateInstance ti) { //printf("Visiting TemplateInstance\n"); visitTiargs(ti); } override void visit(AST.TemplateMixin tm) { //printf("Visiting TemplateMixin\n"); visitType(tm.tqual); visitTiargs(tm); } override void visit(AST.EnumDeclaration d) { //printf("Visiting EnumDeclaration\n"); if (d.memtype) visitType(d.memtype); if (!d.members) return; foreach (em; *d.members) { if (!em) continue; em.accept(this); } } override void visit(AST.Nspace d) { //printf("Visiting Nspace\n"); foreach(s; *d.members) s.accept(this); } override void visit(AST.StructDeclaration d) { //printf("Visiting StructDeclaration\n"); if (!d.members) return; foreach (s; *d.members) s.accept(this); } override void visit(AST.ClassDeclaration d) { //printf("Visiting ClassDeclaration\n"); visitBaseClasses(d); if (d.members) foreach (s; *d.members) s.accept(this); } override void visit(AST.AliasDeclaration d) { //printf("Visting AliasDeclaration\n"); if (d.aliassym) d.aliassym.accept(this); else visitType(d.type); } override void visit(AST.VarDeclaration d) { //printf("Visiting VarDeclaration\n"); visitVarDecl(d); } override void visit(AST.FuncDeclaration f) { //printf("Visiting FuncDeclaration\n"); auto tf = cast(AST.TypeFunction)f.type; visitType(tf); visitFuncBody(f); } override void visit(AST.FuncLiteralDeclaration f) { //printf("Visiting FuncLiteralDeclaration\n"); if (f.type.ty == AST.Terror) return; AST.TypeFunction tf = cast(AST.TypeFunction)f.type; if (!f.inferRetType && tf.next) visitType(tf.next); visitParameters(tf.parameters); AST.CompoundStatement cs = f.fbody.isCompoundStatement(); AST.Statement s = !cs ? f.fbody : null; AST.ReturnStatement rs = s ? s.isReturnStatement() : null; if (rs && rs.exp) rs.exp.accept(this); else visitFuncBody(f); } override void visit(AST.PostBlitDeclaration d) { //printf("Visiting PostBlitDeclaration\n"); visitFuncBody(d); } override void visit(AST.DtorDeclaration d) { //printf("Visiting DtorDeclaration\n"); visitFuncBody(d); } override void visit(AST.StaticCtorDeclaration d) { //printf("Visiting StaticCtorDeclaration\n"); visitFuncBody(d); } override void visit(AST.StaticDtorDeclaration d) { //printf("Visiting StaticDtorDeclaration\n"); visitFuncBody(d); } override void visit(AST.InvariantDeclaration d) { //printf("Visiting InvariantDeclaration\n"); visitFuncBody(d); } override void visit(AST.UnitTestDeclaration d) { //printf("Visiting UnitTestDeclaration\n"); visitFuncBody(d); } override void visit(AST.NewDeclaration d) { //printf("Visiting NewDeclaration\n"); visitParameters(d.parameters); visitFuncBody(d); } override void visit(AST.DeleteDeclaration d) { //printf("Visiting DeleteDeclaration\n"); visitParameters(d.parameters); visitFuncBody(d); } // Initializers //============================================================ override void visit(AST.StructInitializer si) { //printf("Visiting StructInitializer\n"); foreach (i, const id; si.field) if (auto iz = si.value[i]) iz.accept(this); } override void visit(AST.ArrayInitializer ai) { //printf("Visiting ArrayInitializer\n"); foreach (i, ex; ai.index) { if (ex) ex.accept(this); if (auto iz = ai.value[i]) iz.accept(this); } } override void visit(AST.ExpInitializer ei) { //printf("Visiting ExpInitializer\n"); ei.exp.accept(this); } // Expressions //=================================================== override void visit(AST.ArrayLiteralExp e) { //printf("Visiting ArrayLiteralExp\n"); visitArgs(e.elements, e.basis); } override void visit(AST.AssocArrayLiteralExp e) { //printf("Visiting AssocArrayLiteralExp\n"); foreach (i, key; *e.keys) { key.accept(this); ((*e.values)[i]).accept(this); } } override void visit(AST.TypeExp e) { //printf("Visiting TypeExp\n"); visitType(e.type); } override void visit(AST.ScopeExp e) { //printf("Visiting ScopeExp\n"); if (e.sds.isTemplateInstance()) e.sds.accept(this); } override void visit(AST.NewExp e) { //printf("Visiting NewExp\n"); if (e.thisexp) e.thisexp.accept(this); if (e.newargs && e.newargs.dim) visitArgs(e.newargs); visitType(e.newtype); if (e.arguments && e.arguments.dim) visitArgs(e.arguments); } override void visit(AST.NewAnonClassExp e) { //printf("Visiting NewAnonClassExp\n"); if (e.thisexp) e.thisexp.accept(this); if (e.newargs && e.newargs.dim) visitArgs(e.newargs); if (e.arguments && e.arguments.dim) visitArgs(e.arguments); if (e.cd) e.cd.accept(this); } override void visit(AST.TupleExp e) { //printf("Visiting TupleExp\n"); if (e.e0) e.e0.accept(this); visitArgs(e.exps); } override void visit(AST.FuncExp e) { //printf("Visiting FuncExp\n"); e.fd.accept(this); } override void visit(AST.DeclarationExp e) { //printf("Visiting DeclarationExp\n"); if (auto v = e.declaration.isVarDeclaration()) visitVarDecl(v); else e.declaration.accept(this); } override void visit(AST.TypeidExp e) { //printf("Visiting TypeidExp\n"); visitObject(e.obj); } override void visit(AST.TraitsExp e) { //printf("Visiting TraitExp\n"); if (e.args) foreach (arg; *e.args) visitObject(arg); } override void visit(AST.IsExp e) { //printf("Visiting IsExp\n"); visitType(e.targ); if (e.tspec) visitType(e.tspec); if (e.parameters && e.parameters.dim) visitTemplateParameters(e.parameters); } override void visit(AST.UnaExp e) { //printf("Visiting UnaExp\n"); e.e1.accept(this); } override void visit(AST.BinExp e) { //printf("Visiting BinExp\n"); e.e1.accept(this); e.e2.accept(this); } override void visit(AST.CompileExp e) { //printf("Visiting CompileExp\n"); visitArgs(e.exps); } override void visit(AST.ImportExp e) { //printf("Visiting ImportExp\n"); e.e1.accept(this); } override void visit(AST.AssertExp e) { //printf("Visiting AssertExp\n"); e.e1.accept(this); if (e.msg) e.msg.accept(this); } override void visit(AST.DotIdExp e) { //printf("Visiting DotIdExp\n"); e.e1.accept(this); } override void visit(AST.DotTemplateInstanceExp e) { //printf("Visiting DotTemplateInstanceExp\n"); e.e1.accept(this); e.ti.accept(this); } override void visit(AST.CallExp e) { //printf("Visiting CallExp\n"); e.e1.accept(this); visitArgs(e.arguments); } override void visit(AST.PtrExp e) { //printf("Visiting PtrExp\n"); e.e1.accept(this); } override void visit(AST.DeleteExp e) { //printf("Visiting DeleteExp\n"); e.e1.accept(this); } override void visit(AST.CastExp e) { //printf("Visiting CastExp\n"); if (e.to) visitType(e.to); e.e1.accept(this); } override void visit(AST.IntervalExp e) { //printf("Visiting IntervalExp\n"); e.lwr.accept(this); e.upr.accept(this); } override void visit(AST.ArrayExp e) { //printf("Visiting ArrayExp\n"); e.e1.accept(this); visitArgs(e.arguments); } override void visit(AST.PostExp e) { //printf("Visiting PostExp\n"); e.e1.accept(this); } override void visit(AST.CondExp e) { //printf("Visiting CondExp\n"); e.econd.accept(this); e.e1.accept(this); e.e2.accept(this); } // Template Parameter //=========================================================== override void visit(AST.TemplateTypeParameter tp) { //printf("Visiting TemplateTypeParameter\n"); if (tp.specType) visitType(tp.specType); if (tp.defaultType) visitType(tp.defaultType); } override void visit(AST.TemplateThisParameter tp) { //printf("Visiting TemplateThisParameter\n"); visit(cast(AST.TemplateTypeParameter)tp); } override void visit(AST.TemplateAliasParameter tp) { //printf("Visiting TemplateAliasParameter\n"); if (tp.specType) visitType(tp.specType); if (tp.specAlias) visitObject(tp.specAlias); if (tp.defaultAlias) visitObject(tp.defaultAlias); } override void visit(AST.TemplateValueParameter tp) { //printf("Visiting TemplateValueParameter\n"); visitType(tp.valType); if (tp.specValue) tp.specValue.accept(this); if (tp.defaultValue) tp.defaultValue.accept(this); } //=========================================================== override void visit(AST.StaticIfCondition c) { //printf("Visiting StaticIfCondition\n"); c.exp.accept(this); } override void visit(AST.Parameter p) { //printf("Visiting Parameter\n"); visitType(p.type); if (p.defaultArg) p.defaultArg.accept(this); } override void visit(AST.Module m) { //printf("Visiting Module\n"); foreach (s; *m.members) { s.accept(this); } } } ================================================ FILE: gcc/d/dmd/typesem.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/typesem.d, _typesem.d) * Documentation: https://dlang.org/phobos/dmd_typesem.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d */ module dmd.typesem; import core.checkedint; import core.stdc.string; import core.stdc.stdio; import dmd.access; import dmd.aggregate; import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.complex; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dmangle; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.imphint; import dmd.init; import dmd.initsem; import dmd.visitor; import dmd.mtype; import dmd.objc; import dmd.opover; import dmd.root.ctfloat; import dmd.root.rmem; import dmd.root.outbuffer; import dmd.root.rootobject; import dmd.root.stringtable; import dmd.semantic3; import dmd.sideeffect; import dmd.target; import dmd.tokens; import dmd.typesem; /************************** * This evaluates exp while setting length to be the number * of elements in the tuple t. */ private Expression semanticLength(Scope* sc, Type t, Expression exp) { if (t.ty == Ttuple) { ScopeDsymbol sym = new ArrayScopeSymbol(sc, cast(TypeTuple)t); sym.parent = sc.scopesym; sc = sc.push(sym); sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); sc = sc.endCTFE(); sc.pop(); } else { sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); sc = sc.endCTFE(); } return exp; } private Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp) { ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup); sym.parent = sc.scopesym; sc = sc.push(sym); sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); sc = sc.endCTFE(); sc.pop(); return exp; } /************************************* * Resolve a tuple index. */ private void resolveTupleIndex(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Expression* pe, Type* pt, Dsymbol* ps, RootObject oindex) { *pt = null; *ps = null; *pe = null; auto tup = s.isTupleDeclaration(); auto eindex = isExpression(oindex); auto tindex = isType(oindex); auto sindex = isDsymbol(oindex); if (!tup) { // It's really an index expression if (tindex) eindex = new TypeExp(loc, tindex); else if (sindex) eindex = dmd.expressionsem.resolve(loc, sc, sindex, false); Expression e = new IndexExp(loc, dmd.expressionsem.resolve(loc, sc, s, false), eindex); e = e.expressionSemantic(sc); mt.resolveExp(e, pt, pe, ps); return; } // Convert oindex to Expression, then try to resolve to constant. if (tindex) tindex.resolve(loc, sc, &eindex, &tindex, &sindex); if (sindex) eindex = dmd.expressionsem.resolve(loc, sc, sindex, false); if (!eindex) { .error(loc, "index `%s` is not an expression", oindex.toChars()); *pt = Type.terror; return; } eindex = semanticLength(sc, tup, eindex); eindex = eindex.ctfeInterpret(); if (eindex.op == TOK.error) { *pt = Type.terror; return; } const(uinteger_t) d = eindex.toUInteger(); if (d >= tup.objects.dim) { .error(loc, "tuple index `%llu` exceeds length %u", d, tup.objects.dim); *pt = Type.terror; return; } RootObject o = (*tup.objects)[cast(size_t)d]; *pt = isType(o); *ps = isDsymbol(o); *pe = isExpression(o); if (*pt) *pt = (*pt).typeSemantic(loc, sc); if (*pe) mt.resolveExp(*pe, pt, pe, ps); } /************************************* * Takes an array of Identifiers and figures out if * it represents a Type or an Expression. * Output: * if expression, *pe is set * if type, *pt is set */ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym, Expression* pe, Type* pt, Dsymbol* ps, bool intypeid = false) { version (none) { printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars()); if (scopesym) printf("\tscopesym = '%s'\n", scopesym.toChars()); } *pe = null; *pt = null; *ps = null; if (s) { //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind()); Declaration d = s.isDeclaration(); if (d && (d.storage_class & STC.templateparameter)) s = s.toAlias(); else { // check for deprecated or disabled aliases s.checkDeprecated(loc, sc); if (d) d.checkDisabled(loc, sc, true); } s = s.toAlias(); //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind()); for (size_t i = 0; i < mt.idents.dim; i++) { RootObject id = mt.idents[i]; if (id.dyncast() == DYNCAST.expression || id.dyncast() == DYNCAST.type) { Type tx; Expression ex; Dsymbol sx; resolveTupleIndex(mt, loc, sc, s, &ex, &tx, &sx, id); if (sx) { s = sx.toAlias(); continue; } if (tx) ex = new TypeExp(loc, tx); assert(ex); ex = typeToExpressionHelper(mt, ex, i + 1); ex = ex.expressionSemantic(sc); mt.resolveExp(ex, pt, pe, ps); return; } Type t = s.getType(); // type symbol, type alias, or type tuple? uint errorsave = global.errors; int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports; Dsymbol sm = s.searchX(loc, sc, id, flags); if (sm && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm)) { .deprecation(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars()); // sm = null; } if (global.errors != errorsave) { *pt = Type.terror; return; } //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm); if (intypeid && !t && sm && sm.needThis()) goto L3; if (VarDeclaration v = s.isVarDeclaration()) { if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) || v.type.isConst() || v.type.isImmutable()) { // https://issues.dlang.org/show_bug.cgi?id=13087 // this.field is not constant always if (!v.isThisDeclaration()) goto L3; } } if (!sm) { if (!t) { if (s.isDeclaration()) // var, func, or tuple declaration? { t = s.isDeclaration().type; if (!t && s.isTupleDeclaration()) // expression tuple? goto L3; } else if (s.isTemplateInstance() || s.isImport() || s.isPackage() || s.isModule()) { goto L3; } } if (t) { sm = t.toDsymbol(sc); if (sm && id.dyncast() == DYNCAST.identifier) { sm = sm.search(loc, cast(Identifier)id /*, IgnorePrivateImports*/); // Deprecated in 2018-01. // Change to error by deleting the deprecation line and uncommenting // the above parameter. The error will be issued in Type.getProperty. // The deprecation is highlighted here to avoid a redundant call to // ScopeDsymbol.search. // @@@DEPRECATED_2019-01@@@. if (sm) { .deprecation(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars()); goto L2; } } L3: Expression e; VarDeclaration v = s.isVarDeclaration(); FuncDeclaration f = s.isFuncDeclaration(); if (intypeid || !v && !f) e = dmd.expressionsem.resolve(loc, sc, s, true); else e = new VarExp(loc, s.isDeclaration(), true); e = typeToExpressionHelper(mt, e, i); e = e.expressionSemantic(sc); mt.resolveExp(e, pt, pe, ps); return; } else { if (id.dyncast() == DYNCAST.dsymbol) { // searchX already handles errors for template instances assert(global.errors); } else { assert(id.dyncast() == DYNCAST.identifier); sm = s.search_correct(cast(Identifier)id); if (sm) error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars()); else error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars()); } *pe = new ErrorExp(); } return; } L2: s = sm.toAlias(); } if (auto em = s.isEnumMember()) { // It's not a type, it's an expression *pe = em.getVarExp(loc, sc); return; } if (auto v = s.isVarDeclaration()) { /* This is mostly same with DsymbolExp::semantic(), but we cannot use it * because some variables used in type context need to prevent lowering * to a literal or contextful expression. For example: * * enum a = 1; alias b = a; * template X(alias e){ alias v = e; } alias x = X!(1); * struct S { int v; alias w = v; } * // TypeIdentifier 'a', 'e', and 'v' should be TOK.variable, * // because getDsymbol() need to work in AliasDeclaration::semantic(). */ if (!v.type || !v.type.deco && v.inuse) { if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); else error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); *pt = Type.terror; return; } if (v.type.ty == Terror) *pt = Type.terror; else *pe = new VarExp(loc, v); return; } if (auto fld = s.isFuncLiteralDeclaration()) { //printf("'%s' is a function literal\n", fld.toChars()); *pe = new FuncExp(loc, fld); *pe = (*pe).expressionSemantic(sc); return; } version (none) { if (FuncDeclaration fd = s.isFuncDeclaration()) { *pe = new DsymbolExp(loc, fd); return; } } L1: Type t = s.getType(); if (!t) { // If the symbol is an import, try looking inside the import if (Import si = s.isImport()) { s = si.search(loc, s.ident); if (s && s != si) goto L1; s = si; } *ps = s; return; } if (t.ty == Tinstance && t != mt && !t.deco) { if (!(cast(TypeInstance)t).tempinst.errors) error(loc, "forward reference to `%s`", t.toChars()); *pt = Type.terror; return; } if (t.ty == Ttuple) *pt = t; else *pt = t.merge(); } if (!s) { /* Look for what user might have intended */ const p = mt.mutableOf().unSharedOf().toChars(); auto id = Identifier.idPool(p, cast(uint)strlen(p)); if (const n = importHint(id.toString())) error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr); else if (auto s2 = sc.search_correct(id)) error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars()); else if (const q = Scope.search_correct_C(id)) error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q); else error(loc, "undefined identifier `%s`", p); *pt = Type.terror; } } /************************************ * Transitively search a type for all function types. * If any function types with parameters are found that have parameter identifiers * or default arguments, remove those and create a new type stripped of those. * This is used to determine the "canonical" version of a type which is useful for * comparisons. * Params: * t = type to scan * Returns: * `t` if no parameter identifiers or default arguments found, otherwise a new type that is * the same as t but with no parameter identifiers or default arguments. */ private Type stripDefaultArgs(Type t) { static Parameters* stripParams(Parameters* parameters) { static Parameter stripParameter(Parameter p) { Type t = stripDefaultArgs(p.type); return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl) ? new Parameter(p.storageClass, t, null, null, null) : null; } if (parameters) { foreach (i, p; *parameters) { Parameter ps = stripParameter(p); if (ps) { // Replace params with a copy we can modify Parameters* nparams = new Parameters(parameters.dim); foreach (j, ref np; *nparams) { Parameter pj = (*parameters)[j]; if (j < i) np = pj; else if (j == i) np = ps; else { Parameter nps = stripParameter(pj); np = nps ? nps : pj; } } return nparams; } } } return parameters; } if (t is null) return t; if (t.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)t; Type tret = stripDefaultArgs(tf.next); Parameters* params = stripParams(tf.parameters); if (tret == tf.next && params == tf.parameters) return t; TypeFunction tr = cast(TypeFunction)tf.copy(); tr.parameters = params; tr.next = tret; //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars()); return tr; } else if (t.ty == Ttuple) { TypeTuple tt = cast(TypeTuple)t; Parameters* args = stripParams(tt.arguments); if (args == tt.arguments) return t; TypeTuple tr = cast(TypeTuple)t.copy(); tr.arguments = args; return tr; } else if (t.ty == Tenum) { // TypeEnum::nextOf() may be != NULL, but it's not necessary here. return t; } else { Type tn = t.nextOf(); Type n = stripDefaultArgs(tn); if (n == tn) return t; TypeNext tr = cast(TypeNext)t.copy(); tr.next = n; return tr; } } /****************************************** * Perform semantic analysis on a type. * Params: * t = Type AST node * loc = the location of the type * sc = context * Returns: * `Type` with completed semantic analysis, `Terror` if errors * were encountered */ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc) { scope v = new TypeSemanticVisitor(loc, sc); t.accept(v); return v.result; } private extern (C++) final class TypeToExpressionVisitor : Visitor { alias visit = Visitor.visit; Expression result; Type itype; this() {} this(Type itype) { this.itype = itype; } override void visit(Type t) { result = null; } override void visit(TypeSArray t) { Expression e = t.next.typeToExpression(); if (e) e = new ArrayExp(t.dim.loc, e, t.dim); result = e; } override void visit(TypeAArray t) { Expression e = t.next.typeToExpression(); if (e) { Expression ei = t.index.typeToExpression(); if (ei) { result = new ArrayExp(t.loc, e, ei); return; } } result = null; } override void visit(TypeIdentifier t) { result = typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident)); } override void visit(TypeInstance t) { result = typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst)); } } /* We've mistakenly parsed this as a type. * Redo it as an Expression. * NULL if cannot. */ Expression typeToExpression(Type t) { scope v = new TypeToExpressionVisitor(); t.accept(v); return v.result; } /* Helper function for `typeToExpression`. Contains common code * for TypeQualified derived classes. */ Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0) { //printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars()); foreach (id; t.idents[i .. t.idents.dim]) { //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars()); final switch (id.dyncast()) { // ... '. ident' case DYNCAST.identifier: e = new DotIdExp(e.loc, e, cast(Identifier)id); break; // ... '. name!(tiargs)' case DYNCAST.dsymbol: auto ti = (cast(Dsymbol)id).isTemplateInstance(); assert(ti); e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs); break; // ... '[type]' case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215 e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id)); break; // ... '[expr]' case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215 e = new ArrayExp(t.loc, e, cast(Expression)id); break; case DYNCAST.object: case DYNCAST.tuple: case DYNCAST.parameter: case DYNCAST.statement: case DYNCAST.condition: case DYNCAST.templateparameter: assert(0); } } return e; } private extern (C++) final class TypeSemanticVisitor : Visitor { alias visit = Visitor.visit; Loc loc; Scope* sc; Type result; this(Loc loc, Scope* sc) { this.loc = loc; this.sc = sc; } void error() { result = Type.terror; } override void visit(Type t) { if (t.ty == Tint128 || t.ty == Tuns128) { .error(loc, "`cent` and `ucent` types not implemented"); return error(); } result = t.merge(); } override void visit(TypeVector mtype) { uint errors = global.errors; mtype.basetype = mtype.basetype.typeSemantic(loc, sc); if (errors != global.errors) return error(); mtype.basetype = mtype.basetype.toBasetype().mutableOf(); if (mtype.basetype.ty != Tsarray) { .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars()); return error(); } TypeSArray t = cast(TypeSArray)mtype.basetype; const sz = cast(int)t.size(loc); final switch (Target.isVectorTypeSupported(sz, t.nextOf())) { case 0: // valid break; case 1: // no support at all .error(loc, "SIMD vector types not supported on this platform"); return error(); case 2: // invalid base type .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars()); return error(); case 3: // invalid size if (sz == 32) deprecation(loc, "%d byte vector types are only supported with -mcpu=avx", sz, mtype.toChars()); else { .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars()); return error(); } break; } result = merge(mtype); } override void visit(TypeSArray mtype) { //printf("TypeSArray::semantic() %s\n", toChars()); Type t; Expression e; Dsymbol s; mtype.next.resolve(loc, sc, &e, &t, &s); if (auto tup = s ? s.isTupleDeclaration() : null) { mtype.dim = semanticLength(sc, tup, mtype.dim); mtype.dim = mtype.dim.ctfeInterpret(); if (mtype.dim.op == TOK.error) return error(); uinteger_t d = mtype.dim.toUInteger(); if (d >= tup.objects.dim) { .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tup.objects.dim); return error(); } RootObject o = (*tup.objects)[cast(size_t)d]; if (o.dyncast() != DYNCAST.type) { .error(loc, "`%s` is not a type", mtype.toChars()); return error(); } result = (cast(Type)o).addMod(mtype.mod); return; } Type tn = mtype.next.typeSemantic(loc, sc); if (tn.ty == Terror) return error(); Type tbn = tn.toBasetype(); if (mtype.dim) { auto errors = global.errors; mtype.dim = semanticLength(sc, tbn, mtype.dim); if (errors != global.errors) return error(); mtype.dim = mtype.dim.optimize(WANTvalue); mtype.dim = mtype.dim.ctfeInterpret(); if (mtype.dim.op == TOK.error) return error(); errors = global.errors; dinteger_t d1 = mtype.dim.toInteger(); if (errors != global.errors) return error(); mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t); mtype.dim = mtype.dim.optimize(WANTvalue); if (mtype.dim.op == TOK.error) return error(); errors = global.errors; dinteger_t d2 = mtype.dim.toInteger(); if (errors != global.errors) return error(); if (mtype.dim.op == TOK.error) return error(); void overflowError() { .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array", mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, Target.maxStaticDataSize); return error(); } if (d1 != d2) return overflowError(); Type tbx = tbn.baseElemOf(); if (tbx.ty == Tstruct && !(cast(TypeStruct)tbx).sym.members || tbx.ty == Tenum && !(cast(TypeEnum)tbx).sym.members) { /* To avoid meaningless error message, skip the total size limit check * when the bottom of element type is opaque. */ } else if (tbn.isintegral() || tbn.isfloating() || tbn.ty == Tpointer || tbn.ty == Tarray || tbn.ty == Tsarray || tbn.ty == Taarray || (tbn.ty == Tstruct && ((cast(TypeStruct)tbn).sym.sizeok == Sizeok.done)) || tbn.ty == Tclass) { /* Only do this for types that don't need to have semantic() * run on them for the size, since they may be forward referenced. */ bool overflow = false; if (mulu(tbn.size(loc), d2, overflow) >= Target.maxStaticDataSize || overflow) return overflowError(); } } switch (tbn.ty) { case Ttuple: { // Index the tuple to get the type assert(mtype.dim); TypeTuple tt = cast(TypeTuple)tbn; uinteger_t d = mtype.dim.toUInteger(); if (d >= tt.arguments.dim) { .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tt.arguments.dim); return error(); } Type telem = (*tt.arguments)[cast(size_t)d].type; result = telem.addMod(mtype.mod); return; } case Tfunction: case Tnone: .error(loc, "cannot have array of `%s`", tbn.toChars()); return error(); default: break; } if (tbn.isscope()) { .error(loc, "cannot have array of scope `%s`", tbn.toChars()); return error(); } /* Ensure things like const(immutable(T)[3]) become immutable(T[3]) * and const(T)[3] become const(T[3]) */ mtype.next = tn; mtype.transitive(); result = mtype.addMod(tn.mod).merge(); } override void visit(TypeDArray mtype) { Type tn = mtype.next.typeSemantic(loc, sc); Type tbn = tn.toBasetype(); switch (tbn.ty) { case Ttuple: result = tbn; return; case Tfunction: case Tnone: .error(loc, "cannot have array of `%s`", tbn.toChars()); return error(); case Terror: return error(); default: break; } if (tn.isscope()) { .error(loc, "cannot have array of scope `%s`", tn.toChars()); return error(); } mtype.next = tn; mtype.transitive(); result = merge(mtype); } override void visit(TypeAArray mtype) { //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty); if (mtype.deco) { result = mtype; return; } mtype.loc = loc; mtype.sc = sc; if (sc) sc.setNoFree(); // Deal with the case where we thought the index was a type, but // in reality it was an expression. if (mtype.index.ty == Tident || mtype.index.ty == Tinstance || mtype.index.ty == Tsarray || mtype.index.ty == Ttypeof || mtype.index.ty == Treturn) { Expression e; Type t; Dsymbol s; mtype.index.resolve(loc, sc, &e, &t, &s); if (e) { // It was an expression - // Rewrite as a static array auto tsa = new TypeSArray(mtype.next, e); result = tsa.typeSemantic(loc, sc); return; } else if (t) mtype.index = t.typeSemantic(loc, sc); else { .error(loc, "index is not a type or an expression"); return error(); } } else mtype.index = mtype.index.typeSemantic(loc, sc); mtype.index = mtype.index.merge2(); if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable()) { mtype.index = mtype.index.constOf().mutableOf(); version (none) { printf("index is %p %s\n", mtype.index, mtype.index.toChars()); mtype.index.check(); printf("index.mod = x%x\n", mtype.index.mod); printf("index.ito = x%x\n", mtype.index.ito); if (mtype.index.ito) { printf("index.ito.mod = x%x\n", mtype.index.ito.mod); printf("index.ito.ito = x%x\n", mtype.index.ito.ito); } } } switch (mtype.index.toBasetype().ty) { case Tfunction: case Tvoid: case Tnone: case Ttuple: .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars()); goto case Terror; case Terror: return error(); default: break; } Type tbase = mtype.index.baseElemOf(); while (tbase.ty == Tarray) tbase = tbase.nextOf().baseElemOf(); if (tbase.ty == Tstruct) { /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up. */ StructDeclaration sd = (cast(TypeStruct)tbase).sym; if (sd.semanticRun < PASS.semanticdone) sd.dsymbolSemantic(null); // duplicate a part of StructDeclaration::semanticTypeInfoMembers //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash); if (sd.xeq && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done) { uint errors = global.startGagging(); sd.xeq.semantic3(sd.xeq._scope); if (global.endGagging(errors)) sd.xeq = sd.xerreq; } //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash); const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : ""; if (!sd.xeq) { // If sd.xhash != NULL: // sd or its fields have user-defined toHash. // AA assumes that its result is consistent with bitwise equality. // else: // bitwise equality & hashing } else if (sd.xeq == sd.xerreq) { if (search_function(sd, Id.eq)) { .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars()); } else { .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars()); } return error(); } else if (!sd.xhash) { if (search_function(sd, Id.eq)) { .error(loc, "%sAA key type `%s` should have `size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars()); } else { .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars()); } return error(); } else { // defined equality & hashing assert(sd.xeq && sd.xhash); /* xeq and xhash may be implicitly defined by compiler. For example: * struct S { int[] arr; } * With 'arr' field equality and hashing, compiler will implicitly * generate functions for xopEquals and xtoHash in TypeInfo_Struct. */ } } else if (tbase.ty == Tclass && !(cast(TypeClass)tbase).sym.isInterfaceDeclaration()) { ClassDeclaration cd = (cast(TypeClass)tbase).sym; if (cd.semanticRun < PASS.semanticdone) cd.dsymbolSemantic(null); if (!ClassDeclaration.object) { .error(Loc.initial, "missing or corrupt object.d"); fatal(); } __gshared FuncDeclaration feq = null; __gshared FuncDeclaration fcmp = null; __gshared FuncDeclaration fhash = null; if (!feq) feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration(); if (!fcmp) fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration(); if (!fhash) fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration(); assert(fcmp && feq && fhash); if (feq.vtblIndex < cd.vtbl.dim && cd.vtbl[feq.vtblIndex] == feq) { version (all) { if (fcmp.vtblIndex < cd.vtbl.dim && cd.vtbl[fcmp.vtblIndex] != fcmp) { const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : ""; .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars()); errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`."); } } } } mtype.next = mtype.next.typeSemantic(loc, sc).merge2(); mtype.transitive(); switch (mtype.next.toBasetype().ty) { case Tfunction: case Tvoid: case Tnone: case Ttuple: .error(loc, "cannot have associative array of `%s`", mtype.next.toChars()); goto case Terror; case Terror: return error(); default: break; } if (mtype.next.isscope()) { .error(loc, "cannot have array of scope `%s`", mtype.next.toChars()); return error(); } result = merge(mtype); } override void visit(TypePointer mtype) { //printf("TypePointer::semantic() %s\n", toChars()); if (mtype.deco) { result = mtype; return; } Type n = mtype.next.typeSemantic(loc, sc); switch (n.toBasetype().ty) { case Ttuple: .error(loc, "cannot have pointer to `%s`", n.toChars()); goto case Terror; case Terror: return error(); default: break; } if (n != mtype.next) { mtype.deco = null; } mtype.next = n; if (mtype.next.ty != Tfunction) { mtype.transitive(); result = merge(mtype); return; } version (none) { result = merge(mtype); return; } else { mtype.deco = merge(mtype).deco; /* Don't return merge(), because arg identifiers and default args * can be different * even though the types match */ result = mtype; return; } } override void visit(TypeReference mtype) { //printf("TypeReference::semantic()\n"); Type n = mtype.next.typeSemantic(loc, sc); if (n != mtype.next) mtype.deco = null; mtype.next = n; mtype.transitive(); result = merge(mtype); } override void visit(TypeFunction mtype) { if (mtype.deco) // if semantic() already run { //printf("already done\n"); result = mtype; return; } //printf("TypeFunction::semantic() this = %p\n", this); //printf("TypeFunction::semantic() %s, sc.stc = %llx, fargs = %p\n", toChars(), sc.stc, fargs); bool errors = false; if (mtype.inuse > 500) { mtype.inuse = 0; .error(loc, "recursive type"); return error(); } /* Copy in order to not mess up original. * This can produce redundant copies if inferring return type, * as semantic() will get called again on this. */ TypeFunction tf = mtype.copy().toTypeFunction(); if (mtype.parameters) { tf.parameters = mtype.parameters.copy(); for (size_t i = 0; i < mtype.parameters.dim; i++) { Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter)); memcpy(cast(void*)p, cast(void*)(*mtype.parameters)[i], __traits(classInstanceSize, Parameter)); (*tf.parameters)[i] = p; } } if (sc.stc & STC.pure_) tf.purity = PURE.fwdref; if (sc.stc & STC.nothrow_) tf.isnothrow = true; if (sc.stc & STC.nogc) tf.isnogc = true; if (sc.stc & STC.ref_) tf.isref = true; if (sc.stc & STC.return_) tf.isreturn = true; if (sc.stc & STC.scope_) tf.isscope = true; if (sc.stc & STC.scopeinferred) tf.isscopeinferred = true; // if (tf.isreturn && !tf.isref) // tf.isscope = true; // return by itself means 'return scope' if (tf.trust == TRUST.default_) { if (sc.stc & STC.safe) tf.trust = TRUST.safe; else if (sc.stc & STC.system) tf.trust = TRUST.system; else if (sc.stc & STC.trusted) tf.trust = TRUST.trusted; } if (sc.stc & STC.property) tf.isproperty = true; tf.linkage = sc.linkage; version (none) { /* If the parent is @safe, then this function defaults to safe * too. * If the parent's @safe-ty is inferred, then this function's @safe-ty needs * to be inferred first. */ if (tf.trust == TRUST.default_) for (Dsymbol p = sc.func; p; p = p.toParent2()) { FuncDeclaration fd = p.isFuncDeclaration(); if (fd) { if (fd.isSafeBypassingInference()) tf.trust = TRUST.safe; // default to @safe break; } } } bool wildreturn = false; if (tf.next) { sc = sc.push(); sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR); tf.next = tf.next.typeSemantic(loc, sc); sc = sc.pop(); errors |= tf.checkRetType(loc); if (tf.next.isscope() && !(sc.flags & SCOPE.ctor)) { .error(loc, "functions cannot return `scope %s`", tf.next.toChars()); errors = true; } if (tf.next.hasWild()) wildreturn = true; if (tf.isreturn && !tf.isref && !tf.next.hasPointers()) { tf.isreturn = false; } } ubyte wildparams = 0; if (tf.parameters) { /* Create a scope for evaluating the default arguments for the parameters */ Scope* argsc = sc.push(); argsc.stc = 0; // don't inherit storage class argsc.protection = Prot(Prot.Kind.public_); argsc.func = null; size_t dim = Parameter.dim(tf.parameters); for (size_t i = 0; i < dim; i++) { Parameter fparam = Parameter.getNth(tf.parameters, i); mtype.inuse++; fparam.type = fparam.type.typeSemantic(loc, argsc); mtype.inuse--; if (fparam.type.ty == Terror) { errors = true; continue; } fparam.type = fparam.type.addStorageClass(fparam.storageClass); if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_)) { if (!fparam.type) continue; } Type t = fparam.type.toBasetype(); if (t.ty == Tfunction) { .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars()); errors = true; } else if (!(fparam.storageClass & (STC.ref_ | STC.out_)) && (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum)) { Type tb2 = t.baseElemOf(); if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members || tb2.ty == Tenum && !(cast(TypeEnum)tb2).sym.memtype) { .error(loc, "cannot have parameter of opaque type `%s` by value", fparam.type.toChars()); errors = true; } } else if (!(fparam.storageClass & STC.lazy_) && t.ty == Tvoid) { .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars()); errors = true; } if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild)) { // 'ref inout' implies 'return' fparam.storageClass |= STC.return_; } if (fparam.storageClass & STC.return_) { if (fparam.storageClass & (STC.ref_ | STC.out_)) { // Disabled for the moment awaiting improvement to allow return by ref // to be transformed into return by scope. if (0 && !tf.isref) { auto stc = fparam.storageClass & (STC.ref_ | STC.out_); .error(loc, "parameter `%s` is `return %s` but function does not return by `ref`", fparam.ident ? fparam.ident.toChars() : "", stcToChars(stc)); errors = true; } } else { fparam.storageClass |= STC.scope_; // 'return' implies 'scope' if (tf.isref) { } else if (tf.next && !tf.next.hasPointers()) { fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963 } } } if (fparam.storageClass & (STC.ref_ | STC.lazy_)) { } else if (fparam.storageClass & STC.out_) { if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild)) { .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars()); errors = true; } else { Type tv = t; while (tv.ty == Tsarray) tv = tv.nextOf().toBasetype(); if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.noDefaultCtor) { .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars()); errors = true; } } } if (fparam.storageClass & STC.scope_ && !fparam.type.hasPointers() && fparam.type.ty != Ttuple) { fparam.storageClass &= ~STC.scope_; if (!(fparam.storageClass & STC.ref_)) fparam.storageClass &= ~STC.return_; } if (t.hasWild()) { wildparams |= 1; //if (tf.next && !wildreturn) // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)"); } if (fparam.defaultArg) { Expression e = fparam.defaultArg; if (fparam.storageClass & (STC.ref_ | STC.out_)) { e = e.expressionSemantic(argsc); e = resolveProperties(argsc, e); } else { e = inferType(e, fparam.type); Initializer iz = new ExpInitializer(e.loc, e); iz = iz.initializerSemantic(argsc, fparam.type, INITnointerpret); e = iz.initializerToExpression(); } if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { FuncExp fe = cast(FuncExp)e; // Replace function literal with a function symbol, // since default arg expression must be copied when used // and copying the literal itself is wrong. e = new VarExp(e.loc, fe.fd, false); e = new AddrExp(e.loc, e); e = e.expressionSemantic(argsc); } e = e.implicitCastTo(argsc, fparam.type); // default arg must be an lvalue if (fparam.storageClass & (STC.out_ | STC.ref_)) e = e.toLvalue(argsc, e); fparam.defaultArg = e; if (e.op == TOK.error) errors = true; } /* If fparam after semantic() turns out to be a tuple, the number of parameters may * change. */ if (t.ty == Ttuple) { /* TypeFunction::parameter also is used as the storage of * Parameter objects for FuncDeclaration. So we should copy * the elements of TypeTuple::arguments to avoid unintended * sharing of Parameter object among other functions. */ TypeTuple tt = cast(TypeTuple)t; if (tt.arguments && tt.arguments.dim) { /* Propagate additional storage class from tuple parameters to their * element-parameters. * Make a copy, as original may be referenced elsewhere. */ size_t tdim = tt.arguments.dim; auto newparams = new Parameters(tdim); for (size_t j = 0; j < tdim; j++) { Parameter narg = (*tt.arguments)[j]; // https://issues.dlang.org/show_bug.cgi?id=12744 // If the storage classes of narg // conflict with the ones in fparam, it's ignored. StorageClass stc = fparam.storageClass | narg.storageClass; StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_); StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_); if (stc1 && stc2 && stc1 != stc2) { OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0)); OutBuffer buf2; stcToBuffer(&buf2, stc2); .error(loc, "incompatible parameter storage classes `%s` and `%s`", buf1.peekString(), buf2.peekString()); errors = true; stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_)); } (*newparams)[j] = new Parameter( stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl); } fparam.type = new TypeTuple(newparams); } fparam.storageClass = 0; /* Reset number of parameters, and back up one to do this fparam again, * now that it is a tuple */ dim = Parameter.dim(tf.parameters); i--; continue; } /* Resolve "auto ref" storage class to be either ref or value, * based on the argument matching the parameter */ if (fparam.storageClass & STC.auto_) { if (mtype.fargs && i < mtype.fargs.dim && (fparam.storageClass & STC.ref_)) { Expression farg = (*mtype.fargs)[i]; if (farg.isLvalue()) { // ref parameter } else fparam.storageClass &= ~STC.ref_; // value parameter fparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656 fparam.storageClass |= STC.autoref; } else { .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters"); errors = true; } } // Remove redundant storage classes for type, they are already applied fparam.storageClass &= ~(STC.TYPECTOR | STC.in_); } argsc.pop(); } if (tf.isWild()) wildparams |= 2; if (wildreturn && !wildparams) { .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars()); errors = true; } tf.iswild = wildparams; if (tf.isproperty && (tf.varargs || Parameter.dim(tf.parameters) > 2)) { .error(loc, "properties can only have zero, one, or two parameter"); errors = true; } if (tf.varargs == 1 && tf.linkage != LINK.d && Parameter.dim(tf.parameters) == 0) { .error(loc, "variadic functions with non-D linkage must have at least one parameter"); errors = true; } if (errors) return error(); if (tf.next) tf.deco = tf.merge().deco; /* Don't return merge(), because arg identifiers and default args * can be different * even though the types match */ result = tf; } override void visit(TypeDelegate mtype) { //printf("TypeDelegate::semantic() %s\n", toChars()); if (mtype.deco) // if semantic() already run { //printf("already done\n"); result = mtype; return; } mtype.next = mtype.next.typeSemantic(loc, sc); if (mtype.next.ty != Tfunction) return error(); /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028 * perhaps default arguments should * be removed from next before the merge. */ version (none) { result = mtype.merge(); return; } else { /* Don't return merge(), because arg identifiers and default args * can be different * even though the types match */ mtype.deco = mtype.merge().deco; result = mtype; } } override void visit(TypeIdentifier mtype) { Type t; Expression e; Dsymbol s; //printf("TypeIdentifier::semantic(%s)\n", toChars()); mtype.resolve(loc, sc, &e, &t, &s); if (t) { //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco); result = t.addMod(mtype.mod); } else { if (s) { auto td = s.isTemplateDeclaration; if (td && td.onemember && td.onemember.isAggregateDeclaration) .error(loc, "template %s `%s` is used as a type without instantiation" ~ "; to instantiate it use `%s!(arguments)`", s.kind, s.toPrettyChars, s.ident.toChars); else .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars); //assert(0); } else .error(loc, "`%s` is used as a type", mtype.toChars()); return error(); } } override void visit(TypeInstance mtype) { Type t; Expression e; Dsymbol s; //printf("TypeInstance::semantic(%p, %s)\n", this, toChars()); { const errors = global.errors; mtype.resolve(loc, sc, &e, &t, &s); // if we had an error evaluating the symbol, suppress further errors if (!t && errors != global.errors) { result = Type.terror; return; } } if (!t) { if (!e && s && s.errors) { // if there was an error evaluating the symbol, it might actually // be a type. Avoid misleading error messages. .error(loc, "`%s` had previous errors", mtype.toChars()); } else .error(loc, "`%s` is used as a type", mtype.toChars()); return error(); } result = t; } override void visit(TypeTypeof mtype) { //printf("TypeTypeof::semantic() %s\n", toChars()); Expression e; Type t; Dsymbol s; mtype.resolve(loc, sc, &e, &t, &s); if (s && (t = s.getType()) !is null) t = t.addMod(mtype.mod); if (!t) { .error(loc, "`%s` is used as a type", mtype.toChars()); return error(); } result = t; } override void visit(TypeReturn mtype) { //printf("TypeReturn::semantic() %s\n", toChars()); Expression e; Type t; Dsymbol s; mtype.resolve(loc, sc, &e, &t, &s); if (s && (t = s.getType()) !is null) t = t.addMod(mtype.mod); if (!t) { .error(loc, "`%s` is used as a type", mtype.toChars()); return error(); } result = t; } override void visit(TypeStruct mtype) { //printf("TypeStruct::semantic('%s')\n", mtype.toChars()); if (mtype.deco) { if (sc && sc.cppmangle != CPPMANGLE.def) { if (mtype.cppmangle == CPPMANGLE.def) mtype.cppmangle = sc.cppmangle; } result = mtype; return; } /* Don't semantic for sym because it should be deferred until * sizeof needed or its members accessed. */ // instead, parent should be set correctly assert(mtype.sym.parent); if (mtype.sym.type.ty == Terror) return error(); if (sc && sc.cppmangle != CPPMANGLE.def) mtype.cppmangle = sc.cppmangle; else mtype.cppmangle = CPPMANGLE.asStruct; result = merge(mtype); } override void visit(TypeEnum mtype) { //printf("TypeEnum::semantic() %s\n", toChars()); result = mtype.deco ? mtype : merge(mtype); } override void visit(TypeClass mtype) { //printf("TypeClass::semantic(%s)\n", mtype.toChars()); if (mtype.deco) { if (sc && sc.cppmangle != CPPMANGLE.def) { if (mtype.cppmangle == CPPMANGLE.def) mtype.cppmangle = sc.cppmangle; } result = mtype; return; } /* Don't semantic for sym because it should be deferred until * sizeof needed or its members accessed. */ // instead, parent should be set correctly assert(mtype.sym.parent); if (mtype.sym.type.ty == Terror) return error(); if (sc && sc.cppmangle != CPPMANGLE.def) mtype.cppmangle = sc.cppmangle; else mtype.cppmangle = CPPMANGLE.asClass; result = merge(mtype); } override void visit(TypeTuple mtype) { //printf("TypeTuple::semantic(this = %p)\n", this); //printf("TypeTuple::semantic() %p, %s\n", this, toChars()); if (!mtype.deco) mtype.deco = merge(mtype).deco; /* Don't return merge(), because a tuple with one type has the * same deco as that type. */ result = mtype; } override void visit(TypeSlice mtype) { //printf("TypeSlice::semantic() %s\n", toChars()); Type tn = mtype.next.typeSemantic(loc, sc); //printf("next: %s\n", tn.toChars()); Type tbn = tn.toBasetype(); if (tbn.ty != Ttuple) { .error(loc, "can only slice tuple types, not `%s`", tbn.toChars()); return error(); } TypeTuple tt = cast(TypeTuple)tbn; mtype.lwr = semanticLength(sc, tbn, mtype.lwr); mtype.upr = semanticLength(sc, tbn, mtype.upr); mtype.lwr = mtype.lwr.ctfeInterpret(); mtype.upr = mtype.upr.ctfeInterpret(); if (mtype.lwr.op == TOK.error || mtype.upr.op == TOK.error) return error(); uinteger_t i1 = mtype.lwr.toUInteger(); uinteger_t i2 = mtype.upr.toUInteger(); if (!(i1 <= i2 && i2 <= tt.arguments.dim)) { .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`", cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.dim); return error(); } mtype.next = tn; mtype.transitive(); auto args = new Parameters(); args.reserve(cast(size_t)(i2 - i1)); foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2]) { args.push(arg); } Type t = new TypeTuple(args); result = t.typeSemantic(loc, sc); } } /************************************ * If an identical type to `type` is in `type.stringtable`, return * the latter one. Otherwise, add it to `type.stringtable`. * Some types don't get merged and are returned as-is. * Params: * type = Type to check against existing types * Returns: * the type that was merged */ Type merge(Type type) { switch (type.ty) { case Terror: case Ttypeof: case Tident: case Tinstance: return type; case Tenum: break; case Taarray: if (!(cast(TypeAArray)type).index.merge().deco) return type; goto default; default: if (type.nextOf() && !type.nextOf().deco) return type; break; } //printf("merge(%s)\n", toChars()); if (!type.deco) { OutBuffer buf; buf.reserve(32); mangleToBuffer(type, &buf); StringValue* sv = type.stringtable.update(cast(char*)buf.data, buf.offset); if (sv.ptrvalue) { Type t = cast(Type)sv.ptrvalue; debug { import core.stdc.stdio; if (!t.deco) printf("t = %s\n", t.toChars()); } assert(t.deco); //printf("old value, deco = '%s' %p\n", t.deco, t.deco); return t; } else { Type t = stripDefaultArgs(type); sv.ptrvalue = cast(char*)t; type.deco = t.deco = cast(char*)sv.toDchars(); //printf("new value, deco = '%s' %p\n", t.deco, t.deco); return t; } } return type; } /*************************************** * Calculate built-in properties which just the type is necessary. * * Params: * t = the type for which the property is calculated * loc = the location where the property is encountered * ident = the identifier of the property * flag = if flag & 1, don't report "not a property" error and just return NULL. */ Expression getProperty(Type t, const ref Loc loc, Identifier ident, int flag) { scope v = new GetPropertyVisitor(loc, ident, flag); t.accept(v); return v.result; } private extern (C++) final class GetPropertyVisitor : Visitor { alias visit = typeof(super).visit; Loc loc; Identifier ident; int flag; Expression result; this(const ref Loc loc, Identifier ident, int flag) { this.loc = loc; this.ident = ident; this.flag = flag; } override void visit(Type mt) { Expression e; static if (LOGDOTEXP) { printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars()); } if (ident == Id.__sizeof) { d_uns64 sz = mt.size(loc); if (sz == SIZE_INVALID) { result = new ErrorExp(); return; } e = new IntegerExp(loc, sz, Type.tsize_t); } else if (ident == Id.__xalignof) { const explicitAlignment = mt.alignment(); const naturalAlignment = mt.alignsize(); const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment); e = new IntegerExp(loc, actualAlignment, Type.tsize_t); } else if (ident == Id._init) { Type tb = mt.toBasetype(); e = mt.defaultInitLiteral(loc); if (tb.ty == Tstruct && tb.needsNested()) { StructLiteralExp se = cast(StructLiteralExp)e; se.useStaticInit = true; } } else if (ident == Id._mangleof) { if (!mt.deco) { error(loc, "forward reference of type `%s.mangleof`", mt.toChars()); e = new ErrorExp(); } else { e = new StringExp(loc, mt.deco); Scope sc; e = e.expressionSemantic(&sc); } } else if (ident == Id.stringof) { const s = mt.toChars(); e = new StringExp(loc, cast(char*)s); Scope sc; e = e.expressionSemantic(&sc); } else if (flag && mt != Type.terror) { result = null; return; } else { Dsymbol s = null; if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum) s = mt.toDsymbol(null); if (s) s = s.search_correct(ident); if (mt != Type.terror) { if (s) error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars()); else { if (ident == Id.call && mt.ty == Tclass) error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars()); else error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toChars()); } } e = new ErrorExp(); } result = e; } override void visit(TypeError) { result = new ErrorExp(); } override void visit(TypeBasic mt) { Expression e; dinteger_t ivalue; real_t fvalue; //printf("TypeBasic::getProperty('%s')\n", ident.toChars()); if (ident == Id.max) { switch (mt.ty) { case Tint8: ivalue = 0x7F; goto Livalue; case Tuns8: ivalue = 0xFF; goto Livalue; case Tint16: ivalue = 0x7FFFU; goto Livalue; case Tuns16: ivalue = 0xFFFFU; goto Livalue; case Tint32: ivalue = 0x7FFFFFFFU; goto Livalue; case Tuns32: ivalue = 0xFFFFFFFFU; goto Livalue; case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFL; goto Livalue; case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFUL; goto Livalue; case Tbool: ivalue = 1; goto Livalue; case Tchar: ivalue = 0xFF; goto Livalue; case Twchar: ivalue = 0xFFFFU; goto Livalue; case Tdchar: ivalue = 0x10FFFFU; goto Livalue; case Tcomplex32: case Timaginary32: case Tfloat32: fvalue = Target.FloatProperties.max; goto Lfvalue; case Tcomplex64: case Timaginary64: case Tfloat64: fvalue = Target.DoubleProperties.max; goto Lfvalue; case Tcomplex80: case Timaginary80: case Tfloat80: fvalue = Target.RealProperties.max; goto Lfvalue; default: break; } } else if (ident == Id.min) { switch (mt.ty) { case Tint8: ivalue = -128; goto Livalue; case Tuns8: ivalue = 0; goto Livalue; case Tint16: ivalue = -32768; goto Livalue; case Tuns16: ivalue = 0; goto Livalue; case Tint32: ivalue = -2147483647 - 1; goto Livalue; case Tuns32: ivalue = 0; goto Livalue; case Tint64: ivalue = (-9223372036854775807L - 1L); goto Livalue; case Tuns64: ivalue = 0; goto Livalue; case Tbool: ivalue = 0; goto Livalue; case Tchar: ivalue = 0; goto Livalue; case Twchar: ivalue = 0; goto Livalue; case Tdchar: ivalue = 0; goto Livalue; default: break; } } else if (ident == Id.min_normal) { Lmin_normal: switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: fvalue = Target.FloatProperties.min_normal; goto Lfvalue; case Tcomplex64: case Timaginary64: case Tfloat64: fvalue = Target.DoubleProperties.min_normal; goto Lfvalue; case Tcomplex80: case Timaginary80: case Tfloat80: fvalue = Target.RealProperties.min_normal; goto Lfvalue; default: break; } } else if (ident == Id.nan) { switch (mt.ty) { case Tcomplex32: case Tcomplex64: case Tcomplex80: case Timaginary32: case Timaginary64: case Timaginary80: case Tfloat32: case Tfloat64: case Tfloat80: fvalue = Target.RealProperties.nan; goto Lfvalue; default: break; } } else if (ident == Id.infinity) { switch (mt.ty) { case Tcomplex32: case Tcomplex64: case Tcomplex80: case Timaginary32: case Timaginary64: case Timaginary80: case Tfloat32: case Tfloat64: case Tfloat80: fvalue = Target.RealProperties.infinity; goto Lfvalue; default: break; } } else if (ident == Id.dig) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.dig; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.dig; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.dig; goto Lint; default: break; } } else if (ident == Id.epsilon) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: fvalue = Target.FloatProperties.epsilon; goto Lfvalue; case Tcomplex64: case Timaginary64: case Tfloat64: fvalue = Target.DoubleProperties.epsilon; goto Lfvalue; case Tcomplex80: case Timaginary80: case Tfloat80: fvalue = Target.RealProperties.epsilon; goto Lfvalue; default: break; } } else if (ident == Id.mant_dig) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.mant_dig; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.mant_dig; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.mant_dig; goto Lint; default: break; } } else if (ident == Id.max_10_exp) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.max_10_exp; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.max_10_exp; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.max_10_exp; goto Lint; default: break; } } else if (ident == Id.max_exp) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.max_exp; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.max_exp; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.max_exp; goto Lint; default: break; } } else if (ident == Id.min_10_exp) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.min_10_exp; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.min_10_exp; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.min_10_exp; goto Lint; default: break; } } else if (ident == Id.min_exp) { switch (mt.ty) { case Tcomplex32: case Timaginary32: case Tfloat32: ivalue = Target.FloatProperties.min_exp; goto Lint; case Tcomplex64: case Timaginary64: case Tfloat64: ivalue = Target.DoubleProperties.min_exp; goto Lint; case Tcomplex80: case Timaginary80: case Tfloat80: ivalue = Target.RealProperties.min_exp; goto Lint; default: break; } } visit(cast(Type)mt); return; Livalue: e = new IntegerExp(loc, ivalue, mt); result = e; return; Lfvalue: if (mt.isreal() || mt.isimaginary()) e = new RealExp(loc, fvalue, mt); else { const cvalue = complex_t(fvalue, fvalue); //for (int i = 0; i < 20; i++) // printf("%02x ", ((unsigned char *)&cvalue)[i]); //printf("\n"); e = new ComplexExp(loc, cvalue, mt); } result = e; return; Lint: e = new IntegerExp(loc, ivalue, Type.tint32); result = e; } override void visit(TypeVector mt) { visit(cast(Type)mt); } override void visit(TypeEnum mt) { Expression e; if (ident == Id.max || ident == Id.min) { result = mt.sym.getMaxMinValue(loc, ident); return; } else if (ident == Id._init) { e = mt.defaultInitLiteral(loc); } else if (ident == Id.stringof) { const s = mt.toChars(); e = new StringExp(loc, cast(char*)s); Scope sc; e = e.expressionSemantic(&sc); } else if (ident == Id._mangleof) { visit(cast(Type)mt); e = result; } else { e = mt.toBasetype().getProperty(loc, ident, flag); } result = e; } override void visit(TypeTuple mt) { Expression e; static if (LOGDOTEXP) { printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars()); } if (ident == Id.length) { e = new IntegerExp(loc, mt.arguments.dim, Type.tsize_t); } else if (ident == Id._init) { e = mt.defaultInitLiteral(loc); } else if (flag) { e = null; } else { error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars()); e = new ErrorExp(); } result = e; } } /************************************ * Resolve type 'mt' to either type, symbol, or expression. * If errors happened, resolved to Type.terror. * * Params: * mt = type to be resolved * loc = the location where the type is encountered * sc = the scope of the type * pe = is set if t is an expression * pt = is set if t is a type * ps = is set if t is a symbol * intypeid = true if in type id */ void resolve(Type mt, const ref Loc loc, Scope* sc, Expression* pe, Type* pt, Dsymbol* ps, bool intypeid = false) { scope v = new ResolveVisitor(loc, sc, pe, pt, ps, intypeid); mt.accept(v); } private extern(C++) final class ResolveVisitor : Visitor { alias visit = typeof(super).visit; Loc loc; Scope* sc; Expression* pe; Type* pt; Dsymbol* ps; bool intypeid; this(const ref Loc loc, Scope* sc, Expression* pe, Type* pt, Dsymbol* ps, bool intypeid) { this.loc = loc; this.sc = sc; this.pe = pe; this.pt = pt; this.ps = ps; this.intypeid = intypeid; } override void visit(Type mt) { //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty); Type t = typeSemantic(mt, loc, sc); assert(t); *pt = t; *pe = null; *ps = null; } override void visit(TypeSArray mt) { //printf("TypeSArray::resolve() %s\n", mt.toChars()); mt.next.resolve(loc, sc, pe, pt, ps, intypeid); //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) { // It's really an index expression if (Dsymbol s = getDsymbol(*pe)) *pe = new DsymbolExp(loc, s); *pe = new ArrayExp(loc, *pe, mt.dim); } else if (*ps) { Dsymbol s = *ps; if (auto tup = s.isTupleDeclaration()) { mt.dim = semanticLength(sc, tup, mt.dim); mt.dim = mt.dim.ctfeInterpret(); if (mt.dim.op == TOK.error) { *ps = null; *pt = Type.terror; return; } uinteger_t d = mt.dim.toUInteger(); if (d >= tup.objects.dim) { error(loc, "tuple index `%llu` exceeds length %u", d, tup.objects.dim); *ps = null; *pt = Type.terror; return; } RootObject o = (*tup.objects)[cast(size_t)d]; if (o.dyncast() == DYNCAST.dsymbol) { *ps = cast(Dsymbol)o; return; } if (o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; if (e.op == TOK.dSymbol) { *ps = (cast(DsymbolExp)e).s; *pe = null; } else { *ps = null; *pe = e; } return; } if (o.dyncast() == DYNCAST.type) { *ps = null; *pt = (cast(Type)o).addMod(mt.mod); return; } /* Create a new TupleDeclaration which * is a slice [d..d+1] out of the old one. * Do it this way because TemplateInstance::semanticTiargs() * can handle unresolved Objects this way. */ auto objects = new Objects(1); (*objects)[0] = o; *ps = new TupleDeclaration(loc, tup.ident, objects); } else goto Ldefault; } else { if ((*pt).ty != Terror) mt.next = *pt; // prevent re-running semantic() on 'next' Ldefault: visit(cast(Type)mt); } } override void visit(TypeDArray mt) { //printf("TypeDArray::resolve() %s\n", mt.toChars()); mt.next.resolve(loc, sc, pe, pt, ps, intypeid); //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) { // It's really a slice expression if (Dsymbol s = getDsymbol(*pe)) *pe = new DsymbolExp(loc, s); *pe = new ArrayExp(loc, *pe); } else if (*ps) { if (auto tup = (*ps).isTupleDeclaration()) { // keep *ps } else goto Ldefault; } else { if ((*pt).ty != Terror) mt.next = *pt; // prevent re-running semantic() on 'next' Ldefault: visit(cast(Type)mt); } } override void visit(TypeAArray mt) { //printf("TypeAArray::resolve() %s\n", mt.toChars()); // Deal with the case where we thought the index was a type, but // in reality it was an expression. if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray) { Expression e; Type t; Dsymbol s; mt.index.resolve(loc, sc, &e, &t, &s, intypeid); if (e) { // It was an expression - // Rewrite as a static array auto tsa = new TypeSArray(mt.next, e); tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done return tsa.resolve(loc, sc, pe, pt, ps, intypeid); } else if (t) mt.index = t; else .error(loc, "index is not a type or an expression"); } visit(cast(Type)mt); } /************************************* * Takes an array of Identifiers and figures out if * it represents a Type or an Expression. * Output: * if expression, *pe is set * if type, *pt is set */ override void visit(TypeIdentifier mt) { //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars()); if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc)) { // @@@DEPRECATED_v2.086@@@. if (mt.ident.equals(Id._super)) { deprecation(mt.loc, "Using `super` as a type is deprecated. Use `typeof(super)` instead"); } // @@@DEPRECATED_v2.086@@@. if (mt.ident.equals(Id.This)) { deprecation(mt.loc, "Using `this` as a type is deprecated. Use `typeof(this)` instead"); } AggregateDeclaration ad = sc.getStructClassScope(); if (ad) { ClassDeclaration cd = ad.isClassDeclaration(); if (cd) { if (mt.ident.equals(Id.This)) mt.ident = cd.ident; else if (cd.baseClass && mt.ident.equals(Id._super)) mt.ident = cd.baseClass.ident; } else { StructDeclaration sd = ad.isStructDeclaration(); if (sd && mt.ident.equals(Id.This)) mt.ident = sd.ident; } } } if (mt.ident == Id.ctfe) { error(loc, "variable `__ctfe` cannot be read at compile time"); *pe = null; *ps = null; *pt = Type.terror; return; } Dsymbol scopesym; Dsymbol s = sc.search(loc, mt.ident, &scopesym); if (s) { // https://issues.dlang.org/show_bug.cgi?id=16042 // If `f` is really a function template, then replace `f` // with the function template declaration. if (auto f = s.isFuncDeclaration()) { if (auto td = getFuncTemplateDecl(f)) { // If not at the beginning of the overloaded list of // `TemplateDeclaration`s, then get the beginning if (td.overroot) td = td.overroot; s = td; } } } mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid); if (*pt) (*pt) = (*pt).addMod(mt.mod); } override void visit(TypeInstance mt) { // Note close similarity to TypeIdentifier::resolve() *pe = null; *pt = null; *ps = null; //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars()); mt.tempinst.dsymbolSemantic(sc); if (!global.gag && mt.tempinst.errors) { *pt = Type.terror; return; } mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid); if (*pt) *pt = (*pt).addMod(mt.mod); //if (*pt) printf("*pt = %d '%s'\n", (*pt).ty, (*pt).toChars()); } override void visit(TypeTypeof mt) { *pe = null; *pt = null; *ps = null; //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars()); //static int nest; if (++nest == 50) *(char*)0=0; if (sc is null) { *pt = Type.terror; error(loc, "Invalid scope."); return; } if (mt.inuse) { mt.inuse = 2; error(loc, "circular `typeof` definition"); Lerr: *pt = Type.terror; mt.inuse--; return; } mt.inuse++; /* Currently we cannot evaluate 'exp' in speculative context, because * the type implementation may leak to the final execution. Consider: * * struct S(T) { * string toString() const { return "x"; } * } * void main() { * alias X = typeof(S!int()); * assert(typeid(X).toString() == "x"); * } */ Scope* sc2 = sc.push(); sc2.intypeof = 1; auto exp2 = mt.exp.expressionSemantic(sc2); exp2 = resolvePropertiesOnly(sc2, exp2); sc2.pop(); if (exp2.op == TOK.error) { if (!global.gag) mt.exp = exp2; goto Lerr; } mt.exp = exp2; if (mt.exp.op == TOK.type || mt.exp.op == TOK.scope_) { if (mt.exp.checkType()) goto Lerr; /* Today, 'typeof(func)' returns void if func is a * function template (TemplateExp), or * template lambda (FuncExp). * It's actually used in Phobos as an idiom, to branch code for * template functions. */ } if (auto f = mt.exp.op == TOK.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration() : mt.exp.op == TOK.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null) { if (f.checkForwardRef(loc)) goto Lerr; } if (auto f = isFuncAddress(mt.exp)) { if (f.checkForwardRef(loc)) goto Lerr; } Type t = mt.exp.type; if (!t) { error(loc, "expression `%s` has no type", mt.exp.toChars()); goto Lerr; } if (t.ty == Ttypeof) { error(loc, "forward reference to `%s`", mt.toChars()); goto Lerr; } if (mt.idents.dim == 0) *pt = t; else { if (Dsymbol s = t.toDsymbol(sc)) mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid); else { auto e = typeToExpressionHelper(mt, new TypeExp(loc, t)); e = e.expressionSemantic(sc); mt.resolveExp(e, pt, pe, ps); } } if (*pt) (*pt) = (*pt).addMod(mt.mod); mt.inuse--; return; } override void visit(TypeReturn mt) { *pe = null; *pt = null; *ps = null; //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars()); Type t; { FuncDeclaration func = sc.func; if (!func) { error(loc, "`typeof(return)` must be inside function"); goto Lerr; } if (func.fes) func = func.fes.func; t = func.type.nextOf(); if (!t) { error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars()); goto Lerr; } } if (mt.idents.dim == 0) *pt = t; else { if (Dsymbol s = t.toDsymbol(sc)) mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid); else { auto e = typeToExpressionHelper(mt, new TypeExp(loc, t)); e = e.expressionSemantic(sc); mt.resolveExp(e, pt, pe, ps); } } if (*pt) (*pt) = (*pt).addMod(mt.mod); return; Lerr: *pt = Type.terror; } override void visit(TypeSlice mt) { mt.next.resolve(loc, sc, pe, pt, ps, intypeid); if (*pe) { // It's really a slice expression if (Dsymbol s = getDsymbol(*pe)) *pe = new DsymbolExp(loc, s); *pe = new ArrayExp(loc, *pe, new IntervalExp(loc, mt.lwr, mt.upr)); } else if (*ps) { Dsymbol s = *ps; TupleDeclaration td = s.isTupleDeclaration(); if (td) { /* It's a slice of a TupleDeclaration */ ScopeDsymbol sym = new ArrayScopeSymbol(sc, td); sym.parent = sc.scopesym; sc = sc.push(sym); sc = sc.startCTFE(); mt.lwr = mt.lwr.expressionSemantic(sc); mt.upr = mt.upr.expressionSemantic(sc); sc = sc.endCTFE(); sc = sc.pop(); mt.lwr = mt.lwr.ctfeInterpret(); mt.upr = mt.upr.ctfeInterpret(); uinteger_t i1 = mt.lwr.toUInteger(); uinteger_t i2 = mt.upr.toUInteger(); if (!(i1 <= i2 && i2 <= td.objects.dim)) { error(loc, "slice `[%llu..%llu]` is out of range of [0..%u]", i1, i2, td.objects.dim); *ps = null; *pt = Type.terror; return; } if (i1 == 0 && i2 == td.objects.dim) { *ps = td; return; } /* Create a new TupleDeclaration which * is a slice [i1..i2] out of the old one. */ auto objects = new Objects(cast(size_t)(i2 - i1)); for (size_t i = 0; i < objects.dim; i++) { (*objects)[i] = (*td.objects)[cast(size_t)i1 + i]; } auto tds = new TupleDeclaration(loc, td.ident, objects); *ps = tds; } else goto Ldefault; } else { if ((*pt).ty != Terror) mt.next = *pt; // prevent re-running semantic() on 'next' Ldefault: visit(cast(Type)mt); } } } /************************ * Access the members of the object e. This type is same as e.type. * Params: * mt = type for which the dot expression is used * sc = instantiating scope * e = expression to convert * ident = identifier being used * flag = DotExpFlag bit flags * * Returns: * resulting expression with e.ident resolved */ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { scope v = new DotExpVisitor(sc, e, ident, flag); mt.accept(v); return v.result; } private extern(C++) final class DotExpVisitor : Visitor { alias visit = typeof(super).visit; Scope *sc; Expression e; Identifier ident; int flag; Expression result; this(Scope* sc, Expression e, Identifier ident, int flag) { this.sc = sc; this.e = e; this.ident = ident; this.flag = flag; } override void visit(Type mt) { VarDeclaration v = null; static if (LOGDOTEXP) { printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } Expression ex = e; while (ex.op == TOK.comma) ex = (cast(CommaExp)ex).e2; if (ex.op == TOK.dotVariable) { DotVarExp dv = cast(DotVarExp)ex; v = dv.var.isVarDeclaration(); } else if (ex.op == TOK.variable) { VarExp ve = cast(VarExp)ex; v = ve.var.isVarDeclaration(); } if (v) { if (ident == Id.offsetof) { if (v.isField()) { auto ad = v.toParent().isAggregateDeclaration(); objc.checkOffsetof(e, ad); ad.size(e.loc); if (ad.sizeok != Sizeok.done) { result = new ErrorExp(); return; } e = new IntegerExp(e.loc, v.offset, Type.tsize_t); result = e; return; } } else if (ident == Id._init) { Type tb = mt.toBasetype(); e = mt.defaultInitLiteral(e.loc); if (tb.ty == Tstruct && tb.needsNested()) { StructLiteralExp se = cast(StructLiteralExp)e; se.useStaticInit = true; } goto Lreturn; } } if (ident == Id.stringof) { /* https://issues.dlang.org/show_bug.cgi?id=3796 * this should demangle e.type.deco rather than * pretty-printing the type. */ const s = e.toChars(); e = new StringExp(e.loc, cast(char*)s); } else e = mt.getProperty(e.loc, ident, flag & DotExpFlag.gag); Lreturn: if (e) e = e.expressionSemantic(sc); result = e; } override void visit(TypeError) { result = new ErrorExp(); } override void visit(TypeBasic mt) { static if (LOGDOTEXP) { printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } Type t; if (ident == Id.re) { switch (mt.ty) { case Tcomplex32: t = mt.tfloat32; goto L1; case Tcomplex64: t = mt.tfloat64; goto L1; case Tcomplex80: t = mt.tfloat80; goto L1; L1: e = e.castTo(sc, t); break; case Tfloat32: case Tfloat64: case Tfloat80: break; case Timaginary32: t = mt.tfloat32; goto L2; case Timaginary64: t = mt.tfloat64; goto L2; case Timaginary80: t = mt.tfloat80; goto L2; L2: e = new RealExp(e.loc, CTFloat.zero, t); break; default: e = mt.Type.getProperty(e.loc, ident, flag); break; } } else if (ident == Id.im) { Type t2; switch (mt.ty) { case Tcomplex32: t = mt.timaginary32; t2 = mt.tfloat32; goto L3; case Tcomplex64: t = mt.timaginary64; t2 = mt.tfloat64; goto L3; case Tcomplex80: t = mt.timaginary80; t2 = mt.tfloat80; goto L3; L3: e = e.castTo(sc, t); e.type = t2; break; case Timaginary32: t = mt.tfloat32; goto L4; case Timaginary64: t = mt.tfloat64; goto L4; case Timaginary80: t = mt.tfloat80; goto L4; L4: e = e.copy(); e.type = t; break; case Tfloat32: case Tfloat64: case Tfloat80: e = new RealExp(e.loc, CTFloat.zero, mt); break; default: e = mt.Type.getProperty(e.loc, ident, flag); break; } } else { visit(cast(Type)mt); return; } if (!(flag & 1) || e) e = e.expressionSemantic(sc); result = e; } override void visit(TypeVector mt) { static if (LOGDOTEXP) { printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } if (ident == Id.ptr && e.op == TOK.call) { /* The trouble with TOK.call is the return ABI for float[4] is different from * __vector(float[4]), and a type paint won't do. */ e = new AddrExp(e.loc, e); e = e.expressionSemantic(sc); e = e.castTo(sc, mt.basetype.nextOf().pointerTo()); result = e; return; } if (ident == Id.array) { //e = e.castTo(sc, basetype); // Keep lvalue-ness e = e.copy(); e.type = mt.basetype; result = e; return; } if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof) { // init should return a new VectorExp // https://issues.dlang.org/show_bug.cgi?id=12776 // offsetof does not work on a cast expression, so use e directly // stringof should not add a cast to the output visit(cast(Type)mt); return; } result = mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag); } override void visit(TypeArray mt) { static if (LOGDOTEXP) { printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } visit(cast(Type)mt); e = result; if (!(flag & 1) || e) e = e.expressionSemantic(sc); result = e; } override void visit(TypeSArray mt) { static if (LOGDOTEXP) { printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } if (ident == Id.length) { Loc oldLoc = e.loc; e = mt.dim.copy(); e.loc = oldLoc; } else if (ident == Id.ptr) { if (e.op == TOK.type) { e.error("`%s` is not an expression", e.toChars()); result = new ErrorExp(); return; } else if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars()); result = new ErrorExp(); return; } e = e.castTo(sc, e.type.nextOf().pointerTo()); } else { visit(cast(TypeArray)mt); e = result; } if (!(flag & 1) || e) e = e.expressionSemantic(sc); result = e; } override void visit(TypeDArray mt) { static if (LOGDOTEXP) { printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } if (e.op == TOK.type && (ident == Id.length || ident == Id.ptr)) { e.error("`%s` is not an expression", e.toChars()); result = new ErrorExp(); return; } if (ident == Id.length) { if (e.op == TOK.string_) { StringExp se = cast(StringExp)e; result = new IntegerExp(se.loc, se.len, Type.tsize_t); return; } if (e.op == TOK.null_) { result = new IntegerExp(e.loc, 0, Type.tsize_t); return; } if (checkNonAssignmentArrayOp(e)) { result = new ErrorExp(); return; } e = new ArrayLengthExp(e.loc, e); e.type = Type.tsize_t; result = e; return; } else if (ident == Id.ptr) { if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars()); result = new ErrorExp(); return; } e = e.castTo(sc, mt.next.pointerTo()); result = e; return; } else { visit(cast(TypeArray)mt); e = result; } result = e; } override void visit(TypeAArray mt) { static if (LOGDOTEXP) { printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } if (ident == Id.length) { __gshared FuncDeclaration fd_aaLen = null; if (fd_aaLen is null) { auto fparams = new Parameters(); fparams.push(new Parameter(STC.in_, mt, null, null, null)); fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen); TypeFunction tf = fd_aaLen.type.toTypeFunction(); tf.purity = PURE.const_; tf.isnothrow = true; tf.isnogc = false; } Expression ev = new VarExp(e.loc, fd_aaLen, false); e = new CallExp(e.loc, ev, e); e.type = fd_aaLen.type.toTypeFunction().next; } else { visit(cast(Type)mt); e = result; } result = e; } override void visit(TypeReference mt) { static if (LOGDOTEXP) { printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } // References just forward things along result = mt.next.dotExp(sc, e, ident, flag); } override void visit(TypeDelegate mt) { static if (LOGDOTEXP) { printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } if (ident == Id.ptr) { e = new DelegatePtrExp(e.loc, e); e = e.expressionSemantic(sc); } else if (ident == Id.funcptr) { if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) { e.error("`%s.funcptr` cannot be used in `@safe` code", e.toChars()); result = new ErrorExp(); return; } e = new DelegateFuncptrExp(e.loc, e); e = e.expressionSemantic(sc); } else { visit(cast(Type)mt); e = result; } result = e; } /*************************************** * Figures out what to do with an undefined member reference * for classes and structs. * * If flag & 1, don't report "not a property" error and just return NULL. */ Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag); bool gagError = flag & 1; __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380 static Expression returnExp(Expression e) { --nest; return e; } if (++nest > 500) { .error(e.loc, "cannot resolve identifier `%s`", ident.toChars()); return returnExp(gagError ? null : new ErrorExp()); } assert(mt.ty == Tstruct || mt.ty == Tclass); auto sym = mt.toDsymbol(sc).isAggregateDeclaration(); assert(sym); if (ident != Id.__sizeof && ident != Id.__xalignof && ident != Id._init && ident != Id._mangleof && ident != Id.stringof && ident != Id.offsetof && // https://issues.dlang.org/show_bug.cgi?id=15045 // Don't forward special built-in member functions. ident != Id.ctor && ident != Id.dtor && ident != Id.__xdtor && ident != Id.postblit && ident != Id.__xpostblit) { /* Look for overloaded opDot() to see if we should forward request * to it. */ if (auto fd = search_function(sym, Id.opDot)) { /* Rewrite e.ident as: * e.opDot().ident */ e = build_overload(e.loc, sc, e, null, fd); // @@@DEPRECATED_2.087@@@. e.deprecation("`opDot` is deprecated. Use `alias this`"); e = new DotIdExp(e.loc, e, ident); return returnExp(e.expressionSemantic(sc)); } /* Look for overloaded opDispatch to see if we should forward request * to it. */ if (auto fd = search_function(sym, Id.opDispatch)) { /* Rewrite e.ident as: * e.opDispatch!("ident") */ TemplateDeclaration td = fd.isTemplateDeclaration(); if (!td) { fd.error("must be a template `opDispatch(string s)`, not a %s", fd.kind()); return returnExp(new ErrorExp()); } auto se = new StringExp(e.loc, cast(char*)ident.toChars()); auto tiargs = new Objects(); tiargs.push(se); auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs); dti.ti.tempdecl = td; /* opDispatch, which doesn't need IFTI, may occur instantiate error. * e.g. * template opDispatch(name) if (isValid!name) { ... } */ uint errors = gagError ? global.startGagging() : 0; e = dti.semanticY(sc, 0); if (gagError && global.endGagging(errors)) e = null; return returnExp(e); } /* See if we should forward to the alias this. */ auto alias_e = resolveAliasThis(sc, e, gagError); if (alias_e && alias_e != e) { /* Rewrite e.ident as: * e.aliasthis.ident */ auto die = new DotIdExp(e.loc, alias_e, ident); auto errors = gagError ? 0 : global.startGagging(); auto exp = die.semanticY(sc, gagError); if (!gagError) { global.endGagging(errors); if (exp && exp.op == TOK.error) exp = null; } if (exp && gagError) // now that we know that the alias this leads somewhere useful, // go back and print deprecations/warnings that we skipped earlier due to the gag resolveAliasThis(sc, e, false); return returnExp(exp); } } visit(cast(Type)mt); return returnExp(result); } override void visit(TypeStruct mt) { Dsymbol s; static if (LOGDOTEXP) { printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } assert(e.op != TOK.dot); // https://issues.dlang.org/show_bug.cgi?id=14010 if (ident == Id._mangleof) { result = mt.getProperty(e.loc, ident, flag & 1); return; } /* If e.tupleof */ if (ident == Id._tupleof) { /* Create a TupleExp out of the fields of the struct e: * (e.field0, e.field1, e.field2, ...) */ e = e.expressionSemantic(sc); // do this before turning on noaccesscheck if (!mt.sym.determineFields()) { error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars()); } Expression e0; Expression ev = e.op == TOK.type ? null : e; if (ev) ev = extractSideEffect(sc, "__tup", e0, ev); auto exps = new Expressions(); exps.reserve(mt.sym.fields.dim); for (size_t i = 0; i < mt.sym.fields.dim; i++) { VarDeclaration v = mt.sym.fields[i]; Expression ex; if (ev) ex = new DotVarExp(e.loc, ev, v); else { ex = new VarExp(e.loc, v); ex.type = ex.type.addMod(e.type.mod); } exps.push(ex); } e = new TupleExp(e.loc, e0, exps); Scope* sc2 = sc.push(); sc2.flags |= global.params.vsafe ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck; e = e.expressionSemantic(sc2); sc2.pop(); result = e; return; } Dsymbol searchSym() { int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; Dsymbol sold = void; if (global.params.bug10378 || global.params.check10378) { sold = mt.sym.search(e.loc, ident, flags); if (!global.params.check10378) return sold; } auto s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); if (global.params.check10378) { alias snew = s; if (sold !is snew) Scope.deprecation10378(e.loc, sold, snew); if (global.params.bug10378) s = sold; } return s; } s = searchSym(); L1: if (!s) { result = noMember(mt, sc, e, ident, flag); return; } if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s)) { .deprecation(e.loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), sc._module.toPrettyChars()); // return noMember(sc, e, ident, flag); } if (!s.isFuncDeclaration()) // because of overloading { s.checkDeprecated(e.loc, sc); if (auto d = s.isDeclaration()) d.checkDisabled(e.loc, sc); } s = s.toAlias(); if (auto em = s.isEnumMember()) { result = em.getVarExp(e.loc, sc); return; } if (auto v = s.isVarDeclaration()) { if (!v.type || !v.type.deco && v.inuse) { if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars()); else e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars()); result = new ErrorExp(); return; } if (v.type.ty == Terror) { result = new ErrorExp(); return; } if ((v.storage_class & STC.manifest) && v._init) { if (v.inuse) { e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); result = new ErrorExp(); return; } checkAccess(e.loc, sc, null, v); Expression ve = new VarExp(e.loc, v); if (!isTrivialExp(e)) { ve = new CommaExp(e.loc, e, ve); } ve = ve.expressionSemantic(sc); result = ve; return; } } if (auto t = s.getType()) { result = (new TypeExp(e.loc, t)).expressionSemantic(sc); return; } TemplateMixin tm = s.isTemplateMixin(); if (tm) { Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm)); de.type = e.type; result = de; return; } TemplateDeclaration td = s.isTemplateDeclaration(); if (td) { if (e.op == TOK.type) e = new TemplateExp(e.loc, td); else e = new DotTemplateExp(e.loc, e, td); e = e.expressionSemantic(sc); result = e; return; } TemplateInstance ti = s.isTemplateInstance(); if (ti) { if (!ti.semanticRun) { ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) // if template failed to expand { result = new ErrorExp(); return; } } s = ti.inst.toAlias(); if (!s.isTemplateInstance()) goto L1; if (e.op == TOK.type) e = new ScopeExp(e.loc, ti); else e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); result = e.expressionSemantic(sc); return; } if (s.isImport() || s.isModule() || s.isPackage()) { e = dmd.expressionsem.resolve(e.loc, sc, s, false); result = e; return; } OverloadSet o = s.isOverloadSet(); if (o) { auto oe = new OverExp(e.loc, o); if (e.op == TOK.type) { result = oe; return; } result = new DotExp(e.loc, e, oe); return; } Declaration d = s.isDeclaration(); if (!d) { e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars()); result = new ErrorExp(); return; } if (e.op == TOK.type) { /* It's: * Struct.d */ if (TupleDeclaration tup = d.isTupleDeclaration()) { e = new TupleExp(e.loc, tup); e = e.expressionSemantic(sc); result = e; return; } if (d.needThis() && sc.intypeof != 1) { /* Rewrite as: * this.d */ if (hasThis(sc)) { e = new DotVarExp(e.loc, new ThisExp(e.loc), d); e = e.expressionSemantic(sc); result = e; return; } } if (d.semanticRun == PASS.init) d.dsymbolSemantic(null); checkAccess(e.loc, sc, e, d); auto ve = new VarExp(e.loc, d); if (d.isVarDeclaration() && d.needThis()) ve.type = d.type.addMod(e.type.mod); result = ve; return; } bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField(); if (d.isDataseg() || unreal && d.isField()) { // (e, d) checkAccess(e.loc, sc, e, d); Expression ve = new VarExp(e.loc, d); e = unreal ? ve : new CommaExp(e.loc, e, ve); e = e.expressionSemantic(sc); result = e; return; } e = new DotVarExp(e.loc, e, d); e = e.expressionSemantic(sc); result = e; } override void visit(TypeEnum mt) { static if (LOGDOTEXP) { printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars()); } // https://issues.dlang.org/show_bug.cgi?id=14010 if (ident == Id._mangleof) { result = mt.getProperty(e.loc, ident, flag & 1); return; } if (mt.sym.semanticRun < PASS.semanticdone) mt.sym.dsymbolSemantic(null); if (!mt.sym.members) { if (mt.sym.isSpecial()) { /* Special enums forward to the base type */ e = mt.sym.memtype.dotExp(sc, e, ident, flag); } else if (!(flag & 1)) { mt.sym.error("is forward referenced when looking for `%s`", ident.toChars()); e = new ErrorExp(); } else e = null; result = e; return; } Dsymbol s = mt.sym.search(e.loc, ident); if (!s) { if (ident == Id.max || ident == Id.min || ident == Id._init) { result = mt.getProperty(e.loc, ident, flag & 1); return; } Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1); if (!(flag & 1) && !res) { if (auto ns = mt.sym.search_correct(ident)) e.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(), ns.toChars()); else e.error("no property `%s` for type `%s`", ident.toChars(), mt.toChars()); result = new ErrorExp(); return; } result = res; return; } EnumMember m = s.isEnumMember(); result = m.getVarExp(e.loc, sc); } override void visit(TypeClass mt) { Dsymbol s; static if (LOGDOTEXP) { printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } assert(e.op != TOK.dot); // https://issues.dlang.org/show_bug.cgi?id=12543 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof) { result = mt.Type.getProperty(e.loc, ident, 0); return; } /* If e.tupleof */ if (ident == Id._tupleof) { objc.checkTupleof(e, mt); /* Create a TupleExp */ e = e.expressionSemantic(sc); // do this before turning on noaccesscheck mt.sym.size(e.loc); // do semantic of type Expression e0; Expression ev = e.op == TOK.type ? null : e; if (ev) ev = extractSideEffect(sc, "__tup", e0, ev); auto exps = new Expressions(); exps.reserve(mt.sym.fields.dim); for (size_t i = 0; i < mt.sym.fields.dim; i++) { VarDeclaration v = mt.sym.fields[i]; // Don't include hidden 'this' pointer if (v.isThisDeclaration()) continue; Expression ex; if (ev) ex = new DotVarExp(e.loc, ev, v); else { ex = new VarExp(e.loc, v); ex.type = ex.type.addMod(e.type.mod); } exps.push(ex); } e = new TupleExp(e.loc, e0, exps); Scope* sc2 = sc.push(); sc2.flags |= global.params.vsafe ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck; e = e.expressionSemantic(sc2); sc2.pop(); result = e; return; } Dsymbol searchSym() { int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; Dsymbol sold = void; if (global.params.bug10378 || global.params.check10378) { sold = mt.sym.search(e.loc, ident, flags | IgnoreSymbolVisibility); if (!global.params.check10378) return sold; } auto s = mt.sym.search(e.loc, ident, flags | SearchLocalsOnly); if (!s && !(flags & IgnoreSymbolVisibility)) { s = mt.sym.search(e.loc, ident, flags | SearchLocalsOnly | IgnoreSymbolVisibility); if (s && !(flags & IgnoreErrors)) .deprecation(e.loc, "`%s` is not visible from class `%s`", s.toPrettyChars(), mt.sym.toChars()); } if (global.params.check10378) { alias snew = s; if (sold !is snew) Scope.deprecation10378(e.loc, sold, snew); if (global.params.bug10378) s = sold; } return s; } s = searchSym(); L1: if (!s) { // See if it's 'this' class or a base class if (mt.sym.ident == ident) { if (e.op == TOK.type) { result = mt.Type.getProperty(e.loc, ident, 0); return; } e = new DotTypeExp(e.loc, e, mt.sym); e = e.expressionSemantic(sc); result = e; return; } if (auto cbase = mt.sym.searchBase(ident)) { if (e.op == TOK.type) { result = mt.Type.getProperty(e.loc, ident, 0); return; } if (auto ifbase = cbase.isInterfaceDeclaration()) e = new CastExp(e.loc, e, ifbase.type); else e = new DotTypeExp(e.loc, e, cbase); e = e.expressionSemantic(sc); result = e; return; } if (ident == Id.classinfo) { assert(Type.typeinfoclass); Type t = Type.typeinfoclass.type; if (e.op == TOK.type || e.op == TOK.dotType) { /* For type.classinfo, we know the classinfo * at compile time. */ if (!mt.sym.vclassinfo) mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type); e = new VarExp(e.loc, mt.sym.vclassinfo); e = e.addressOf(); e.type = t; // do this so we don't get redundant dereference } else { /* For class objects, the classinfo reference is the first * entry in the vtbl[] */ e = new PtrExp(e.loc, e); e.type = t.pointerTo(); if (mt.sym.isInterfaceDeclaration()) { if (mt.sym.isCPPinterface()) { /* C++ interface vtbl[]s are different in that the * first entry is always pointer to the first virtual * function, not classinfo. * We can't get a .classinfo for it. */ error(e.loc, "no `.classinfo` for C++ interface objects"); } /* For an interface, the first entry in the vtbl[] * is actually a pointer to an instance of struct Interface. * The first member of Interface is the .classinfo, * so add an extra pointer indirection. */ e.type = e.type.pointerTo(); e = new PtrExp(e.loc, e); e.type = t.pointerTo(); } e = new PtrExp(e.loc, e, t); } result = e; return; } if (ident == Id.__vptr) { /* The pointer to the vtbl[] * *cast(immutable(void*)**)e */ e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo()); e = new PtrExp(e.loc, e); e = e.expressionSemantic(sc); result = e; return; } if (ident == Id.__monitor) { /* The handle to the monitor (call it a void*) * *(cast(void**)e + 1) */ e = e.castTo(sc, mt.tvoidptr.pointerTo()); e = new AddExp(e.loc, e, new IntegerExp(1)); e = new PtrExp(e.loc, e); e = e.expressionSemantic(sc); result = e; return; } if (ident == Id.outer && mt.sym.vthis) { if (mt.sym.vthis.semanticRun == PASS.init) mt.sym.vthis.dsymbolSemantic(null); if (auto cdp = mt.sym.toParent2().isClassDeclaration()) { auto dve = new DotVarExp(e.loc, e, mt.sym.vthis); dve.type = cdp.type.addMod(e.type.mod); result = dve; return; } /* https://issues.dlang.org/show_bug.cgi?id=15839 * Find closest parent class through nested functions. */ for (auto p = mt.sym.toParent2(); p; p = p.toParent2()) { auto fd = p.isFuncDeclaration(); if (!fd) break; if (fd.isNested()) continue; auto ad = fd.isThis(); if (!ad) break; if (auto cdp = ad.isClassDeclaration()) { auto ve = new ThisExp(e.loc); ve.var = fd.vthis; const nestedError = fd.vthis.checkNestedReference(sc, e.loc); assert(!nestedError); ve.type = fd.vthis.type.addMod(e.type.mod); result = ve; return; } break; } // Continue to show enclosing function's frame (stack or closure). auto dve = new DotVarExp(e.loc, e, mt.sym.vthis); dve.type = mt.sym.vthis.type.addMod(e.type.mod); result = dve; return; } result = noMember(mt, sc, e, ident, flag & 1); return; } if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s)) { .deprecation(e.loc, "`%s` is not visible from module `%s`", s.toPrettyChars(), sc._module.toPrettyChars()); // return noMember(sc, e, ident, flag); } if (!s.isFuncDeclaration()) // because of overloading { s.checkDeprecated(e.loc, sc); if (auto d = s.isDeclaration()) d.checkDisabled(e.loc, sc); } s = s.toAlias(); if (auto em = s.isEnumMember()) { result = em.getVarExp(e.loc, sc); return; } if (auto v = s.isVarDeclaration()) { if (!v.type || !v.type.deco && v.inuse) { if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494 e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars()); else e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars()); result = new ErrorExp(); return; } if (v.type.ty == Terror) { result = new ErrorExp(); return; } if ((v.storage_class & STC.manifest) && v._init) { if (v.inuse) { e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); result = new ErrorExp(); return; } checkAccess(e.loc, sc, null, v); Expression ve = new VarExp(e.loc, v); ve = ve.expressionSemantic(sc); result = ve; return; } } if (auto t = s.getType()) { result = (new TypeExp(e.loc, t)).expressionSemantic(sc); return; } TemplateMixin tm = s.isTemplateMixin(); if (tm) { Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm)); de.type = e.type; result = de; return; } TemplateDeclaration td = s.isTemplateDeclaration(); if (td) { if (e.op == TOK.type) e = new TemplateExp(e.loc, td); else e = new DotTemplateExp(e.loc, e, td); e = e.expressionSemantic(sc); result = e; return; } TemplateInstance ti = s.isTemplateInstance(); if (ti) { if (!ti.semanticRun) { ti.dsymbolSemantic(sc); if (!ti.inst || ti.errors) // if template failed to expand { result = new ErrorExp(); return; } } s = ti.inst.toAlias(); if (!s.isTemplateInstance()) goto L1; if (e.op == TOK.type) e = new ScopeExp(e.loc, ti); else e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); result = e.expressionSemantic(sc); return; } if (s.isImport() || s.isModule() || s.isPackage()) { e = dmd.expressionsem.resolve(e.loc, sc, s, false); result = e; return; } OverloadSet o = s.isOverloadSet(); if (o) { auto oe = new OverExp(e.loc, o); if (e.op == TOK.type) { result = oe; return; } result = new DotExp(e.loc, e, oe); return; } Declaration d = s.isDeclaration(); if (!d) { e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars()); result = new ErrorExp(); return; } if (e.op == TOK.type) { /* It's: * Class.d */ if (TupleDeclaration tup = d.isTupleDeclaration()) { e = new TupleExp(e.loc, tup); e = e.expressionSemantic(sc); result = e; return; } if (mt.sym.classKind == ClassKind.objc && d.isFuncDeclaration() && d.isFuncDeclaration().isStatic && d.isFuncDeclaration().selector) { auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym); result = new DotVarExp(e.loc, classRef, d).expressionSemantic(sc); return; } else if (d.needThis() && sc.intypeof != 1) { /* Rewrite as: * this.d */ if (hasThis(sc)) { // This is almost same as getRightThis() in expression.c Expression e1 = new ThisExp(e.loc); e1 = e1.expressionSemantic(sc); L2: Type t = e1.type.toBasetype(); ClassDeclaration cd = e.type.isClassHandle(); ClassDeclaration tcd = t.isClassHandle(); if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null))) { e = new DotTypeExp(e1.loc, e1, cd); e = new DotVarExp(e.loc, e, d); e = e.expressionSemantic(sc); result = e; return; } if (tcd && tcd.isNested()) { /* e1 is the 'this' pointer for an inner class: tcd. * Rewrite it as the 'this' pointer for the outer class. */ e1 = new DotVarExp(e.loc, e1, tcd.vthis); e1.type = tcd.vthis.type; e1.type = e1.type.addMod(t.mod); // Do not call ensureStaticLinkTo() //e1 = e1.expressionSemantic(sc); // Skip up over nested functions, and get the enclosing // class type. int n = 0; for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) { FuncDeclaration f = s.isFuncDeclaration(); if (f.vthis) { //printf("rewriting e1 to %s's this\n", f.toChars()); n++; e1 = new VarExp(e.loc, f.vthis); } else { e = new VarExp(e.loc, d); result = e; return; } } if (s && s.isClassDeclaration()) { e1.type = s.isClassDeclaration().type; e1.type = e1.type.addMod(t.mod); if (n > 1) e1 = e1.expressionSemantic(sc); } else e1 = e1.expressionSemantic(sc); goto L2; } } } //printf("e = %s, d = %s\n", e.toChars(), d.toChars()); if (d.semanticRun == PASS.init) d.dsymbolSemantic(null); // If static function, get the most visible overload. // Later on the call is checked for correctness. // https://issues.dlang.org/show_bug.cgi?id=12511 if (auto fd = d.isFuncDeclaration()) { import dmd.access : mostVisibleOverload; d = cast(Declaration)mostVisibleOverload(fd, sc._module); } checkAccess(e.loc, sc, e, d); auto ve = new VarExp(e.loc, d); if (d.isVarDeclaration() && d.needThis()) ve.type = d.type.addMod(e.type.mod); result = ve; return; } bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField(); if (d.isDataseg() || unreal && d.isField()) { // (e, d) checkAccess(e.loc, sc, e, d); Expression ve = new VarExp(e.loc, d); e = unreal ? ve : new CommaExp(e.loc, e, ve); e = e.expressionSemantic(sc); result = e; return; } e = new DotVarExp(e.loc, e, d); e = e.expressionSemantic(sc); result = e; } } /************************ * Get the the default initialization expression for a type. * Params: * mt = the type for which the init expression is returned * loc = the location where the expression needs to be evaluated * * Returns: * The initialization expression for the type. */ Expression defaultInit(Type mt, const ref Loc loc) { scope v = new DefaultInitVisitor(loc); mt.accept(v); return v.result; } private extern(C++) final class DefaultInitVisitor : Visitor { alias visit = typeof(super).visit; const Loc loc; Expression result; this(const ref Loc loc) { this.loc = loc; } override void visit(Type mt) { static if (LOGDEFAULTINIT) { printf("Type::defaultInit() '%s'\n", mt.toChars()); } result = null; } override void visit(TypeError mt) { result = new ErrorExp(); } override void visit(TypeBasic mt) { static if (LOGDEFAULTINIT) { printf("TypeBasic::defaultInit() '%s'\n", mt.toChars()); } dinteger_t value = 0; switch (mt.ty) { case Tchar: value = 0xFF; break; case Twchar: case Tdchar: value = 0xFFFF; break; case Timaginary32: case Timaginary64: case Timaginary80: case Tfloat32: case Tfloat64: case Tfloat80: result = new RealExp(loc, Target.RealProperties.snan, mt); return; case Tcomplex32: case Tcomplex64: case Tcomplex80: { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). const cvalue = complex_t(Target.RealProperties.snan, Target.RealProperties.snan); result = new ComplexExp(loc, cvalue, mt); return; } case Tvoid: error(loc, "`void` does not have a default initializer"); result = new ErrorExp(); return; default: break; } result = new IntegerExp(loc, value, mt); } override void visit(TypeVector mt) { //printf("TypeVector::defaultInit()\n"); assert(mt.basetype.ty == Tsarray); Expression e = mt.basetype.defaultInit(loc); auto ve = new VectorExp(loc, e, mt); ve.type = mt; ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc)); result = ve; } override void visit(TypeSArray mt) { static if (LOGDEFAULTINIT) { printf("TypeSArray::defaultInit() '%s'\n", mt.toChars()); } if (mt.next.ty == Tvoid) result = mt.tuns8.defaultInit(loc); else result = mt.next.defaultInit(loc); } override void visit(TypeDArray mt) { static if (LOGDEFAULTINIT) { printf("TypeDArray::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypeAArray mt) { static if (LOGDEFAULTINIT) { printf("TypeAArray::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypePointer mt) { static if (LOGDEFAULTINIT) { printf("TypePointer::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypeReference mt) { static if (LOGDEFAULTINIT) { printf("TypeReference::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypeFunction mt) { error(loc, "`function` does not have a default initializer"); result = new ErrorExp(); } override void visit(TypeDelegate mt) { static if (LOGDEFAULTINIT) { printf("TypeDelegate::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypeStruct mt) { static if (LOGDEFAULTINIT) { printf("TypeStruct::defaultInit() '%s'\n", mt.toChars()); } Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym); assert(d); d.type = mt; d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398 result = new VarExp(mt.sym.loc, d); } override void visit(TypeEnum mt) { static if (LOGDEFAULTINIT) { printf("TypeEnum::defaultInit() '%s'\n", mt.toChars()); } // Initialize to first member of enum Expression e = mt.sym.getDefaultValue(loc); e = e.copy(); e.loc = loc; e.type = mt; // to deal with const, immutable, etc., variants result = e; } override void visit(TypeClass mt) { static if (LOGDEFAULTINIT) { printf("TypeClass::defaultInit() '%s'\n", mt.toChars()); } result = new NullExp(loc, mt); } override void visit(TypeTuple mt) { static if (LOGDEFAULTINIT) { printf("TypeTuple::defaultInit() '%s'\n", mt.toChars()); } auto exps = new Expressions(mt.arguments.dim); for (size_t i = 0; i < mt.arguments.dim; i++) { Parameter p = (*mt.arguments)[i]; assert(p.type); Expression e = p.type.defaultInitLiteral(loc); if (e.op == TOK.error) { result = e; return; } (*exps)[i] = e; } result = new TupleExp(loc, exps); } override void visit(TypeNull mt) { result = new NullExp(Loc.initial, Type.tnull); } } ================================================ FILE: gcc/d/dmd/typinf.d ================================================ /* typinf.d -- D runtime type identification * Copyright (C) 2018 Free Software Foundation, Inc. * * GCC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GCC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GCC; see the file COPYING3. If not see * . */ module dmd.typinf; import dmd.dscope; import dmd.globals; import dmd.mtype; /**************************************************** * Gets the type of the `TypeInfo` object associated with `t` * Params: * loc = the location for reporting line nunbers in errors * t = the type to get the type of the `TypeInfo` object for * sc = the scope * Returns: * The type of the `TypeInfo` object associated with `t` */ extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc); ================================================ FILE: gcc/d/dmd/utf.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/utf.d, _utf.d) * Documentation: https://dlang.org/phobos/dmd_utf.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utf.d */ module dmd.utf; nothrow pure @nogc: /// The Unicode code space is the range of code points [0x000000,0x10FFFF] /// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF] bool utf_isValidDchar(dchar c) { // TODO: Whether non-char code points should be rejected is pending review. // 0xFFFE and 0xFFFF are valid for internal use, like Phobos std.utf.isValidDChar // See also https://issues.dlang.org/show_bug.cgi?id=1357 if (c < 0xD800) // Almost all characters in a typical document. return true; if (c > 0xDFFF && c <= 0x10FFFF) return true; return false; } /******************************* * Return !=0 if unicode alpha. * Use table from C99 Appendix D. */ bool isUniAlpha(dchar c) { static immutable wchar[2][] ALPHA_TABLE = [ [0x00AA, 0x00AA], [0x00B5, 0x00B5], [0x00B7, 0x00B7], [0x00BA, 0x00BA], [0x00C0, 0x00D6], [0x00D8, 0x00F6], [0x00F8, 0x01F5], [0x01FA, 0x0217], [0x0250, 0x02A8], [0x02B0, 0x02B8], [0x02BB, 0x02BB], [0x02BD, 0x02C1], [0x02D0, 0x02D1], [0x02E0, 0x02E4], [0x037A, 0x037A], [0x0386, 0x0386], [0x0388, 0x038A], [0x038C, 0x038C], [0x038E, 0x03A1], [0x03A3, 0x03CE], [0x03D0, 0x03D6], [0x03DA, 0x03DA], [0x03DC, 0x03DC], [0x03DE, 0x03DE], [0x03E0, 0x03E0], [0x03E2, 0x03F3], [0x0401, 0x040C], [0x040E, 0x044F], [0x0451, 0x045C], [0x045E, 0x0481], [0x0490, 0x04C4], [0x04C7, 0x04C8], [0x04CB, 0x04CC], [0x04D0, 0x04EB], [0x04EE, 0x04F5], [0x04F8, 0x04F9], [0x0531, 0x0556], [0x0559, 0x0559], [0x0561, 0x0587], [0x05B0, 0x05B9], [0x05BB, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2], [0x05D0, 0x05EA], [0x05F0, 0x05F2], [0x0621, 0x063A], [0x0640, 0x0652], [0x0660, 0x0669], [0x0670, 0x06B7], [0x06BA, 0x06BE], [0x06C0, 0x06CE], [0x06D0, 0x06DC], [0x06E5, 0x06E8], [0x06EA, 0x06ED], [0x06F0, 0x06F9], [0x0901, 0x0903], [0x0905, 0x0939], [0x093D, 0x094D], [0x0950, 0x0952], [0x0958, 0x0963], [0x0966, 0x096F], [0x0981, 0x0983], [0x0985, 0x098C], [0x098F, 0x0990], [0x0993, 0x09A8], [0x09AA, 0x09B0], [0x09B2, 0x09B2], [0x09B6, 0x09B9], [0x09BE, 0x09C4], [0x09C7, 0x09C8], [0x09CB, 0x09CD], [0x09DC, 0x09DD], [0x09DF, 0x09E3], [0x09E6, 0x09F1], [0x0A02, 0x0A02], [0x0A05, 0x0A0A], [0x0A0F, 0x0A10], [0x0A13, 0x0A28], [0x0A2A, 0x0A30], [0x0A32, 0x0A33], [0x0A35, 0x0A36], [0x0A38, 0x0A39], [0x0A3E, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D], [0x0A59, 0x0A5C], [0x0A5E, 0x0A5E], [0x0A66, 0x0A6F], [0x0A74, 0x0A74], [0x0A81, 0x0A83], [0x0A85, 0x0A8B], [0x0A8D, 0x0A8D], [0x0A8F, 0x0A91], [0x0A93, 0x0AA8], [0x0AAA, 0x0AB0], [0x0AB2, 0x0AB3], [0x0AB5, 0x0AB9], [0x0ABD, 0x0AC5], [0x0AC7, 0x0AC9], [0x0ACB, 0x0ACD], [0x0AD0, 0x0AD0], [0x0AE0, 0x0AE0], [0x0AE6, 0x0AEF], [0x0B01, 0x0B03], [0x0B05, 0x0B0C], [0x0B0F, 0x0B10], [0x0B13, 0x0B28], [0x0B2A, 0x0B30], [0x0B32, 0x0B33], [0x0B36, 0x0B39], [0x0B3D, 0x0B43], [0x0B47, 0x0B48], [0x0B4B, 0x0B4D], [0x0B5C, 0x0B5D], [0x0B5F, 0x0B61], [0x0B66, 0x0B6F], [0x0B82, 0x0B83], [0x0B85, 0x0B8A], [0x0B8E, 0x0B90], [0x0B92, 0x0B95], [0x0B99, 0x0B9A], [0x0B9C, 0x0B9C], [0x0B9E, 0x0B9F], [0x0BA3, 0x0BA4], [0x0BA8, 0x0BAA], [0x0BAE, 0x0BB5], [0x0BB7, 0x0BB9], [0x0BBE, 0x0BC2], [0x0BC6, 0x0BC8], [0x0BCA, 0x0BCD], [0x0BE7, 0x0BEF], [0x0C01, 0x0C03], [0x0C05, 0x0C0C], [0x0C0E, 0x0C10], [0x0C12, 0x0C28], [0x0C2A, 0x0C33], [0x0C35, 0x0C39], [0x0C3E, 0x0C44], [0x0C46, 0x0C48], [0x0C4A, 0x0C4D], [0x0C60, 0x0C61], [0x0C66, 0x0C6F], [0x0C82, 0x0C83], [0x0C85, 0x0C8C], [0x0C8E, 0x0C90], [0x0C92, 0x0CA8], [0x0CAA, 0x0CB3], [0x0CB5, 0x0CB9], [0x0CBE, 0x0CC4], [0x0CC6, 0x0CC8], [0x0CCA, 0x0CCD], [0x0CDE, 0x0CDE], [0x0CE0, 0x0CE1], [0x0CE6, 0x0CEF], [0x0D02, 0x0D03], [0x0D05, 0x0D0C], [0x0D0E, 0x0D10], [0x0D12, 0x0D28], [0x0D2A, 0x0D39], [0x0D3E, 0x0D43], [0x0D46, 0x0D48], [0x0D4A, 0x0D4D], [0x0D60, 0x0D61], [0x0D66, 0x0D6F], [0x0E01, 0x0E3A], [0x0E40, 0x0E5B], [0x0E81, 0x0E82], [0x0E84, 0x0E84], [0x0E87, 0x0E88], [0x0E8A, 0x0E8A], [0x0E8D, 0x0E8D], [0x0E94, 0x0E97], [0x0E99, 0x0E9F], [0x0EA1, 0x0EA3], [0x0EA5, 0x0EA5], [0x0EA7, 0x0EA7], [0x0EAA, 0x0EAB], [0x0EAD, 0x0EAE], [0x0EB0, 0x0EB9], [0x0EBB, 0x0EBD], [0x0EC0, 0x0EC4], [0x0EC6, 0x0EC6], [0x0EC8, 0x0ECD], [0x0ED0, 0x0ED9], [0x0EDC, 0x0EDD], [0x0F00, 0x0F00], [0x0F18, 0x0F19], [0x0F20, 0x0F33], [0x0F35, 0x0F35], [0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F3E, 0x0F47], [0x0F49, 0x0F69], [0x0F71, 0x0F84], [0x0F86, 0x0F8B], [0x0F90, 0x0F95], [0x0F97, 0x0F97], [0x0F99, 0x0FAD], [0x0FB1, 0x0FB7], [0x0FB9, 0x0FB9], [0x10A0, 0x10C5], [0x10D0, 0x10F6], [0x1E00, 0x1E9B], [0x1EA0, 0x1EF9], [0x1F00, 0x1F15], [0x1F18, 0x1F1D], [0x1F20, 0x1F45], [0x1F48, 0x1F4D], [0x1F50, 0x1F57], [0x1F59, 0x1F59], [0x1F5B, 0x1F5B], [0x1F5D, 0x1F5D], [0x1F5F, 0x1F7D], [0x1F80, 0x1FB4], [0x1FB6, 0x1FBC], [0x1FBE, 0x1FBE], [0x1FC2, 0x1FC4], [0x1FC6, 0x1FCC], [0x1FD0, 0x1FD3], [0x1FD6, 0x1FDB], [0x1FE0, 0x1FEC], [0x1FF2, 0x1FF4], [0x1FF6, 0x1FFC], [0x203F, 0x2040], [0x207F, 0x207F], [0x2102, 0x2102], [0x2107, 0x2107], [0x210A, 0x2113], [0x2115, 0x2115], [0x2118, 0x211D], [0x2124, 0x2124], [0x2126, 0x2126], [0x2128, 0x2128], [0x212A, 0x2131], [0x2133, 0x2138], [0x2160, 0x2182], [0x3005, 0x3007], [0x3021, 0x3029], [0x3041, 0x3093], [0x309B, 0x309C], [0x30A1, 0x30F6], [0x30FB, 0x30FC], [0x3105, 0x312C], [0x4E00, 0x9FA5], [0xAC00, 0xD7A3] ]; size_t high = ALPHA_TABLE.length - 1; // Shortcut search if c is out of range size_t low = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0; // Binary search while (low <= high) { size_t mid = (low + high) >> 1; if (c < ALPHA_TABLE[mid][0]) high = mid - 1; else if (ALPHA_TABLE[mid][1] < c) low = mid + 1; else { assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]); return true; } } return false; } /** * Returns the code length of c in code units. */ int utf_codeLengthChar(dchar c) { if (c <= 0x7F) return 1; if (c <= 0x7FF) return 2; if (c <= 0xFFFF) return 3; if (c <= 0x10FFFF) return 4; assert(false); } int utf_codeLengthWchar(dchar c) { return c <= 0xFFFF ? 1 : 2; } /** * Returns the code length of c in code units for the encoding. * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32. */ int utf_codeLength(int sz, dchar c) { if (sz == 1) return utf_codeLengthChar(c); if (sz == 2) return utf_codeLengthWchar(c); assert(sz == 4); return 1; } void utf_encodeChar(char* s, dchar c) { assert(s !is null); assert(utf_isValidDchar(c)); if (c <= 0x7F) { s[0] = cast(char)c; } else if (c <= 0x07FF) { s[0] = cast(char)(0xC0 | (c >> 6)); s[1] = cast(char)(0x80 | (c & 0x3F)); } else if (c <= 0xFFFF) { s[0] = cast(char)(0xE0 | (c >> 12)); s[1] = cast(char)(0x80 | ((c >> 6) & 0x3F)); s[2] = cast(char)(0x80 | (c & 0x3F)); } else if (c <= 0x10FFFF) { s[0] = cast(char)(0xF0 | (c >> 18)); s[1] = cast(char)(0x80 | ((c >> 12) & 0x3F)); s[2] = cast(char)(0x80 | ((c >> 6) & 0x3F)); s[3] = cast(char)(0x80 | (c & 0x3F)); } else assert(0); } void utf_encodeWchar(wchar* s, dchar c) { assert(s !is null); assert(utf_isValidDchar(c)); if (c <= 0xFFFF) { s[0] = cast(wchar)c; } else { s[0] = cast(wchar)((((c - 0x010000) >> 10) & 0x03FF) + 0xD800); s[1] = cast(wchar)(((c - 0x010000) & 0x03FF) + 0xDC00); } } void utf_encode(int sz, void* s, dchar c) { if (sz == 1) utf_encodeChar(cast(char*)s, c); else if (sz == 2) utf_encodeWchar(cast(wchar*)s, c); else { assert(sz == 4); *(cast(dchar*)s) = c; } } /******************************************** * Decode a UTF-8 sequence as a single UTF-32 code point. * Params: * s = UTF-8 sequence * len = number of code units in s[] * ridx = starting index in s[], updated to reflect number of code units decoded * rresult = set to character decoded * Returns: * null on success, otherwise error message string */ immutable(char*) utf_decodeChar(const(char)* s, size_t len, ref size_t ridx, out dchar rresult) { // UTF-8 decoding errors static immutable char* UTF8_DECODE_OK = null; // no error static immutable char* UTF8_DECODE_OUTSIDE_CODE_SPACE = "Outside Unicode code space"; static immutable char* UTF8_DECODE_TRUNCATED_SEQUENCE = "Truncated UTF-8 sequence"; static immutable char* UTF8_DECODE_OVERLONG = "Overlong UTF-8 sequence"; static immutable char* UTF8_DECODE_INVALID_TRAILER = "Invalid trailing code unit"; static immutable char* UTF8_DECODE_INVALID_CODE_POINT = "Invalid code point decoded"; /* The following encodings are valid, except for the 5 and 6 byte * combinations: * 0xxxxxxx * 110xxxxx 10xxxxxx * 1110xxxx 10xxxxxx 10xxxxxx * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ static immutable uint[] UTF8_STRIDE = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0xFF, 0xFF ]; assert(s !is null); size_t i = ridx++; assert(i < len); char u = s[i]; // Pre-stage results for ASCII and error cases rresult = u; //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); // Get expected sequence length size_t n = UTF8_STRIDE[u]; switch (n) { case 1: // ASCII return UTF8_DECODE_OK; case 2: case 3: case 4: // multi-byte UTF-8 break; default: // 5- or 6-byte sequence return UTF8_DECODE_OUTSIDE_CODE_SPACE; } if (len < i + n) // source too short return UTF8_DECODE_TRUNCATED_SEQUENCE; // Pick off 7 - n low bits from first code unit dchar c = u & ((1 << (7 - n)) - 1); /* The following combinations are overlong, and illegal: * 1100000x (10xxxxxx) * 11100000 100xxxxx (10xxxxxx) * 11110000 1000xxxx (10xxxxxx 10xxxxxx) * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) */ char u2 = s[++i]; // overlong combination if ((u & 0xFE) == 0xC0 || (u == 0xE0 && (u2 & 0xE0) == 0x80) || (u == 0xF0 && (u2 & 0xF0) == 0x80) || (u == 0xF8 && (u2 & 0xF8) == 0x80) || (u == 0xFC && (u2 & 0xFC) == 0x80)) return UTF8_DECODE_OVERLONG; // Decode remaining bits for (n += i - 1; i != n; ++i) { u = s[i]; if ((u & 0xC0) != 0x80) // trailing bytes are 10xxxxxx return UTF8_DECODE_INVALID_TRAILER; c = (c << 6) | (u & 0x3F); } if (!utf_isValidDchar(c)) return UTF8_DECODE_INVALID_CODE_POINT; ridx = i; rresult = c; return UTF8_DECODE_OK; } /******************************************** * Decode a UTF-16 sequence as a single UTF-32 code point. * Params: * s = UTF-16 sequence * len = number of code units in s[] * ridx = starting index in s[], updated to reflect number of code units decoded * rresult = set to character decoded * Returns: * null on success, otherwise error message string */ immutable(char*) utf_decodeWchar(const(wchar)* s, size_t len, ref size_t ridx, out dchar rresult) { // UTF-16 decoding errors static immutable char* UTF16_DECODE_OK = null; // no error static immutable char* UTF16_DECODE_TRUNCATED_SEQUENCE = "Truncated UTF-16 sequence"; static immutable char* UTF16_DECODE_INVALID_SURROGATE = "Invalid low surrogate"; static immutable char* UTF16_DECODE_UNPAIRED_SURROGATE = "Unpaired surrogate"; static immutable char* UTF16_DECODE_INVALID_CODE_POINT = "Invalid code point decoded"; assert(s !is null); size_t i = ridx++; assert(i < len); // Pre-stage results for ASCII and error cases dchar u = rresult = s[i]; if (u < 0x80) // ASCII return UTF16_DECODE_OK; if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair { if (len <= i + 1) return UTF16_DECODE_TRUNCATED_SEQUENCE; wchar u2 = s[i + 1]; if (u2 < 0xDC00 || 0xDFFF < u) return UTF16_DECODE_INVALID_SURROGATE; u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); ++ridx; } else if (0xDC00 <= u && u <= 0xDFFF) return UTF16_DECODE_UNPAIRED_SURROGATE; if (!utf_isValidDchar(u)) return UTF16_DECODE_INVALID_CODE_POINT; rresult = u; return UTF16_DECODE_OK; } ================================================ FILE: gcc/d/dmd/utils.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * Utility functions for DMD. * * This modules defines some utility functions for DMD. * * Copyright: Copyright (C) 1999-2018 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/utils.d, _utils.d) * Documentation: https://dlang.org/phobos/dmd_utils.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utils.d */ module dmd.utils; import core.stdc.string; import dmd.errors; import dmd.globals; import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; /** * Normalize path by turning forward slashes into backslashes * * Params: * src = Source path, using unix-style ('/') path separators * * Returns: * A newly-allocated string with '/' turned into backslashes */ const(char)* toWinPath(const(char)* src) { if (src is null) return null; char* result = strdup(src); char* p = result; while (*p != '\0') { if (*p == '/') *p = '\\'; p++; } return result; } /** * Reads a file, terminate the program on error * * Params: * loc = The line number information from where the call originates * f = a `dmd.root.file.File` handle to read */ extern (C++) void readFile(Loc loc, File* f) { if (f.read()) { error(loc, "Error reading file '%s'", f.name.toChars()); fatal(); } } /** * Writes a file, terminate the program on error * * Params: * loc = The line number information from where the call originates * f = a `dmd.root.file.File` handle to write */ extern (C++) void writeFile(Loc loc, File* f) { if (f.write()) { error(loc, "Error writing file '%s'", f.name.toChars()); fatal(); } } /** * Ensure the root path (the path minus the name) of the provided path * exists, and terminate the process if it doesn't. * * Params: * loc = The line number information from where the call originates * name = a path to check (the name is stripped) */ extern (C++) void ensurePathToNameExists(Loc loc, const(char)* name) { const(char)* pt = FileName.path(name); if (*pt) { if (!FileName.ensurePathExists(pt)) { error(loc, "cannot create directory %s", pt); fatal(); } } FileName.free(pt); } /** * Takes a path, and escapes '(', ')' and backslashes * * Params: * buf = Buffer to write the escaped path to * fname = Path to escape */ extern (C++) void escapePath(OutBuffer* buf, const(char)* fname) { while (1) { switch (*fname) { case 0: return; case '(': case ')': case '\\': buf.writeByte('\\'); goto default; default: buf.writeByte(*fname); break; } fname++; } } /// Slices a `\0`-terminated C-string, excluding the terminator inout(char)[] toDString (inout(char)* s) pure nothrow @nogc { return s ? s[0 .. strlen(s)] : null; } /** Compare two slices for equality, in a case-insensitive way Comparison is based on `char` and does not do decoding. As a result, it's only really accurate for plain ASCII strings. Params: s1 = string to compare s2 = string to compare Returns: `true` if `s1 == s2` regardless of case */ extern(D) static bool iequals(const(char)[] s1, const(char)[] s2) { import core.stdc.ctype : toupper; if (s1.length != s2.length) return false; int result = 0; foreach (idx, c1; s1) { // Since we did a length check, it is safe to bypass bounds checking const c2 = s2.ptr[idx]; if (c1 != c2) if (toupper(c1) != toupper(c2)) return false; } return true; } /** Copy the content of `src` into a C-string ('\0' terminated) then call `dg` The intent of this function is to provide an allocation-less way to call a C function using a D slice. The function internally allocates a buffer if needed, but frees it on exit. Note: The argument to `dg` is `scope`. To keep the data around after `dg` exits, one has to copy it. Params: src = Slice to use to call the C function dg = Delegate to call afterwards Returns: The return value of `T` */ auto toCStringThen(alias dg)(const(char)[] src) nothrow { const len = src.length + 1; char[512] small = void; scope ptr = (src.length < (small.length - 1)) ? small[0 .. len] : (cast(char*)mem.xmalloc(len))[0 .. len]; scope (exit) { if (&ptr[0] != &small[0]) mem.xfree(&ptr[0]); } ptr[0 .. src.length] = src[]; ptr[src.length] = '\0'; return dg(ptr); } unittest { assert("Hello world".toCStringThen!((v) => v == "Hello world\0")); assert("Hello world\0".toCStringThen!((v) => v == "Hello world\0\0")); assert(null.toCStringThen!((v) => v == "\0")); } ================================================ FILE: gcc/d/dmd/visitor.d ================================================ /** * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * * Copyright: Copyright (C) 1999-2018 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/visitor.d, _visitor.d) * Documentation: https://dlang.org/phobos/dmd_visitor.html * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/visitor.d */ module dmd.visitor; import dmd.astcodegen; import dmd.parsetimevisitor; import dmd.tokens; import dmd.transitivevisitor; import dmd.expression; import dmd.root.rootobject; /** * Classic Visitor class which implements visit methods for all the AST * nodes present in the compiler. The visit methods for AST nodes * created at parse time are inherited while the visiting methods * for AST nodes created at semantic time are implemented. */ extern (C++) class Visitor : ParseTimeVisitor!ASTCodegen { alias visit = ParseTimeVisitor!ASTCodegen.visit; public: void visit(ASTCodegen.ErrorStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.PeelStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.UnrolledLoopStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.SwitchErrorStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.DebugStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.DtorExpStatement s) { visit(cast(ASTCodegen.ExpStatement)s); } void visit(ASTCodegen.ForwardingStatement s) { visit(cast(ASTCodegen.Statement)s); } void visit(ASTCodegen.OverloadSet s) { visit(cast(ASTCodegen.Dsymbol)s); } void visit(ASTCodegen.LabelDsymbol s) { visit(cast(ASTCodegen.Dsymbol)s); } void visit(ASTCodegen.WithScopeSymbol s) { visit(cast(ASTCodegen.ScopeDsymbol)s); } void visit(ASTCodegen.ArrayScopeSymbol s) { visit(cast(ASTCodegen.ScopeDsymbol)s); } void visit(ASTCodegen.OverDeclaration s) { visit(cast(ASTCodegen.Declaration)s); } void visit(ASTCodegen.SymbolDeclaration s) { visit(cast(ASTCodegen.Declaration)s); } void visit(ASTCodegen.ThisDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); } void visit(ASTCodegen.TypeInfoDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); } void visit(ASTCodegen.TypeInfoStructDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoClassDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoInterfaceDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoPointerDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoStaticArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoAssociativeArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoEnumDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoFunctionDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoDelegateDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoTupleDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoConstDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoInvariantDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoSharedDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoWildDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.TypeInfoVectorDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } void visit(ASTCodegen.FuncAliasDeclaration s) { visit(cast(ASTCodegen.FuncDeclaration)s); } void visit(ASTCodegen.ErrorInitializer i) { visit(cast(ASTCodegen.Initializer)i); } void visit(ASTCodegen.ErrorExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.ComplexExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.StructLiteralExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.ObjcClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.SymOffExp e) { visit(cast(ASTCodegen.SymbolExp)e); } void visit(ASTCodegen.OverExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.HaltExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.DotTemplateExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DotVarExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DelegateExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DotTypeExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.VectorExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.SliceExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.ArrayLengthExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DelegatePtrExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DelegateFuncptrExp e) { visit(cast(ASTCodegen.UnaExp)e); } void visit(ASTCodegen.DotExp e) { visit(cast(ASTCodegen.BinExp)e); } void visit(ASTCodegen.IndexExp e) { visit(cast(ASTCodegen.BinExp)e); } void visit(ASTCodegen.ConstructExp e) { visit(cast(ASTCodegen.AssignExp)e); } void visit(ASTCodegen.BlitExp e) { visit(cast(ASTCodegen.AssignExp)e); } void visit(ASTCodegen.RemoveExp e) { visit(cast(ASTCodegen.BinExp)e); } void visit(ASTCodegen.ClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.VoidInitExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.ThrownExceptionExp e) { visit(cast(ASTCodegen.Expression)e); } } /** * The PermissiveVisitor overrides the root AST nodes with * empty visiting methods. */ extern (C++) class SemanticTimePermissiveVisitor : Visitor { alias visit = Visitor.visit; override void visit(ASTCodegen.Dsymbol){} override void visit(ASTCodegen.Parameter){} override void visit(ASTCodegen.Statement){} override void visit(ASTCodegen.Type){} override void visit(ASTCodegen.Expression){} override void visit(ASTCodegen.TemplateParameter){} override void visit(ASTCodegen.Condition){} override void visit(ASTCodegen.Initializer){} } /** * The TransitiveVisitor implements the AST traversal logic for all AST nodes. */ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor { alias visit = SemanticTimePermissiveVisitor.visit; mixin ParseVisitMethods!ASTCodegen __methods; alias visit = __methods.visit; override void visit(ASTCodegen.PeelStatement s) { if (s.s) s.s.accept(this); } override void visit(ASTCodegen.UnrolledLoopStatement s) { foreach(sx; *s.statements) { if (sx) sx.accept(this); } } override void visit(ASTCodegen.DebugStatement s) { if (s.statement) s.statement.accept(this); } override void visit(ASTCodegen.ForwardingStatement s) { if (s.statement) s.statement.accept(this); } override void visit(ASTCodegen.StructLiteralExp e) { // CTFE can generate struct literals that contain an AddrExp pointing to themselves, // need to avoid infinite recursion. if (!(e.stageflags & stageToCBuffer)) { int old = e.stageflags; e.stageflags |= stageToCBuffer; foreach (el; *e.elements) if (el) el.accept(this); e.stageflags = old; } } override void visit(ASTCodegen.DotTemplateExp e) { e.e1.accept(this); } override void visit(ASTCodegen.DotVarExp e) { e.e1.accept(this); } override void visit(ASTCodegen.DelegateExp e) { if (!e.func.isNested()) e.e1.accept(this); } override void visit(ASTCodegen.DotTypeExp e) { e.e1.accept(this); } override void visit(ASTCodegen.VectorExp e) { visitType(e.to); e.e1.accept(this); } override void visit(ASTCodegen.SliceExp e) { e.e1.accept(this); if (e.upr) e.upr.accept(this); if (e.lwr) e.lwr.accept(this); } override void visit(ASTCodegen.ArrayLengthExp e) { e.e1.accept(this); } override void visit(ASTCodegen.DelegatePtrExp e) { e.e1.accept(this); } override void visit(ASTCodegen.DelegateFuncptrExp e) { e.e1.accept(this); } override void visit(ASTCodegen.DotExp e) { e.e1.accept(this); e.e2.accept(this); } override void visit(ASTCodegen.IndexExp e) { e.e1.accept(this); e.e2.accept(this); } override void visit(ASTCodegen.RemoveExp e) { e.e1.accept(this); e.e2.accept(this); } } extern (C++) class StoppableVisitor : Visitor { alias visit = Visitor.visit; public: bool stop; final extern (D) this() { } } ================================================ FILE: gcc/d/dmd/visitor.h ================================================ /* Compiler implementation of the D programming language * Copyright (C) 2013-2018 by The D Language Foundation, All Rights Reserved * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/dlang/dmd/blob/master/src/dmd/visitor.h */ #pragma once #include class Statement; class ErrorStatement; class PeelStatement; class ExpStatement; class DtorExpStatement; class CompileStatement; class CompoundStatement; class CompoundDeclarationStatement; class UnrolledLoopStatement; class ScopeStatement; class ForwardingStatement; class WhileStatement; class DoStatement; class ForStatement; class ForeachStatement; class ForeachRangeStatement; class StaticForeachStatement; class IfStatement; class ConditionalStatement; class PragmaStatement; class StaticAssertStatement; class SwitchStatement; class CaseStatement; class CaseRangeStatement; class DefaultStatement; class GotoDefaultStatement; class GotoCaseStatement; class SwitchErrorStatement; class ReturnStatement; class BreakStatement; class ContinueStatement; class SynchronizedStatement; class WithStatement; class TryCatchStatement; class TryFinallyStatement; class OnScopeStatement; class ThrowStatement; class DebugStatement; class GotoStatement; class LabelStatement; class AsmStatement; class InlineAsmStatement; class GccAsmStatement; class CompoundAsmStatement; class ImportStatement; class Type; class TypeError; class TypeNext; class TypeBasic; class TypeVector; class TypeArray; class TypeSArray; class TypeDArray; class TypeAArray; class TypePointer; class TypeReference; class TypeFunction; class TypeDelegate; class TypeQualified; class TypeIdentifier; class TypeInstance; class TypeTypeof; class TypeReturn; class TypeStruct; class TypeEnum; class TypeClass; class TypeTuple; class TypeSlice; class TypeNull; class Dsymbol; class StaticAssert; class DebugSymbol; class VersionSymbol; class EnumMember; class Import; class OverloadSet; class LabelDsymbol; class AliasThis; class AttribDeclaration; class StorageClassDeclaration; class DeprecatedDeclaration; class LinkDeclaration; class CPPMangleDeclaration; class ProtDeclaration; class AlignDeclaration; class AnonDeclaration; class PragmaDeclaration; class ConditionalDeclaration; class StaticIfDeclaration; class CompileDeclaration; class StaticForeachDeclaration; class UserAttributeDeclaration; class ScopeDsymbol; class TemplateDeclaration; class TemplateInstance; class TemplateMixin; class EnumDeclaration; class Package; class Module; class WithScopeSymbol; class ArrayScopeSymbol; class Nspace; class AggregateDeclaration; class StructDeclaration; class UnionDeclaration; class ClassDeclaration; class InterfaceDeclaration; class Declaration; class TupleDeclaration; class AliasDeclaration; class OverDeclaration; class VarDeclaration; class SymbolDeclaration; class ThisDeclaration; class TypeInfoDeclaration; class TypeInfoStructDeclaration; class TypeInfoClassDeclaration; class TypeInfoInterfaceDeclaration; class TypeInfoPointerDeclaration; class TypeInfoArrayDeclaration; class TypeInfoStaticArrayDeclaration; class TypeInfoAssociativeArrayDeclaration; class TypeInfoEnumDeclaration; class TypeInfoFunctionDeclaration; class TypeInfoDelegateDeclaration; class TypeInfoTupleDeclaration; class TypeInfoConstDeclaration; class TypeInfoInvariantDeclaration; class TypeInfoSharedDeclaration; class TypeInfoWildDeclaration; class TypeInfoVectorDeclaration; class FuncDeclaration; class FuncAliasDeclaration; class FuncLiteralDeclaration; class CtorDeclaration; class PostBlitDeclaration; class DtorDeclaration; class StaticCtorDeclaration; class SharedStaticCtorDeclaration; class StaticDtorDeclaration; class SharedStaticDtorDeclaration; class InvariantDeclaration; class UnitTestDeclaration; class NewDeclaration; class DeleteDeclaration; class Initializer; class VoidInitializer; class ErrorInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; class Expression; class IntegerExp; class ErrorExp; class RealExp; class ComplexExp; class IdentifierExp; class DollarExp; class DsymbolExp; class ThisExp; class SuperExp; class NullExp; class StringExp; class TupleExp; class ArrayLiteralExp; class AssocArrayLiteralExp; class StructLiteralExp; class ObjcClassReferenceExp; class TypeExp; class ScopeExp; class TemplateExp; class NewExp; class NewAnonClassExp; class SymbolExp; class SymOffExp; class VarExp; class OverExp; class FuncExp; class DeclarationExp; class TypeidExp; class TraitsExp; class HaltExp; class IsExp; class UnaExp; class BinExp; class BinAssignExp; class CompileExp; class ImportExp; class AssertExp; class DotIdExp; class DotTemplateExp; class DotVarExp; class DotTemplateInstanceExp; class DelegateExp; class DotTypeExp; class CallExp; class AddrExp; class PtrExp; class NegExp; class UAddExp; class ComExp; class NotExp; class DeleteExp; class CastExp; class VectorExp; class SliceExp; class ArrayLengthExp; class IntervalExp; class DelegatePtrExp; class DelegateFuncptrExp; class ArrayExp; class DotExp; class CommaExp; class IndexExp; class PostExp; class PreExp; class AssignExp; class ConstructExp; class BlitExp; class AddAssignExp; class MinAssignExp; class MulAssignExp; class DivAssignExp; class ModAssignExp; class AndAssignExp; class OrAssignExp; class XorAssignExp; class PowAssignExp; class ShlAssignExp; class ShrAssignExp; class UshrAssignExp; class CatAssignExp; class AddExp; class MinExp; class CatExp; class MulExp; class DivExp; class ModExp; class PowExp; class ShlExp; class ShrExp; class UshrExp; class AndExp; class OrExp; class XorExp; class LogicalExp; class CmpExp; class InExp; class RemoveExp; class EqualExp; class IdentityExp; class CondExp; class DefaultInitExp; class FileInitExp; class LineInitExp; class ModuleInitExp; class FuncInitExp; class PrettyFuncInitExp; class ClassReferenceExp; class VoidInitExp; class ThrownExceptionExp; class TemplateParameter; class TemplateTypeParameter; class TemplateThisParameter; class TemplateValueParameter; class TemplateAliasParameter; class TemplateTupleParameter; class Condition; class DVCondition; class DebugCondition; class VersionCondition; class StaticIfCondition; class Parameter; class ParseTimeVisitor { public: virtual void visit(Dsymbol *) { assert(0); } virtual void visit(Parameter *) { assert(0); } virtual void visit(Statement *) { assert(0); } virtual void visit(Type *) { assert(0); } virtual void visit(Expression *) { assert(0); } virtual void visit(TemplateParameter *) { assert(0); } virtual void visit(Condition *) { assert(0); } virtual void visit(Initializer *) { assert(0); } // Dsymbols virtual void visit(AliasThis *s) { visit((Dsymbol *)s); } virtual void visit(Declaration *s) { visit((Dsymbol *)s); } virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); } virtual void visit(Import *s) { visit((Dsymbol *)s); } virtual void visit(AttribDeclaration *s) { visit((Dsymbol *)s); } virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); } virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); } virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); } // ScopeDsymbols virtual void visit(Package *s) { visit((ScopeDsymbol *)s); } virtual void visit(EnumDeclaration *s) { visit((ScopeDsymbol *)s); } virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); } virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); } virtual void visit(TemplateInstance *s) { visit((ScopeDsymbol *)s); } virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); } // Declarations virtual void visit(VarDeclaration *s) { visit((Declaration *)s); } virtual void visit(FuncDeclaration *s) { visit((Declaration *)s); } virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); } virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); } // FuncDeclarations virtual void visit(FuncLiteralDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(PostBlitDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(CtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(DtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(DeleteDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); } virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); } // AttribDeclarations virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(AlignDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(CPPMangleDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(ProtDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(PragmaDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(StorageClassDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(ConditionalDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); } // Miscellaneous virtual void visit(DeprecatedDeclaration *s) { visit((StorageClassDeclaration *)s); } virtual void visit(StaticIfDeclaration *s) { visit((ConditionalDeclaration *)s); } virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); } virtual void visit(Module *s) { visit((Package *)s); } virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); } virtual void visit(UnionDeclaration *s) { visit((StructDeclaration *)s); } virtual void visit(ClassDeclaration *s) { visit((AggregateDeclaration *)s); } virtual void visit(InterfaceDeclaration *s) { visit((ClassDeclaration *)s); } virtual void visit(TemplateMixin *s) { visit((TemplateInstance *)s); } // Statements virtual void visit(ImportStatement *s) { visit((Statement *)s); } virtual void visit(ScopeStatement *s) { visit((Statement *)s); } virtual void visit(ReturnStatement *s) { visit((Statement *)s); } virtual void visit(LabelStatement *s) { visit((Statement *)s); } virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); } virtual void visit(CompileStatement *s) { visit((Statement *)s); } virtual void visit(WhileStatement *s) { visit((Statement *)s); } virtual void visit(ForStatement *s) { visit((Statement *)s); } virtual void visit(DoStatement *s) { visit((Statement *)s); } virtual void visit(ForeachRangeStatement *s) { visit((Statement *)s); } virtual void visit(ForeachStatement *s) { visit((Statement *)s); } virtual void visit(IfStatement *s) { visit((Statement *)s); } virtual void visit(OnScopeStatement *s) { visit((Statement *)s); } virtual void visit(ConditionalStatement *s) { visit((Statement *)s); } virtual void visit(StaticForeachStatement *s) { visit((Statement *)s); } virtual void visit(PragmaStatement *s) { visit((Statement *)s); } virtual void visit(SwitchStatement *s) { visit((Statement *)s); } virtual void visit(CaseRangeStatement *s) { visit((Statement *)s); } virtual void visit(CaseStatement *s) { visit((Statement *)s); } virtual void visit(DefaultStatement *s) { visit((Statement *)s); } virtual void visit(BreakStatement *s) { visit((Statement *)s); } virtual void visit(ContinueStatement *s) { visit((Statement *)s); } virtual void visit(GotoDefaultStatement *s) { visit((Statement *)s); } virtual void visit(GotoCaseStatement *s) { visit((Statement *)s); } virtual void visit(GotoStatement *s) { visit((Statement *)s); } virtual void visit(SynchronizedStatement *s) { visit((Statement *)s); } virtual void visit(WithStatement *s) { visit((Statement *)s); } virtual void visit(TryCatchStatement *s) { visit((Statement *)s); } virtual void visit(TryFinallyStatement *s) { visit((Statement *)s); } virtual void visit(ThrowStatement *s) { visit((Statement *)s); } virtual void visit(AsmStatement *s) { visit((Statement *)s); } virtual void visit(ExpStatement *s) { visit((Statement *)s); } virtual void visit(CompoundStatement *s) { visit((Statement *)s); } // CompoundStatements virtual void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); } virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); } // AsmStatements virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); } virtual void visit(GccAsmStatement *s) { visit((AsmStatement *)s); } // Types virtual void visit(TypeBasic *t) { visit((Type *)t); } virtual void visit(TypeError *t) { visit((Type *)t); } virtual void visit(TypeNull *t) { visit((Type *)t); } virtual void visit(TypeVector *t) { visit((Type *)t); } virtual void visit(TypeEnum *t) { visit((Type *)t); } virtual void visit(TypeTuple *t) { visit((Type *)t); } virtual void visit(TypeClass *t) { visit((Type *)t); } virtual void visit(TypeStruct *t) { visit((Type *)t); } virtual void visit(TypeNext *t) { visit((Type *)t); } virtual void visit(TypeQualified *t) { visit((Type *)t); } // TypeNext virtual void visit(TypeReference *t) { visit((TypeNext *)t); } virtual void visit(TypeSlice *t) { visit((TypeNext *)t); } virtual void visit(TypeDelegate *t) { visit((TypeNext *)t); } virtual void visit(TypePointer *t) { visit((TypeNext *)t); } virtual void visit(TypeFunction *t) { visit((TypeNext *)t); } virtual void visit(TypeArray *t) { visit((TypeNext *)t); } // TypeArray virtual void visit(TypeDArray *t) { visit((TypeArray *)t); } virtual void visit(TypeAArray *t) { visit((TypeArray *)t); } virtual void visit(TypeSArray *t) { visit((TypeArray *)t); } // TypeQualified virtual void visit(TypeIdentifier *t) { visit((TypeQualified *)t); } virtual void visit(TypeReturn *t) { visit((TypeQualified *)t); } virtual void visit(TypeTypeof *t) { visit((TypeQualified *)t); } virtual void visit(TypeInstance *t) { visit((TypeQualified *)t); } // Expressions virtual void visit(DeclarationExp *e) { visit((Expression *)e); } virtual void visit(IntegerExp *e) { visit((Expression *)e); } virtual void visit(NewAnonClassExp *e) { visit((Expression *)e); } virtual void visit(IsExp *e) { visit((Expression *)e); } virtual void visit(RealExp *e) { visit((Expression *)e); } virtual void visit(NullExp *e) { visit((Expression *)e); } virtual void visit(TypeidExp *e) { visit((Expression *)e); } virtual void visit(TraitsExp *e) { visit((Expression *)e); } virtual void visit(StringExp *e) { visit((Expression *)e); } virtual void visit(NewExp *e) { visit((Expression *)e); } virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); } virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); } virtual void visit(CompileExp *e) { visit((Expression *)e); } virtual void visit(FuncExp *e) { visit((Expression *)e); } virtual void visit(IntervalExp *e) { visit((Expression *)e); } virtual void visit(TypeExp *e) { visit((Expression *)e); } virtual void visit(ScopeExp *e) { visit((Expression *)e); } virtual void visit(IdentifierExp *e) { visit((Expression *)e); } virtual void visit(UnaExp *e) { visit((Expression *)e); } virtual void visit(DefaultInitExp *e) { visit((Expression *)e); } virtual void visit(BinExp *e) { visit((Expression *)e); } virtual void visit(DsymbolExp *e) { visit((Expression *)e); } virtual void visit(TemplateExp *e) { visit((Expression *)e); } virtual void visit(SymbolExp *e) { visit((Expression *)e); } virtual void visit(TupleExp *e) { visit((Expression *)e); } virtual void visit(ThisExp *e) { visit((Expression *)e); } // Miscellaneous virtual void visit(VarExp *e) { visit((SymbolExp *)e); } virtual void visit(DollarExp *e) { visit((IdentifierExp *)e); } virtual void visit(SuperExp *e) { visit((ThisExp *)e); } // UnaExp virtual void visit(AddrExp *e) { visit((UnaExp *)e); } virtual void visit(PreExp *e) { visit((UnaExp *)e); } virtual void visit(PtrExp *e) { visit((UnaExp *)e); } virtual void visit(NegExp *e) { visit((UnaExp *)e); } virtual void visit(UAddExp *e) { visit((UnaExp *)e); } virtual void visit(NotExp *e) { visit((UnaExp *)e); } virtual void visit(ComExp *e) { visit((UnaExp *)e); } virtual void visit(DeleteExp *e) { visit((UnaExp *)e); } virtual void visit(CastExp *e) { visit((UnaExp *)e); } virtual void visit(CallExp *e) { visit((UnaExp *)e); } virtual void visit(DotIdExp *e) { visit((UnaExp *)e); } virtual void visit(AssertExp *e) { visit((UnaExp *)e); } virtual void visit(ImportExp *e) { visit((UnaExp *)e); } virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); } virtual void visit(ArrayExp *e) { visit((UnaExp *)e); } // DefaultInitExp virtual void visit(FuncInitExp *e) { visit((DefaultInitExp *)e); } virtual void visit(PrettyFuncInitExp *e) { visit((DefaultInitExp *)e); } virtual void visit(FileInitExp *e) { visit((DefaultInitExp *)e); } virtual void visit(LineInitExp *e) { visit((DefaultInitExp *)e); } virtual void visit(ModuleInitExp *e) { visit((DefaultInitExp *)e); } // BinExp virtual void visit(CommaExp *e) { visit((BinExp *)e); } virtual void visit(PostExp *e) { visit((BinExp *)e); } virtual void visit(PowExp *e) { visit((BinExp *)e); } virtual void visit(MulExp *e) { visit((BinExp *)e); } virtual void visit(DivExp *e) { visit((BinExp *)e); } virtual void visit(ModExp *e) { visit((BinExp *)e); } virtual void visit(AddExp *e) { visit((BinExp *)e); } virtual void visit(MinExp *e) { visit((BinExp *)e); } virtual void visit(CatExp *e) { visit((BinExp *)e); } virtual void visit(ShlExp *e) { visit((BinExp *)e); } virtual void visit(ShrExp *e) { visit((BinExp *)e); } virtual void visit(UshrExp *e) { visit((BinExp *)e); } virtual void visit(EqualExp *e) { visit((BinExp *)e); } virtual void visit(InExp *e) { visit((BinExp *)e); } virtual void visit(IdentityExp *e) { visit((BinExp *)e); } virtual void visit(CmpExp *e) { visit((BinExp *)e); } virtual void visit(AndExp *e) { visit((BinExp *)e); } virtual void visit(XorExp *e) { visit((BinExp *)e); } virtual void visit(OrExp *e) { visit((BinExp *)e); } virtual void visit(LogicalExp *e) { visit((BinExp *)e); } virtual void visit(CondExp *e) { visit((BinExp *)e); } virtual void visit(AssignExp *e) { visit((BinExp *)e); } virtual void visit(BinAssignExp *e) { visit((BinExp *)e); } // BinAssignExp virtual void visit(AddAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(MinAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(MulAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(DivAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(ModAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(PowAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(AndAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(OrAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(XorAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(ShlAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(ShrAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); } // TemplateParameter virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); } virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); } virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); } virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); } virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); } // Condition virtual void visit(StaticIfCondition *c) { visit((Condition *)c); } virtual void visit(DVCondition *c) { visit((Condition *)c); } virtual void visit(DebugCondition *c) { visit((DVCondition *)c); } virtual void visit(VersionCondition *c) { visit((DVCondition *)c); } // Initializer virtual void visit(ExpInitializer *i) { visit((Initializer *)i); } virtual void visit(StructInitializer *i) { visit((Initializer *)i); } virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); } virtual void visit(VoidInitializer *i) { visit((Initializer *)i); } }; class Visitor : public ParseTimeVisitor { public: using ParseTimeVisitor::visit; // Miscellaneous virtual void visit(ErrorStatement *s) { visit((Statement *)s); } virtual void visit(PeelStatement *s) { visit((Statement *)s); } virtual void visit(UnrolledLoopStatement *s) { visit((Statement *)s); } virtual void visit(SwitchErrorStatement *s) { visit((Statement *)s); } virtual void visit(DebugStatement *s) { visit((Statement *)s); } virtual void visit(DtorExpStatement *s) { visit((ExpStatement *)s); } virtual void visit(ForwardingStatement *s) { visit((Statement *)s); } virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); } virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); } virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); } virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); } virtual void visit(OverDeclaration *s) { visit((Declaration *)s); } virtual void visit(SymbolDeclaration *s) { visit((Declaration *)s); } virtual void visit(ThisDeclaration *s) { visit((VarDeclaration *)s); } virtual void visit(TypeInfoDeclaration *s) { visit((VarDeclaration *)s); } virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoClassDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoInterfaceDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoPointerDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoStaticArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoAssociativeArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoEnumDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoFunctionDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoDelegateDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoTupleDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoConstDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoInvariantDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoSharedDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoWildDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoVectorDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(FuncAliasDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(ErrorInitializer *i) { visit((Initializer *)i); } virtual void visit(ErrorExp *e) { visit((Expression *)e); } virtual void visit(ComplexExp *e) { visit((Expression *)e); } virtual void visit(StructLiteralExp *e) { visit((Expression *)e); } virtual void visit(ObjcClassReferenceExp *e) { visit((Expression *)e); } virtual void visit(SymOffExp *e) { visit((SymbolExp *)e); } virtual void visit(OverExp *e) { visit((Expression *)e); } virtual void visit(HaltExp *e) { visit((Expression *)e); } virtual void visit(DotTemplateExp *e) { visit((UnaExp *)e); } virtual void visit(DotVarExp *e) { visit((UnaExp *)e); } virtual void visit(DelegateExp *e) { visit((UnaExp *)e); } virtual void visit(DotTypeExp *e) { visit((UnaExp *)e); } virtual void visit(VectorExp *e) { visit((UnaExp *)e); } virtual void visit(SliceExp *e) { visit((UnaExp *)e); } virtual void visit(ArrayLengthExp *e) { visit((UnaExp *)e); } virtual void visit(DelegatePtrExp *e) { visit((UnaExp *)e); } virtual void visit(DelegateFuncptrExp *e) { visit((UnaExp *)e); } virtual void visit(DotExp *e) { visit((BinExp *)e); } virtual void visit(IndexExp *e) { visit((BinExp *)e); } virtual void visit(ConstructExp *e) { visit((AssignExp *)e); } virtual void visit(BlitExp *e) { visit((AssignExp *)e); } virtual void visit(RemoveExp *e) { visit((BinExp *)e); } virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); } virtual void visit(VoidInitExp *e) { visit((Expression *)e); } virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); } }; class StoppableVisitor : public Visitor { public: bool stop; StoppableVisitor() : stop(false) {} }; ================================================ FILE: gcc/d/expr.cc ================================================ /* expr.cc -- Lower D frontend expressions to GCC trees. Copyright (C) 2015-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/ctfe.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/init.h" #include "dmd/module.h" #include "dmd/mtype.h" #include "dmd/template.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "tm.h" #include "function.h" #include "toplev.h" #include "varasm.h" #include "predict.h" #include "stor-layout.h" #include "d-tree.h" /* Implements the visitor interface to build the GCC trees of all Expression AST classes emitted from the D Front-end. All visit methods accept one parameter E, which holds the frontend AST of the expression to compile. They also don't return any value, instead generated code is cached in RESULT_ and returned from the caller. */ class ExprVisitor : public Visitor { using Visitor::visit; tree result_; bool constp_; /* Determine if type is a struct that has a postblit. */ bool needs_postblit (Type *t) { t = t->baseElemOf (); if (t->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *) t)->sym; if (sd->postblit) return true; } return false; } /* Determine if type is a struct that has a destructor. */ bool needs_dtor (Type *t) { t = t->baseElemOf (); if (t->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *) t)->sym; if (sd->dtor) return true; } return false; } /* Determine if expression is suitable lvalue. */ bool lvalue_p (Expression *e) { return ((e->op != TOKslice && e->isLvalue ()) || (e->op == TOKslice && ((UnaExp *) e)->e1->isLvalue ()) || (e->op == TOKcast && ((UnaExp *) e)->e1->isLvalue ())); } /* Build an expression of code CODE, data type TYPE, and operands ARG0 and ARG1. Perform relevant conversions needed for correct code operations. */ tree binary_op (tree_code code, tree type, tree arg0, tree arg1) { tree t0 = TREE_TYPE (arg0); tree t1 = TREE_TYPE (arg1); tree ret = NULL_TREE; bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1); /* Deal with float mod expressions immediately. */ if (code == FLOAT_MOD_EXPR) return build_float_modulus (type, arg0, arg1); if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1)) return build_nop (type, build_offset_op (code, arg0, arg1)); if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1)) return build_nop (type, build_offset_op (code, arg1, arg0)); if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1)) { gcc_assert (code == MINUS_EXPR); tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode, 0); /* POINTER_DIFF_EXPR requires a signed integer type of the same size as pointers. If some platform cannot provide that, or has a larger ptrdiff_type to support differences larger than half the address space, cast the pointers to some larger integer type and do the computations in that type. */ if (TYPE_PRECISION (ptrtype) > TYPE_PRECISION (t0)) ret = fold_build2 (MINUS_EXPR, ptrtype, d_convert (ptrtype, arg0), d_convert (ptrtype, arg1)); else ret = fold_build2 (POINTER_DIFF_EXPR, ptrtype, arg0, arg1); } else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp)) { tree inttype = (unsignedp) ? d_unsigned_type (type) : d_signed_type (type); ret = fold_build2 (code, inttype, arg0, arg1); } else { /* If the operation needs excess precision. */ tree eptype = excess_precision_type (type); if (eptype != NULL_TREE) { arg0 = d_convert (eptype, arg0); arg1 = d_convert (eptype, arg1); } else { /* Front-end does not do this conversion and GCC does not always do it right. */ if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1)) arg1 = d_convert (t0, arg1); else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0)) arg0 = d_convert (t1, arg0); eptype = type; } ret = fold_build2 (code, eptype, arg0, arg1); } return d_convert (type, ret); } /* Build a binary expression of code CODE, assigning the result into E1. */ tree binop_assignment (tree_code code, Expression *e1, Expression *e2) { /* Skip casts for lhs assignment. */ Expression *e1b = e1; while (e1b->op == TOKcast) { CastExp *ce = (CastExp *) e1b; gcc_assert (same_type_p (ce->type, ce->to)); e1b = ce->e1; } /* Stabilize LHS for assignment. */ tree lhs = build_expr (e1b); tree lexpr = stabilize_expr (&lhs); /* The LHS expression could be an assignment, to which its operation gets lost during gimplification. */ if (TREE_CODE (lhs) == MODIFY_EXPR) { /* If LHS has side effects, call stabilize_reference on it, so it can be evaluated multiple times. */ if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))) lhs = build_assign (MODIFY_EXPR, stabilize_reference (TREE_OPERAND (lhs, 0)), TREE_OPERAND (lhs, 1)); lexpr = compound_expr (lexpr, lhs); lhs = TREE_OPERAND (lhs, 0); } lhs = stabilize_reference (lhs); /* Save RHS, to ensure that the expression is evaluated before LHS. */ tree rhs = build_expr (e2); tree rexpr = d_save_expr (rhs); rhs = this->binary_op (code, build_ctype (e1->type), convert_expr (lhs, e1b->type, e1->type), rexpr); if (TREE_SIDE_EFFECTS (rhs)) rhs = compound_expr (rexpr, rhs); tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type)); return compound_expr (lexpr, expr); } public: ExprVisitor (bool constp) { this->result_ = NULL_TREE; this->constp_ = constp; } tree result (void) { return this->result_; } /* Visitor interfaces, each Expression class should have overridden the default. */ void visit (Expression *) { gcc_unreachable (); } /* Build a conditional expression. If either the second or third expression is void, then the resulting type is void. Otherwise they are implicitly converted to a common type. */ void visit (CondExp *e) { tree cond = convert_for_condition (build_expr (e->econd), e->econd->type); tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); if (e->type->ty != Tvoid) { t1 = convert_expr (t1, e->e1->type, e->type); t2 = convert_expr (t2, e->e2->type, e->type); } this->result_ = build_condition (build_ctype (e->type), cond, t1, t2); } /* Build an identity comparison expression. Operands go through the usual conversions to bring them to a common type before comparison. The result type is bool. */ void visit (IdentityExp *e) { tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR; Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); if ((tb1->ty == Tsarray || tb1->ty == Tarray) && (tb2->ty == Tsarray || tb2->ty == Tarray)) { /* For static and dynamic arrays, identity is defined as referring to the same array elements and the same number of elements. */ tree t1 = d_array_convert (e->e1); tree t2 = d_array_convert (e->e2); this->result_ = d_convert (build_ctype (e->type), build_boolop (code, t1, t2)); } else if (tb1->isfloating () && tb1->ty != Tvector) { /* For floating-point values, identity is defined as the bits in the operands being identical. */ tree t1 = d_save_expr (build_expr (e->e1)); tree t2 = d_save_expr (build_expr (e->e2)); tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP); tree size = size_int (TYPE_PRECISION (TREE_TYPE (t1)) / BITS_PER_UNIT); tree result = build_call_expr (tmemcmp, 3, build_address (t1), build_address (t2), size); this->result_ = build_boolop (code, result, integer_zero_node); } else if (tb1->ty == Tstruct) { /* For struct objects, identity is defined as bits in operands being identical also. Alignment holes in structs are ignored. */ StructDeclaration *sd = ((TypeStruct *) tb1)->sym; tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); gcc_assert (same_type_p (tb1, tb2)); this->result_ = build_struct_comparison (code, sd, t1, t2); } else { /* For operands of other types, identity is defined as being the same as equality expressions. */ tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); this->result_ = d_convert (build_ctype (e->type), build_boolop (code, t1, t2)); } } /* Build an equality expression, which compare the two operands for either equality or inequality. Operands go through the usual conversions to bring them to a common type before comparison. The result type is bool. */ void visit (EqualExp *e) { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR; if ((tb1->ty == Tsarray || tb1->ty == Tarray) && (tb2->ty == Tsarray || tb2->ty == Tarray)) { /* For static and dynamic arrays, equality is defined as the lengths of the arrays matching, and all the elements are equal. */ Type *t1elem = tb1->nextOf ()->toBasetype (); Type *t2elem = tb1->nextOf ()->toBasetype (); /* Check if comparisons of arrays can be optimized using memcmp. This will inline EQ expressions as: e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0; Or when generating a NE expression: e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */ if ((t1elem->isintegral () || t1elem->ty == Tvoid || (t1elem->ty == Tstruct && !((TypeStruct *)t1elem)->sym->xeq)) && t1elem->ty == t2elem->ty) { tree t1 = d_array_convert (e->e1); tree t2 = d_array_convert (e->e2); tree result; /* Make temporaries to prevent multiple evaluations. */ tree t1saved = d_save_expr (t1); tree t2saved = d_save_expr (t2); /* Length of arrays, for comparisons done before calling memcmp. */ tree t1len = d_array_length (t1saved); tree t2len = d_array_length (t2saved); /* Reference to array data. */ tree t1ptr = d_array_ptr (t1saved); tree t2ptr = d_array_ptr (t2saved); /* Compare arrays using memcmp if possible, otherwise for structs, each field is compared inline. */ if (t1elem->ty != Tstruct || identity_compare_p (((TypeStruct *) t1elem)->sym)) { tree size = size_mult_expr (t1len, size_int (t1elem->size ())); tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP); result = build_call_expr (tmemcmp, 3, t1ptr, t2ptr, size); result = build_boolop (code, result, integer_zero_node); } else { StructDeclaration *sd = ((TypeStruct *) t1elem)->sym; result = build_array_struct_comparison (code, sd, t1len, t1ptr, t2ptr); } /* Check array length first before passing to memcmp. For equality expressions, this becomes: (e1.length == 0 || memcmp); Otherwise for inequality: (e1.length != 0 && memcmp); */ tree tsizecmp = build_boolop (code, t1len, size_zero_node); if (e->op == TOKequal) result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result); else result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result); /* Finally, check if lengths of both arrays match if dynamic. The frontend should have already guaranteed that static arrays have same size. */ if (tb1->ty == Tsarray && tb2->ty == Tsarray) gcc_assert (tb1->size () == tb2->size ()); else { tree tlencmp = build_boolop (code, t1len, t2len); if (e->op == TOKequal) result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result); else result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result); } /* Ensure left-to-right order of evaluation. */ if (TREE_SIDE_EFFECTS (t2)) result = compound_expr (t2saved, result); if (TREE_SIDE_EFFECTS (t1)) result = compound_expr (t1saved, result); this->result_ = result; } else { /* Use _adEq2() to compare each element. */ Type *t1array = t1elem->arrayOf (); tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3, d_array_convert (e->e1), d_array_convert (e->e2), build_typeinfo (e->loc, t1array)); if (e->op == TOKnotequal) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; } } else if (tb1->ty == Tstruct) { /* Equality for struct objects means the logical product of all equality results of the corresponding object fields. */ StructDeclaration *sd = ((TypeStruct *) tb1)->sym; tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); gcc_assert (same_type_p (tb1, tb2)); this->result_ = build_struct_comparison (code, sd, t1, t2); } else if (tb1->ty == Taarray && tb2->ty == Taarray) { /* Use _aaEqual() for associative arrays. */ TypeAArray *taa1 = (TypeAArray *) tb1; tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3, build_typeinfo (e->loc, taa1), build_expr (e->e1), build_expr (e->e2)); if (e->op == TOKnotequal) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; } else { /* For operands of other types, equality is defined as the bit pattern of the type matches exactly. */ tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); this->result_ = d_convert (build_ctype (e->type), build_boolop (code, t1, t2)); } } /* Build an `in' expression. This is a condition to see if an element exists in an associative array. The result is a pointer to the element, or null if false. */ void visit (InExp *e) { Type *tb2 = e->e2->type->toBasetype (); gcc_assert (tb2->ty == Taarray); Type *tkey = ((TypeAArray *) tb2)->index->toBasetype (); tree key = convert_expr (build_expr (e->e1), e->e1->type, tkey); /* Build a call to _aaInX(). */ this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3, build_expr (e->e2), build_typeinfo (e->loc, tkey), build_address (key)); } /* Build a relational expression. The result type is bool. */ void visit (CmpExp *e) { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); tree result; tree_code code; switch (e->op) { case TOKle: code = LE_EXPR; break; case TOKlt: code = LT_EXPR; break; case TOKge: code = GE_EXPR; break; case TOKgt: code = GT_EXPR; break; default: gcc_unreachable (); } /* For static and dynamic arrays, the relational op is turned into a library call. It is not lowered during codegen. */ if ((tb1->ty == Tsarray || tb1->ty == Tarray) && (tb2->ty == Tsarray || tb2->ty == Tarray)) { error ("cannot handle comparison of type %<%s == %s%>", tb1->toChars (), tb2->toChars ()); gcc_unreachable (); } /* Simple comparison. */ result = build_boolop (code, build_expr (e->e1), build_expr (e->e2)); this->result_ = d_convert (build_ctype (e->type), result); } /* Build a logical `and if' or `or if' expression. If the right operand expression is void, then the resulting type is void. Otherwise the result is bool. */ void visit (LogicalExp *e) { tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; if (e->e2->type->toBasetype ()->ty != Tvoid) { tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); t1 = convert_for_condition (t1, e->e1->type); t2 = convert_for_condition (t2, e->e2->type); this->result_ = d_convert (build_ctype (e->type), build_boolop (code, t1, t2)); } else { tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type); tree t2 = build_expr_dtor (e->e2); /* Invert condition for logical or if expression. */ if (e->op == TOKoror) t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1); this->result_ = build_condition (build_ctype (e->type), t1, t2, void_node); } } /* Build a binary operand expression. Operands go through usual arithmetic conversions to bring them to a common type before evaluating. */ void visit (BinExp *e) { tree_code code; switch (e->op) { case TOKadd: case TOKmin: if ((e->e1->type->isreal () && e->e2->type->isimaginary ()) || (e->e1->type->isimaginary () && e->e2->type->isreal ())) { /* If the result is complex, then we can shortcut binary_op. Frontend should have already validated types and sizes. */ tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); if (e->op == TOKmin) t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2); if (e->e1->type->isreal ()) this->result_ = complex_expr (build_ctype (e->type), t1, t2); else this->result_ = complex_expr (build_ctype (e->type), t2, t1); return; } else code = (e->op == TOKadd) ? PLUS_EXPR : MINUS_EXPR; break; case TOKmul: code = MULT_EXPR; break; case TOKdiv: code = e->e1->type->isintegral () ? TRUNC_DIV_EXPR : RDIV_EXPR; break; case TOKmod: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; case TOKand: code = BIT_AND_EXPR; break; case TOKor: code = BIT_IOR_EXPR; break; case TOKxor: code = BIT_XOR_EXPR; break; case TOKshl: code = LSHIFT_EXPR; break; case TOKshr: code = RSHIFT_EXPR; break; case TOKushr: code = UNSIGNED_RSHIFT_EXPR; break; default: gcc_unreachable (); } this->result_ = this->binary_op (code, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); } /* Build a concat expression, which concatenates two or more arrays of the same type, producing a dynamic array with the result. If one operand is an element type, that element is converted to an array of length 1. */ void visit (CatExp *e) { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); Type *etype; if (tb1->ty == Tarray || tb1->ty == Tsarray) etype = tb1->nextOf (); else etype = tb2->nextOf (); vec *elemvars = NULL; tree result; if (e->e1->op == TOKcat) { /* Flatten multiple concatenations to an array. So the expression ((a ~ b) ~ c) becomes [a, b, c] */ int ndims = 2; for (Expression *ex = e->e1; ex->op == TOKcat;) { if (ex->op == TOKcat) { ex = ((CatExp *) ex)->e1; ndims++; } } /* Store all concatenation args to a temporary byte[][ndims] array. */ Type *targselem = Type::tint8->arrayOf (); tree var = create_temporary_var (make_array_type (targselem, ndims)); tree init = build_constructor (TREE_TYPE (var), NULL); vec_safe_push (elemvars, var); /* Loop through each concatenation from right to left. */ vec *elms = NULL; CatExp *ce = e; int dim = ndims - 1; for (Expression *oe = ce->e2; oe != NULL; (ce->e1->op != TOKcat ? (oe = ce->e1) : (ce = (CatExp *)ce->e1, oe = ce->e2))) { tree arg = d_array_convert (etype, oe, &elemvars); tree index = size_int (dim); CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg)); /* Finished pushing all arrays. */ if (oe == ce->e1) break; dim -= 1; } /* Check there is no logic bug in constructing byte[][] of arrays. */ gcc_assert (dim == 0); CONSTRUCTOR_ELTS (init) = elms; DECL_INITIAL (var) = init; tree arrs = d_array_value (build_ctype (targselem->arrayOf ()), size_int (ndims), build_address (var)); result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2, build_typeinfo (e->loc, e->type), arrs); } else { /* Handle single concatenation (a ~ b). */ result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3, build_typeinfo (e->loc, e->type), d_array_convert (etype, e->e1, &elemvars), d_array_convert (etype, e->e2, &elemvars)); } for (size_t i = 0; i < vec_safe_length (elemvars); ++i) result = bind_expr ((*elemvars)[i], result); this->result_ = result; } /* Build an assignment operator expression. The right operand is implicitly converted to the type of the left operand, and assigned to it. */ void visit (BinAssignExp *e) { tree_code code; Expression *e1b = e->e1; switch (e->op) { case TOKaddass: code = PLUS_EXPR; break; case TOKminass: code = MINUS_EXPR; break; case TOKmulass: code = MULT_EXPR; break; case TOKdivass: code = e->e1->type->isintegral () ? TRUNC_DIV_EXPR : RDIV_EXPR; break; case TOKmodass: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; case TOKandass: code = BIT_AND_EXPR; break; case TOKorass: code = BIT_IOR_EXPR; break; case TOKxorass: code = BIT_XOR_EXPR; break; case TOKpowass: gcc_unreachable (); case TOKshlass: code = LSHIFT_EXPR; break; case TOKshrass: case TOKushrass: /* Use the original lhs type before it was promoted. The left operand of `>>>=' does not undergo integral promotions before shifting. Strip off casts just incase anyway. */ while (e1b->op == TOKcast) { CastExp *ce = (CastExp *) e1b; gcc_assert (same_type_p (ce->type, ce->to)); e1b = ce->e1; } code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR; break; default: gcc_unreachable (); } tree exp = this->binop_assignment (code, e1b, e->e2); this->result_ = convert_expr (exp, e1b->type, e->type); } /* Build a concat assignment expression. The right operand is appended to the the left operand. */ void visit (CatAssignExp *e) { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); Type *etype = tb1->nextOf ()->toBasetype (); if (tb1->ty == Tarray && tb2->ty == Tdchar && (etype->ty == Tchar || etype->ty == Twchar)) { /* Append a dchar to a char[] or wchar[] */ libcall_fn libcall = (etype->ty == Tchar) ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD; this->result_ = build_libcall (libcall, e->type, 2, build_address (build_expr (e->e1)), build_expr (e->e2)); } else { gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray); tree tinfo = build_typeinfo (e->loc, e->type); tree ptr = build_address (build_expr (e->e1)); if ((tb2->ty == Tarray || tb2->ty == Tsarray) && same_type_p (etype, tb2->nextOf ()->toBasetype ())) { /* Append an array. */ this->result_ = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3, tinfo, ptr, d_array_convert (e->e2)); } else if (same_type_p (etype, tb2)) { /* Append an element. */ tree result = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3, tinfo, ptr, size_one_node); result = d_save_expr (result); /* Assign e2 to last element. */ tree offexp = d_array_length (result); offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp), offexp, size_one_node); offexp = d_save_expr (offexp); tree ptrexp = d_array_ptr (result); ptrexp = void_okay_p (ptrexp); ptrexp = build_array_index (ptrexp, offexp); /* Evaluate expression before appending. */ tree t2 = build_expr (e->e2); tree expr = stabilize_expr (&t2); t2 = d_save_expr (t2); result = modify_expr (build_deref (ptrexp), t2); result = compound_expr (t2, result); this->result_ = compound_expr (expr, result); } else gcc_unreachable (); } } /* Build an assignment expression. The right operand is implicitly converted to the type of the left operand, and assigned to it. */ void visit (AssignExp *e) { /* First, handle special assignment semantics. */ /* Look for array.length = n; */ if (e->e1->op == TOKarraylength) { /* Assignment to an array's length property; resize the array. */ ArrayLengthExp *ale = (ArrayLengthExp *) e->e1; tree newlength = convert_expr (build_expr (e->e2), e->e2->type, Type::tsize_t); tree ptr = build_address (build_expr (ale->e1)); /* Don't want the basetype for the element type. */ Type *etype = ale->e1->type->toBasetype ()->nextOf (); libcall_fn libcall = etype->isZeroInit () ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT; tree result = build_libcall (libcall, ale->e1->type, 3, build_typeinfo (ale->loc, ale->e1->type), newlength, ptr); this->result_ = d_array_length (result); return; } /* Look for array[] = n; */ if (e->e1->op == TOKslice) { SliceExp *se = (SliceExp *) e->e1; Type *stype = se->e1->type->toBasetype (); Type *etype = stype->nextOf ()->toBasetype (); /* Determine if we need to run postblit or dtor. */ bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2); bool destructor = this->needs_dtor (etype); if (e->memset & blockAssign) { /* Set a range of elements to one value. */ tree t1 = d_save_expr (build_expr (e->e1)); tree t2 = build_expr (e->e2); tree result; if ((postblit || destructor) && e->op != TOKblit) { libcall_fn libcall = (e->op == TOKconstruct) ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN; /* So we can call postblits on const/immutable objects. */ Type *tm = etype->unSharedOf ()->mutableOf (); tree ti = build_typeinfo (e->loc, tm); tree result = build_libcall (libcall, Type::tvoid, 4, d_array_ptr (t1), build_address (t2), d_array_length (t1), ti); this->result_ = compound_expr (result, t1); return; } if (integer_zerop (t2)) { tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET); tree size = size_mult_expr (d_array_length (t1), size_int (etype->size ())); result = build_call_expr (tmemset, 3, d_array_ptr (t1), integer_zero_node, size); } else result = build_array_set (d_array_ptr (t1), d_array_length (t1), t2); this->result_ = compound_expr (result, t1); } else { /* Perform a memcpy operation. */ gcc_assert (e->e2->type->ty != Tpointer); if (!postblit && !destructor && !array_bounds_check ()) { tree t1 = d_save_expr (d_array_convert (e->e1)); tree t2 = d_array_convert (e->e2); tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY); tree size = size_mult_expr (d_array_length (t1), size_int (etype->size ())); tree result = build_call_expr (tmemcpy, 3, d_array_ptr (t1), d_array_ptr (t2), size); this->result_ = compound_expr (result, t1); } else if ((postblit || destructor) && e->op != TOKblit) { /* Generate: _d_arrayassign(ti, from, to) or: _d_arrayctor(ti, from, to) */ libcall_fn libcall = (e->op == TOKconstruct) ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN; this->result_ = build_libcall (libcall, e->type, 3, build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); } else { /* Generate: _d_arraycopy() */ this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3, size_int (etype->size ()), d_array_convert (e->e2), d_array_convert (e->e1)); } } return; } /* Look for reference initializations. */ if (e->memset & referenceInit) { gcc_assert (e->op == TOKconstruct || e->op == TOKblit); gcc_assert (e->e1->op == TOKvar); Declaration *decl = ((VarExp *) e->e1)->var; if (decl->storage_class & (STCout | STCref)) { tree t2 = convert_for_assignment (build_expr (e->e2), e->e2->type, e->e1->type); tree t1 = build_expr (e->e1); /* Want reference to lhs, not indirect ref. */ t1 = TREE_OPERAND (t1, 0); t2 = build_address (t2); this->result_ = indirect_ref (build_ctype (e->type), build_assign (INIT_EXPR, t1, t2)); return; } } /* Other types of assignments that may require post construction. */ Type *tb1 = e->e1->type->toBasetype (); tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR; /* Look for struct assignment. */ if (tb1->ty == Tstruct) { tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), e->e2->type, e->e1->type); /* Look for struct = 0. */ if (e->e2->op == TOKint64) { /* Use memset to fill struct. */ gcc_assert (e->op == TOKblit); StructDeclaration *sd = ((TypeStruct *) tb1)->sym; tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET); tree result = build_call_expr (tmemset, 3, build_address (t1), t2, size_int (sd->structsize)); /* Maybe set-up hidden pointer to outer scope context. */ if (sd->isNested ()) { tree field = get_symbol_decl (sd->vthis); tree value = build_vthis (sd); tree vthis_exp = modify_expr (component_ref (t1, field), value); result = compound_expr (result, vthis_exp); } this->result_ = compound_expr (result, t1); } else this->result_ = build_assign (modifycode, t1, t2); return; } /* Look for static array assignment. */ if (tb1->ty == Tsarray) { /* Look for array = 0. */ if (e->e2->op == TOKint64) { /* Use memset to fill the array. */ gcc_assert (e->op == TOKblit); tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), e->e2->type, e->e1->type); tree size = size_int (e->e1->type->size ()); tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET); this->result_ = build_call_expr (tmemset, 3, build_address (t1), t2, size); return; } Type *etype = tb1->nextOf (); gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray); /* Determine if we need to run postblit. */ bool postblit = this->needs_postblit (etype); bool destructor = this->needs_dtor (etype); bool lvalue_p = this->lvalue_p (e->e2); /* Even if the elements in rhs are all rvalues and don't have to call postblits, this assignment should call dtors on old assigned elements. */ if ((!postblit && !destructor) || (e->op == TOKconstruct && !lvalue_p && postblit) || (e->op == TOKblit || e->e1->type->size () == 0)) { tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), e->e2->type, e->e1->type); this->result_ = build_assign (modifycode, t1, t2); return; } Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type; tree result; if (e->op == TOKconstruct) { /* Generate: _d_arrayctor(ti, from, to) */ result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3, build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); } else { /* Generate: _d_arrayassign_l() or: _d_arrayassign_r() */ libcall_fn libcall = (lvalue_p) ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; tree elembuf = build_local_temp (build_ctype (etype)); result = build_libcall (libcall, arrtype, 4, build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1), build_address (elembuf)); } /* Cast the libcall result back to a static array. */ if (e->type->ty == Tsarray) result = indirect_ref (build_ctype (e->type), d_array_ptr (result)); this->result_ = result; return; } /* Simple assignment. */ tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), e->e2->type, e->e1->type); this->result_ = build_assign (modifycode, t1, t2); } /* Build a postfix expression. */ void visit (PostExp *e) { tree result; if (e->op == TOKplusplus) { result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); } else if (e->op == TOKminusminus) { result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); } else gcc_unreachable (); TREE_SIDE_EFFECTS (result) = 1; this->result_ = result; } /* Build an index expression. */ void visit (IndexExp *e) { Type *tb1 = e->e1->type->toBasetype (); if (tb1->ty == Taarray) { /* Get the key for the associative array. */ Type *tkey = ((TypeAArray *) tb1)->index->toBasetype (); tree key = convert_expr (build_expr (e->e2), e->e2->type, tkey); libcall_fn libcall; tree tinfo, ptr; if (e->modifiable) { libcall = LIBCALL_AAGETY; ptr = build_address (build_expr (e->e1)); tinfo = build_typeinfo (e->loc, tb1->unSharedOf ()->mutableOf ()); } else { libcall = LIBCALL_AAGETRVALUEX; ptr = build_expr (e->e1); tinfo = build_typeinfo (e->loc, tkey); } /* Index the associative array. */ tree result = build_libcall (libcall, e->type->pointerTo (), 4, ptr, tinfo, size_int (tb1->nextOf ()->size ()), build_address (key)); if (!e->indexIsInBounds && array_bounds_check ()) { tree tassert = (global.params.checkAction == CHECKACTION_C) ? build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0) : d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS); result = d_save_expr (result); result = build_condition (TREE_TYPE (result), d_truthvalue_conversion (result), result, tassert); } this->result_ = indirect_ref (build_ctype (e->type), result); } else { /* Get the data pointer and length for static and dynamic arrays. */ tree array = d_save_expr (build_expr (e->e1)); tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ()); tree length = NULL_TREE; if (tb1->ty != Tpointer) length = get_array_length (array, tb1); else gcc_assert (e->lengthVar == NULL); /* The __dollar variable just becomes a placeholder for the actual length. */ if (e->lengthVar) e->lengthVar->csym = length; /* Generate the index. */ tree index = build_expr (e->e2); /* If it's a static array and the index is constant, the front end has already checked the bounds. */ if (tb1->ty != Tpointer && !e->indexIsInBounds) index = build_bounds_condition (e->e2->loc, index, length, false); /* Index the .ptr. */ ptr = void_okay_p (ptr); this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)), build_array_index (ptr, index)); } } /* Build a comma expression. The type is the type of the right operand. */ void visit (CommaExp *e) { tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); tree type = e->type ? build_ctype (e->type) : void_type_node; this->result_ = build2 (COMPOUND_EXPR, type, t1, t2); } /* Build an array length expression. Returns the number of elements in the array. The result is of type size_t. */ void visit (ArrayLengthExp *e) { if (e->e1->type->toBasetype ()->ty == Tarray) this->result_ = d_array_length (build_expr (e->e1)); else { /* Static arrays have already been handled by the front-end. */ error ("unexpected type for array length: %qs", e->type->toChars ()); this->result_ = error_mark_node; } } /* Build a delegate pointer expression. This will return the frame pointer value as a type void*. */ void visit (DelegatePtrExp *e) { tree t1 = build_expr (e->e1); this->result_ = delegate_object (t1); } /* Build a delegate function pointer expression. This will return the function pointer value as a function type. */ void visit (DelegateFuncptrExp *e) { tree t1 = build_expr (e->e1); this->result_ = delegate_method (t1); } /* Build a slice expression. */ void visit (SliceExp *e) { Type *tb = e->type->toBasetype (); Type *tb1 = e->e1->type->toBasetype (); gcc_assert (tb->ty == Tarray || tb->ty == Tsarray); /* Use convert-to-dynamic-array code if possible. */ if (!e->lwr) { tree result = build_expr (e->e1); if (e->e1->type->toBasetype ()->ty == Tsarray) result = convert_expr (result, e->e1->type, e->type); this->result_ = result; return; } else gcc_assert (e->upr != NULL); /* Get the data pointer and length for static and dynamic arrays. */ tree array = d_save_expr (build_expr (e->e1)); tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ()); tree length = NULL_TREE; /* Our array is already a SAVE_EXPR if necessary, so we don't make length a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array. */ if (tb1->ty != Tpointer) length = get_array_length (array, tb1); else gcc_assert (e->lengthVar == NULL); /* The __dollar variable just becomes a placeholder for the actual length. */ if (e->lengthVar) e->lengthVar->csym = length; /* Generate upper and lower bounds. */ tree lwr_tree = d_save_expr (build_expr (e->lwr)); tree upr_tree = d_save_expr (build_expr (e->upr)); /* If the upper bound has any side effects, then the lower bound should be copied to a temporary always. */ if (TREE_CODE (upr_tree) == SAVE_EXPR && TREE_CODE (lwr_tree) != SAVE_EXPR) lwr_tree = save_expr (lwr_tree); /* Adjust the .ptr offset. */ if (!integer_zerop (lwr_tree)) { tree ptrtype = TREE_TYPE (ptr); ptr = build_array_index (void_okay_p (ptr), lwr_tree); ptr = build_nop (ptrtype, ptr); } else lwr_tree = NULL_TREE; /* Nothing more to do for static arrays, their bounds checking has been done at compile-time. */ if (tb->ty == Tsarray) { this->result_ = indirect_ref (build_ctype (e->type), ptr); return; } else gcc_assert (tb->ty == Tarray); /* Generate bounds checking code. */ tree newlength; if (!e->upperIsInBounds) { if (length) { newlength = build_bounds_condition (e->upr->loc, upr_tree, length, true); } else { /* Still need to check bounds lwr <= upr for pointers. */ gcc_assert (tb1->ty == Tpointer); newlength = upr_tree; } } else newlength = upr_tree; if (lwr_tree) { /* Enforces lwr <= upr. No need to check lwr <= length as we've already ensured that upr <= length. */ if (!e->lowerIsLessThanUpper) { tree cond = build_bounds_condition (e->lwr->loc, lwr_tree, upr_tree, true); /* When bounds checking is off, the index value is returned directly. */ if (cond != lwr_tree) newlength = compound_expr (cond, newlength); } /* Need to ensure lwr always gets evaluated first, as it may be a function call. Generates (lwr, upr) - lwr. */ newlength = fold_build2 (MINUS_EXPR, TREE_TYPE (newlength), compound_expr (lwr_tree, newlength), lwr_tree); } tree result = d_array_value (build_ctype (e->type), newlength, ptr); this->result_ = compound_expr (array, result); } /* Build a cast expression, which converts the given unary expression to the type of result. */ void visit (CastExp *e) { Type *ebtype = e->e1->type->toBasetype (); Type *tbtype = e->to->toBasetype (); tree result = build_expr (e->e1, this->constp_); /* Just evaluate e1 if it has any side effects. */ if (tbtype->ty == Tvoid) this->result_ = build_nop (build_ctype (tbtype), result); else this->result_ = convert_expr (result, ebtype, tbtype); } /* Build a delete expression. */ void visit (DeleteExp *e) { tree t1 = build_expr (e->e1); Type *tb1 = e->e1->type->toBasetype (); if (tb1->ty == Tclass) { /* For class object references, if there is a destructor for that class, the destructor is called for the object instance. */ libcall_fn libcall; if (e->e1->op == TOKvar) { VarDeclaration *v = ((VarExp *) e->e1)->var->isVarDeclaration (); if (v && v->onstack) { libcall = tb1->isClassHandle ()->isInterfaceDeclaration () ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER; this->result_ = build_libcall (libcall, Type::tvoid, 1, t1); return; } } /* Otherwise, the garbage collector is called to immediately free the memory allocated for the class instance. */ libcall = tb1->isClassHandle ()->isInterfaceDeclaration () ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS; t1 = build_address (t1); this->result_ = build_libcall (libcall, Type::tvoid, 1, t1); } else if (tb1->ty == Tarray) { /* For dynamic arrays, the garbage collector is called to immediately release the memory. */ Type *telem = tb1->nextOf ()->baseElemOf (); tree ti = null_pointer_node; if (telem->ty == Tstruct) { /* Might need to run destructor on array contents. */ TypeStruct *ts = (TypeStruct *) telem; if (ts->sym->dtor) ti = build_typeinfo (e->loc, tb1->nextOf ()); } /* Generate: _delarray_t (&t1, ti); */ this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2, build_address (t1), ti); } else if (tb1->ty == Tpointer) { /* For pointers to a struct instance, if the struct has overloaded operator delete, then that operator is called. */ t1 = build_address (t1); Type *tnext = ((TypePointer *)tb1)->next->toBasetype (); if (tnext->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tnext; if (ts->sym->dtor) { tree ti = build_typeinfo (e->loc, tnext); this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid, 2, t1, ti); return; } } /* Otherwise, the garbage collector is called to immediately free the memory allocated for the pointer. */ this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1); } else { error ("don't know how to delete %qs", e->e1->toChars ()); this->result_ = error_mark_node; } } /* Build a remove expression, which removes a particular key from an associative array. */ void visit (RemoveExp *e) { /* Check that the array is actually an associative array. */ if (e->e1->type->toBasetype ()->ty == Taarray) { Type *tb = e->e1->type->toBasetype (); Type *tkey = ((TypeAArray *) tb)->index->toBasetype (); tree index = convert_expr (build_expr (e->e2), e->e2->type, tkey); this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3, build_expr (e->e1), build_typeinfo (e->loc, tkey), build_address (index)); } else { error ("%qs is not an associative array", e->e1->toChars ()); this->result_ = error_mark_node; } } /* Build an unary not expression. */ void visit (NotExp *e) { tree result = convert_for_condition (build_expr (e->e1), e->e1->type); /* Need to convert to boolean type or this will fail. */ result = fold_build1 (TRUTH_NOT_EXPR, d_bool_type, result); this->result_ = d_convert (build_ctype (e->type), result); } /* Build a compliment expression, where all the bits in the value are complemented. Note: unlike in C, the usual integral promotions are not performed prior to the complement operation. */ void visit (ComExp *e) { TY ty1 = e->e1->type->toBasetype ()->ty; gcc_assert (ty1 != Tarray && ty1 != Tsarray); this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type), build_expr (e->e1)); } /* Build an unary negation expression. */ void visit (NegExp *e) { TY ty1 = e->e1->type->toBasetype ()->ty; gcc_assert (ty1 != Tarray && ty1 != Tsarray); tree type = build_ctype (e->type); tree expr = build_expr (e->e1); /* If the operation needs excess precision. */ tree eptype = excess_precision_type (type); if (eptype != NULL_TREE) expr = d_convert (eptype, expr); else eptype = type; tree ret = fold_build1 (NEGATE_EXPR, eptype, expr); this->result_ = d_convert (type, ret); } /* Build a pointer index expression. */ void visit (PtrExp *e) { Type *tnext = NULL; size_t offset; tree result; if (e->e1->op == TOKadd) { BinExp *be = (BinExp *) e->e1; if (be->e1->op == TOKaddress && be->e2->isConst () && be->e2->type->isintegral ()) { Expression *ae = ((AddrExp *) be->e1)->e1; tnext = ae->type->toBasetype (); result = build_expr (ae); offset = be->e2->toUInteger (); } } else if (e->e1->op == TOKsymoff) { SymOffExp *se = (SymOffExp *) e->e1; if (!declaration_reference_p (se->var)) { tnext = se->var->type->toBasetype (); result = get_decl_tree (se->var); offset = se->offset; } } /* Produce better code by converting *(#record + n) to COMPONENT_REFERENCE. Otherwise, the variable will always be allocated in memory because its address is taken. */ if (tnext && tnext->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *) tnext)->sym; for (size_t i = 0; i < sd->fields.dim; i++) { VarDeclaration *field = sd->fields[i]; if (field->offset == offset && same_type_p (field->type, e->type)) { /* Catch errors, backend will ICE otherwise. */ if (error_operand_p (result)) this->result_ = result; else { result = component_ref (result, get_symbol_decl (field)); this->result_ = result; } return; } else if (field->offset > offset) break; } } this->result_ = indirect_ref (build_ctype (e->type), build_expr (e->e1)); } /* Build an unary address expression. */ void visit (AddrExp *e) { tree type = build_ctype (e->type); tree exp; /* The frontend optimizer can convert const symbol into a struct literal. Taking the address of a struct literal is otherwise illegal. */ if (e->e1->op == TOKstructliteral) { StructLiteralExp *sle = ((StructLiteralExp *) e->e1)->origin; gcc_assert (sle != NULL); /* Build the reference symbol, the decl is built first as the initializer may have recursive references. */ if (!sle->sym) { sle->sym = build_artificial_decl (build_ctype (sle->type), NULL_TREE, "S"); DECL_INITIAL (sle->sym) = build_expr (sle, true); d_pushdecl (sle->sym); rest_of_decl_compilation (sle->sym, 1, 0); } exp = sle->sym; } else exp = build_expr (e->e1, this->constp_); TREE_CONSTANT (exp) = 0; this->result_ = d_convert (type, build_address (exp)); } /* Build a function call expression. */ void visit (CallExp *e) { Type *tb = e->e1->type->toBasetype (); Expression *e1b = e->e1; tree callee = NULL_TREE; tree object = NULL_TREE; tree cleanup = NULL_TREE; TypeFunction *tf = NULL; /* Calls to delegates can sometimes look like this. */ if (e1b->op == TOKcomma) { e1b = ((CommaExp *) e1b)->e2; gcc_assert (e1b->op == TOKvar); Declaration *var = ((VarExp *) e1b)->var; gcc_assert (var->isFuncDeclaration () && !var->needThis ()); } if (e1b->op == TOKdotvar && tb->ty != Tdelegate) { DotVarExp *dve = (DotVarExp *) e1b; /* Don't modify the static initializer for struct literals. */ if (dve->e1->op == TOKstructliteral) { StructLiteralExp *sle = (StructLiteralExp *) dve->e1; sle->useStaticInit = false; } FuncDeclaration *fd = dve->var->isFuncDeclaration (); if (fd != NULL) { /* Get the correct callee from the DotVarExp object. */ tree fndecl = get_symbol_decl (fd); AggregateDeclaration *ad = fd->isThis (); /* Static method; ignore the object instance. */ if (!ad) callee = build_address (fndecl); else { tree thisexp = build_expr (dve->e1); /* When constructing temporaries, if the constructor throws, then the object is destructed even though it is not a fully constructed object yet. And so this call will need to be moved inside the TARGET_EXPR_INITIAL slot. */ if (fd->isCtorDeclaration () && TREE_CODE (thisexp) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (thisexp, 0)) == TARGET_EXPR && TARGET_EXPR_CLEANUP (TREE_OPERAND (thisexp, 0))) { cleanup = TREE_OPERAND (thisexp, 0); thisexp = TREE_OPERAND (thisexp, 1); } /* Want reference to 'this' object. */ if (!POINTER_TYPE_P (TREE_TYPE (thisexp))) thisexp = build_address (thisexp); /* Make the callee a virtual call. */ if (fd->isVirtual () && !fd->isFinalFunc () && !e->directcall) { tree fntype = build_pointer_type (TREE_TYPE (fndecl)); tree thistype = build_ctype (ad->handleType ()); thisexp = build_nop (thistype, d_save_expr (thisexp)); fndecl = build_vindex_ref (thisexp, fntype, fd->vtblIndex); } else fndecl = build_address (fndecl); callee = build_method_call (fndecl, thisexp, fd->type); } } } if (callee == NULL_TREE) callee = build_expr (e1b); if (METHOD_CALL_EXPR (callee)) { /* This could be a delegate expression (TY == Tdelegate), but not actually a delegate variable. */ if (e1b->op == TOKdotvar) { /* This gets the true function type, getting the function type from e1->type can sometimes be incorrect, such as when calling a 'ref' return function. */ tf = get_function_type (((DotVarExp *) e1b)->var->type); } else tf = get_function_type (tb); extract_from_method_call (callee, callee, object); } else if (tb->ty == Tdelegate) { /* Delegate call, extract .object and .funcptr from var. */ callee = d_save_expr (callee); tf = get_function_type (tb); object = delegate_object (callee); callee = delegate_method (callee); } else if (e1b->op == TOKvar) { FuncDeclaration *fd = ((VarExp *) e1b)->var->isFuncDeclaration (); gcc_assert (fd != NULL); tf = get_function_type (fd->type); if (fd->isNested ()) { /* Maybe re-evaluate symbol storage treating 'fd' as public. */ if (call_by_alias_p (d_function_chain->function, fd)) TREE_PUBLIC (callee) = 1; object = get_frame_for_symbol (fd); } else if (fd->needThis ()) { error_at (make_location_t (e1b->loc), "need % to access member %qs", fd->toChars ()); /* Continue compiling... */ object = null_pointer_node; } } else { /* Normal direct function call. */ tf = get_function_type (tb); } gcc_assert (tf != NULL); /* Now we have the type, callee and maybe object reference, build the call expression. */ tree exp = d_build_call (tf, callee, object, e->arguments); if (tf->isref) exp = build_deref (exp); /* Some library calls are defined to return a generic type. this->type is the real type we want to return. */ if (e->type->isTypeBasic ()) exp = d_convert (build_ctype (e->type), exp); /* If this call was found to be a constructor for a temporary with a cleanup, then move the call inside the TARGET_EXPR. The original initializer is turned into an assignment, to keep its side effect. */ if (cleanup != NULL_TREE) { tree init = TARGET_EXPR_INITIAL (cleanup); tree slot = TARGET_EXPR_SLOT (cleanup); d_mark_addressable (slot); init = build_assign (INIT_EXPR, slot, init); TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp); exp = cleanup; } this->result_ = exp; } /* Build a delegate expression. */ void visit (DelegateExp *e) { if (e->func->semanticRun == PASSsemantic3done) { /* Add the function as nested function if it belongs to this module. ie: it is a member of this module, or it is a template instance. */ Dsymbol *owner = e->func->toParent (); while (!owner->isTemplateInstance () && owner->toParent ()) owner = owner->toParent (); if (owner->isTemplateInstance () || owner == d_function_chain->module) build_decl_tree (e->func); } tree fndecl; tree object; if (e->func->isNested ()) { if (e->e1->op == TOKnull) object = build_expr (e->e1); else object = get_frame_for_symbol (e->func); fndecl = build_address (get_symbol_decl (e->func)); } else { if (!e->func->isThis ()) { error ("delegates are only for non-static functions"); this->result_ = error_mark_node; return; } object = build_expr (e->e1); /* Want reference to `this' object. */ if (e->e1->type->ty != Tclass && e->e1->type->ty != Tpointer) object = build_address (object); /* Object reference could be the outer `this' field of a class or closure of type `void*'. Cast it to the right type. */ if (e->e1->type->ty == Tclass) object = d_convert (build_ctype (e->e1->type), object); fndecl = get_symbol_decl (e->func); /* Get pointer to function out of the virtual table. */ if (e->func->isVirtual () && !e->func->isFinalFunc () && e->e1->op != TOKsuper && e->e1->op != TOKdottype) { tree fntype = build_pointer_type (TREE_TYPE (fndecl)); object = d_save_expr (object); fndecl = build_vindex_ref (object, fntype, e->func->vtblIndex); } else fndecl = build_address (fndecl); } this->result_ = build_method_call (fndecl, object, e->type); } /* Build a type component expression. */ void visit (DotTypeExp *e) { /* Just a pass through to underlying expression. */ this->result_ = build_expr (e->e1); } /* Build a component reference expression. */ void visit (DotVarExp *e) { VarDeclaration *vd = e->var->isVarDeclaration (); /* This could also be a function, but relying on that being taken care of by the visitor interface for CallExp. */ if (vd != NULL) { if (!vd->isField ()) this->result_ = get_decl_tree (vd); else { tree object = build_expr (e->e1); if (e->e1->type->toBasetype ()->ty != Tstruct) object = build_deref (object); this->result_ = component_ref (object, get_symbol_decl (vd)); } } else { error ("%qs is not a field, but a %qs", e->var->toChars (), e->var->kind ()); this->result_ = error_mark_node; } } /* Build an assert expression, used to declare conditions that must hold at that a given point in the program. */ void visit (AssertExp *e) { Type *tb1 = e->e1->type->toBasetype (); tree arg = build_expr (e->e1); tree tmsg = NULL_TREE; tree assert_pass = void_node; tree assert_fail; if (global.params.useAssert == CHECKENABLEon && global.params.checkAction == CHECKACTION_D) { /* Generate: ((bool) e1 ? (void)0 : _d_assert (...)) or: (e1 != null ? e1._invariant() : _d_assert (...)) */ bool unittest_p = d_function_chain->function->isUnitTestDeclaration (); libcall_fn libcall; if (e->msg) { tmsg = build_expr_dtor (e->msg); libcall = unittest_p ? LIBCALL_UNITTEST_MSG : LIBCALL_ASSERT_MSG; } else libcall = unittest_p ? LIBCALL_UNITTEST : LIBCALL_ASSERT; /* Build a call to _d_assert(). */ assert_fail = d_assert_call (e->loc, libcall, tmsg); if (global.params.useInvariants) { /* If the condition is a D class or struct object with an invariant, call it if the condition result is true. */ if (tb1->ty == Tclass) { ClassDeclaration *cd = tb1->isClassHandle (); if (!cd->isInterfaceDeclaration () && !cd->isCPPclass ()) { arg = d_save_expr (arg); assert_pass = build_libcall (LIBCALL_INVARIANT, Type::tvoid, 1, arg); } } else if (tb1->ty == Tpointer && tb1->nextOf ()->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *) tb1->nextOf ())->sym; if (sd->inv != NULL) { Expressions args; arg = d_save_expr (arg); assert_pass = d_build_call_expr (sd->inv, arg, &args); } } } } else if (global.params.useAssert == CHECKENABLEon && global.params.checkAction == CHECKACTION_C) { /* Generate: __builtin_trap() */ tree fn = builtin_decl_explicit (BUILT_IN_TRAP); assert_fail = build_call_expr (fn, 0); } else { /* Assert contracts are turned off, if the contract condition has no side effects can still use it as a predicate for the optimizer. */ if (TREE_SIDE_EFFECTS (arg)) { this->result_ = void_node; return; } assert_fail = build_predict_expr (PRED_NORETURN, NOT_TAKEN); } /* Build condition that we are asserting in this contract. */ tree condition = convert_for_condition (arg, e->e1->type); /* We expect the condition to always be true, as what happens if an assert contract is false is undefined behavior. */ tree fn = builtin_decl_explicit (BUILT_IN_EXPECT); tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); tree pred_type = TREE_VALUE (arg_types); tree expected_type = TREE_VALUE (TREE_CHAIN (arg_types)); condition = build_call_expr (fn, 2, d_convert (pred_type, condition), build_int_cst (expected_type, 1)); condition = d_truthvalue_conversion (condition); this->result_ = build_vcondition (condition, assert_pass, assert_fail); } /* Build a declaration expression. */ void visit (DeclarationExp *e) { /* Compile the declaration. */ push_stmt_list (); build_decl_tree (e->declaration); tree result = pop_stmt_list (); /* Construction of an array for typesafe-variadic function arguments can cause an empty STMT_LIST here. This can causes problems during gimplification. */ if (TREE_CODE (result) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (result)) result = build_empty_stmt (input_location); this->result_ = result; } /* Build a typeid expression. Returns an instance of class TypeInfo corresponding to. */ void visit (TypeidExp *e) { if (Type *tid = isType (e->obj)) { tree ti = build_typeinfo (e->loc, tid); /* If the typeinfo is at an offset. */ if (tid->vtinfo->offset) ti = build_offset (ti, size_int (tid->vtinfo->offset)); this->result_ = build_nop (build_ctype (e->type), ti); } else if (Expression *tid = isExpression (e->obj)) { Type *type = tid->type->toBasetype (); assert (type->ty == Tclass); /* Generate **classptr to get the classinfo. */ tree ci = build_expr (tid); ci = indirect_ref (ptr_type_node, ci); ci = indirect_ref (ptr_type_node, ci); /* Add extra indirection for interfaces. */ if (((TypeClass *) type)->sym->isInterfaceDeclaration ()) ci = indirect_ref (ptr_type_node, ci); this->result_ = build_nop (build_ctype (e->type), ci); } else gcc_unreachable (); } /* Build a function/lambda expression. */ void visit (FuncExp *e) { Type *ftype = e->type->toBasetype (); /* This check is for lambda's, remove 'vthis' as function isn't nested. */ if (e->fd->tok == TOKreserved && ftype->ty == Tpointer) { e->fd->tok = TOKfunction; e->fd->vthis = NULL; } /* Compile the function literal body. */ build_decl_tree (e->fd); /* If nested, this will be a trampoline. */ if (e->fd->isNested ()) { tree func = build_address (get_symbol_decl (e->fd)); tree object; if (this->constp_) { /* Static delegate variables have no context pointer. */ object = null_pointer_node; this->result_ = build_method_call (func, object, e->fd->type); TREE_CONSTANT (this->result_) = 1; } else { object = get_frame_for_symbol (e->fd); this->result_ = build_method_call (func, object, e->fd->type); } } else { this->result_ = build_nop (build_ctype (e->type), build_address (get_symbol_decl (e->fd))); } } /* Build a halt expression. */ void visit (HaltExp *) { /* Should we use trap() or abort()? */ tree ttrap = builtin_decl_explicit (BUILT_IN_TRAP); this->result_ = build_call_expr (ttrap, 0); } /* Build a symbol pointer offset expression. */ void visit (SymOffExp *e) { /* Build the address and offset of the symbol. */ size_t soffset = ((SymOffExp *) e)->offset; tree result = get_decl_tree (e->var); TREE_USED (result) = 1; if (declaration_reference_p (e->var)) gcc_assert (POINTER_TYPE_P (TREE_TYPE (result))); else result = build_address (result); if (!soffset) result = d_convert (build_ctype (e->type), result); else { tree offset = size_int (soffset); result = build_nop (build_ctype (e->type), build_offset (result, offset)); } this->result_ = result; } /* Build a variable expression. */ void visit (VarExp *e) { if (e->var->needThis ()) { error ("need % to access member %qs", e->var->ident->toChars ()); this->result_ = error_mark_node; return; } else if (e->var->ident == Identifier::idPool ("__ctfe")) { /* __ctfe is always false at run-time. */ this->result_ = integer_zero_node; return; } /* This check is same as is done in FuncExp for lambdas. */ FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); if (fld != NULL) { if (fld->tok == TOKreserved) { fld->tok = TOKfunction; fld->vthis = NULL; } /* Compiler the function literal body. */ build_decl_tree (fld); } if (this->constp_) { /* Want the initializer, not the expression. */ VarDeclaration *var = e->var->isVarDeclaration (); SymbolDeclaration *sd = e->var->isSymbolDeclaration (); tree init = NULL_TREE; if (var && (var->isConst () || var->isImmutable ()) && e->type->toBasetype ()->ty != Tsarray && var->_init) { if (var->inuse) error_at (make_location_t (e->loc), "recursive reference %qs", e->toChars ()); else { var->inuse++; init = build_expr (initializerToExpression (var->_init), true); var->inuse--; } } else if (sd && sd->dsym) init = layout_struct_initializer (sd->dsym); else error_at (make_location_t (e->loc), "non-constant expression %qs", e->toChars ()); if (init != NULL_TREE) this->result_ = init; else this->result_ = error_mark_node; } else { tree result = get_decl_tree (e->var); TREE_USED (result) = 1; /* For variables that are references - currently only out/inout arguments; objects don't count - evaluating the variable means we want what it refers to. */ if (declaration_reference_p (e->var)) result = indirect_ref (build_ctype (e->var->type), result); this->result_ = result; } } /* Build a this variable expression. */ void visit (ThisExp *e) { FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL; tree result = NULL_TREE; if (e->var) result = get_decl_tree (e->var); else { gcc_assert (fd && fd->vthis); result = get_decl_tree (fd->vthis); } if (e->type->ty == Tstruct) result = build_deref (result); this->result_ = result; } /* Build a new expression, which allocates memory either on the garbage collected heap or by using a class or struct specific allocator. */ void visit (NewExp *e) { Type *tb = e->type->toBasetype (); tree result; if (e->allocator) gcc_assert (e->newargs); if (tb->ty == Tclass) { /* Allocating a new class. */ tb = e->newtype->toBasetype (); gcc_assert (tb->ty == Tclass); ClassDeclaration *cd = ((TypeClass *) tb)->sym; tree type = build_ctype (tb); tree setup_exp = NULL_TREE; tree new_call; if (e->onstack) { /* If being used as an initializer for a local variable with scope storage class, then the instance is allocated on the stack rather than the heap or using the class specific allocator. */ tree var = build_local_temp (TREE_TYPE (type)); new_call = build_nop (type, build_address (var)); setup_exp = modify_expr (var, aggregate_initializer_decl (cd)); } else if (e->allocator) { /* Call class allocator, and copy the initializer into memory. */ new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs); new_call = d_save_expr (new_call); new_call = build_nop (type, new_call); setup_exp = modify_expr (build_deref (new_call), aggregate_initializer_decl (cd)); } else { /* Generate: _d_newclass() */ tree arg = build_address (get_classinfo_decl (cd)); new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg); } /* Set the context pointer for nested classes. */ if (cd->isNested ()) { tree field = get_symbol_decl (cd->vthis); tree value = NULL_TREE; if (e->thisexp) { ClassDeclaration *tcd = e->thisexp->type->isClassHandle (); Dsymbol *outer = cd->toParent2 (); int offset = 0; value = build_expr (e->thisexp); if (outer != tcd) { ClassDeclaration *ocd = outer->isClassDeclaration (); gcc_assert (ocd->isBaseOf (tcd, &offset)); /* Could just add offset... */ value = convert_expr (value, e->thisexp->type, ocd->type); } } else value = build_vthis (cd); if (value != NULL_TREE) { /* Generate: (new())->vthis = this; */ new_call = d_save_expr (new_call); field = component_ref (build_deref (new_call), field); setup_exp = compound_expr (setup_exp, modify_expr (field, value)); } } new_call = compound_expr (setup_exp, new_call); /* Call the class constructor. */ if (e->member) result = d_build_call_expr (e->member, new_call, e->arguments); else result = new_call; if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); } else if (tb->ty == Tpointer && tb->nextOf ()->toBasetype ()->ty == Tstruct) { /* Allocating memory for a new struct. */ Type *htype = e->newtype->toBasetype (); gcc_assert (htype->ty == Tstruct); gcc_assert (!e->onstack); TypeStruct *stype = (TypeStruct *) htype; StructDeclaration *sd = stype->sym; tree new_call; /* Cannot new an opaque struct. */ if (sd->size (e->loc) == 0) { this->result_ = d_convert (build_ctype (e->type), integer_zero_node); return; } if (e->allocator) { /* Call struct allocator. */ new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs); new_call = build_nop (build_ctype (tb), new_call); } else { /* Generate: _d_newitemT() */ libcall_fn libcall = htype->isZeroInit () ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; tree arg = build_typeinfo (e->loc, e->newtype); new_call = build_libcall (libcall, tb, 1, arg); } if (e->member || !e->arguments) { /* Set the context pointer for nested structs. */ if (sd->isNested ()) { tree value = build_vthis (sd); tree field = get_symbol_decl (sd->vthis); tree type = build_ctype (stype); new_call = d_save_expr (new_call); field = component_ref (indirect_ref (type, new_call), field); new_call = compound_expr (modify_expr (field, value), new_call); } /* Call the struct constructor. */ if (e->member) result = d_build_call_expr (e->member, new_call, e->arguments); else result = new_call; } else { /* If we have a user supplied initializer, then set-up with a struct literal. */ if (e->arguments != NULL && sd->fields.dim != 0) { StructLiteralExp *se = StructLiteralExp::create (e->loc, sd, e->arguments, htype); new_call = d_save_expr (new_call); se->type = sd->type; se->sym = new_call; result = compound_expr (build_expr (se), new_call); } else result = new_call; } if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); } else if (tb->ty == Tarray) { /* Allocating memory for a new D array. */ tb = e->newtype->toBasetype (); gcc_assert (tb->ty == Tarray); TypeDArray *tarray = (TypeDArray *) tb; gcc_assert (!e->allocator); gcc_assert (e->arguments && e->arguments->dim >= 1); if (e->arguments->dim == 1) { /* Single dimension array allocations. */ Expression *arg = (*e->arguments)[0]; if (tarray->next->size () == 0) { /* Array element size is unknown. */ this->result_ = d_array_value (build_ctype (e->type), size_int (0), null_pointer_node); return; } libcall_fn libcall = tarray->next->isZeroInit () ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT; result = build_libcall (libcall, tb, 2, build_typeinfo (e->loc, e->type), build_expr (arg)); } else { /* Multidimensional array allocations. */ vec *elms = NULL; Type *telem = e->newtype->toBasetype (); tree tarray = make_array_type (Type::tsize_t, e->arguments->dim); tree var = create_temporary_var (tarray); tree init = build_constructor (TREE_TYPE (var), NULL); for (size_t i = 0; i < e->arguments->dim; i++) { Expression *arg = (*e->arguments)[i]; CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg)); gcc_assert (telem->ty == Tarray); telem = telem->toBasetype ()->nextOf (); gcc_assert (telem); } CONSTRUCTOR_ELTS (init) = elms; DECL_INITIAL (var) = init; /* Generate: _d_newarraymTX(ti, dims) or: _d_newarraymiTX(ti, dims) */ libcall_fn libcall = telem->isZeroInit () ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX; tree tinfo = build_typeinfo (e->loc, e->type); tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()), size_int (e->arguments->dim), build_address (var)); result = build_libcall (libcall, tb, 2, tinfo, dims); result = bind_expr (var, result); } if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); } else if (tb->ty == Tpointer) { /* Allocating memory for a new pointer. */ TypePointer *tpointer = (TypePointer *) tb; if (tpointer->next->size () == 0) { /* Pointer element size is unknown. */ this->result_ = d_convert (build_ctype (e->type), integer_zero_node); return; } libcall_fn libcall = tpointer->next->isZeroInit (e->loc) ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; tree arg = build_typeinfo (e->loc, e->newtype); result = build_libcall (libcall, tb, 1, arg); if (e->arguments && e->arguments->dim == 1) { result = d_save_expr (result); tree init = modify_expr (build_deref (result), build_expr ((*e->arguments)[0])); result = compound_expr (init, result); } if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); } else gcc_unreachable (); this->result_ = convert_expr (result, tb, e->type); } /* Build an integer literal. */ void visit (IntegerExp *e) { tree ctype = build_ctype (e->type->toBasetype ()); this->result_ = build_integer_cst (e->value, ctype); } /* Build a floating-point literal. */ void visit (RealExp *e) { this->result_ = build_float_cst (e->value, e->type->toBasetype ()); } /* Build a complex literal. */ void visit (ComplexExp *e) { Type *tnext; switch (e->type->toBasetype ()->ty) { case Tcomplex32: tnext = (TypeBasic *) Type::tfloat32; break; case Tcomplex64: tnext = (TypeBasic *) Type::tfloat64; break; case Tcomplex80: tnext = (TypeBasic *) Type::tfloat80; break; default: gcc_unreachable (); } this->result_ = build_complex (build_ctype (e->type), build_float_cst (creall (e->value), tnext), build_float_cst (cimagl (e->value), tnext)); } /* Build a string literal, all strings are null terminated except for static arrays. */ void visit (StringExp *e) { Type *tb = e->type->toBasetype (); tree type = build_ctype (e->type); if (tb->ty == Tsarray) { /* Turn the string into a constructor for the static array. */ vec *elms = NULL; vec_safe_reserve (elms, e->len); tree etype = TREE_TYPE (type); for (size_t i = 0; i < e->len; i++) { tree value = build_integer_cst (e->charAt (i), etype); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } tree ctor = build_constructor (type, elms); TREE_CONSTANT (ctor) = 1; this->result_ = ctor; } else { /* Copy the string contents to a null terminated string. */ dinteger_t length = (e->len * e->sz); char *string = XALLOCAVEC (char, length + 1); memcpy (string, e->string, length); string[length] = '\0'; /* String value and type includes the null terminator. */ tree value = build_string (length, string); TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); value = build_address (value); if (tb->ty == Tarray) value = d_array_value (type, size_int (e->len), value); TREE_CONSTANT (value) = 1; this->result_ = d_convert (type, value); } } /* Build a tuple literal. Just an argument list that may have side effects that need evaluation. */ void visit (TupleExp *e) { tree result = NULL_TREE; if (e->e0) result = build_expr (e->e0); for (size_t i = 0; i < e->exps->dim; ++i) { Expression *exp = (*e->exps)[i]; result = compound_expr (result, build_expr (exp)); } if (result == NULL_TREE) result = void_node; this->result_ = result; } /* Build an array literal. The common type of the all elements is taken to be the type of the array element, and all elements are implicitly converted to that type. */ void visit (ArrayLiteralExp *e) { Type *tb = e->type->toBasetype (); /* Implicitly convert void[n] to ubyte[n]. */ if (tb->ty == Tsarray && tb->nextOf ()->toBasetype ()->ty == Tvoid) tb = Type::tuns8->sarrayOf (((TypeSArray *) tb)->dim->toUInteger ()); gcc_assert (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tpointer); /* Handle empty array literals. */ if (e->elements->dim == 0) { if (tb->ty == Tarray) this->result_ = d_array_value (build_ctype (e->type), size_int (0), null_pointer_node); else this->result_ = build_constructor (make_array_type (tb->nextOf (), 0), NULL); return; } /* Build an expression that assigns the expressions in ELEMENTS to a constructor. */ vec *elms = NULL; vec_safe_reserve (elms, e->elements->dim); bool constant_p = true; tree saved_elems = NULL_TREE; Type *etype = tb->nextOf (); tree satype = make_array_type (etype, e->elements->dim); for (size_t i = 0; i < e->elements->dim; i++) { Expression *expr = e->getElement (i); tree value = build_expr (expr, this->constp_); /* Only append nonzero values, the backend will zero out the rest of the constructor as we don't set CONSTRUCTOR_NO_CLEARING. */ if (!initializer_zerop (value)) { if (!TREE_CONSTANT (value)) constant_p = false; /* Split construction of values out of the constructor if there may be side effects. */ tree init = stabilize_expr (&value); if (init != NULL_TREE) saved_elems = compound_expr (saved_elems, init); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), convert_expr (value, expr->type, etype)); } } /* Now return the constructor as the correct type. For static arrays there is nothing else to do. For dynamic arrays, return a two field struct. For pointers, return the address. */ tree ctor = build_constructor (satype, elms); tree type = build_ctype (e->type); /* Nothing else to do for static arrays. */ if (tb->ty == Tsarray || this->constp_) { /* Can't take the address of the constructor, so create an anonymous static symbol, and then refer to it. */ if (tb->ty != Tsarray) { tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor, "A"); ctor = build_address (decl); if (tb->ty == Tarray) ctor = d_array_value (type, size_int (e->elements->dim), ctor); d_pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } /* If the array literal is readonly or static. */ if (constant_p) TREE_CONSTANT (ctor) = 1; if (constant_p && initializer_constant_valid_p (ctor, TREE_TYPE (ctor))) TREE_STATIC (ctor) = 1; this->result_ = compound_expr (saved_elems, d_convert (type, ctor)); } else { /* Allocate space on the memory managed heap. */ tree mem = build_libcall (LIBCALL_ARRAYLITERALTX, etype->pointerTo (), 2, build_typeinfo (e->loc, etype->arrayOf ()), size_int (e->elements->dim)); mem = d_save_expr (mem); /* Now copy the constructor into memory. */ tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY); tree size = size_mult_expr (size_int (e->elements->dim), size_int (tb->nextOf ()->size ())); tree result = build_call_expr (tmemcpy, 3, mem, build_address (ctor), size); /* Return the array pointed to by MEM. */ result = compound_expr (result, mem); if (tb->ty == Tarray) result = d_array_value (type, size_int (e->elements->dim), result); this->result_ = compound_expr (saved_elems, result); } } /* Build an associative array literal. The common type of the all keys is taken to be the key type, and common type of all values the value type. All keys and values are then implicitly converted as needed. */ void visit (AssocArrayLiteralExp *e) { /* Want the mutable type for typeinfo reference. */ Type *tb = e->type->toBasetype ()->mutableOf (); gcc_assert (tb->ty == Taarray); /* Handle empty assoc array literals. */ TypeAArray *ta = (TypeAArray *) tb; if (e->keys->dim == 0) { this->result_ = build_constructor (build_ctype (ta), NULL); return; } /* Build an expression that assigns all expressions in KEYS to a constructor. */ vec *kelts = NULL; vec_safe_reserve (kelts, e->keys->dim); for (size_t i = 0; i < e->keys->dim; i++) { Expression *key = (*e->keys)[i]; tree t = build_expr (key); CONSTRUCTOR_APPEND_ELT (kelts, size_int (i), convert_expr (t, key->type, ta->index)); } tree tkeys = make_array_type (ta->index, e->keys->dim); tree akeys = build_constructor (tkeys, kelts); /* Do the same with all expressions in VALUES. */ vec *velts = NULL; vec_safe_reserve (velts, e->values->dim); for (size_t i = 0; i < e->values->dim; i++) { Expression *value = (*e->values)[i]; tree t = build_expr (value); CONSTRUCTOR_APPEND_ELT (velts, size_int (i), convert_expr (t, value->type, ta->next)); } tree tvals = make_array_type (ta->next, e->values->dim); tree avals = build_constructor (tvals, velts); /* Generate: _d_assocarrayliteralTX (ti, keys, vals); */ tree keys = d_array_value (build_ctype (ta->index->arrayOf ()), size_int (e->keys->dim), build_address (akeys)); tree vals = d_array_value (build_ctype (ta->next->arrayOf ()), size_int (e->values->dim), build_address (avals)); tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3, build_typeinfo (e->loc, ta), keys, vals); /* Return an associative array pointed to by MEM. */ tree aatype = build_ctype (ta); vec *ce = NULL; CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem); this->result_ = build_nop (build_ctype (e->type), build_constructor (aatype, ce)); } /* Build a struct literal. */ void visit (StructLiteralExp *e) { /* Handle empty struct literals. */ if (e->elements == NULL || e->sd->fields.dim == 0) { this->result_ = build_constructor (build_ctype (e->type), NULL); return; } /* Building sinit trees are delayed until after frontend semantic processing has complete. Build the static initializer now. */ if (e->useStaticInit && !this->constp_) { this->result_ = aggregate_initializer_decl (e->sd); return; } /* Build a constructor that assigns the expressions in ELEMENTS at each field index that has been filled in. */ vec *ve = NULL; tree saved_elems = NULL_TREE; /* CTFE may fill the hidden pointer by NullExp. */ gcc_assert (e->elements->dim <= e->sd->fields.dim); Type *tb = e->type->toBasetype (); gcc_assert (tb->ty == Tstruct); for (size_t i = 0; i < e->elements->dim; i++) { Expression *exp = (*e->elements)[i]; if (!exp) continue; VarDeclaration *field = e->sd->fields[i]; Type *type = exp->type->toBasetype (); Type *ftype = field->type->toBasetype (); tree value = NULL_TREE; if (ftype->ty == Tsarray && !same_type_p (type, ftype)) { /* Initialize a static array with a single element. */ tree elem = build_expr (exp, this->constp_); elem = d_save_expr (elem); if (initializer_zerop (elem)) value = build_constructor (build_ctype (ftype), NULL); else value = build_array_from_val (ftype, elem); } else { value = convert_expr (build_expr (exp, this->constp_), exp->type, field->type); } /* Split construction of values out of the constructor. */ tree init = stabilize_expr (&value); if (init != NULL_TREE) saved_elems = compound_expr (saved_elems, init); CONSTRUCTOR_APPEND_ELT (ve, get_symbol_decl (field), value); } /* Maybe setup hidden pointer to outer scope context. */ if (e->sd->isNested () && e->elements->dim != e->sd->fields.dim && this->constp_ == false) { tree field = get_symbol_decl (e->sd->vthis); tree value = build_vthis (e->sd); CONSTRUCTOR_APPEND_ELT (ve, field, value); gcc_assert (e->useStaticInit == false); } /* Build a constructor in the correct shape of the aggregate type. */ tree ctor = build_struct_literal (build_ctype (e->type), ve); /* Nothing more to do for constant literals. */ if (this->constp_) { /* If the struct literal is a valid for static data. */ if (TREE_CONSTANT (ctor) && initializer_constant_valid_p (ctor, TREE_TYPE (ctor))) TREE_STATIC (ctor) = 1; this->result_ = compound_expr (saved_elems, ctor); return; } if (e->sym != NULL) { tree var = build_deref (e->sym); ctor = compound_expr (modify_expr (var, ctor), var); this->result_ = compound_expr (saved_elems, ctor); } else if (e->sd->isUnionDeclaration ()) { /* For unions, use memset to fill holes in the object. */ tree var = build_local_temp (TREE_TYPE (ctor)); tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET); tree init = build_call_expr (tmemset, 3, build_address (var), size_zero_node, size_int (e->sd->structsize)); init = compound_expr (init, saved_elems); init = compound_expr (init, modify_expr (var, ctor)); this->result_ = compound_expr (init, var); } else this->result_ = compound_expr (saved_elems, ctor); } /* Build a null literal. */ void visit (NullExp *e) { Type *tb = e->type->toBasetype (); tree value; /* Handle certain special case conversions, where the underlying type is an aggregate with a nullable interior pointer. */ if (tb->ty == Tarray) { /* For dynamic arrays, set length and pointer fields to zero. */ value = d_array_value (build_ctype (e->type), size_int (0), null_pointer_node); } else if (tb->ty == Taarray) { /* For associative arrays, set the pointer field to null. */ value = build_constructor (build_ctype (e->type), NULL); } else if (tb->ty == Tdelegate) { /* For delegates, set the frame and function pointer to null. */ value = build_delegate_cst (null_pointer_node, null_pointer_node, e->type); } else value = d_convert (build_ctype (e->type), integer_zero_node); TREE_CONSTANT (value) = 1; this->result_ = value; } /* Build a vector literal. */ void visit (VectorExp *e) { tree type = build_ctype (e->type); tree etype = TREE_TYPE (type); /* First handle array literal expressions. */ if (e->e1->op == TOKarrayliteral) { ArrayLiteralExp *ale = ((ArrayLiteralExp *) e->e1); vec *elms = NULL; bool constant_p = true; vec_safe_reserve (elms, ale->elements->dim); for (size_t i = 0; i < ale->elements->dim; i++) { Expression *expr = ale->getElement (i); tree value = d_convert (etype, build_expr (expr, this->constp_)); if (!CONSTANT_CLASS_P (value)) constant_p = false; CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } /* Build a VECTOR_CST from a constant vector constructor. */ if (constant_p) this->result_ = build_vector_from_ctor (type, elms); else this->result_ = build_constructor (type, elms); } else { /* Build constructor from single value. */ tree val = d_convert (etype, build_expr (e->e1, this->constp_)); this->result_ = build_vector_from_val (type, val); } } /* Build a static class literal, return its reference. */ void visit (ClassReferenceExp *e) { /* The result of build_new_class_expr is a RECORD_TYPE, we want the reference. */ tree var = build_address (build_new_class_expr (e)); /* If the type of this literal is an interface, the we must add the interface offset to symbol. */ if (this->constp_) { TypeClass *tc = (TypeClass *) e->type; InterfaceDeclaration *to = tc->sym->isInterfaceDeclaration (); if (to != NULL) { ClassDeclaration *from = e->originalClass (); int offset = 0; gcc_assert (to->isBaseOf (from, &offset) != 0); if (offset != 0) var = build_offset (var, size_int (offset)); } } this->result_ = var; } /* These expressions are mainly just a placeholders in the frontend. We shouldn't see them here. */ void visit (ScopeExp *e) { error_at (make_location_t (e->loc), "%qs is not an expression", e->toChars ()); this->result_ = error_mark_node; } void visit (TypeExp *e) { error_at (make_location_t (e->loc), "type %qs is not an expression", e->toChars ()); this->result_ = error_mark_node; } }; /* Main entry point for ExprVisitor interface to generate code for the Expression AST class E. If CONST_P is true, then E is a constant expression. */ tree build_expr (Expression *e, bool const_p) { ExprVisitor v = ExprVisitor (const_p); location_t saved_location = input_location; input_location = make_location_t (e->loc); e->accept (&v); tree expr = v.result (); input_location = saved_location; /* Check if initializer expression is valid constant. */ if (const_p && !initializer_constant_valid_p (expr, TREE_TYPE (expr))) { error_at (make_location_t (e->loc), "non-constant expression %qs", e->toChars ()); return error_mark_node; } return expr; } /* Same as build_expr, but also calls destructors on any temporaries. */ tree build_expr_dtor (Expression *e) { /* Codegen can be improved by determining if no exceptions can be thrown between the ctor and dtor, and eliminating the ctor and dtor. */ size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope); tree result = build_expr (e); if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope)) { result = fold_build_cleanup_point_expr (TREE_TYPE (result), result); vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars); } return result; } /* Same as build_expr_dtor, but handles the result of E as a return value. */ tree build_return_dtor (Expression *e, Type *type, TypeFunction *tf) { size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope); tree result = build_expr (e); /* Convert for initializing the DECL_RESULT. */ result = convert_expr (result, e->type, type); /* If we are returning a reference, take the address. */ if (tf->isref) result = build_address (result); /* The decl to store the return expression. */ tree decl = DECL_RESULT (cfun->decl); /* Split comma expressions, so that the result is returned directly. */ tree expr = stabilize_expr (&result); result = build_assign (INIT_EXPR, decl, result); result = compound_expr (expr, return_expr (result)); /* May nest the return expression inside the try/finally expression. */ if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope)) { result = fold_build_cleanup_point_expr (TREE_TYPE (result), result); vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars); } return result; } ================================================ FILE: gcc/d/gdc.texi ================================================ \input texinfo @c -*-texinfo-*- @setfilename gdc.info @settitle The GNU D Compiler @c Merge the standard indexes into a single one. @syncodeindex fn cp @syncodeindex vr cp @syncodeindex ky cp @syncodeindex pg cp @syncodeindex tp cp @include gcc-common.texi @c Copyright years for this manual. @set copyrights-d 2006-2018 @copying @c man begin COPYRIGHT Copyright @copyright{} @value{copyrights-d} Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the @c man end section entitled ``GNU Free Documentation License''. @ignore @c man begin COPYRIGHT man page gfdl(7). @c man end @end ignore @end copying @ifinfo @format @dircategory Software development @direntry * gdc: (gdc). A GCC-based compiler for the D language @end direntry @end format @insertcopying @end ifinfo @titlepage @title The GNU D Compiler @versionsubtitle @author David Friedman, Iain Buclaw @page @vskip 0pt plus 1filll Published by the Free Software Foundation @* 51 Franklin Street, Fifth Floor@* Boston, MA 02110-1301, USA@* @sp 1 @insertcopying @end titlepage @contents @page @node Top @top Introduction This manual describes how to use @command{gdc}, the GNU compiler for the D programming language. This manual is specifically about @command{gdc}. For more information about the D programming language in general, including language specifications and standard package documentation, see @uref{http://dlang.org/}. @menu * Copying:: The GNU General Public License. * GNU Free Documentation License:: How you can share and copy this manual. * Invoking gdc:: How to run gdc. * Index:: Index. @end menu @include gpl_v3.texi @include fdl.texi @node Invoking gdc @chapter Invoking gdc @c man title gdc A GCC-based compiler for the D language @ignore @c man begin SYNOPSIS gdc gdc [@option{-c}|@option{-S}] [@option{-g}] [@option{-pg}] [@option{-O}@var{level}] [@option{-W}@var{warn}@dots{}] [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}] [@option{-f}@var{option}@dots{}] [@option{-m}@var{machine-option}@dots{}] [@option{-o} @var{outfile}] [@@@var{file}] @var{infile}@dots{} Only the most useful options are listed here; see below for the remainder. @c man end @c man begin SEEALSO gpl(7), gfdl(7), fsf-funding(7), gcc(1) and the Info entries for @file{gdc} and @file{gcc}. @c man end @end ignore @c man begin DESCRIPTION gdc The @command{gdc} command is the GNU compiler for the D language and supports many of the same options as @command{gcc}. @xref{Option Summary, , Option Summary, gcc, Using the GNU Compiler Collection (GCC)}. This manual only documents the options specific to @command{gdc}. @c man end @menu * Input and Output files:: Controlling the kind of output: an executable, object files, assembler files, * Runtime Options:: Options controlling runtime behavior * Directory Options:: Where to find module files * Code Generation:: Options controlling the output of gdc * Warnings:: Options controlling warnings specific to gdc * Linking:: Options influencing the linking step * Developer Options:: Options useful for developers of gdc @end menu @c man begin OPTIONS @node Input and Output files @section Input and Output files @cindex suffixes for D source @cindex D source file suffixes For any given input file, the file name suffix determines what kind of compilation is done. The following kinds of input file names are supported: @table @gcctabopt @item @var{file}.d D source files. @item @var{file}.dd Ddoc source files. @item @var{file}.di D interface files. @end table You can specify more than one input file on the @command{gdc} command line, each being compiled separately in the compilation process. If you specify a @code{-o @var{file}} option, all the input files are compiled together, producing a single output file, named @var{file}. This is allowed even when using @code{-S} or @code{-c}. @cindex D interface files. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module. They can be created by @command{gdc} from a D source file by using the @code{-H} option. When the compiler resolves an import declaration, it searches for matching @file{.di} files first, then for @file{.d}. @cindex Ddoc source files. A Ddoc source file contains code in the D macro processor language. It is primarily designed for use in producing user documentation from embedded comments, with a slight affinity towards HTML generation. If a @file{.d} source file starts with the string @code{Ddoc} then it is treated as general purpose documentation, not as a D source file. @node Runtime Options @section Runtime Options @cindex options, runtime These options affect the runtime behavior of programs compiled with @command{gdc}. @table @gcctabopt @item -fall-instantiations @cindex @option{-fall-instantiations} @cindex @option{-fno-all-instantiations} Generate code for all template instantiations. The default template emission strategy is to not generate code for declarations that were either instantiated speculatively, such as from @code{__traits(compiles, ...)}, or that come from an imported module not being compiled. @item -fno-assert @cindex @option{-fassert} @cindex @option{-fno-assert} Turn off code generation for @code{assert} contracts. @item -fno-bounds-check @cindex @option{-fbounds-check} @cindex @option{-fno-bounds-check} Turns off array bounds checking for all functions, which can improve performance for code that uses arrays extensively. Note that this can result in unpredictable behavior if the code in question actually does violate array bounds constraints. It is safe to use this option if you are sure that your code never throws a @code{RangeError}. @item -fbounds-check=@var{value} @cindex @option{-fbounds-check=} An alternative to @option{-fbounds-check} that allows more control as to where bounds checking is turned on or off. The following values are supported: @table @samp @item on Turns on array bounds checking for all functions. @item safeonly Turns on array bounds checking only for @code{@@safe} functions. @item off Turns off array bounds checking completely. @end table @item -fno-builtin @cindex @option{-fbuiltin} @cindex @option{-fno-builtin} Don't recognize built-in functions unless they begin with the prefix @samp{__builtin_}. By default, the compiler will recognize when a function in the @code{core.stdc} package is a built-in function. @item -fdebug @item -fdebug=@var{value} @cindex @option{-fdebug} @cindex @option{-fno-debug} Turn on compilation of conditional @code{debug} code into the program. The @option{-fdebug} option itself sets the debug level to @code{1}, while @option{-fdebug=} enables @code{debug} code that are identified by any of the following values: @table @samp @item level Sets the debug level to @var{level}, any @code{debug} code <= @var{level} is compiled into the program. @item ident Turns on compilation of any @code{debug} code identified by @var{ident}. @end table @item -fno-invariants @cindex @option{-finvariants} @cindex @option{-fno-invariants} Turns off code generation for class @code{invariant} contracts. @item -fno-moduleinfo @cindex @option{-fmoduleinfo} @cindex @option{-fno-moduleinfo} Turns off generation of the @code{ModuleInfo} and related functions that would become unreferenced without it, which may allow linking to programs not written in D. Functions that are not be generated include module constructors and destructors (@code{static this} and @code{static ~this}), @code{unittest} code, and @code{DSO} registry functions for dynamically linked code. @item -fonly=@var{filename} @cindex @option{-fonly} Tells the compiler to parse and run semantic analysis on all modules on the command line, but only generate code for the module specified by @var{filename}. @item -fno-postconditions @cindex @option{-fpostconditions} @cindex @option{-fno-postconditions} Turns off code generation for postcondition @code{out} contracts. @item -fno-preconditions @cindex @option{-fpreconditions} @cindex @option{-fno-preconditions} Turns off code generation for precondition @code{in} contracts. @item -frelease @cindex @option{-frelease} @cindex @option{-fno-release} Turns on compiling in release mode, which means not emitting runtime checks for contracts and asserts. Array bounds checking is not done for @code{@@system} and @code{@@trusted} functions, and assertion failures are undefined behavior. This is equivalent to compiling with the following options: @example gdc -fno-assert -fbounds-check=safe -fno-invariants \ -fno-postconditions -fno-preconditions -fno-switch-errors @end example @item -fno-switch-errors @cindex @option{-fswitch-errors} @cindex @option{-fno-switch-errors} This option controls what code is generated when no case is matched in a @code{final switch} statement. The default run time behavior is to throw a @code{SwitchError}. Turning off @option{-fswitch-errors} means that instead the execution of the program is immediately halted. @item -funittest @cindex @option{-funittest} @cindex @option{-fno-unittest} Turns on compilation of @code{unittest} code, and turns on the @code{version(unittest)} identifier. This implies @option{-fassert}. @item -fversion=@var{value} @cindex @option{-fversion} Turns on compilation of conditional @code{version} code into the program identified by any of the following values: @table @samp @item level Sets the version level to @var{level}, any @code{version} code >= @var{level} is compiled into the program. @item ident Turns on compilation of @code{version} code identified by @var{ident}. @end table @item -fno-weak @cindex @option{-fweak} @cindex @option{-fno-weak} Turns off emission of instantiated declarations that can be defined in multiple objects as weak or one-only symbols. The default is to emit all public symbols as weak, unless the target lacks support for weak symbols. Disabling this option means that common symbols are instead put in COMDAT or become private. @end table @node Directory Options @section Options for Directory Search @cindex directory options @cindex options, directory search @cindex search path These options specify directories to search for files, libraries, and other parts of the compiler: @table @gcctabopt @item -I@var{dir} @cindex @option{-I} Specify a directory to use when searching for imported modules at compile time. Multiple @option{-I} options can be used, and the paths are searched in the same order. @item -J@var{dir} @cindex @option{-J} Specify a directory to use when searching for files in string imports at compile time. This switch is required in order to use @code{import(file)} expressions. Multiple @option{-J} options can be used, and the paths are searched in the same order. @item -L@var{dir} @cindex @option{-L} When linking, specify a library search directory, as with @command{gcc}. @item -B@var{dir} @cindex @option{-B} This option specifies where to find the executables, libraries, source files, and data files of the compiler itself, as with @command{gcc}. @item -fmodule-file=@var{module}=@var{spec} @cindex @option{-fmodule-file} This option manipulates file paths of imported modules, such that if an imported module matches all or the leftmost part of @var{module}, the file path in @var{spec} is used as the location to search for D sources. This is used when the source file path and names are not the same as the package and module hierarchy. Consider the following examples: @example gdc test.d -fmodule-file=A.B=foo.d -fmodule-file=C=bar @end example This will tell the compiler to search in all import paths for the source file @var{foo.d} when importing @var{A.B}, and the directory @var{bar/} when importing @var{C}, as annotated in the following D code: @example module test; import A.B; // Matches A.B, searches for foo.d import C.D.E; // Matches C, searches for bar/D/E.d import A.B.C; // No match, searches for A/B/C.d @end example @item -imultilib @var{dir} @cindex @option{-imultilib} Use @var{dir} as a subdirectory of the gcc directory containing target-specific D sources and interfaces. @item -iprefix @var{prefix} @cindex @option{-iprefix} Specify @var{prefix} as the prefix for the gcc directory containing target-specific D sources and interfaces. If the @var{prefix} represents a directory, you should include the final @code{'/'}. @item -nostdinc @cindex @option{-nostdinc} Do not search the standard system directories for D source and interface files. Only the directories that have been specified with @option{-I} options (and the directory of the current file, if appropriate) are searched. @end table @node Code Generation @section Code Generation @cindex options, code generation In addition to the many @command{gcc} options controlling code generation, @command{gdc} has several options specific to itself. @table @gcctabopt @item -H @cindex @option{-H} Generates D interface files for all modules being compiled. The compiler determines the output file based on the name of the input file, removes any directory components and suffix, and applies the @file{.di} suffix. @item -Hd @var{dir} @cindex @option{-Hd} Same as @option{-H}, but writes interface files to directory @var{dir}. This option can be used with @option{-Hf @var{file}} to independently set the output file and directory path. @item -Hf @var{file} @cindex @option{-Hf} Same as @option{-H} but writes interface files to @var{file}. This option can be used with @option{-Hd @var{dir}} to independently set the output file and directory path. @item -M @cindex @option{-M} Output the module dependencies of all source files being compiled in a format suitable for @command{make}. The compiler outputs one @command{make} rule containing the object file name for that source file, a colon, and the names of all imported files. @item -MM @cindex @option{-MM} Like @option{-M} but does not mention imported modules from the D standard library package directories. @item -MF @var{file} @cindex @option{-MF} When used with @option{-M} or @option{-MM}, specifies a @var{file} to write the dependencies to. When used with the driver options @option{-MD} or @option{-MMD}, @option{-MF} overrides the default dependency output file. @item -MG @cindex @option{-MG} This option is for compatibility with @command{gcc}, and is ignored by the compiler. @item -MP @cindex @option{-MP} Outputs a phony target for each dependency other than the modules being compiled, causing each to depend on nothing. @item -MT @var{target} @cindex @option{-MT} Change the @var{target} of the rule emitted by dependency generation to be exactly the string you specify. If you want multiple targets, you can specify them as a single argument to @option{-MT}, or use multiple @option{-MT} options. @item -MQ @var{target} @cindex @option{-MQ} Same as @option{-MT}, but it quotes any characters which are special to @command{make}. @item -MD @cindex @option{-MD} This option is equivalent to @option{-M -MF @var{file}}. The driver determines @var{file} by removing any directory components and suffix from the input file, and then adding a @file{.deps} suffix. @item -MMD @cindex @option{-MMD} Like @option{-MD} but does not mention imported modules from the D standard library package directories. @item -X @cindex @option{-X} Output information describing the contents of all source files being compiled in JSON format to a file. The driver determines @var{file} by removing any directory components and suffix from the input file, and then adding a @file{.json} suffix. @item -Xf @var{file} @cindex @option{-Xf} Same as @option{-X}, but writes all JSON contents to the specified @var{file}. @item -fdoc @cindex @option{-fdoc} Generates @code{Ddoc} documentation and writes it to a file. The compiler determines @var{file} by removing any directory components and suffix from the input file, and then adding a @file{.html} suffix. @item -fdoc-dir=@var{dir} @cindex @option{-fdoc-dir} Same as @option{-fdoc}, but writes documentation to directory @var{dir}. This option can be used with @option{-fdoc-file=@var{file}} to independently set the output file and directory path. @item -fdoc-file=@var{file} @cindex @option{-fdoc-file} Same as @option{-fdoc}, but writes documentation to @var{file}. This option can be used with @option{-fdoc-dir=@var{dir}} to independently set the output file and directory path. @item -fdoc-inc=@var{file} @cindex @option{-fdoc-inc} Specify @var{file} as a @var{Ddoc} macro file to be read. Multiple @option{-fdoc-inc} options can be used, and files are read and processed in the same order. @end table @node Warnings @section Warnings @cindex options to control warnings @cindex warning messages @cindex messages, warning @cindex suppressing warnings Warnings are diagnostic messages that report constructions that are not inherently erroneous but that are risky or suggest there is likely to be a bug in the program. Unless @option{-Werror} is specified, they do not prevent compilation of the program. @table @gcctabopt @item -Wall @cindex @option{-Wall} @cindex @option{-Wno-all} Turns on all warnings messages. Warnings are not a defined part of the D language, and all constructs for which this may generate a warning message are valid code. @item -Walloca @cindex @option{-Walloca} This option warns on all uses of "alloca" in the source. @item -Walloca-larger-than=@var{n} @cindex @option{-Walloca-larger-than} @cindex @option{-Wno-alloca-larger-than} Warn on unbounded uses of alloca, and on bounded uses of alloca whose bound can be larger than @var{n} bytes. @option{-Wno-alloca-larger-than} disables @option{-Walloca-larger-than} warning and is equivalent to @option{-Walloca-larger-than=@var{SIZE_MAX}} or larger. @item -Wcast-result @cindex @option{-Wcast-result} @cindex @option{-Wno-cast-result} Warn about casts that will produce a null or zero result. Currently this is only done for casting between an imaginary and non-imaginary data type, or casting between a D and C++ class. @item -Wno-deprecated @cindex @option{-Wdeprecated} @cindex @option{-Wno-deprecated} Do not warn about usage of deprecated features and symbols with @code{deprecated} attributes. @item -Werror @cindex @option{-Werror} @cindex @option{-Wno-error} Turns all warnings into errors. @item -Wspeculative @cindex @option{-Wspeculative} @cindex @option{-Wno-speculative} List all error messages from speculative compiles, such as @code{__traits(compiles, ...)}. This option does not report messages as warnings, and these messages therefore never become errors when the @option{-Werror} option is also used. @item -Wtemplates @cindex @option{-Wtemplates} @cindex @option{-Wno-templates} Warn when a template instantiation is encountered. Some coding rules disallow templates, and this may be used to enforce that rule. @item -Wunknown-pragmas @cindex @option{-Wunknown-pragmas} @cindex @option{-Wno-unknown-pragmas} Warn when a @code{pragma()} is encountered that is not understood by @command{gdc}. This differs from @option{-fignore-unknown-pragmas} where a pragma that is part of the D language, but not implemented by the compiler, won't get reported. @item -fignore-unknown-pragmas @cindex @option{-fignore-unknown-pragmas} @cindex @option{-fno-ignore-unknown-pragmas} Turns off errors for unsupported pragmas. @item -fmax-errors=@var{n} @cindex @option{-fmax-errors} Limits the maximum number of error messages to @var{n}, at which point @command{gdc} bails out rather than attempting to continue processing the source code. If @var{n} is 0 (the default), there is no limit on the number of error messages produced. @item -fsyntax-only @cindex @option{-fsyntax-only} @cindex @option{-fno-syntax-only} Check the code for syntax errors, but do not actually compile it. This can be used in conjunction with @option{-fdoc} or @option{-H} to generate files for each module present on the command-line, but no other output file. @item -ftransition=@var{id} @cindex @option{-ftransition} Report additional information about D language changes identified by @var{id}. The following values are supported: @table @samp @item all List information on all language changes. @item checkimports Give deprecation messages about @option{-ftransition=import} anomalies. @item complex List all usages of complex or imaginary types. @item dip1000 Implements @uref{http://wiki.dlang.org/DIP1000} (experimental). @item dip25 Implements @uref{http://wiki.dlang.org/DIP25} (experimental). @item field List all non-mutable fields which occupy an object instance. @item import Tells the compiler to revert to using an old lookup behavior for resolving unqualified symbol names, where this was done in a single pass, ignoring any protection attributes. The default name lookup strategy is to use two passes, the first ignoring imported declarations, and the second only looking at imports. The protection (@code{private}, @code{package}, @code{protected}) of symbols is also enforced to resolve any conflicts between private and public symbols. @item nogc List all hidden GC allocations. @item tls List all variables going into thread local storage. @end table @end table @node Linking @section Options for Linking @cindex options, linking @cindex linking, static These options come into play when the compiler links object files into an executable output file. They are meaningless if the compiler is not doing a link step. @table @gcctabopt @item -defaultlib @var{libname} @cindex @option{-defaultlib} Specify the library to use instead of libphobos when linking. Options specifying the linkage of libphobos, such as @option{-static-libphobos} or @option{-shared-libphobos}, are ignored. @item -debuglib @cindex @option{-debuglib} Specify the debug library to use instead of libphobos when linking. This option has no effect unless the @option{-g} option was also given on the command line. Options specifying the linkage of libphobos, such as @option{-static-libphobos} or @option{-shared-libphobos}, are ignored. @item -nophoboslib @cindex @option{-nophoboslib} Do not use the Phobos or D runtime library when linking. Options specifying the linkage of libphobos, such as @option{-static-libphobos} or @option{-shared-libphobos}, are ignored. The standard system libraries are used normally, unless @option{-nostdlib} or @option{-nodefaultlibs} is used. @item -shared-libphobos @cindex @option{-shared-libphobos} On systems that provide @file{libgphobos} and @file{libgdruntime} as a shared and a static library, this option forces the use of the shared version. If no shared version was built when the compiler was configured, this option has no effect. @item -static-libphobos @cindex @option{-static-libphobos} On systems that provide @file{libgphobos} and @file{libgdruntime} as a shared and a static library, this option forces the use of the static version. If no static version was built when the compiler was configured, this option has no effect. @end table @node Developer Options @section Developer Options @cindex developer options @cindex debug dump options @cindex dump options This section describes command-line options that are primarily of interest to developers or language tooling. @table @gcctabopt @item -fdump-d-original @cindex @option{-fdump-d-original} Output the internal front-end AST after the @code{semantic3} stage. This option is only useful for debugging the GNU D compiler itself. @item -v @cindex @option{-v} Dump information about the compiler language processing stages as the source program is being compiled. This includes listing all modules that are processed through the @code{parse}, @code{semantic}, @code{semantic2}, and @code{semantic3} stages; all @code{import} modules and their file paths; and all @code{function} bodies that are being compiled. @end table @c man end @node Index @unnumbered Index @printindex cp @bye ================================================ FILE: gcc/d/imports.cc ================================================ /* imports.cc -- Build imported modules/declarations. Copyright (C) 2014-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/declaration.h" #include "dmd/enum.h" #include "dmd/identifier.h" #include "dmd/import.h" #include "dmd/module.h" #include "tree.h" #include "stringpool.h" #include "d-tree.h" /* Implements the visitor interface to build debug trees for all module and import declarations, where ISYM holds the cached back-end representation to be returned. */ class ImportVisitor : public Visitor { using Visitor::visit; /* Build the declaration DECL as an imported symbol. */ tree make_import (tree decl) { gcc_assert (decl != NULL_TREE); tree import = build_decl (input_location, IMPORTED_DECL, DECL_NAME (decl), void_type_node); IMPORTED_DECL_ASSOCIATED_DECL (import) = decl; d_keep (import); return import; } public: ImportVisitor (void) { } /* This should be overridden by each symbol class. */ void visit (Dsymbol *) { gcc_unreachable (); } /* Build the module decl for M, this is considered toplevel, regardless of whether there are any parent packages in the module system. */ void visit (Module *m) { Loc loc = (m->md != NULL) ? m->md->loc : Loc (m->srcfile->toChars (), 1, 0); m->isym = build_decl (make_location_t (loc), NAMESPACE_DECL, get_identifier (m->toPrettyChars ()), void_type_node); d_keep (m->isym); if (!m->isRoot ()) DECL_EXTERNAL (m->isym) = 1; TREE_PUBLIC (m->isym) = 1; DECL_CONTEXT (m->isym) = NULL_TREE; } /* Build an import of another module symbol. */ void visit (Import *m) { tree module = build_import_decl (m->mod); m->isym = this->make_import (module); } /* Build an import for any kind of user defined type. Use the TYPE_DECL associated with the type symbol. */ void visit (EnumDeclaration *d) { tree type = build_ctype (d->type); /* Not all kinds of D enums create a TYPE_DECL. */ if (TREE_CODE (type) == ENUMERAL_TYPE) d->isym = this->make_import (TYPE_STUB_DECL (type)); } void visit (AggregateDeclaration *d) { tree type = build_ctype (d->type); d->isym = this->make_import (TYPE_STUB_DECL (type)); } void visit (ClassDeclaration *d) { /* Want the RECORD_TYPE, not POINTER_TYPE. */ tree type = TREE_TYPE (build_ctype (d->type)); d->isym = this->make_import (TYPE_STUB_DECL (type)); } /* For now, ignore importing other kinds of dsymbols. */ void visit (ScopeDsymbol *) { } /* Alias symbols aren't imported, but their targets are. */ void visit (AliasDeclaration *d) { Dsymbol *dsym = d->toAlias (); if (dsym == d) { Type *type = d->getType (); /* Type imports should really be part of their own visit method. */ if (type != NULL) { if (type->ty == Tenum) dsym = ((TypeEnum *) type)->sym; else if (type->ty == Tstruct) dsym = ((TypeStruct *) type)->sym; else if (type->ty == Tclass) dsym = ((TypeClass *) type)->sym; } } /* This symbol is really an alias for another, visit the other. */ if (dsym != d) { dsym->accept (this); d->isym = dsym->isym; } } /* Visit the underlying alias symbol of overloadable aliases. */ void visit (OverDeclaration *d) { if (d->aliassym != NULL) { d->aliassym->accept (this); d->isym = d->aliassym->isym; } } /* Function aliases are the same as alias symbols. */ void visit (FuncAliasDeclaration *d) { FuncDeclaration *fd = d->toAliasFunc (); if (fd != NULL) { fd->accept (this); d->isym = fd->isym; } } /* Skip over importing templates and tuples. */ void visit (TemplateDeclaration *) { } void visit (TupleDeclaration *) { } /* Import any other kind of declaration. If the class does not implement symbol generation routines, the compiler will throw an error. */ void visit (Declaration *d) { d->isym = this->make_import (get_symbol_decl (d)); } }; /* Build a declaration for the symbol D that can be used for the debug_hook imported_module_or_decl. */ tree build_import_decl (Dsymbol *d) { if (!d->isym) { location_t saved_location = input_location; ImportVisitor v; input_location = make_location_t (d->loc); d->accept (&v); input_location = saved_location; } /* Not all visitors set 'isym'. */ return d->isym ? d->isym : NULL_TREE; } ================================================ FILE: gcc/d/intrinsics.cc ================================================ /* intrinsics.cc -- D language compiler intrinsics. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/declaration.h" #include "dmd/identifier.h" #include "dmd/mangle.h" #include "dmd/module.h" #include "dmd/template.h" #include "tm.h" #include "function.h" #include "tree.h" #include "fold-const.h" #include "stringpool.h" #include "builtins.h" #include "d-tree.h" /* An internal struct used to hold information on D intrinsics. */ struct intrinsic_decl { /* The DECL_FUNCTION_CODE of this decl. */ intrinsic_code code; /* The name of the intrinsic. */ const char *name; /* The module where the intrinsic is located. */ const char *module; /* The mangled signature decoration of the intrinsic. */ const char *deco; /* True if the intrinsic is only handled in CTFE. */ bool ctfeonly; }; static const intrinsic_decl intrinsic_decls[] = { #define DEF_D_INTRINSIC(CODE, ALIAS, NAME, MODULE, DECO, CTFE) \ { INTRINSIC_ ## ALIAS, NAME, MODULE, DECO, CTFE }, #include "intrinsics.def" #undef DEF_D_INTRINSIC }; /* Checks if DECL is an intrinsic or run time library function that requires special processing. Sets DECL_INTRINSIC_CODE so it can be identified later in maybe_expand_intrinsic. */ void maybe_set_intrinsic (FuncDeclaration *decl) { if (!decl->ident || decl->builtin != BUILTINunknown) return; /* The builtin flag is updated only if we can evaluate the intrinsic at compile-time. Such as the math or bitop intrinsics. */ decl->builtin = BUILTINno; /* Check if it's a compiler intrinsic. We only require that any internally recognised intrinsics are declared in a module with an explicit module declaration. */ Module *m = decl->getModule (); if (!m || !m->md) return; TemplateInstance *ti = decl->isInstantiated (); TemplateDeclaration *td = ti ? ti->tempdecl->isTemplateDeclaration () : NULL; const char *tname = decl->ident->toChars (); const char *tmodule = m->md->toChars (); const char *tdeco = (td == NULL) ? decl->type->deco : NULL; /* Look through all D intrinsics. */ for (size_t i = 0; i < (int) INTRINSIC_LAST; i++) { if (!intrinsic_decls[i].name) continue; if (strcmp (intrinsic_decls[i].name, tname) != 0 || strcmp (intrinsic_decls[i].module, tmodule) != 0) continue; /* Instantiated functions would have the wrong type deco, get it from the template member instead. */ if (tdeco == NULL) { if (!td || !td->onemember) return; FuncDeclaration *fd = td->onemember->isFuncDeclaration (); if (fd == NULL) return; OutBuffer buf; mangleToBuffer (fd->type, &buf); tdeco = buf.extractString (); } /* Matching the type deco may be a bit too strict, as it means that all function attributes that end up in the signature must be kept aligned between the compiler and library declaration. */ if (strcmp (intrinsic_decls[i].deco, tdeco) == 0) { intrinsic_code code = intrinsic_decls[i].code; if (decl->csym == NULL) get_symbol_decl (decl); /* If there is no function body, then the implementation is always provided by the compiler. */ if (!decl->fbody) { DECL_BUILT_IN_CLASS (decl->csym) = BUILT_IN_FRONTEND; DECL_FUNCTION_CODE (decl->csym) = (built_in_function) code; } /* Infer whether the intrinsic can be used for CTFE, let the front-end know that it can be evaluated at compile-time. */ switch (code) { case INTRINSIC_VA_ARG: case INTRINSIC_C_VA_ARG: case INTRINSIC_VASTART: case INTRINSIC_ADDS: case INTRINSIC_SUBS: case INTRINSIC_MULS: case INTRINSIC_NEGS: case INTRINSIC_VLOAD: case INTRINSIC_VSTORE: break; case INTRINSIC_POW: { /* Check that this overload of pow() is has an equivalent built-in function. It could be `int pow(int, int)'. */ tree rettype = TREE_TYPE (TREE_TYPE (decl->csym)); if (mathfn_built_in (rettype, BUILT_IN_POW) != NULL_TREE) decl->builtin = BUILTINyes; break; } default: decl->builtin = BUILTINyes; break; } /* The intrinsic was marked as CTFE-only. */ if (intrinsic_decls[i].ctfeonly) DECL_BUILT_IN_CTFE (decl->csym) = 1; DECL_INTRINSIC_CODE (decl->csym) = code; break; } } } /* Construct a function call to the built-in function CODE, N is the number of arguments, and the `...' parameters are the argument expressions. The original call expression is held in CALLEXP. */ static tree call_builtin_fn (tree callexp, built_in_function code, int n, ...) { tree *argarray = XALLOCAVEC (tree, n); va_list ap; va_start (ap, n); for (int i = 0; i < n; i++) argarray[i] = va_arg (ap, tree); va_end (ap); tree exp = build_call_expr_loc_array (EXPR_LOCATION (callexp), builtin_decl_explicit (code), n, argarray); return convert (TREE_TYPE (callexp), fold (exp)); } /* Expand a front-end instrinsic call to bsf(). This takes one argument, the signature to which can be either: int bsf (uint arg); int bsf (ulong arg); This scans all bits in the given argument starting with the first, returning the bit number of the first bit set. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_bsf (tree callexp) { /* The bsr() intrinsic gets turned into __builtin_ctz(arg). The return value is supposed to be undefined if arg is zero. */ tree arg = CALL_EXPR_ARG (callexp, 0); int argsize = TYPE_PRECISION (TREE_TYPE (arg)); /* Which variant of __builtin_ctz* should we call? */ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CTZ : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CTZL : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CTZLL : END_BUILTINS; gcc_assert (code != END_BUILTINS); return call_builtin_fn (callexp, code, 1, arg); } /* Expand a front-end instrinsic call to bsr(). This takes one argument, the signature to which can be either: int bsr (uint arg); int bsr (ulong arg); This scans all bits in the given argument from the most significant bit to the least significant, returning the bit number of the first bit set. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_bsr (tree callexp) { /* The bsr() intrinsic gets turned into (size - 1) - __builtin_clz(arg). The return value is supposed to be undefined if arg is zero. */ tree arg = CALL_EXPR_ARG (callexp, 0); tree type = TREE_TYPE (arg); int argsize = TYPE_PRECISION (type); /* Which variant of __builtin_clz* should we call? */ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CLZ : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CLZL : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CLZLL : END_BUILTINS; gcc_assert (code != END_BUILTINS); tree result = call_builtin_fn (callexp, code, 1, arg); /* Handle int -> long conversions. */ if (TREE_TYPE (result) != type) result = fold_convert (type, result); result = fold_build2 (MINUS_EXPR, type, build_integer_cst (argsize - 1, type), result); return fold_convert (TREE_TYPE (callexp), result); } /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to bt(), btc(), btr(), or bts(). These intrinsics expect to take two arguments, the signature to which is: int bt (size_t* ptr, size_t bitnum); All intrinsics test if a bit is set and return the result of that condition. Variants of `bt' will then update that bit. `btc' compliments the bit, `bts' sets the bit, and `btr' resets the bit. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_bt (intrinsic_code intrinsic, tree callexp) { tree ptr = CALL_EXPR_ARG (callexp, 0); tree bitnum = CALL_EXPR_ARG (callexp, 1); tree type = TREE_TYPE (TREE_TYPE (ptr)); /* size_t bitsize = sizeof(*ptr) * BITS_PER_UNIT; */ tree bitsize = fold_convert (type, TYPE_SIZE (type)); /* ptr[bitnum / bitsize] */ ptr = build_array_index (ptr, fold_build2 (TRUNC_DIV_EXPR, type, bitnum, bitsize)); ptr = indirect_ref (type, ptr); /* mask = 1 << (bitnum % bitsize); */ bitnum = fold_build2 (TRUNC_MOD_EXPR, type, bitnum, bitsize); bitnum = fold_build2 (LSHIFT_EXPR, type, size_one_node, bitnum); /* cond = ptr[bitnum / size] & mask; */ tree cond = fold_build2 (BIT_AND_EXPR, type, ptr, bitnum); /* cond ? -1 : 0; */ cond = build_condition (TREE_TYPE (callexp), d_truthvalue_conversion (cond), integer_minus_one_node, integer_zero_node); /* Update the bit as needed, only testing the bit for bt(). */ if (intrinsic == INTRINSIC_BT) return cond; tree_code code = (intrinsic == INTRINSIC_BTC) ? BIT_XOR_EXPR : (intrinsic == INTRINSIC_BTR) ? BIT_AND_EXPR : (intrinsic == INTRINSIC_BTS) ? BIT_IOR_EXPR : ERROR_MARK; gcc_assert (code != ERROR_MARK); /* ptr[bitnum / size] op= mask; */ if (intrinsic == INTRINSIC_BTR) bitnum = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bitnum), bitnum); ptr = modify_expr (ptr, fold_build2 (code, TREE_TYPE (ptr), ptr, bitnum)); /* Store the condition result in a temporary, and return expressions in correct order of evaluation. */ tree tmp = build_local_temp (TREE_TYPE (callexp)); cond = modify_expr (tmp, cond); return compound_expr (cond, compound_expr (ptr, tmp)); } /* Expand a front-end intrinsic call to bswap(). This takes one argument, the signature to which can be either: int bswap (uint arg); int bswap (ulong arg); This swaps all bytes in an N byte type end-to-end. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_bswap (tree callexp) { tree arg = CALL_EXPR_ARG (callexp, 0); int argsize = TYPE_PRECISION (TREE_TYPE (arg)); /* Which variant of __builtin_bswap* should we call? */ built_in_function code = (argsize == 32) ? BUILT_IN_BSWAP32 : (argsize == 64) ? BUILT_IN_BSWAP64 : END_BUILTINS; gcc_assert (code != END_BUILTINS); return call_builtin_fn (callexp, code, 1, arg); } /* Expand a front-end intrinsic call to popcnt(). This takes one argument, the signature to which can be either: int popcnt (uint arg); int popcnt (ulong arg); Calculates the number of set bits in an integer. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_popcnt (tree callexp) { tree arg = CALL_EXPR_ARG (callexp, 0); int argsize = TYPE_PRECISION (TREE_TYPE (arg)); /* Which variant of __builtin_popcount* should we call? */ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_POPCOUNT : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTL : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTLL : END_BUILTINS; gcc_assert (code != END_BUILTINS); return call_builtin_fn (callexp, code, 1, arg); } /* Expand a front-end intrinsic call to INTRINSIC, which is either a call to sqrt(), sqrtf(), sqrtl(). These intrinsics expect to take one argument, the signature to which can be either: float sqrt (float arg); double sqrt (double arg); real sqrt (real arg); This computes the square root of the given argument. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_sqrt (intrinsic_code intrinsic, tree callexp) { tree arg = CALL_EXPR_ARG (callexp, 0); /* Which variant of __builtin_sqrt* should we call? */ built_in_function code = (intrinsic == INTRINSIC_SQRT) ? BUILT_IN_SQRT : (intrinsic == INTRINSIC_SQRTF) ? BUILT_IN_SQRTF : (intrinsic == INTRINSIC_SQRTL) ? BUILT_IN_SQRTL : END_BUILTINS; gcc_assert (code != END_BUILTINS); return call_builtin_fn (callexp, code, 1, arg); } /* Expand a front-end intrinsic call to copysign(). This takes two arguments, the signature to which can be either: float copysign (T to, float from); double copysign (T to, double from); real copysign (T to, real from); This computes a value composed of TO with the sign bit of FROM. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_copysign (tree callexp) { tree to = CALL_EXPR_ARG (callexp, 0); tree from = CALL_EXPR_ARG (callexp, 1); tree type = TREE_TYPE (to); /* Convert parameters to the same type. Prefer the first parameter unless it is an integral type. */ if (INTEGRAL_TYPE_P (type)) { to = fold_convert (TREE_TYPE (from), to); type = TREE_TYPE (to); } else from = fold_convert (type, from); /* Which variant of __builtin_copysign* should we call? */ tree builtin = mathfn_built_in (type, BUILT_IN_COPYSIGN); gcc_assert (builtin != NULL_TREE); return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2, to, from); } /* Expand a front-end intrinsic call to pow(). This takes two arguments, the signature to which can be either: float pow (float base, T exponent); double pow (double base, T exponent); real pow (real base, T exponent); This computes the value of BASE raised to the power of EXPONENT. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_pow (tree callexp) { tree base = CALL_EXPR_ARG (callexp, 0); tree exponent = CALL_EXPR_ARG (callexp, 1); tree exptype = TREE_TYPE (exponent); /* Which variant of __builtin_pow* should we call? */ built_in_function code = SCALAR_FLOAT_TYPE_P (exptype) ? BUILT_IN_POW : INTEGRAL_TYPE_P (exptype) ? BUILT_IN_POWI : END_BUILTINS; gcc_assert (code != END_BUILTINS); tree builtin = mathfn_built_in (TREE_TYPE (base), code); gcc_assert (builtin != NULL_TREE); return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2, base, exponent); } /* Expand a front-end intrinsic call to va_arg(). This takes either one or two arguments, the signature to which can be either: T va_arg(T) (ref va_list ap); void va_arg(T) (va_list ap, ref T parmn); This retrieves the next variadic parameter that is type T from the given va_list. If also given, store the value into parmn, otherwise return it. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_vaarg (tree callexp) { tree ap = CALL_EXPR_ARG (callexp, 0); tree parmn = NULL_TREE; tree type; STRIP_NOPS (ap); if (call_expr_nargs (callexp) == 1) type = TREE_TYPE (callexp); else { parmn = CALL_EXPR_ARG (callexp, 1); STRIP_NOPS (parmn); gcc_assert (TREE_CODE (parmn) == ADDR_EXPR); parmn = TREE_OPERAND (parmn, 0); type = TREE_TYPE (parmn); } /* (T) VA_ARG_EXP; */ tree exp = build1 (VA_ARG_EXPR, type, ap); /* parmn = (T) VA_ARG_EXP; */ if (parmn != NULL_TREE) exp = modify_expr (parmn, exp); return exp; } /* Expand a front-end intrinsic call to va_start(), which takes two arguments, the signature to which is: void va_start(T) (out va_list ap, ref T parmn); This initializes the va_list type, where parmn should be the last named parameter. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_vastart (tree callexp) { tree ap = CALL_EXPR_ARG (callexp, 0); tree parmn = CALL_EXPR_ARG (callexp, 1); STRIP_NOPS (ap); STRIP_NOPS (parmn); /* The va_list argument should already have its address taken. The second argument, however, is inout and that needs to be fixed to prevent a warning. Could be casting, so need to check type too? */ gcc_assert (TREE_CODE (ap) == ADDR_EXPR && TREE_CODE (parmn) == ADDR_EXPR); /* Assuming nobody tries to change the return type. */ parmn = TREE_OPERAND (parmn, 0); return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn); } /* Expand a front-end instrinsic call to INTRINSIC, which is either a call to adds(), addu(), subs(), subu(), negs(), muls(), or mulu(). These intrinsics expect to take two or three arguments, the signature to which can be either: int adds (int x, int y, ref bool overflow); long adds (long x, long y, ref bool overflow); int negs (int x, ref bool overflow); long negs (long x, ref bool overflow); This performs an operation on two signed or unsigned integers, checking for overflow. The overflow is sticky, meaning that a sequence of operations can be done and overflow need only be checked at the end. The original call expression is held in CALLEXP. */ static tree expand_intrinsic_checkedint (intrinsic_code intrinsic, tree callexp) { tree type = TREE_TYPE (callexp); tree x; tree y; tree overflow; /* The negs() intrinsic gets turned into SUB_OVERFLOW (0, y). */ if (intrinsic == INTRINSIC_NEGS) { x = fold_convert (type, integer_zero_node); y = CALL_EXPR_ARG (callexp, 0); overflow = CALL_EXPR_ARG (callexp, 1); } else { x = CALL_EXPR_ARG (callexp, 0); y = CALL_EXPR_ARG (callexp, 1); overflow = CALL_EXPR_ARG (callexp, 2); } /* Which variant of *_OVERFLOW should we generate? */ internal_fn icode = (intrinsic == INTRINSIC_ADDS) ? IFN_ADD_OVERFLOW : (intrinsic == INTRINSIC_SUBS) ? IFN_SUB_OVERFLOW : (intrinsic == INTRINSIC_MULS) ? IFN_MUL_OVERFLOW : (intrinsic == INTRINSIC_NEGS) ? IFN_SUB_OVERFLOW : IFN_LAST; gcc_assert (icode != IFN_LAST); tree result = build_call_expr_internal_loc (EXPR_LOCATION (callexp), icode, build_complex_type (type), 2, x, y); STRIP_NOPS (overflow); overflow = build_deref (overflow); /* Assign returned result to overflow parameter, however if overflow is already true, maintain its value. */ type = TREE_TYPE (overflow); result = save_expr (result); tree exp = fold_build2 (BIT_IOR_EXPR, type, overflow, fold_convert (type, imaginary_part (result))); exp = modify_expr (overflow, exp); /* Return the value of result. */ return compound_expr (exp, real_part (result)); } /* Expand a front-end instrinsic call to volatileLoad(). This takes one argument, the signature to which can be either: ubyte volatileLoad (ubyte* ptr); ushort volatileLoad (ushort* ptr); uint volatileLoad (uint* ptr); ulong volatileLoad (ulong* ptr); This reads a value from the memory location indicated by ptr. Calls to them are be guaranteed to not be removed (such as during DCE) or reordered in the same thread. The original call expression is held in CALLEXP. */ static tree expand_volatile_load (tree callexp) { tree ptr = CALL_EXPR_ARG (callexp, 0); tree ptrtype = TREE_TYPE (ptr); gcc_assert (POINTER_TYPE_P (ptrtype)); /* (T) *(volatile T *) ptr; */ tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE); tree result = indirect_ref (type, ptr); TREE_THIS_VOLATILE (result) = 1; return result; } /* Expand a front-end instrinsic call to volatileStore(). This takes two arguments, the signature to which can be either: void volatileStore (ubyte* ptr, ubyte value); void volatileStore (ushort* ptr, ushort value); void volatileStore (uint* ptr, uint value); void volatileStore (ulong* ptr, ulong value); This writes a value to the memory location indicated by ptr. Calls to them are be guaranteed to not be removed (such as during DCE) or reordered in the same thread. The original call expression is held in CALLEXP. */ static tree expand_volatile_store (tree callexp) { tree ptr = CALL_EXPR_ARG (callexp, 0); tree ptrtype = TREE_TYPE (ptr); gcc_assert (POINTER_TYPE_P (ptrtype)); /* (T) *(volatile T *) ptr; */ tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE); tree result = indirect_ref (type, ptr); TREE_THIS_VOLATILE (result) = 1; /* (*(volatile T *) ptr) = value; */ tree value = CALL_EXPR_ARG (callexp, 1); return modify_expr (result, value); } /* If CALLEXP is for an intrinsic , expand and return inlined compiler generated instructions. Most map directly to GCC builtins, others require a little extra work around them. */ tree maybe_expand_intrinsic (tree callexp) { tree callee = CALL_EXPR_FN (callexp); if (TREE_CODE (callee) == ADDR_EXPR) callee = TREE_OPERAND (callee, 0); if (TREE_CODE (callee) != FUNCTION_DECL) return callexp; /* Don't expand CTFE-only intrinsics outside of semantic processing. */ if (DECL_BUILT_IN_CTFE (callee) && !doing_semantic_analysis_p) return callexp; intrinsic_code intrinsic = DECL_INTRINSIC_CODE (callee); built_in_function code; switch (intrinsic) { case INTRINSIC_NONE: return callexp; case INTRINSIC_BSF: return expand_intrinsic_bsf (callexp); case INTRINSIC_BSR: return expand_intrinsic_bsr (callexp); case INTRINSIC_BT: case INTRINSIC_BTC: case INTRINSIC_BTR: case INTRINSIC_BTS: return expand_intrinsic_bt (intrinsic, callexp); case INTRINSIC_BSWAP: return expand_intrinsic_bswap (callexp); case INTRINSIC_POPCNT: return expand_intrinsic_popcnt (callexp); case INTRINSIC_COS: return call_builtin_fn (callexp, BUILT_IN_COSL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_SIN: return call_builtin_fn (callexp, BUILT_IN_SINL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_RNDTOL: /* Not sure if llroundl stands as a good replacement for the expected behavior of rndtol. */ return call_builtin_fn (callexp, BUILT_IN_LLROUNDL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_SQRT: case INTRINSIC_SQRTF: case INTRINSIC_SQRTL: return expand_intrinsic_sqrt (intrinsic, callexp); case INTRINSIC_LDEXP: return call_builtin_fn (callexp, BUILT_IN_LDEXPL, 2, CALL_EXPR_ARG (callexp, 0), CALL_EXPR_ARG (callexp, 1)); case INTRINSIC_FABS: return call_builtin_fn (callexp, BUILT_IN_FABSL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_RINT: return call_builtin_fn (callexp, BUILT_IN_RINTL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_TAN: return call_builtin_fn (callexp, BUILT_IN_TANL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_ISNAN: return call_builtin_fn (callexp, BUILT_IN_ISNAN, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_ISINFINITY: return call_builtin_fn (callexp, BUILT_IN_ISINF, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_ISFINITE: return call_builtin_fn (callexp, BUILT_IN_ISFINITE, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_EXP: return call_builtin_fn (callexp, BUILT_IN_EXPL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_EXPM1: return call_builtin_fn (callexp, BUILT_IN_EXPM1L, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_EXP2: return call_builtin_fn (callexp, BUILT_IN_EXP2L, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_LOG: return call_builtin_fn (callexp, BUILT_IN_LOGL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_LOG2: return call_builtin_fn (callexp, BUILT_IN_LOG2L, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_LOG10: return call_builtin_fn (callexp, BUILT_IN_LOG10L, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_ROUND: return call_builtin_fn (callexp, BUILT_IN_ROUNDL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_FLOORF: case INTRINSIC_FLOOR: case INTRINSIC_FLOORL: code = (intrinsic == INTRINSIC_FLOOR) ? BUILT_IN_FLOOR : (intrinsic == INTRINSIC_FLOORF) ? BUILT_IN_FLOORF : BUILT_IN_FLOORL; return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_CEILF: case INTRINSIC_CEIL: case INTRINSIC_CEILL: code = (intrinsic == INTRINSIC_CEIL) ? BUILT_IN_CEIL : (intrinsic == INTRINSIC_CEILF) ? BUILT_IN_CEILF : BUILT_IN_CEILL; return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_TRUNC: return call_builtin_fn (callexp, BUILT_IN_TRUNCL, 1, CALL_EXPR_ARG (callexp, 0)); case INTRINSIC_FMIN: return call_builtin_fn (callexp, BUILT_IN_FMINL, 2, CALL_EXPR_ARG (callexp, 0), CALL_EXPR_ARG (callexp, 1)); case INTRINSIC_FMAX: return call_builtin_fn (callexp, BUILT_IN_FMAXL, 2, CALL_EXPR_ARG (callexp, 0), CALL_EXPR_ARG (callexp, 1)); case INTRINSIC_COPYSIGN: return expand_intrinsic_copysign (callexp); case INTRINSIC_POW: return expand_intrinsic_pow (callexp); case INTRINSIC_FMA: return call_builtin_fn (callexp, BUILT_IN_FMAL, 3, CALL_EXPR_ARG (callexp, 0), CALL_EXPR_ARG (callexp, 1), CALL_EXPR_ARG (callexp, 2)); case INTRINSIC_VA_ARG: case INTRINSIC_C_VA_ARG: return expand_intrinsic_vaarg (callexp); case INTRINSIC_VASTART: return expand_intrinsic_vastart (callexp); case INTRINSIC_ADDS: case INTRINSIC_SUBS: case INTRINSIC_MULS: case INTRINSIC_NEGS: return expand_intrinsic_checkedint (intrinsic, callexp); case INTRINSIC_VLOAD: return expand_volatile_load (callexp); case INTRINSIC_VSTORE: return expand_volatile_store (callexp); default: gcc_unreachable (); } } ================================================ FILE: gcc/d/intrinsics.def ================================================ /* intrinsics.def -- Definitions for D compiler intrinsics. Copyright (C) 2014-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* DEF_D_INTRINSIC (CODE, ALIAS, NAME, MODULE, DECO, CTFE) CODE The enum code used to refer to this intrinsic. ALIAS The enum code used to reference the function DECL_FUNCTION_CODE, if there are multiple modules or decos for a single intrinsic, they would all refer to this code. NAME The name of this intrinsic as a string. MODULE The name of the module which the intrinsic belongs to as a string. DECO The function signature decoration of the intrinsic. CTFE True if the function is only handled as a built-in during CTFE, otherwise the runtime implementation is used. Used for declaring internally recognized functions that either map to a GCC builtin, or are specially handled by the compiler. */ /* A D built-in that has no runtime implementation. */ #define DEF_D_BUILTIN(C, A, N, M, D) \ DEF_D_INTRINSIC (C, A, N, M, D, false) /* A D built-in that is specially recognized only during CTFE. */ #define DEF_CTFE_BUILTIN(C, A, N, M, D) \ DEF_D_INTRINSIC (C, A, N, M, D, true) DEF_D_BUILTIN (NONE, NONE, 0, 0, 0) /* core.bitop intrinsics. */ DEF_D_BUILTIN (BSF, BSF, "bsf", "core.bitop", "FNaNbNiNfkZi") DEF_D_BUILTIN (BSR, BSR, "bsr", "core.bitop", "FNaNbNiNfkZi") DEF_D_BUILTIN (BT, BT, "bt", "core.bitop", "FNaNbNixPkkZi") DEF_D_BUILTIN (BTC, BTC, "btc", "core.bitop", "FNaNbNiPkkZi") DEF_D_BUILTIN (BTR, BTR, "btr", "core.bitop", "FNaNbNiPkkZi") DEF_D_BUILTIN (BTS, BTS, "bts", "core.bitop", "FNaNbNiPkkZi") DEF_D_BUILTIN (BSF64, BSF, "bsf", "core.bitop", "FNaNbNiNfmZi") DEF_D_BUILTIN (BSR64, BSR, "bsr", "core.bitop", "FNaNbNiNfmZi") DEF_D_BUILTIN (BT64, BT, "bt", "core.bitop", "FNaNbNixPmmZi") DEF_D_BUILTIN (BTC64, BTC, "btc", "core.bitop", "FNaNbNiPmmZi") DEF_D_BUILTIN (BTR64, BTR, "btr", "core.bitop", "FNaNbNiPmmZi") DEF_D_BUILTIN (BTS64, BTS, "bts", "core.bitop", "FNaNbNiPmmZi") DEF_D_BUILTIN (BSWAP, BSWAP, "bswap", "core.bitop", "FNaNbNiNfkZk") DEF_D_BUILTIN (BSWAP64, BSWAP, "bswap", "core.bitop", "FNaNbNiNfmZm") DEF_D_BUILTIN (POPCNT, POPCNT, "popcnt", "core.bitop", "FNaNbNiNfkZi") DEF_D_BUILTIN (POPCNT64, POPCNT, "popcnt", "core.bitop", "FNaNbNiNfmZi") DEF_D_BUILTIN (VLOAD, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPhZh") DEF_D_BUILTIN (VLOAD16, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPtZt") DEF_D_BUILTIN (VLOAD32, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPkZk") DEF_D_BUILTIN (VLOAD64, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPmZm") DEF_D_BUILTIN (VSTORE, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPhhZv") DEF_D_BUILTIN (VSTORE16, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPttZv") DEF_D_BUILTIN (VSTORE32, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPkkZv") DEF_D_BUILTIN (VSTORE64, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPmmZv") /* core.checkedint intrinsics. */ DEF_D_BUILTIN (ADDS, ADDS, "adds", "core.checkedint", "FNaNbNiNfiiKbZi") DEF_D_BUILTIN (ADDSL, ADDS, "adds", "core.checkedint", "FNaNbNiNfllKbZl") DEF_D_BUILTIN (ADDU, ADDS, "addu", "core.checkedint", "FNaNbNiNfkkKbZk") DEF_D_BUILTIN (ADDUL, ADDS, "addu", "core.checkedint", "FNaNbNiNfmmKbZm") DEF_D_BUILTIN (SUBS, SUBS, "subs", "core.checkedint", "FNaNbNiNfiiKbZi") DEF_D_BUILTIN (SUBSL, SUBS, "subs", "core.checkedint", "FNaNbNiNfllKbZl") DEF_D_BUILTIN (SUBU, SUBS, "subu", "core.checkedint", "FNaNbNiNfkkKbZk") DEF_D_BUILTIN (SUBUL, SUBS, "subu", "core.checkedint", "FNaNbNiNfmmKbZm") DEF_D_BUILTIN (MULS, MULS, "muls", "core.checkedint", "FNaNbNiNfiiKbZi") DEF_D_BUILTIN (MULSL, MULS, "muls", "core.checkedint", "FNaNbNiNfllKbZl") DEF_D_BUILTIN (MULU, MULS, "mulu", "core.checkedint", "FNaNbNiNfkkKbZk") DEF_D_BUILTIN (MULUI, MULS, "mulu", "core.checkedint", "FNaNbNiNfmkKbZm") DEF_D_BUILTIN (MULUL, MULS, "mulu", "core.checkedint", "FNaNbNiNfmmKbZm") DEF_D_BUILTIN (NEGS, NEGS, "negs", "core.checkedint", "FNaNbNiNfiKbZi") DEF_D_BUILTIN (NEGSL, NEGS, "negs", "core.checkedint", "FNaNbNiNflKbZl") /* core.math intrinsics. */ DEF_D_BUILTIN (COS, COS, "cos", "core.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (FABS, FABS, "fabs", "core.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (LDEXP, LDEXP, "ldexp", "core.math", "FNaNbNiNfeiZe") DEF_D_BUILTIN (RINT, RINT, "rint", "core.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (RNDTOL, RNDTOL, "rndtol", "core.math", "FNaNbNiNfeZl") DEF_D_BUILTIN (SIN, SIN, "sin", "core.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (SQRTF, SQRTF, "sqrt", "core.math", "FNaNbNiNffZf") DEF_D_BUILTIN (SQRT, SQRT, "sqrt", "core.math", "FNaNbNiNfdZd") DEF_D_BUILTIN (SQRTL, SQRTL, "sqrt", "core.math", "FNaNbNiNfeZe") /* std.math intrinsics. */ DEF_D_BUILTIN (STD_COS, COS, "cos", "std.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (STD_FABS, FABS, "fabs", "std.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (STD_LDEXP, LDEXP, "ldexp", "std.math", "FNaNbNiNfeiZe") DEF_D_BUILTIN (STD_RINT, RINT, "rint", "std.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (STD_RNDTOL, RNDTOL, "rndtol", "std.math", "FNaNbNiNfeZl") DEF_D_BUILTIN (STD_SIN, SIN, "sin", "std.math", "FNaNbNiNfeZe") DEF_D_BUILTIN (STD_SQRTF, SQRTF, "sqrt", "std.math", "FNaNbNiNffZf") DEF_D_BUILTIN (STD_SQRT, SQRT, "sqrt", "std.math", "FNaNbNiNfdZd") DEF_D_BUILTIN (STD_SQRTL, SQRTL, "sqrt", "std.math", "FNaNbNiNfeZe") DEF_CTFE_BUILTIN (TAN, TAN, "tan", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (ISNAN, ISNAN, "isNaN", "std.math", "FNaNbNiNeI1XZb") DEF_CTFE_BUILTIN (ISINFINITY, ISINFINITY, "isInfinity", "std.math", "FNaNbNiNeI1XZb") DEF_CTFE_BUILTIN (ISFINITE, ISFINITE, "isFinite", "std.math", "FNaNbNiNeI1XZb") DEF_CTFE_BUILTIN (EXP, EXP, "exp", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (EXPM1, EXPM1, "expm1", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (EXP2, EXP2, "exp2", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (LOG, LOG, "log", "std.math", "FNaNbNiNfeZe") DEF_CTFE_BUILTIN (LOG2, LOG2, "log2", "std.math", "FNaNbNiNfeZe") DEF_CTFE_BUILTIN (LOG10, LOG10, "log10", "std.math", "FNaNbNiNfeZe") DEF_CTFE_BUILTIN (ROUND, ROUND, "round", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (FLOORF, FLOORF, "floor", "std.math", "FNaNbNiNefZf") DEF_CTFE_BUILTIN (FLOOR, FLOOR, "floor", "std.math", "FNaNbNiNedZd") DEF_CTFE_BUILTIN (FLOORL, FLOORL, "floor", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (CEILF, CEILF, "ceil", "std.math", "FNaNbNiNefZf") DEF_CTFE_BUILTIN (CEIL, CEIL, "ceil", "std.math", "FNaNbNiNedZd") DEF_CTFE_BUILTIN (CEILL, CEILL, "ceil", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (TRUNC, TRUNC, "trunc", "std.math", "FNaNbNiNeeZe") DEF_CTFE_BUILTIN (FMIN, FMIN, "fmin", "std.math", "FNaNbNiNfeeZe") DEF_CTFE_BUILTIN (FMAX, FMAX, "fmax", "std.math", "FNaNbNiNfeeZe") DEF_CTFE_BUILTIN (COPYSIGN, COPYSIGN, "copysign", "std.math", "FNaNbNiNeI1RI1XZI1R") DEF_CTFE_BUILTIN (COPYSIGNI, COPYSIGN, "copysign", "std.math", "FNaNbNiNeI1XI1RZI1R") DEF_CTFE_BUILTIN (POW, POW, "pow", "std.math", "FNaNbNiNeI1FI1GZ@") DEF_CTFE_BUILTIN (FMA, FMA, "fma", "std.math", "FNaNbNiNfeeeZe") /* core.stdc.stdarg intrinsics. */ DEF_D_BUILTIN (VA_ARG, VA_ARG, "va_arg", "core.stdc.stdarg", "FKI7va_listKI1TZv") DEF_D_BUILTIN (C_VA_ARG, C_VA_ARG, "va_arg", "core.stdc.stdarg", "FKI7va_listZI1T") DEF_D_BUILTIN (VASTART, VASTART, "va_start", "core.stdc.stdarg", "FJI7va_listKI1TZv") #undef DEF_D_BUILTIN #undef DEF_CTFE_BUILTIN ================================================ FILE: gcc/d/lang-specs.h ================================================ /* lang-specs.h -- GCC driver specs for D frontend. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* This is the contribution to the `default_compilers' array in gcc.c for the D language. */ {".d", "@d", 0, 1, 0 }, {".dd", "@d", 0, 1, 0 }, {".di", "@d", 0, 1, 0 }, {"@d", "%{!E:d21 %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \ %{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \ %{X:-Xf %b.json} %{Xf*} \ %{v} %{!fsyntax-only:%(invoke_as)}}", 0, 1, 0 }, ================================================ FILE: gcc/d/lang.opt ================================================ ; lang.opt -- Options for the D front end. ; Copyright (C) 2006-2018 Free Software Foundation, Inc. ; ; GCC is free software; you can redistribute it and/or modify it under ; the terms of the GNU General Public License as published by the Free ; Software Foundation; either version 3, or (at your option) any later ; version. ; ; GCC is distributed in the hope that it will be useful, but WITHOUT ANY ; WARRANTY; without even the implied warranty of MERCHANTABILITY or ; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ; for more details. ; ; You should have received a copy of the GNU General Public License ; along with GCC; see the file COPYING3. If not see ; . ; See the GCC internals manual for a description of this file's format. ; Please try to keep this file in ASCII collating order. Language D -dependencies D Alias(M) ; Documented in C -print-missing-file-dependencies D Alias(MG) ; Documented in C -user-dependencies D Alias(MM) ; Documented in C -write-dependencies D NoDriverArg Separate Alias(MD) ; Documented in C -write-user-dependencies D NoDriverArg Separate Alias(MMD) ; Documented in C H D ; Different from documented use in C. Hd D Joined Separate -Hd Write D interface files to directory . Hf D Joined Separate -Hf Write D interface to . I D Joined Separate ; Documented in C J D Joined Separate ; Different from documented use in Fortran. M D ; Documented in C MD D Separate NoDriverArg ; Documented in C MF D Joined Separate ; Documented in C MG D ; Documented in C MM D ; Documented in C MMD D Separate NoDriverArg ; Documented in C MP D ; Documented in C MT D Joined Separate ; Documented in C MQ D Joined Separate ; Documented in C Waddress D Warning Var(warn_address) ; Documented in C Wall D ; Documented in C Wcast-result D Warning Var(warn_cast_result) Warn about casts that will produce a null result. Wdeprecated D ; Documented in C Werror D ; Documented in common.opt Walloca D ; Documented in C Walloca-larger-than= D ; Documented in C Wno-alloca-larger-than D ; Documented in C Wspeculative D Warn from speculative compiles such as __traits(compiles). Wtemplates D ; Documented in C Wunknown-pragmas D LangEnabledBy(D, Wall) ; Documented in C X D Generate JSON file. Xf D Joined Separate -Xf Write JSON output to the given . debuglib= Driver Joined Debug library to use instead of phobos. defaultlib= Driver Joined Default library to use instead of phobos. -verbose D Alias(v) fall-instantiations D Generate code for all template instantiations. fassert D Var(flag_assert) Generate code for assert contracts. fbounds-check D ; Documented in common.opt fbounds-check= D Joined RejectNegative Enum(bounds_check) Var(flag_bounds_check) -fbounds-check=[on|safeonly|off] Turn array bounds checks on, in @safe code only, or off. Enum Name(bounds_check) Type(int) UnknownError(unknown array bounds setting %qs) EnumValue Enum(bounds_check) String(off) Value(0) EnumValue Enum(bounds_check) String(safeonly) Value(1) EnumValue Enum(bounds_check) String(on) Value(2) fbuiltin D Var(flag_no_builtin, 0) ; Documented in C fdebug D Compile in debug code. fdebug= D Joined RejectNegative -fdebug= Compile in debug code, code <= , or code identified by . fdoc D Generate documentation. fdoc-dir= D Joined RejectNegative -fdoc-dir= Write documentation file to directory . fdoc-file= D Joined RejectNegative -fdoc-file= Write documentation to . fdoc-inc= D Joined RejectNegative -fdoc-inc= Include a Ddoc macro . fdruntime D Assume that standard D runtime libraries and \"D main\" exist. fdump-d-original D Display the frontend AST after parsing and semantic passes. fignore-unknown-pragmas D Ignore unsupported pragmas. finvariants D Var(flag_invariants) Generate code for class invariant contracts. fmain D RejectNegative Generate a default D main() function when compiling. fmodule-file= D Joined RejectNegative -fmodule-file== use as source file for . fmoduleinfo D Var(flag_moduleinfo) Generate ModuleInfo struct for output module. fonly= D Joined RejectNegative Process all modules specified on the command line, but only generate code for the module specified by the argument. fpostconditions D Var(flag_postconditions) Generate code for postcondition contracts. fpreconditions D Var(flag_preconditions) Generate code for precondition contracts. frelease D Compile release version. frtti D ; Documented in C fswitch-errors D Var(flag_switch_errors) Generate code for switches without a default case. ftransition=all D RejectNegative List information on all language changes. ftransition=checkimports D RejectNegative Give deprecation messages about -ftransition=import anomalies. ftransition=complex D RejectNegative List all usages of complex or imaginary types. ftransition=dip1000 D RejectNegative Implement DIP1000: Scoped pointers (experimental). ftransition=dip1008 D RejectNegative Implement DIP1008: Allow exceptions in @nogc code (experimental). ftransition=dip25 D RejectNegative Implement DIP25: Sealed references (experimental). ftransition=dtorfields D RejectNegative Destruct fields of partially constructed objects. ftransition=field D RejectNegative List all non-mutable fields which occupy an object instance. ftransition=import D RejectNegative Revert to single phase name lookup. ftransition=intpromote D RejectNegative Use C-style integral promotion for unary '+', '-' and '~'. ftransition=nogc D RejectNegative List all hidden GC allocations. ftransition=tls D RejectNegative List all variables going into thread local storage. funittest D Compile in unittest code. fversion= D Joined RejectNegative -fversion= Compile in version code >= or identified by . fweak D Var(flag_weak) Init(1) Emit common-like symbols as weak symbols. imultilib D Joined Separate ; Documented in C iprefix D Joined Separate ; Documented in C isysroot D Joined Separate ; Documented in C isystem D Joined Separate ; Documented in C nophoboslib Driver Do not link the standard D library in the compilation. nostdinc D ; Documented in C static-libphobos Driver Link the standard D library statically in the compilation. shared-libphobos Driver Link the standard D library dynamically in the compilation. v D ; Documented in C ================================================ FILE: gcc/d/longdouble.h ================================================ /* longdouble.h -- Definitions of floating-point access for the frontend. Copyright (C) 2015-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #ifndef GCC_D_LONGDOUBLE_H #define GCC_D_LONGDOUBLE_H struct real_value; class Type; struct longdouble { public: /* Return the hidden real_value from the longdouble type. */ const real_value& rv (void) const { return *(const real_value *) this; } real_value& rv (void) { return *(real_value *) this; } /* Normalize the value to be the precision supported by target. */ longdouble normalize (void); /* No constructor to be able to use this class in a union. */ template longdouble& operator = (T x) { set (x); return *this; } /* Lvalue operators. */ void set (real_value& d); void set (int32_t d); void set (int64_t d); void set (uint32_t d); void set (uint64_t d); void set (bool d); /* Rvalue operators. */ bool to_bool () const; int64_t to_int () const; uint64_t to_uint () const; operator int32_t (void) { return (int32_t) this->to_int (); } operator int64_t (void) { return this->to_int (); } operator uint32_t (void) { return (uint32_t) this->to_uint (); } operator uint64_t (void) { return this->to_uint (); } operator bool (void) { return this->to_bool (); } /* Arithmetic operators. */ longdouble add (const longdouble& r) const; longdouble sub (const longdouble& r) const; longdouble mul (const longdouble& r) const; longdouble div (const longdouble& r) const; longdouble mod (const longdouble& r) const; longdouble neg () const; longdouble operator + (const longdouble& r) { return this->add (r); } longdouble operator - (const longdouble& r) { return this->sub (r); } longdouble operator * (const longdouble& r) { return this->mul (r); } longdouble operator / (const longdouble& r) { return this->div (r); } longdouble operator % (const longdouble& r) { return this->mod (r); } longdouble operator -() { return this->neg (); } /* Comparison operators. */ int cmp (const longdouble& t) const; int equals (const longdouble& t) const; bool operator < (const longdouble& r) { return this->cmp (r) < 0; } bool operator <= (const longdouble& r) { return this->cmp (r) <= 0; } bool operator > (const longdouble& r) { return this->cmp (r) > 0; } bool operator >= (const longdouble& r) { return this->cmp (r) >= 0; } bool operator == (const longdouble& r) { return this->equals (r); } bool operator != (const longdouble& r) { return !this->equals (r); } private: /* Including gcc/real.h presents too many problems, so just statically allocate enough space for REAL_VALUE_TYPE. */ long realvalue[(2 + (16 + sizeof (long)) / sizeof (long))]; }; /* Declared, but "volatile" is not required. */ typedef longdouble volatile_longdouble; /* Use ldouble() to explicitly create a longdouble value. */ template inline longdouble ldouble (T x) { longdouble d; d.set (x); return d; } #endif /* GCC_D_LONGDOUBLE_H */ ================================================ FILE: gcc/d/modules.cc ================================================ /* modules.cc -- D module initialization and termination. Copyright (C) 2013-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/declaration.h" #include "dmd/identifier.h" #include "dmd/module.h" #include "tree.h" #include "fold-const.h" #include "tm.h" #include "function.h" #include "cgraph.h" #include "stor-layout.h" #include "toplev.h" #include "target.h" #include "common/common-target.h" #include "stringpool.h" #include "d-tree.h" /* D generates module information to inform the runtime library which modules need some kind of special handling. All `static this()', `static ~this()', and `unittest' functions for a given module are aggregated into a single function - one for each kind - and a pointer to that function is inserted into the ModuleInfo instance for that module. Module information for a particular module is indicated with an ABI defined structure derived from ModuleInfo. ModuleInfo is a variably sized struct with two fixed base fields. The first field `flags' determines what information is packed immediately after the record type. Like TypeInfo, the runtime library provides the definitions of the ModuleInfo structure, as well as accessors for the variadic fields. So we only define layout compatible POD_structs for ModuleInfo. */ /* The internally represented ModuleInfo and CompilerDSO types. */ static tree moduleinfo_type; static tree compiler_dso_type; static tree dso_registry_fn; /* The DSO slot for use by the druntime implementation. */ static tree dso_slot_node; /* For registering and deregistering DSOs with druntime, we have one global constructor and destructor per object that calls _d_dso_registry with the respective DSO record. To ensure that this is only done once, a `dso_initialized' variable is introduced to guard repeated calls. */ static tree dso_initialized_node; /* The beginning and end of the `minfo' section. */ static tree start_minfo_node; static tree stop_minfo_node; /* Record information about module initialization, termination, unit testing, and thread local storage in the compilation. */ struct GTY(()) module_info { vec *ctors; vec *dtors; vec *ctorgates; vec *sharedctors; vec *shareddtors; vec *sharedctorgates; vec *unitTests; }; /* These must match the values in libdruntime/object_.d. */ enum module_info_flags { MIctorstart = 0x1, MIctordone = 0x2, MIstandalone = 0x4, MItlsctor = 0x8, MItlsdtor = 0x10, MIctor = 0x20, MIdtor = 0x40, MIxgetMembers = 0x80, MIictor = 0x100, MIunitTest = 0x200, MIimportedModules = 0x400, MIlocalClasses = 0x800, MIname = 0x1000 }; /* The ModuleInfo information structure for the module currently being compiled. Assuming that only ever process one at a time. */ static module_info *current_moduleinfo; /* The declaration of the current module being compiled. */ static Module *current_module_decl; /* Static constructors and destructors (not D `static this'). */ static GTY(()) vec *static_ctor_list; static GTY(()) vec *static_dtor_list; /* Returns an internal function identified by IDENT. This is used by both module initialization and dso handlers. */ static FuncDeclaration * get_internal_fn (tree ident) { Module *mod = current_module_decl; const char *name = IDENTIFIER_POINTER (ident); if (!mod) mod = Module::rootModule; if (name[0] == '*') { tree s = mangle_internal_decl (mod, name + 1, "FZv"); name = IDENTIFIER_POINTER (s); } FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid, Identifier::idPool (name)); fd->loc = Loc (mod->srcfile->toChars (), 1, 0); fd->parent = mod; fd->protection.kind = Prot::private_; fd->semanticRun = PASSsemantic3done; return fd; } /* Generate an internal function identified by IDENT. The function body to add is in EXPR. */ static tree build_internal_fn (tree ident, tree expr) { FuncDeclaration *fd = get_internal_fn (ident); tree decl = get_symbol_decl (fd); tree old_context = start_function (fd); rest_of_decl_compilation (decl, 1, 0); add_stmt (expr); finish_function (old_context); /* D static ctors, static dtors, unittests, and the ModuleInfo chain function are always private. */ TREE_PUBLIC (decl) = 0; TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; return decl; } /* Build and emit a function identified by IDENT that increments (in order) all variables in GATES, then calls the list of functions in FUNCTIONS. */ static tree build_funcs_gates_fn (tree ident, vec *functions, vec *gates) { tree expr_list = NULL_TREE; /* Increment gates first. */ for (size_t i = 0; i < vec_safe_length (gates); i++) { tree decl = (*gates)[i]; tree value = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, integer_one_node); tree var_expr = modify_expr (decl, value); expr_list = compound_expr (expr_list, var_expr); } /* Call Functions. */ for (size_t i = 0; i < vec_safe_length (functions); i++) { tree decl = (*functions)[i]; tree call_expr = build_call_expr (decl, 0); expr_list = compound_expr (expr_list, call_expr); } if (expr_list) return build_internal_fn (ident, expr_list); return NULL_TREE; } /* Return the type for ModuleInfo, create it if it doesn't already exist. */ static tree get_moduleinfo_type (void) { if (moduleinfo_type) return moduleinfo_type; /* Layout of ModuleInfo is: uint flags; uint index; */ tree fields = create_field_decl (d_uint_type, NULL, 1, 1); DECL_CHAIN (fields) = create_field_decl (d_uint_type, NULL, 1, 1); moduleinfo_type = make_node (RECORD_TYPE); finish_builtin_struct (moduleinfo_type, "ModuleInfo", fields, NULL_TREE); return moduleinfo_type; } /* Get the VAR_DECL of the ModuleInfo for DECL. If this does not yet exist, create it. The ModuleInfo decl is used to keep track of constructors, destructors, unittests, members, classes, and imports for the given module. This is used by the D runtime for module initialization and termination. */ static tree get_moduleinfo_decl (Module *decl) { if (decl->csym) return decl->csym; tree ident = mangle_internal_decl (decl, "__ModuleInfo", "Z"); tree type = get_moduleinfo_type (); decl->csym = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL); DECL_CONTEXT (decl->csym) = build_import_decl (decl); /* Not readonly, moduleinit depends on this. */ TREE_READONLY (decl->csym) = 0; return decl->csym; } /* Return the type for CompilerDSOData, create it if it doesn't exist. */ static tree get_compiler_dso_type (void) { if (compiler_dso_type) return compiler_dso_type; /* Layout of CompilerDSOData is: size_t version; void** slot; ModuleInfo** _minfo_beg; ModuleInfo** _minfo_end; FuncTable* _deh_beg; FuncTable* _deh_end; Note, finish_builtin_struct() expects these fields in reverse order. */ tree fields = create_field_decl (ptr_type_node, NULL, 1, 1); tree field = create_field_decl (ptr_type_node, NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; field = create_field_decl (build_pointer_type (get_moduleinfo_type ()), NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; field = create_field_decl (build_pointer_type (get_moduleinfo_type ()), NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; field = create_field_decl (build_pointer_type (ptr_type_node), NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; field = create_field_decl (size_type_node, NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; compiler_dso_type = make_node (RECORD_TYPE); finish_builtin_struct (compiler_dso_type, "CompilerDSOData", fields, NULL_TREE); return compiler_dso_type; } /* Returns the _d_dso_registry FUNCTION_DECL. */ static tree get_dso_registry_fn (void) { if (dso_registry_fn) return dso_registry_fn; tree dso_type = get_compiler_dso_type (); tree fntype = build_function_type_list (void_type_node, build_pointer_type (dso_type), NULL_TREE); dso_registry_fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, get_identifier ("_d_dso_registry"), fntype); TREE_PUBLIC (dso_registry_fn) = 1; DECL_EXTERNAL (dso_registry_fn) = 1; return dso_registry_fn; } /* Depending on CTOR_P, builds and emits eiter a constructor or destructor calling _d_dso_registry if `dso_initialized' is `false' in a constructor or `true' in a destructor. */ static tree build_dso_cdtor_fn (bool ctor_p) { const char *name = ctor_p ? GDC_PREFIX ("dso_ctor") : GDC_PREFIX ("dso_dtor"); tree condition = ctor_p ? boolean_true_node : boolean_false_node; /* Declaration of dso_ctor/dso_dtor is: extern(C) void dso_{c,d}tor (void) { if (dso_initialized != condition) { dso_initialized = condition; CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo}; _d_dso_registry (&dso); } } */ FuncDeclaration *fd = get_internal_fn (get_identifier (name)); tree decl = get_symbol_decl (fd); TREE_PUBLIC (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (decl) = 1; d_comdat_linkage (decl); /* Start laying out the body. */ tree old_context = start_function (fd); rest_of_decl_compilation (decl, 1, 0); /* if (dso_initialized != condition). */ tree if_cond = build_boolop (NE_EXPR, dso_initialized_node, condition); /* dso_initialized = condition; */ tree expr_list = modify_expr (dso_initialized_node, condition); /* CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo}; */ tree dso_type = get_compiler_dso_type (); tree dso = build_local_temp (dso_type); vec *ve = NULL; CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_integer_cst (1, size_type_node)); CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (dso_slot_node)); CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (start_minfo_node)); CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (stop_minfo_node)); tree assign_expr = modify_expr (dso, build_struct_literal (dso_type, ve)); expr_list = compound_expr (expr_list, assign_expr); /* _d_dso_registry (&dso); */ tree call_expr = build_call_expr (get_dso_registry_fn (), 1, build_address (dso)); expr_list = compound_expr (expr_list, call_expr); add_stmt (build_vcondition (if_cond, expr_list, void_node)); finish_function (old_context); return decl; } /* Build a variable used in the dso_registry code identified by NAME, and data type TYPE. The variable always has VISIBILITY_HIDDEN and TREE_PUBLIC flags set. */ static tree build_dso_registry_var (const char * name, tree type) { tree var = declare_extern_var (get_identifier (name), type); DECL_VISIBILITY (var) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (var) = 1; return var; } /* Place a reference to the ModuleInfo symbol MINFO for DECL into the `minfo' section. Then create the global ctors/dtors to call the _d_dso_registry function if necessary. */ static void register_moduleinfo (Module *decl, tree minfo) { gcc_assert (targetm_common.have_named_sections); /* Build the ModuleInfo reference, this is done once for every Module. */ tree ident = mangle_internal_decl (decl, "__moduleRef", "Z"); tree mref = declare_extern_var (ident, ptr_type_node); /* Build the initializer and emit. Do not start section with a `.' character so that the linker will provide a __start_ and __stop_ symbol to indicate the start and end address of the section respectively. https://sourceware.org/binutils/docs-2.26/ld/Orphan-Sections.html. */ DECL_INITIAL (mref) = build_address (minfo); DECL_EXTERNAL (mref) = 0; DECL_PRESERVE_P (mref) = 1; set_decl_section_name (mref, "minfo"); d_pushdecl (mref); rest_of_decl_compilation (mref, 1, 0); /* Only for the first D module being emitted do we need to generate a static constructor and destructor for. These are only required once per shared library, so it's safe to emit them only once per object file. */ static bool first_module = true; if (!first_module) return; start_minfo_node = build_dso_registry_var ("__start_minfo", ptr_type_node); rest_of_decl_compilation (start_minfo_node, 1, 0); stop_minfo_node = build_dso_registry_var ("__stop_minfo", ptr_type_node); rest_of_decl_compilation (stop_minfo_node, 1, 0); /* Declare dso_slot and dso_initialized. */ dso_slot_node = build_dso_registry_var (GDC_PREFIX ("dso_slot"), ptr_type_node); DECL_EXTERNAL (dso_slot_node) = 0; d_comdat_linkage (dso_slot_node); rest_of_decl_compilation (dso_slot_node, 1, 0); dso_initialized_node = build_dso_registry_var (GDC_PREFIX ("dso_initialized"), boolean_type_node); DECL_EXTERNAL (dso_initialized_node) = 0; d_comdat_linkage (dso_initialized_node); rest_of_decl_compilation (dso_initialized_node, 1, 0); /* Declare dso_ctor() and dso_dtor(). */ tree dso_ctor = build_dso_cdtor_fn (true); vec_safe_push (static_ctor_list, dso_ctor); tree dso_dtor = build_dso_cdtor_fn (false); vec_safe_push (static_dtor_list, dso_dtor); first_module = false; } /* Convenience function for layout_moduleinfo_fields. Adds a field of TYPE to the moduleinfo record at OFFSET, incrementing the offset to the next field position. No alignment is taken into account, all fields are packed. */ static void layout_moduleinfo_field (tree type, tree rec_type, HOST_WIDE_INT& offset) { tree field = create_field_decl (type, NULL, 1, 1); insert_aggregate_field (rec_type, field, offset); offset += int_size_in_bytes (type); } /* Layout fields that immediately come after the moduleinfo TYPE for DECL. Data relating to the module is packed into the type on an as-needed basis, this is done to keep its size to a minimum. */ static tree layout_moduleinfo_fields (Module *decl, tree type) { HOST_WIDE_INT offset = int_size_in_bytes (type); type = copy_aggregate_type (type); /* First fields added are all the function pointers. */ if (decl->sctor) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->sdtor) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->ssharedctor) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->sshareddtor) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->findGetMembers ()) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->sictor) layout_moduleinfo_field (ptr_type_node, type, offset); if (decl->stest) layout_moduleinfo_field (ptr_type_node, type, offset); /* Array of module imports is laid out as a length field, followed by a static array of ModuleInfo pointers. */ size_t aimports_dim = decl->aimports.dim; for (size_t i = 0; i < decl->aimports.dim; i++) { Module *mi = decl->aimports[i]; if (!mi->needmoduleinfo) aimports_dim--; } if (aimports_dim) { layout_moduleinfo_field (size_type_node, type, offset); layout_moduleinfo_field (make_array_type (Type::tvoidptr, aimports_dim), type, offset); } /* Array of local ClassInfo decls are laid out in the same way. */ ClassDeclarations aclasses; for (size_t i = 0; i < decl->members->dim; i++) { Dsymbol *member = (*decl->members)[i]; member->addLocalClass (&aclasses); } if (aclasses.dim) { layout_moduleinfo_field (size_type_node, type, offset); layout_moduleinfo_field (make_array_type (Type::tvoidptr, aclasses.dim), type, offset); } /* Lastly, the name of the module is a static char array. */ size_t namelen = strlen (decl->toPrettyChars ()) + 1; layout_moduleinfo_field (make_array_type (Type::tchar, namelen), type, offset); finish_aggregate_type (offset, 1, type, NULL); return type; } /* Output the ModuleInfo for module DECL and register it with druntime. */ static void layout_moduleinfo (Module *decl) { ClassDeclarations aclasses; FuncDeclaration *sgetmembers; for (size_t i = 0; i < decl->members->dim; i++) { Dsymbol *member = (*decl->members)[i]; member->addLocalClass (&aclasses); } size_t aimports_dim = decl->aimports.dim; for (size_t i = 0; i < decl->aimports.dim; i++) { Module *mi = decl->aimports[i]; if (!mi->needmoduleinfo) aimports_dim--; } sgetmembers = decl->findGetMembers (); size_t flags = 0; if (decl->sctor) flags |= MItlsctor; if (decl->sdtor) flags |= MItlsdtor; if (decl->ssharedctor) flags |= MIctor; if (decl->sshareddtor) flags |= MIdtor; if (sgetmembers) flags |= MIxgetMembers; if (decl->sictor) flags |= MIictor; if (decl->stest) flags |= MIunitTest; if (aimports_dim) flags |= MIimportedModules; if (aclasses.dim) flags |= MIlocalClasses; if (!decl->needmoduleinfo) flags |= MIstandalone; flags |= MIname; tree minfo = get_moduleinfo_decl (decl); tree type = layout_moduleinfo_fields (decl, TREE_TYPE (minfo)); /* Put out the two named fields in a ModuleInfo decl: uint flags; uint index; */ vec *minit = NULL; CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_integer_cst (flags, d_uint_type)); CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_integer_cst (0, d_uint_type)); /* Order of appearance, depending on flags: void function() tlsctor; void function() tlsdtor; void* function() xgetMembers; void function() ctor; void function() dtor; void function() ictor; void function() unitTest; ModuleInfo*[] importedModules; TypeInfo_Class[] localClasses; char[N] name; */ if (flags & MItlsctor) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sctor)); if (flags & MItlsdtor) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sdtor)); if (flags & MIctor) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->ssharedctor)); if (flags & MIdtor) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sshareddtor)); if (flags & MIxgetMembers) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (get_symbol_decl (sgetmembers))); if (flags & MIictor) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sictor)); if (flags & MIunitTest) CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->stest)); if (flags & MIimportedModules) { vec *elms = NULL; tree satype = make_array_type (Type::tvoidptr, aimports_dim); size_t idx = 0; for (size_t i = 0; i < decl->aimports.dim; i++) { Module *mi = decl->aimports[i]; if (mi->needmoduleinfo) { CONSTRUCTOR_APPEND_ELT (elms, size_int (idx), build_address (get_moduleinfo_decl (mi))); idx++; } } CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aimports_dim)); CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_constructor (satype, elms)); } if (flags & MIlocalClasses) { vec *elms = NULL; tree satype = make_array_type (Type::tvoidptr, aclasses.dim); for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration *cd = aclasses[i]; CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_address (get_classinfo_decl (cd))); } CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aclasses.dim)); CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_constructor (satype, elms)); } if (flags & MIname) { /* Put out module name as a 0-terminated C-string, to save bytes. */ const char *name = decl->toPrettyChars (); size_t namelen = strlen (name) + 1; tree strtree = build_string (namelen, name); TREE_TYPE (strtree) = make_array_type (Type::tchar, namelen); CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, strtree); } TREE_TYPE (minfo) = type; DECL_INITIAL (minfo) = build_struct_literal (type, minit); d_finish_decl (minfo); /* Register the module against druntime. */ register_moduleinfo (decl, minfo); } /* Send the Module AST class DECL to GCC back-end. */ void build_module_tree (Module *decl) { /* There may be more than one module per object file, but should only ever compile them one at a time. */ assert (!current_moduleinfo && !current_module_decl); module_info mi = module_info (); current_moduleinfo = &mi; current_module_decl = decl; /* Layout module members. */ if (decl->members) { for (size_t i = 0; i < decl->members->dim; i++) { Dsymbol *s = (*decl->members)[i]; build_decl_tree (s); } } /* Default behavior is to always generate module info because of templates. Can be switched off for not compiling against runtime library. */ if (global.params.useModuleInfo && Module::moduleinfo != NULL && decl->ident != Identifier::idPool ("__entrypoint")) { if (mi.ctors || mi.ctorgates) decl->sctor = build_funcs_gates_fn (get_identifier ("*__modctor"), mi.ctors, mi.ctorgates); if (mi.dtors) decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"), mi.dtors, NULL); if (mi.sharedctors || mi.sharedctorgates) decl->ssharedctor = build_funcs_gates_fn (get_identifier ("*__modsharedctor"), mi.sharedctors, mi.sharedctorgates); if (mi.shareddtors) decl->sshareddtor = build_funcs_gates_fn (get_identifier ("*__modshareddtor"), mi.shareddtors, NULL); if (mi.unitTests) decl->stest = build_funcs_gates_fn (get_identifier ("*__modtest"), mi.unitTests, NULL); layout_moduleinfo (decl); } current_moduleinfo = NULL; current_module_decl = NULL; } /* Returns the current function or module context for the purpose of imported_module_or_decl. */ tree d_module_context (void) { if (cfun != NULL) return current_function_decl; gcc_assert (current_module_decl != NULL); return build_import_decl (current_module_decl); } /* Maybe record declaration D against our module information structure. */ void register_module_decl (Declaration *d) { FuncDeclaration *fd = d->isFuncDeclaration (); if (fd != NULL) { tree decl = get_symbol_decl (fd); /* If a static constructor, push into the current ModuleInfo. Checks for `shared' first because it derives from the non-shared constructor type in the front-end. */ if (fd->isSharedStaticCtorDeclaration ()) vec_safe_push (current_moduleinfo->sharedctors, decl); else if (fd->isStaticCtorDeclaration ()) vec_safe_push (current_moduleinfo->ctors, decl); /* If a static destructor, do same as with constructors, but also increment the destructor's vgate at construction time. */ if (fd->isSharedStaticDtorDeclaration ()) { VarDeclaration *vgate = ((SharedStaticDtorDeclaration *) fd)->vgate; if (vgate != NULL) { tree gate = get_symbol_decl (vgate); vec_safe_push (current_moduleinfo->sharedctorgates, gate); } vec_safe_insert (current_moduleinfo->shareddtors, 0, decl); } else if (fd->isStaticDtorDeclaration ()) { VarDeclaration *vgate = ((StaticDtorDeclaration *) fd)->vgate; if (vgate != NULL) { tree gate = get_symbol_decl (vgate); vec_safe_push (current_moduleinfo->ctorgates, gate); } vec_safe_insert (current_moduleinfo->dtors, 0, decl); } /* If a unittest function. */ if (fd->isUnitTestDeclaration ()) vec_safe_push (current_moduleinfo->unitTests, decl); } } /* Wrapup all global declarations and start the final compilation. */ void d_finish_compilation (tree *vec, int len) { /* Complete all generated thunks. */ symtab->process_same_body_aliases (); /* Process all file scopes in this compilation, and the external_scope, through wrapup_global_declarations. */ for (int i = 0; i < len; i++) { tree decl = vec[i]; wrapup_global_declarations (&decl, 1); } /* If the target does not directly support static constructors, static_ctor_list contains a list of all static constructors defined so far. This routine will create a function to call all of those and is picked up by collect2. */ if (static_ctor_list) { tree decl = build_funcs_gates_fn (get_file_function_name ("I"), static_ctor_list, NULL); DECL_STATIC_CONSTRUCTOR (decl) = 1; decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY); } if (static_dtor_list) { tree decl = build_funcs_gates_fn (get_file_function_name ("D"), static_dtor_list, NULL); DECL_STATIC_DESTRUCTOR (decl) = 1; decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY); } } #include "gt-d-modules.h" ================================================ FILE: gcc/d/patches/patch-gcc-9.patch ================================================ This implements D language support in the GCC back end, and adds relevant documentation about the GDC front end. --- --- a/gcc/config/powerpcspe/powerpcspe.c +++ b/gcc/config/powerpcspe/powerpcspe.c @@ -31965,11 +31965,12 @@ rs6000_output_function_epilogue (FILE *f use language_string. C is 0. Fortran is 1. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. LTO, Go and JIT aren't assigned numbers - either, so for now use 0. */ + a number, so for now use 9. LTO, Go, D and JIT aren't assigned + numbers either, so for now use 0. */ if (lang_GNU_C () || ! strcmp (language_string, "GNU GIMPLE") || ! strcmp (language_string, "GNU Go") + || ! strcmp (language_string, "GNU D") || ! strcmp (language_string, "libgccjit")) i = 0; else if (! strcmp (language_string, "GNU F77") --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -28630,11 +28630,12 @@ rs6000_output_function_epilogue (FILE *f use language_string. C is 0. Fortran is 1. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. LTO, Go and JIT aren't assigned numbers - either, so for now use 0. */ + a number, so for now use 9. LTO, Go, D, and JIT aren't assigned + numbers either, so for now use 0. */ if (lang_GNU_C () || ! strcmp (language_string, "GNU GIMPLE") || ! strcmp (language_string, "GNU Go") + || ! strcmp (language_string, "GNU D") || ! strcmp (language_string, "libgccjit")) i = 0; else if (! strcmp (language_string, "GNU F77") --- a/gcc/doc/frontends.texi +++ b/gcc/doc/frontends.texi @@ -9,6 +9,7 @@ @cindex GNU Compiler Collection @cindex GNU C Compiler @cindex Ada +@cindex D @cindex Fortran @cindex Go @cindex Objective-C @@ -16,7 +17,7 @@ GCC stands for ``GNU Compiler Collection''. GCC is an integrated distribution of compilers for several major programming languages. These languages currently include C, C++, Objective-C, Objective-C++, -Fortran, Ada, Go, and BRIG (HSAIL). +Fortran, Ada, D, Go, and BRIG (HSAIL). The abbreviation @dfn{GCC} has multiple meanings in common use. The current official meaning is ``GNU Compiler Collection'', which refers --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -921,7 +921,7 @@ only for the listed packages. For other will be built. Package names currently recognized in the GCC tree are @samp{libgcc} (also known as @samp{gcc}), @samp{libstdc++} (not @samp{libstdc++-v3}), @samp{libffi}, @samp{zlib}, @samp{boehm-gc}, -@samp{ada}, @samp{libada}, @samp{libgo}, and @samp{libobjc}. +@samp{ada}, @samp{libada}, @samp{libgo}, @samp{libobjc}, and @samp{libphobos}. Note @samp{libiberty} does not support shared libraries at all. Use @option{--disable-shared} to build only static libraries. Note that @@ -1622,12 +1622,12 @@ their runtime libraries should be built. grep ^language= */config-lang.in @end smallexample Currently, you can use any of the following: -@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{fortran}, -@code{go}, @code{jit}, @code{lto}, @code{objc}, @code{obj-c++}. +@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{d}, +@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{objc}, @code{obj-c++}. Building the Ada compiler has special requirements, see below. If you do not pass this flag, or specify the option @code{default}, then the default languages available in the @file{gcc} sub-tree will be configured. -Ada, Go, Jit, and Objective-C++ are not default languages. LTO is not a +Ada, D, Go, Jit, and Objective-C++ are not default languages. LTO is not a default language, but is built by default because @option{--enable-lto} is enabled by default. The other languages are default languages. If @code{all} is specified, then all available languages are built. An @@ -2771,7 +2771,7 @@ on a simulator as described at @uref{htt In order to run sets of tests selectively, there are targets @samp{make check-gcc} and language specific @samp{make check-c}, -@samp{make check-c++}, @samp{make check-fortran}, +@samp{make check-c++}, @samp{make check-d} @samp{make check-fortran}, @samp{make check-ada}, @samp{make check-objc}, @samp{make check-obj-c++}, @samp{make check-lto} in the @file{gcc} subdirectory of the object directory. You can also --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1439,6 +1439,15 @@ Go source code. @item @var{file}.brig BRIG files (binary representation of HSAIL). +@item @var{file}.d +D source code. + +@item @var{file}.di +D interface file. + +@item @var{file}.dd +D documentation code (Ddoc). + @item @var{file}.ads Ada source code file that contains a library unit declaration (a declaration of a package, subprogram, or generic, or a generic @@ -1482,6 +1491,7 @@ objective-c objective-c-header objecti objective-c++ objective-c++-header objective-c++-cpp-output assembler assembler-with-cpp ada +d f77 f77-cpp-input f95 f95-cpp-input go brig --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -106,6 +106,10 @@ The Objective-C and Objective-C++ runtim @item libquadmath The runtime support library for quad-precision math operations. +@item libphobos +The D standard and runtime library. The bulk of this library is mirrored +from the @uref{https://github.com/@/dlang, master D repositories}. + @item libssp The Stack protector runtime library. --- a/gcc/doc/standards.texi +++ b/gcc/doc/standards.texi @@ -320,6 +320,12 @@ capability is typically utilized to impl finalization extension for a gcc supported processor. HSA standards are freely available at @uref{http://www.hsafoundation.com/standards/}. +@section D language + +GCC supports the D 2.0 programming language. The D language itself is +currently defined by its reference implementation and supporting language +specification, described at @uref{https://dlang.org/spec/spec.html}. + @section References for Other Languages @xref{Top, GNAT Reference Manual, About This Guide, gnat_rm, --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -5437,6 +5437,16 @@ is_ada (void) return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83; } +/* Return TRUE if the language is D. */ + +static inline bool +is_dlang (void) +{ + unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language); + + return lang == DW_LANG_D; +} + /* Remove the specified attribute if present. Return TRUE if removal was successful. */ @@ -24450,6 +24460,8 @@ gen_compile_unit_die (const char *filena language = DW_LANG_ObjC; else if (strcmp (language_string, "GNU Objective-C++") == 0) language = DW_LANG_ObjC_plus_plus; + else if (strcmp (language_string, "GNU D") == 0) + language = DW_LANG_D; else if (dwarf_version >= 5 || !dwarf_strict) { if (strcmp (language_string, "GNU Go") == 0) @@ -26034,7 +26046,7 @@ declare_in_namespace (tree thing, dw_die if (ns_context != context_die) { - if (is_fortran ()) + if (is_fortran () || is_dlang ()) return ns_context; if (DECL_P (thing)) gen_decl_die (thing, NULL, NULL, ns_context); @@ -26057,7 +26069,7 @@ gen_namespace_die (tree decl, dw_die_ref { /* Output a real namespace or module. */ context_die = setup_namespace_context (decl, comp_unit_die ()); - namespace_die = new_die (is_fortran () + namespace_die = new_die (is_fortran () || is_dlang () ? DW_TAG_module : DW_TAG_namespace, context_die, decl); /* For Fortran modules defined in different CU don't add src coords. */ @@ -26123,7 +26135,7 @@ gen_decl_die (tree decl, tree origin, st break; case CONST_DECL: - if (!is_fortran () && !is_ada ()) + if (!is_fortran () && !is_ada () && !is_dlang ()) { /* The individual enumerators of an enum type get output when we output the Dwarf representation of the relevant enum type itself. */ @@ -26723,7 +26735,7 @@ dwarf2out_decl (tree decl) case CONST_DECL: if (debug_info_level <= DINFO_LEVEL_TERSE) return; - if (!is_fortran () && !is_ada ()) + if (!is_fortran () && !is_ada () && !is_dlang ()) return; if (TREE_STATIC (decl) && decl_function_context (decl)) context_die = lookup_decl_die (DECL_CONTEXT (decl)); @@ -29126,6 +29138,7 @@ prune_unused_types_walk_local_classes (d case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: + case DW_TAG_interface_type: break; case DW_TAG_subprogram: @@ -29159,6 +29172,7 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: + case DW_TAG_interface_type: if (die->die_perennial_p) break; @@ -29185,7 +29199,6 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_volatile_type: case DW_TAG_typedef: case DW_TAG_array_type: - case DW_TAG_interface_type: case DW_TAG_friend: case DW_TAG_enumeration_type: case DW_TAG_subroutine_type: --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1305,6 +1305,7 @@ static const struct compiler default_com {".f08", "#Fortran", 0, 0, 0}, {".F08", "#Fortran", 0, 0, 0}, {".r", "#Ratfor", 0, 0, 0}, {".go", "#Go", 0, 1, 0}, + {".d", "#D", 0, 1, 0}, {".dd", "#D", 0, 1, 0}, {".di", "#D", 0, 1, 0}, /* Next come the entries for C. */ {".c", "@c", 0, 0, 1}, {"@c", --- a/gcc/testsuite/gcc.misc-tests/help.exp +++ b/gcc/testsuite/gcc.misc-tests/help.exp @@ -115,7 +115,7 @@ check_for_options c "--help=joined,undoc # subsystem. Do this one help class at a time to make it easier to # find the source a failure. -foreach cls { "ada" "c" "c++" "fortran" "go" \ +foreach cls { "ada" "c" "c++" "d" "fortran" "go" \ "optimizers" "param" "target" "warnings" } { check_for_options c "--help=$cls" "" "^ +-.*\[^:.\]$" "" ================================================ FILE: gcc/d/patches/patch-gcc-ddmd-9.patch ================================================ This implements building of self hosted D compiler in GCC back end. --- --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1068,6 +1068,10 @@ SYSLIBS = @GNAT_LIBEXC@ GNATBIND = @GNATBIND@ GNATMAKE = @GNATMAKE@ +# Used from d/Make-lang.in +GDC = @GDC@ +GDCFLAGS = @GDCFLAGS@ + # Libs needed (at present) just for jcf-dump. LDEXP_LIB = @LDEXP_LIB@ --- a/gcc/configure +++ b/gcc/configure @@ -807,6 +807,8 @@ EGREP GREP CXXCPP PICFLAG_FOR_TARGET +GDCFLAGS +GDC GNATMAKE GNATBIND ac_ct_CXX @@ -5022,6 +5024,106 @@ else fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gdc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gdc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC"; then + ac_cv_prog_GDC="$GDC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC="${ac_tool_prefix}gdc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC=$ac_cv_prog_GDC +if test -n "$GDC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5 +$as_echo "$GDC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_GDC"; then + ac_ct_GDC=$GDC + # Extract the first word of "gdc", so it can be a program name with args. +set dummy gdc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_GDC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_GDC"; then + ac_cv_prog_ac_ct_GDC="$ac_ct_GDC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_GDC="gdc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_GDC=$ac_cv_prog_ac_ct_GDC +if test -n "$ac_ct_GDC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GDC" >&5 +$as_echo "$ac_ct_GDC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_GDC" = x; then + GDC="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + GDC=$ac_ct_GDC + fi +else + GDC="$ac_cv_prog_GDC" +fi + +if test "x$GDC" != xno; then + have_gdc=yes +else + have_gdc=no +fi + + # Do configure tests with the C++ compiler, since that's what we build with. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -18510,7 +18612,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18513 "configure" +#line 18615 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18616,7 +18718,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18619 "configure" +#line 18721 "configure" #include "confdefs.h" #if HAVE_DLFCN_H --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -363,6 +363,7 @@ rm -f a.out a.exe b.out AC_PROG_CC AC_PROG_CXX ACX_PROG_GNAT([-I"$srcdir"/ada/libgnat]) +ACX_PROG_GDC([-I"$srcdir"/d]) # Do configure tests with the C++ compiler, since that's what we build with. AC_LANG(C++) @@ -376,6 +377,7 @@ case "$CC" in esac AC_SUBST(CFLAGS) AC_SUBST(CXXFLAGS) +AC_SUBST(GDCFLAGS) # Determine PICFLAG for target gnatlib. GCC_PICFLAG_FOR_TARGET ================================================ FILE: gcc/d/patches/patch-targetdm-9.patch ================================================ This patch implements the support for the D language specific target hooks. The following versions are available for all supported architectures. * D_HardFloat * D_SoftFloat The following CPU versions are implemented: * ARM ** Thumb (deprecated) ** ARM_Thumb ** ARM_HardFloat ** ARM_SoftFloat ** ARM_SoftFP * AArch64 * Alpha ** Alpha_SoftFloat ** Alpha_HardFloat * X86 * X86_64 ** D_X32 * MIPS32 * MIPS64 ** MIPS_O32 ** MIPS_O64 ** MIPS_N32 ** MIPS_N64 ** MIPS_EABI ** MIPS_HardFloat ** MIPS_SoftFloat * PPC * PPC64 ** PPC_HardFloat ** PPC_SoftFloat * S390 * S390X (deprecated) * SystemZ * SPARC * SPARC64 * SPARC_V8Plus ** SPARC_HardFloat ** SPARC_SoftFloat The following OS versions are implemented: * linux * Posix * Hurd * Android * CRuntime_Bionic * CRuntime_Glibc * CRuntime_Musl * CRuntime_UClibc --- --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -554,6 +554,8 @@ tm_include_list=@tm_include_list@ tm_defines=@tm_defines@ tm_p_file_list=@tm_p_file_list@ tm_p_include_list=@tm_p_include_list@ +tm_d_file_list=@tm_d_file_list@ +tm_d_include_list=@tm_d_include_list@ build_xm_file_list=@build_xm_file_list@ build_xm_include_list=@build_xm_include_list@ build_xm_defines=@build_xm_defines@ @@ -848,6 +850,7 @@ BCONFIG_H = bconfig.h $(build_xm_file_li CONFIG_H = config.h $(host_xm_file_list) TCONFIG_H = tconfig.h $(xm_file_list) TM_P_H = tm_p.h $(tm_p_file_list) +TM_D_H = tm_d.h $(tm_d_file_list) GTM_H = tm.h $(tm_file_list) insn-constants.h TM_H = $(GTM_H) insn-flags.h $(OPTIONS_H) @@ -905,9 +908,11 @@ EXCEPT_H = except.h $(HASHTAB_H) TARGET_DEF = target.def target-hooks-macros.h target-insns.def C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h +D_TARGET_DEF = d/d-target.def target-hooks-macros.h TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF) COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF) +D_TARGET_H = d/d-target.h $(D_TARGET_DEF) MACHMODE_H = machmode.h mode-classes.def HOOKS_H = hooks.h HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H) @@ -1191,6 +1196,9 @@ C_TARGET_OBJS=@c_target_objs@ # Target specific, C++ specific object file CXX_TARGET_OBJS=@cxx_target_objs@ +# Target specific, D specific object file +D_TARGET_OBJS=@d_target_objs@ + # Target specific, Fortran specific object file FORTRAN_TARGET_OBJS=@fortran_target_objs@ @@ -1790,6 +1798,7 @@ bconfig.h: cs-bconfig.h ; @true tconfig.h: cs-tconfig.h ; @true tm.h: cs-tm.h ; @true tm_p.h: cs-tm_p.h ; @true +tm_d.h: cs-tm_d.h ; @true cs-config.h: Makefile TARGET_CPU_DEFAULT="" \ @@ -1816,6 +1825,11 @@ cs-tm_p.h: Makefile HEADERS="$(tm_p_include_list)" DEFINES="" \ $(SHELL) $(srcdir)/mkconfig.sh tm_p.h +cs-tm_d.h: Makefile + TARGET_CPU_DEFAULT="" \ + HEADERS="$(tm_d_include_list)" DEFINES="" \ + $(SHELL) $(srcdir)/mkconfig.sh tm_d.h + # Don't automatically run autoconf, since configure.ac might be accidentally # newer than configure. Also, this writes into the source directory which # might be on a read-only file system. If configured for maintainer mode @@ -2140,6 +2154,12 @@ default-c.o: config/default-c.c CFLAGS-prefix.o += -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) prefix.o: $(BASEVER) +# Files used by the D language front end. + +default-d.o: config/default-d.c + $(COMPILE) $< + $(POSTCOMPILE) + # Language-independent files. DRIVER_DEFINES = \ @@ -2436,6 +2456,15 @@ s-common-target-hooks-def-h: build/genho common/common-target-hooks-def.h $(STAMP) s-common-target-hooks-def-h +d/d-target-hooks-def.h: s-d-target-hooks-def-h; @true + +s-d-target-hooks-def-h: build/genhooks$(build_exeext) + $(RUN_GEN) build/genhooks$(build_exeext) "D Target Hook" \ + > tmp-d-target-hooks-def.h + $(SHELL) $(srcdir)/../move-if-change tmp-d-target-hooks-def.h \ + d/d-target-hooks-def.h + $(STAMP) s-d-target-hooks-def-h + # check if someone mistakenly only changed tm.texi. # We use a different pathname here to avoid a circular dependency. s-tm-texi: $(srcdir)/doc/../doc/tm.texi @@ -2459,6 +2488,7 @@ s-tm-texi: build/genhooks$(build_exeext) && ( test $(srcdir)/doc/tm.texi -nt $(srcdir)/target.def \ || test $(srcdir)/doc/tm.texi -nt $(srcdir)/c-family/c-target.def \ || test $(srcdir)/doc/tm.texi -nt $(srcdir)/common/common-target.def \ + || test $(srcdir)/doc/tm.texi -nt $(srcdir)/d/d-target.def \ ); then \ echo >&2 ; \ echo You should edit $(srcdir)/doc/tm.texi.in rather than $(srcdir)/doc/tm.texi . >&2 ; \ @@ -2596,14 +2626,15 @@ s-gtype: build/gengtype$(build_exeext) $ -r gtype.state $(STAMP) s-gtype -generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \ +generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \ $(simple_generated_h) specs.h \ tree-check.h genrtl.h insn-modes.h insn-modes-inline.h \ tm-preds.h tm-constrs.h \ $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h gcov-iov.h \ options.h target-hooks-def.h insn-opinit.h \ common/common-target-hooks-def.h pass-instances.def \ - c-family/c-target-hooks-def.h params.list params.options case-cfn-macros.h \ + c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ + params.list params.options case-cfn-macros.h \ cfn-operators.pd # @@ -2747,7 +2778,7 @@ build/genrecog.o : genrecog.c $(RTL_BASE $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) \ $(HASH_TABLE_H) inchash.h build/genhooks.o : genhooks.c $(TARGET_DEF) $(C_TARGET_DEF) \ - $(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h + $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h build/genmddump.o : genmddump.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \ --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -86,6 +86,9 @@ # tm_p_file Location of file with declarations for functions # in $out_file. # +# tm_d_file A list of headers with definitions of target hook +# macros for the D compiler. +# # out_file The name of the machine description C support # file, if different from "$cpu_type/$cpu_type.c". # @@ -139,6 +142,9 @@ # cxx_target_objs List of extra target-dependent objects that be # linked into the C++ compiler only. # +# d_target_objs List of extra target-dependent objects that be +# linked into the D compiler only. +# # fortran_target_objs List of extra target-dependent objects that be # linked into the fortran compiler only. # @@ -191,6 +197,9 @@ # # target_has_targetm_common Set to yes or no depending on whether the # target has its own definition of targetm_common. +# +# target_has_targetdm Set to yes or no depending on whether the target +# has its own definition of targetdm. out_file= common_out_file= @@ -206,9 +215,11 @@ extra_gcc_objs= extra_options= c_target_objs= cxx_target_objs= +d_target_objs= fortran_target_objs= target_has_targetcm=no target_has_targetm_common=yes +target_has_targetdm=no tm_defines= xm_defines= # Set this to force installation and use of collect2. @@ -305,12 +316,14 @@ aarch64*-*-*) extra_headers="arm_fp16.h arm_neon.h arm_acle.h" c_target_objs="aarch64-c.o" cxx_target_objs="aarch64-c.o" + d_target_objs="aarch64-d.o" extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o" target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c" target_has_targetm_common=yes ;; alpha*-*-*) cpu_type=alpha + d_target_objs="alpha-d.o" extra_options="${extra_options} g.opt" ;; am33_2.0-*-linux*) @@ -330,6 +343,7 @@ arm*-*-*) target_type_format_char='%' c_target_objs="arm-c.o" cxx_target_objs="arm-c.o" + d_target_objs="arm-d.o" extra_options="${extra_options} arm/arm-tables.opt" target_gtfiles="\$(srcdir)/config/arm/arm-builtins.c" ;; @@ -362,6 +376,7 @@ i[34567]86-*-*) cpu_type=i386 c_target_objs="i386-c.o" cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o" extra_options="${extra_options} fused-madd.opt" extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h @@ -392,6 +407,7 @@ x86_64-*-*) cpu_type=i386 c_target_objs="i386-c.o" cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" extra_options="${extra_options} fused-madd.opt" extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o" extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h @@ -442,6 +458,7 @@ microblaze*-*-*) ;; mips*-*-*) cpu_type=mips + d_target_objs="mips-d.o" extra_headers="loongson.h msa.h" extra_objs="frame-header-opt.o" extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" @@ -507,6 +524,7 @@ sparc*-*-*) cpu_type=sparc c_target_objs="sparc-c.o" cxx_target_objs="sparc-c.o" + d_target_objs="sparc-d.o" extra_headers="visintrin.h" ;; spu*-*-*) @@ -514,6 +532,7 @@ spu*-*-*) ;; s390*-*-*) cpu_type=s390 + d_target_objs="s390-d.o" extra_options="${extra_options} fused-madd.opt" extra_headers="s390intrin.h htmintrin.h htmxlintrin.h vecintrin.h" ;; @@ -543,10 +562,13 @@ tilepro*-*-*) esac tm_file=${cpu_type}/${cpu_type}.h +tm_d_file=${cpu_type}/${cpu_type}.h if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-protos.h then tm_p_file=${cpu_type}/${cpu_type}-protos.h + tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-protos.h" fi + extra_modes= if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-modes.def then @@ -810,8 +832,10 @@ case ${target} in esac c_target_objs="${c_target_objs} glibc-c.o" cxx_target_objs="${cxx_target_objs} glibc-c.o" + d_target_objs="${d_target_objs} glibc-d.o" tmake_file="${tmake_file} t-glibc" target_has_targetcm=yes + target_has_targetdm=yes ;; *-*-netbsd*) tm_p_file="${tm_p_file} netbsd-protos.h" @@ -3232,6 +3256,10 @@ if [ "$common_out_file" = "" ]; then fi fi +if [ "$target_has_targetdm" = "no" ]; then + d_target_objs="$d_target_objs default-d.o" +fi + # Support for --with-cpu and related options (and a few unrelated options, # too). case ${with_cpu} in @@ -4858,6 +4886,7 @@ case ${target} in out_file="${cpu_type}/${cpu_type}.c" c_target_objs="${c_target_objs} ${cpu_type}-c.o" cxx_target_objs="${cxx_target_objs} ${cpu_type}-c.o" + d_target_objs="${d_target_objs} ${cpu_type}-d.o" tmake_file="${cpu_type}/t-${cpu_type} ${tmake_file}" ;; --- /dev/null +++ b/gcc/config/aarch64/aarch64-d.c @@ -0,0 +1,39 @@ +/* Subroutines for the D front end on the AArch64 architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for AArch64 targets. */ + +void +aarch64_d_target_versions (void) +{ + d_add_builtin_version ("AArch64"); + d_add_builtin_version ("D_HardFloat"); +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for AArch64 targets. */ + +const char * +aarch64_d_float_abi_type (void) +{ + return "hard"; +} --- a/gcc/config/aarch64/aarch64-linux.h +++ b/gcc/config/aarch64/aarch64-linux.h @@ -81,6 +81,8 @@ } \ while (0) +#define GNU_USER_TARGET_D_CRITSEC_SIZE 48 + #define TARGET_ASM_FILE_END file_end_indicate_exec_stack /* Uninitialized common symbols in non-PIE executables, even with --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -620,6 +620,10 @@ enum aarch64_parse_opt_result aarch64_pa std::string aarch64_get_extension_string_for_isa_flags (unsigned long, unsigned long); +/* Defined in aarch64-d.c */ +extern void aarch64_d_target_versions (void); +extern const char *aarch64_d_float_abi_type (void); + rtl_opt_pass *make_pass_fma_steering (gcc::context *); rtl_opt_pass *make_pass_track_speculation (gcc::context *); rtl_opt_pass *make_pass_tag_collision_avoidance (gcc::context *); --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -30,6 +30,10 @@ #define REGISTER_TARGET_PRAGMAS() aarch64_register_pragmas () +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS aarch64_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE aarch64_d_float_abi_type + /* Target machine storage layout. */ #define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ --- a/gcc/config/aarch64/t-aarch64 +++ b/gcc/config/aarch64/t-aarch64 @@ -56,6 +56,10 @@ aarch64-c.o: $(srcdir)/config/aarch64/aa $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/aarch64/aarch64-c.c +aarch64-d.o: $(srcdir)/config/aarch64/aarch64-d.c + $(COMPILE) $< + $(POSTCOMPILE) + PASSES_EXTRA += $(srcdir)/config/aarch64/aarch64-passes.def cortex-a57-fma-steering.o: $(srcdir)/config/aarch64/cortex-a57-fma-steering.c \ --- /dev/null +++ b/gcc/config/alpha/alpha-d.c @@ -0,0 +1,49 @@ +/* Subroutines for the D front end on the Alpha architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for Alpha targets. */ + +void +alpha_d_target_versions (void) +{ + d_add_builtin_version ("Alpha"); + if (TARGET_SOFT_FP) + { + d_add_builtin_version ("D_SoftFloat"); + d_add_builtin_version ("Alpha_SoftFloat"); + } + else + { + d_add_builtin_version ("D_HardFloat"); + d_add_builtin_version ("Alpha_HardFloat"); + } +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for Alpha targets. */ + +const char * +alpha_d_float_abi_type (void) +{ + return (TARGET_SOFT_FP) ? "soft" : "hard"; +} --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -118,3 +118,7 @@ class rtl_opt_pass; extern rtl_opt_pass *make_pass_handle_trap_shadows (gcc::context *); extern rtl_opt_pass *make_pass_align_insns (gcc::context *); + +/* Routines implemented in alpha-d.c */ +extern void alpha_d_target_versions (void); +extern const char *alpha_d_float_abi_type (void); --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -94,6 +94,10 @@ along with GCC; see the file COPYING3. while (0) #endif +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS alpha_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE alpha_d_float_abi_type + /* Run-time compilation parameters selecting different hardware subsets. */ /* Which processor to schedule for. The cpu attribute defines a list that --- a/gcc/config/alpha/linux.h +++ b/gcc/config/alpha/linux.h @@ -33,6 +33,19 @@ along with GCC; see the file COPYING3. builtin_define ("_GNU_SOURCE"); \ } while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef LIB_SPEC #define LIB_SPEC \ "%{pthread:-lpthread} \ --- a/gcc/config/alpha/t-alpha +++ b/gcc/config/alpha/t-alpha @@ -16,4 +16,8 @@ # along with GCC; see the file COPYING3. If not see # . +alpha-d.o: $(srcdir)/config/alpha/alpha-d.c + $(COMPILE) $< + $(POSTCOMPILE) + PASSES_EXTRA += $(srcdir)/config/alpha/alpha-passes.def --- /dev/null +++ b/gcc/config/arm/arm-d.c @@ -0,0 +1,71 @@ +/* Subroutines for the D front end on the ARM architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tm_p.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for ARM targets. */ + +void +arm_d_target_versions (void) +{ + d_add_builtin_version ("ARM"); + + if (TARGET_THUMB || TARGET_THUMB2) + { + d_add_builtin_version ("Thumb"); + d_add_builtin_version ("ARM_Thumb"); + } + + if (arm_float_abi == ARM_FLOAT_ABI_HARD) + d_add_builtin_version ("ARM_HardFloat"); + else if (arm_float_abi == ARM_FLOAT_ABI_SOFT) + d_add_builtin_version ("ARM_SoftFloat"); + else if (arm_float_abi == ARM_FLOAT_ABI_SOFTFP) + d_add_builtin_version ("ARM_SoftFP"); + + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("D_SoftFloat"); + else if (TARGET_HARD_FLOAT) + d_add_builtin_version ("D_HardFloat"); +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for ARM targets. */ + +const char * +arm_d_float_abi_type (void) +{ + switch (arm_float_abi) + { + case ARM_FLOAT_ABI_HARD: + return "hard"; + + case ARM_FLOAT_ABI_SOFT: + return "soft"; + + case ARM_FLOAT_ABI_SOFTFP: + return "softfp"; + + default: + return NULL; + } +} --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -375,6 +375,10 @@ extern void arm_lang_object_attributes_i extern void arm_register_target_pragmas (void); extern void arm_cpu_cpp_builtins (struct cpp_reader *); +/* Defined in arm-d.c */ +extern void arm_d_target_versions (void); +extern const char *arm_d_float_abi_type (void); + extern bool arm_is_constant_pool_ref (rtx); /* The bits in this mask specify which instruction scheduling options should --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -47,6 +47,10 @@ extern char arm_arch_name[]; /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() arm_cpu_cpp_builtins (pfile) +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS arm_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE arm_d_float_abi_type + #include "config/arm/arm-opts.h" /* The processor for which instructions should be scheduled. */ --- a/gcc/config/arm/linux-eabi.h +++ b/gcc/config/arm/linux-eabi.h @@ -30,6 +30,9 @@ } \ while (false) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + /* We default to a soft-float ABI so that binaries can run on all target hardware. If you override this to use the hard-float ABI then change the setting of GLIBC_DYNAMIC_LINKER_DEFAULT as well. */ --- a/gcc/config/arm/t-arm +++ b/gcc/config/arm/t-arm @@ -152,6 +152,10 @@ arm-c.o: $(srcdir)/config/arm/arm-c.c $( $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/arm/arm-c.c +arm-d.o: $(srcdir)/config/arm/arm-d.c + $(COMPILE) $< + $(POSTCOMPILE) + arm-common.o: arm-cpu-cdata.h driver-arm.o: arm-native.h --- /dev/null +++ b/gcc/config/default-d.c @@ -0,0 +1,25 @@ +/* Default D language target hooks initializer. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/glibc-d.c @@ -0,0 +1,75 @@ +/* Glibc support needed only by D front-end. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "memmodel.h" +#include "tm_p.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for Glibc targets. */ + +static void +glibc_d_os_builtins (void) +{ + d_add_builtin_version ("Posix"); + +#define builtin_version(TXT) d_add_builtin_version (TXT) + +#ifdef GNU_USER_TARGET_D_OS_VERSIONS + GNU_USER_TARGET_D_OS_VERSIONS (); +#endif + +#ifdef EXTRA_TARGET_D_OS_VERSIONS + EXTRA_TARGET_D_OS_VERSIONS (); +#endif +} + +/* Implement TARGET_D_CRITSEC_SIZE for Glibc targets. */ + +static unsigned +glibc_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t. */ +#ifdef GNU_USER_TARGET_D_CRITSEC_SIZE + return GNU_USER_TARGET_D_CRITSEC_SIZE; +#else + return (POINTER_SIZE == 64) ? 40 : 24; +#endif +} + +/* Implement TARGET_D_OBJECT_FORMAT for Glibc targets. */ + +const char * +glibc_d_object_format (void) +{ + return "elf"; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS glibc_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE glibc_d_critsec_size + +#undef TARGET_D_OBJECT_FORMAT +#define TARGET_D_OBJECT_FORMAT glibc_d_object_format + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- a/gcc/config/gnu.h +++ b/gcc/config/gnu.h @@ -31,3 +31,9 @@ along with GCC. If not, see . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for x86 targets. */ + +void +ix86_d_target_versions (void) +{ + if (TARGET_64BIT) + { + d_add_builtin_version ("X86_64"); + + if (TARGET_X32) + d_add_builtin_version ("D_X32"); + } + else + d_add_builtin_version ("X86"); + + if (TARGET_80387) + d_add_builtin_version ("D_HardFloat"); + else + d_add_builtin_version ("D_SoftFloat"); +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for x86 targets. */ + +const char * +ix86_d_float_abi_type (void) +{ + if (! (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387)) + return "soft"; + + return "hard"; +} --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -236,6 +236,10 @@ extern void ix86_expand_sse2_abs (rtx, r extern void ix86_target_macros (void); extern void ix86_register_pragmas (void); +/* In i386-d.c */ +extern void ix86_d_target_versions (void); +extern const char *ix86_d_float_abi_type (void); + /* In winnt.c */ extern void i386_pe_unique_section (tree, int); extern void i386_pe_declare_function_type (FILE *, const char *, int); --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -718,6 +718,10 @@ extern const char *host_detect_local_cpu /* Target Pragmas. */ #define REGISTER_TARGET_PRAGMAS() ix86_register_pragmas () +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS ix86_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE ix86_d_float_abi_type + #ifndef CC1_SPEC #define CC1_SPEC "%(cc1_cpu) " #endif --- a/gcc/config/i386/linux-common.h +++ b/gcc/config/i386/linux-common.h @@ -27,6 +27,12 @@ along with GCC; see the file COPYING3. } \ while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + +#define GNU_USER_TARGET_D_CRITSEC_SIZE \ + (TARGET_64BIT ? (POINTER_SIZE == 64 ? 40 : 32) : 24) + #undef CC1_SPEC #define CC1_SPEC \ LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \ --- a/gcc/config/i386/t-i386 +++ b/gcc/config/i386/t-i386 @@ -40,6 +40,10 @@ x86-tune-sched-core.o: $(srcdir)/config/ $(COMPILE) $< $(POSTCOMPILE) +i386-d.o: $(srcdir)/config/i386/i386-d.c + $(COMPILE) $< + $(POSTCOMPILE) + i386.o: i386-builtin-types.inc i386-builtin-types.inc: s-i386-bt ; @true --- a/gcc/config/kfreebsd-gnu.h +++ b/gcc/config/kfreebsd-gnu.h @@ -29,6 +29,12 @@ along with GCC; see the file COPYING3. } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("FreeBSD"); \ + builtin_version ("CRuntime_Glibc"); \ + } while (0) + #define GNU_USER_DYNAMIC_LINKER GLIBC_DYNAMIC_LINKER #define GNU_USER_DYNAMIC_LINKER32 GLIBC_DYNAMIC_LINKER32 #define GNU_USER_DYNAMIC_LINKER64 GLIBC_DYNAMIC_LINKER64 --- a/gcc/config/kopensolaris-gnu.h +++ b/gcc/config/kopensolaris-gnu.h @@ -30,5 +30,11 @@ along with GCC; see the file COPYING3. } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("Solaris"); \ + builtin_version ("CRuntime_Glibc"); \ + } while (0) + #undef GNU_USER_DYNAMIC_LINKER #define GNU_USER_DYNAMIC_LINKER "/lib/ld.so.1" --- a/gcc/config/linux-android.h +++ b/gcc/config/linux-android.h @@ -25,6 +25,12 @@ builtin_define ("__ANDROID__"); \ } while (0) +#define ANDROID_TARGET_D_OS_VERSIONS() \ + do { \ + if (TARGET_ANDROID) \ + builtin_version ("Android"); \ + } while (0) + #if ANDROID_DEFAULT # define NOANDROID "mno-android" #else --- a/gcc/config/linux.h +++ b/gcc/config/linux.h @@ -53,6 +53,19 @@ see the files COPYING3 and COPYING.RUNTI builtin_assert ("system=posix"); \ } while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + /* Determine which dynamic linker to use depending on whether GLIBC or uClibc or Bionic or musl is the default C library and whether -muclibc or -mglibc or -mbionic or -mmusl has been passed to change --- a/gcc/config/mips/linux-common.h +++ b/gcc/config/mips/linux-common.h @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. ANDROID_TARGET_OS_CPP_BUILTINS(); \ } while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + #undef LINK_SPEC #define LINK_SPEC \ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LINK_SPEC, \ --- /dev/null +++ b/gcc/config/mips/mips-d.c @@ -0,0 +1,69 @@ +/* Subroutines for the D front end on the MIPS architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for MIPS targets. */ + +void +mips_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("MIPS64"); + else + d_add_builtin_version ("MIPS32"); + + if (mips_abi == ABI_32) + d_add_builtin_version ("MIPS_O32"); + else if (mips_abi == ABI_EABI) + d_add_builtin_version ("MIPS_EABI"); + else if (mips_abi == ABI_N32) + d_add_builtin_version ("MIPS_N32"); + else if (mips_abi == ABI_64) + d_add_builtin_version ("MIPS_N64"); + else if (mips_abi == ABI_O64) + d_add_builtin_version ("MIPS_O64"); + + if (TARGET_HARD_FLOAT_ABI) + { + d_add_builtin_version ("MIPS_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT_ABI) + { + d_add_builtin_version ("MIPS_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for MIPS targets. */ + +const char * +mips_d_float_abi_type (void) +{ + if (TARGET_HARD_FLOAT_ABI) + return "hard"; + else if (TARGET_SOFT_FLOAT_ABI) + return "soft"; + + return NULL; +} --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -385,4 +385,8 @@ extern mulsidi3_gen_fn mips_mulsidi3_gen extern void mips_register_frame_header_opt (void); extern void mips_expand_vec_cond_expr (machine_mode, machine_mode, rtx *); +/* Routines implemented in mips-d.c */ +extern void mips_d_target_versions (void); +extern const char *mips_d_float_abi_type (void); + #endif /* ! GCC_MIPS_PROTOS_H */ --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -645,6 +645,10 @@ struct mips_cpu_info { } \ while (0) +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS mips_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE mips_d_float_abi_type + /* Default target_flags if no switches are specified */ #ifndef TARGET_DEFAULT --- a/gcc/config/mips/t-mips +++ b/gcc/config/mips/t-mips @@ -24,3 +24,7 @@ $(srcdir)/config/mips/mips-tables.opt: $ frame-header-opt.o: $(srcdir)/config/mips/frame-header-opt.c $(COMPILE) $< $(POSTCOMPILE) + +mips-d.o: $(srcdir)/config/mips/mips-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- a/gcc/config/powerpcspe/linux.h +++ b/gcc/config/powerpcspe/linux.h @@ -57,6 +57,19 @@ } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" --- a/gcc/config/powerpcspe/linux64.h +++ b/gcc/config/powerpcspe/linux64.h @@ -391,6 +391,19 @@ extern int dot_symbols; } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux) %(include_extra)" --- /dev/null +++ b/gcc/config/powerpcspe/powerpcspe-d.c @@ -0,0 +1,58 @@ +/* Subroutines for the D front end on the PowerPC architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for PowerPC targets. */ + +void +rs6000_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("PPC64"); + else + d_add_builtin_version ("PPC"); + + if (TARGET_HARD_FLOAT) + { + d_add_builtin_version ("PPC_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT) + { + d_add_builtin_version ("PPC_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for PowerPC targets. */ + +const char * +rs6000_d_float_abi_type (void) +{ + if (TARGET_HARD_FLOAT) + return "hard"; + else if (TARGET_SOFT_FLOAT) + return "soft"; + + return NULL; +} --- a/gcc/config/powerpcspe/powerpcspe-protos.h +++ b/gcc/config/powerpcspe/powerpcspe-protos.h @@ -231,6 +231,10 @@ extern void rs6000_target_modify_macros extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT, HOST_WIDE_INT); +/* Declare functions in powerpcspe-d.c */ +extern void rs6000_d_target_versions (void); +extern const char *rs6000_d_float_abi_type (void); + #if TARGET_MACHO char *output_call (rtx_insn *, rtx *, int, int); #endif --- a/gcc/config/powerpcspe/powerpcspe.h +++ b/gcc/config/powerpcspe/powerpcspe.h @@ -702,6 +702,10 @@ extern unsigned char rs6000_recip_bits[] #define TARGET_CPU_CPP_BUILTINS() \ rs6000_cpu_cpp_builtins (pfile) +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS rs6000_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE rs6000_d_float_abi_type + /* This is used by rs6000_cpu_cpp_builtins to indicate the byte order we're compiling for. Some configurations may need to override it. */ #define RS6000_CPU_CPP_ENDIAN_BUILTINS() \ --- a/gcc/config/powerpcspe/t-powerpcspe +++ b/gcc/config/powerpcspe/t-powerpcspe @@ -26,6 +26,10 @@ powerpcspe-c.o: $(srcdir)/config/powerpc $(COMPILE) $< $(POSTCOMPILE) +powerpcspe-d.o: $(srcdir)/config/powerpcspe/powerpcspe-d.c + $(COMPILE) $< + $(POSTCOMPILE) + $(srcdir)/config/powerpcspe/powerpcspe-tables.opt: $(srcdir)/config/powerpcspe/genopt.sh \ $(srcdir)/config/powerpcspe/powerpcspe-cpus.def $(SHELL) $(srcdir)/config/powerpcspe/genopt.sh $(srcdir)/config/powerpcspe > \ --- a/gcc/config/rs6000/linux.h +++ b/gcc/config/rs6000/linux.h @@ -57,6 +57,19 @@ } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" --- a/gcc/config/rs6000/linux64.h +++ b/gcc/config/rs6000/linux64.h @@ -391,6 +391,19 @@ extern int dot_symbols; } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + d_add_builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + d_add_builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + d_add_builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux) %(include_extra)" --- /dev/null +++ b/gcc/config/rs6000/rs6000-d.c @@ -0,0 +1,58 @@ +/* Subroutines for the D front end on the PowerPC architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for PowerPC targets. */ + +void +rs6000_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("PPC64"); + else + d_add_builtin_version ("PPC"); + + if (TARGET_HARD_FLOAT) + { + d_add_builtin_version ("PPC_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT) + { + d_add_builtin_version ("PPC_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for PowerPC targets. */ + +const char * +rs6000_d_float_abi_type (void) +{ + if (TARGET_HARD_FLOAT) + return "hard"; + else if (TARGET_SOFT_FLOAT) + return "soft"; + + return NULL; +} --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -224,6 +224,10 @@ extern void rs6000_target_modify_macros extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT, HOST_WIDE_INT); +/* Declare functions in rs6000-d.c */ +extern void rs6000_d_target_versions (void); +extern const char *rs6000_d_float_abi_type (void); + #if TARGET_MACHO char *output_call (rtx_insn *, rtx *, int, int); #endif --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -613,6 +613,10 @@ extern unsigned char rs6000_recip_bits[] #define TARGET_CPU_CPP_BUILTINS() \ rs6000_cpu_cpp_builtins (pfile) +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS rs6000_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE rs6000_d_float_abi_type + /* This is used by rs6000_cpu_cpp_builtins to indicate the byte order we're compiling for. Some configurations may need to override it. */ #define RS6000_CPU_CPP_ENDIAN_BUILTINS() \ --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -35,6 +35,10 @@ rs6000-p8swap.o: $(srcdir)/config/rs6000 $(COMPILE) $< $(POSTCOMPILE) +rs6000-d.o: $(srcdir)/config/rs6000/rs6000-d.c + $(COMPILE) $< + $(POSTCOMPILE) + $(srcdir)/config/rs6000/rs6000-tables.opt: $(srcdir)/config/rs6000/genopt.sh \ $(srcdir)/config/rs6000/rs6000-cpus.def $(SHELL) $(srcdir)/config/rs6000/genopt.sh $(srcdir)/config/rs6000 > \ --- /dev/null +++ b/gcc/config/s390/s390-d.c @@ -0,0 +1,54 @@ +/* Subroutines for the D front end on the IBM S/390 and zSeries architectures. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for S/390 and zSeries targets. */ + +void +s390_d_target_versions (void) +{ + if (TARGET_ZARCH) + d_add_builtin_version ("SystemZ"); + else if (TARGET_64BIT) + d_add_builtin_version ("S390X"); + else + d_add_builtin_version ("S390"); + + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("D_SoftFloat"); + else if (TARGET_HARD_FLOAT) + d_add_builtin_version ("D_HardFloat"); +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for S/390 and zSeries targets. */ + +const char * +s390_d_float_abi_type (void) +{ + if (TARGET_HARD_FLOAT) + return "hard"; + else if (TARGET_SOFT_FLOAT) + return "soft"; + + return NULL; +} --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -166,6 +166,10 @@ extern void s390_register_target_pragmas /* Routines for s390-c.c */ extern bool s390_const_operand_ok (tree, int, int, tree); +/* Routines for s390-d.c */ +extern void s390_d_target_versions (void); +extern const char *s390_d_float_abi_type (void); + /* Pass management. */ namespace gcc { class context; } class rtl_opt_pass; --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -200,6 +200,10 @@ enum processor_flags /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() s390_cpu_cpp_builtins (pfile) +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS s390_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE s390_d_float_abi_type + #ifdef DEFAULT_TARGET_64BIT #define TARGET_DEFAULT (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP \ | MASK_OPT_HTM | MASK_OPT_VX) --- a/gcc/config/s390/t-s390 +++ b/gcc/config/s390/t-s390 @@ -26,3 +26,7 @@ s390-c.o: $(srcdir)/config/s390/s390-c.c $(TARGET_H) $(TARGET_DEF_H) $(CPPLIB_H) $(C_PRAGMA_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/s390/s390-c.c + +s390-d.o: $(srcdir)/config/s390/s390-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/sparc/sparc-d.c @@ -0,0 +1,56 @@ +/* Subroutines for the D front end on the SPARC architecture. + Copyright (C) 2017-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for SPARC targets. */ + +void +sparc_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("SPARC64"); + else + d_add_builtin_version ("SPARC"); + + if (TARGET_V8PLUS) + d_add_builtin_version ("SPARC_V8Plus"); + + if (TARGET_FPU) + { + d_add_builtin_version ("D_HardFloat"); + d_add_builtin_version ("SPARC_HardFloat"); + } + else + { + d_add_builtin_version ("D_SoftFloat"); + d_add_builtin_version ("SPARC_SoftFloat"); + } +} + +/* Implement TARGET_D_FLOAT_ABI_TYPE for SPARC targets. */ + +const char * +sparc_d_float_abi_type (void) +{ + return (TARGET_FPU) ? "hard" : "soft"; +} --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -111,4 +111,8 @@ unsigned int sparc_regmode_natural_size extern rtl_opt_pass *make_pass_work_around_errata (gcc::context *); +/* Routines implemented in sparc-d.c */ +extern void sparc_d_target_versions (void); +extern const char *sparc_d_float_abi_type (void); + #endif /* __SPARC_PROTOS_H__ */ --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -27,6 +27,10 @@ along with GCC; see the file COPYING3. #define TARGET_CPU_CPP_BUILTINS() sparc_target_macros () +/* Target hooks for D language. */ +#define TARGET_D_CPU_VERSIONS sparc_d_target_versions +#define TARGET_D_FLOAT_ABI_TYPE sparc_d_float_abi_type + /* Specify this in a cover file to provide bi-architecture (32/64) support. */ /* #define SPARC_BI_ARCH */ --- a/gcc/config/sparc/t-sparc +++ b/gcc/config/sparc/t-sparc @@ -23,3 +23,7 @@ PASSES_EXTRA += $(srcdir)/config/sparc/s sparc-c.o: $(srcdir)/config/sparc/sparc-c.c $(COMPILE) $< $(POSTCOMPILE) + +sparc-d.o: $(srcdir)/config/sparc/sparc-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- a/gcc/config/t-glibc +++ b/gcc/config/t-glibc @@ -19,3 +19,7 @@ glibc-c.o: config/glibc-c.c $(COMPILE) $< $(POSTCOMPILE) + +glibc-d.o: config/glibc-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- a/gcc/configure +++ b/gcc/configure @@ -612,6 +612,7 @@ ISLLIBS GMPINC GMPLIBS target_cpu_default +d_target_objs fortran_target_objs cxx_target_objs c_target_objs @@ -619,6 +620,8 @@ use_gcc_stdint xm_defines xm_include_list xm_file_list +tm_d_include_list +tm_d_file_list tm_p_include_list tm_p_file_list tm_defines @@ -5142,6 +5145,7 @@ esac + # Determine PICFLAG for target gnatlib. @@ -11960,6 +11964,7 @@ fi tm_file="${tm_file} defaults.h" tm_p_file="${tm_p_file} tm-preds.h" +tm_d_file="${tm_d_file} defaults.h" host_xm_file="auto-host.h ansidecl.h ${host_xm_file}" build_xm_file="${build_auto} ansidecl.h ${build_xm_file}" # We don't want ansidecl.h in target files, write code there in ISO/GNU C. @@ -12343,6 +12348,21 @@ for f in $tm_p_file; do esac done +tm_d_file_list= +tm_d_include_list="options.h insn-constants.h" +for f in $tm_d_file; do + case $f in + defaults.h ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/$f" + tm_d_include_list="${tm_d_include_list} $f" + ;; + * ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/config/$f" + tm_d_include_list="${tm_d_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do @@ -18612,7 +18632,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18615 "configure" +#line 18634 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18718,7 +18738,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18721 "configure" +#line 18740 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -29526,6 +29546,9 @@ fi + + + --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -1754,6 +1754,7 @@ AC_SUBST(build_subdir) tm_file="${tm_file} defaults.h" tm_p_file="${tm_p_file} tm-preds.h" +tm_d_file="${tm_d_file} defaults.h" host_xm_file="auto-host.h ansidecl.h ${host_xm_file}" build_xm_file="${build_auto} ansidecl.h ${build_xm_file}" # We don't want ansidecl.h in target files, write code there in ISO/GNU C. @@ -1986,6 +1987,21 @@ for f in $tm_p_file; do esac done +tm_d_file_list= +tm_d_include_list="options.h insn-constants.h" +for f in $tm_d_file; do + case $f in + defaults.h ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/$f" + tm_d_include_list="${tm_d_include_list} $f" + ;; + * ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/config/$f" + tm_d_include_list="${tm_d_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do @@ -6323,6 +6339,8 @@ AC_SUBST(tm_include_list) AC_SUBST(tm_defines) AC_SUBST(tm_p_file_list) AC_SUBST(tm_p_include_list) +AC_SUBST(tm_d_file_list) +AC_SUBST(tm_d_include_list) AC_SUBST(xm_file_list) AC_SUBST(xm_include_list) AC_SUBST(xm_defines) @@ -6330,6 +6348,7 @@ AC_SUBST(use_gcc_stdint) AC_SUBST(c_target_objs) AC_SUBST(cxx_target_objs) AC_SUBST(fortran_target_objs) +AC_SUBST(d_target_objs) AC_SUBST(target_cpu_default) AC_SUBST_FILE(language_hooks) --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -52,6 +52,7 @@ through the macros defined in the @file{ * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* D Language and ABI:: Controlling D ABI changes. * Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -106,6 +107,14 @@ documented as ``Common Target Hook''. T @code{target_has_targetm_common=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetdm} variable for hooks that are +specific to the D language front end, documented as ``D Target Hook''. +This is declared in @file{d/d-target.h}, the initializer +@code{TARGETDM_INITIALIZER} in @file{d/d-target-def.h}. If targets +initialize @code{targetdm} themselves, they should set +@code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -10667,6 +10676,40 @@ unloaded. The default is to return false Return target-specific mangling context of @var{decl} or @code{NULL_TREE}. @end deftypefn +@node D Language and ABI +@section D ABI parameters +@cindex parameters, d abi + +@deftypefn {D Target Hook} void TARGET_D_CPU_VERSIONS (void) +Declare all environmental version identifiers relating to the target CPU +using the function @code{builtin_version}, which takes a string representing +the name of the version. Version identifiers predefined by this hook apply +to all modules that are being compiled and imported. +@end deftypefn + +@deftypefn {D Target Hook} void TARGET_D_OS_VERSIONS (void) +Similarly to @code{TARGET_D_CPU_VERSIONS}, but is used for versions +relating to the target operating system. +@end deftypefn + +@deftypefn {D Target Hook} unsigned TARGET_D_CRITSEC_SIZE (void) +Returns the size of the data structure used by the target operating system +for critical sections and monitors. For example, on Microsoft Windows this +would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that +implement pthreads would return @code{sizeof(pthread_mutex_t)}. +@end deftypefn + +@deftypefn {D Target Hook} {const char *} TARGET_D_FLOAT_ABI_TYPE (void) +Returns a string specifying which floating-point ABI is in use, or whether +floating-point value types are passed in FPU registers. For most targets, +this would be described as either "hard" or "soft". +@end deftypefn + +@deftypefn {D Target Hook} {const char *} TARGET_D_OBJECT_FORMAT (void) +Returns a string specifying the executable object format of the platform +the compiler is generating code for. +@end deftypefn + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -52,6 +52,7 @@ through the macros defined in the @file{ * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* D Language and ABI:: Controlling D ABI changes. * Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -106,6 +107,14 @@ documented as ``Common Target Hook''. T @code{target_has_targetm_common=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetdm} variable for hooks that are +specific to the D language front end, documented as ``D Target Hook''. +This is declared in @file{d/d-target.h}, the initializer +@code{TARGETDM_INITIALIZER} in @file{d/d-target-def.h}. If targets +initialize @code{targetdm} themselves, they should set +@code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -7310,6 +7319,20 @@ floating-point support; they are not inc @hook TARGET_CXX_DECL_MANGLING_CONTEXT +@node D Language and ABI +@section D ABI parameters +@cindex parameters, d abi + +@hook TARGET_D_CPU_VERSIONS + +@hook TARGET_D_OS_VERSIONS + +@hook TARGET_D_CRITSEC_SIZE + +@hook TARGET_D_FLOAT_ABI_TYPE + +@hook TARGET_D_OBJECT_FORMAT + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces --- a/gcc/genhooks.c +++ b/gcc/genhooks.c @@ -34,6 +34,7 @@ static struct hook_desc hook_array[] = { #include "target.def" #include "c-family/c-target.def" #include "common/common-target.def" +#include "d/d-target.def" #undef DEFHOOK }; ================================================ FILE: gcc/d/patches/patch-targetdm-untested-9.patch ================================================ This patch implements the support for the D language specific target hooks. The following versions are available for all supported architectures. * D_HardFloat * D_SoftFloat The following CPU versions are implemented: * Epiphany * HPPA * HPPA64 * IA64 * NVPTX * NVPTX64 * RISCV32 * RISCV64 * SH The following OS versions are implemented: * Windows ** Win32 ** Win64 ** Cygwin ** MinGW * OSX ** darwin (deprecated) * FreeBSD * OpenBSD * NetBSD * DragonFlyBSD * Solaris * Posix These official OS versions are not implemented: * AIX * BSD (other BSDs) * Haiku * PlayStation * PlayStation4 * SkyOS * SysV3 * SysV4 * CRuntime_DigitalMars * CRuntime_Microsoft --- --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -356,6 +356,9 @@ bfin*-*) crisv32-*) cpu_type=cris ;; +epiphany-*-* ) + d_target_objs="epiphany-d.o" + ;; frv*) cpu_type=frv extra_options="${extra_options} g.opt" ;; @@ -429,6 +432,7 @@ x86_64-*-*) avx512vpopcntdqvlintrin.h avx512bitalgintrin.h" ;; ia64-*-*) + d_target_objs="ia64-d.o" extra_headers=ia64intrin.h extra_options="${extra_options} g.opt fused-madd.opt" ;; @@ -468,6 +472,7 @@ nios2-*-*) ;; nvptx-*-*) cpu_type=nvptx + d_target_objs="nvptx-d.o" ;; powerpc*-*-*spe*) cpu_type=powerpcspe @@ -499,6 +504,7 @@ powerpc*-*-*) riscv*) cpu_type=riscv extra_objs="riscv-builtins.o riscv-c.o" + d_target_objs="riscv-d.o" ;; rs6000*-*-*) extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" @@ -685,8 +691,10 @@ case ${target} in extra_options="${extra_options} darwin.opt" c_target_objs="${c_target_objs} darwin-c.o" cxx_target_objs="${cxx_target_objs} darwin-c.o" + d_target_objs="${d_target_objs} darwin-d.o" fortran_target_objs="darwin-f.o" target_has_targetcm=yes + target_has_targetdm=yes extra_objs="${extra_objs} darwin.o" extra_gcc_objs="darwin-driver.o" default_use_cxa_atexit=yes @@ -711,6 +719,9 @@ case ${target} in exit 1 ;; esac + d_target_objs="${d_target_objs} dragonfly-d.o" + target_has_targetdm=yes + tmake_file="${tmake_file} t-dragonfly" extra_options="$extra_options rpath.opt dragonfly.opt" default_use_cxa_atexit=yes use_gcc_stdint=wrap @@ -754,6 +765,9 @@ case ${target} in ;; esac fbsd_tm_file="${fbsd_tm_file} freebsd-spec.h freebsd.h freebsd-stdint.h" + d_target_objs="${d_target_objs} freebsd-d.o" + target_has_targetdm=yes + tmake_file="${tmake_file} t-freebsd" extra_options="$extra_options rpath.opt freebsd.opt" case ${target} in *-*-freebsd[345].*) @@ -830,6 +844,8 @@ case ${target} in tm_p_file="${tm_p_file} netbsd-protos.h" tmake_file="t-netbsd t-slibgcc" extra_objs="${extra_objs} netbsd.o" + d_target_objs="${d_target_objs} netbsd-d.o" + target_has_targetdm=yes gas=yes gnu_ld=yes use_gcc_stdint=wrap @@ -841,6 +857,8 @@ case ${target} in ;; *-*-openbsd*) tmake_file="t-openbsd" + d_target_objs="${d_target_objs} netbsd-d.o" + target_has_targetdm=yes case ${enable_threads} in yes) thread_file='posix' @@ -906,6 +924,8 @@ case ${target} in tmake_file="${tmake_file} t-sol2 t-slibgcc" c_target_objs="${c_target_objs} sol2-c.o" cxx_target_objs="${cxx_target_objs} sol2-c.o sol2-cxx.o" + d_target_objs="${d_target_objs} sol2-d.o" + target_has_targetdm="yes" extra_objs="${extra_objs} sol2.o sol2-stubs.o" extra_options="${extra_options} sol2.opt" case ${enable_threads}:${have_pthread_h}:${have_thread_h} in @@ -1768,7 +1788,9 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) xm_file=i386/xm-mingw32.h c_target_objs="${c_target_objs} winnt-c.o" cxx_target_objs="${cxx_target_objs} winnt-c.o" + d_target_objs="${d_target_objs} winnt-d.o" target_has_targetcm="yes" + target_has_targetdm="yes" case ${target} in x86_64-*-* | *-w64-*) need_64bit_isa=yes @@ -4606,6 +4628,8 @@ case ${target} in then target_cpu_default2="MASK_GAS" fi + d_target_objs="${d_target_objs} pa-d.o" + tmake_file="pa/t-pa ${tmake_file}" ;; fido*-*-* | m68k*-*-*) @@ -4699,6 +4723,7 @@ case ${target} in sh[123456ble]*-*-* | sh-*-*) c_target_objs="${c_target_objs} sh-c.o" cxx_target_objs="${cxx_target_objs} sh-c.o" + d_target_objs="${d_target_objs} sh-d.o" ;; sparc*-*-*) --- /dev/null +++ b/gcc/config/darwin-d.c @@ -0,0 +1,55 @@ +/* Darwin support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for Darwin targets. */ + +static void +darwin_d_os_builtins (void) +{ + d_add_builtin_version ("OSX"); + d_add_builtin_version ("darwin"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for Darwin targets. */ + +static unsigned +darwin_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t. */ + if (TYPE_PRECISION (long_integer_type_node) == 64 + && POINTER_SIZE == 64 + && TYPE_PRECISION (integer_type_node) == 32) + return 64; + else + return 44; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS darwin_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE darwin_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/dragonfly-d.c @@ -0,0 +1,49 @@ +/* DragonFly support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for DragonFly targets. */ + +static void +dragonfly_d_os_builtins (void) +{ + d_add_builtin_version ("DragonFlyBSD"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for DragonFly targets. */ + +static unsigned +dragonfly_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t, an opaque pointer. */ + return POINTER_SIZE_UNITS; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS dragonfly_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE dragonfly_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/epiphany/epiphany-d.c @@ -0,0 +1,31 @@ +/* Subroutines for the D front end on the EPIPHANY architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for EPIPHANY targets. */ + +void +epiphany_d_target_versions (void) +{ + d_add_builtin_version ("Epiphany"); + d_add_builtin_version ("D_HardFloat"); +} --- a/gcc/config/epiphany/epiphany-protos.h +++ b/gcc/config/epiphany/epiphany-protos.h @@ -60,3 +60,5 @@ extern bool epiphany_regno_rename_ok (un it uses peephole2 predicates without having all the necessary headers. */ extern int get_attr_sched_use_fpu (rtx_insn *); +/* Routines implemented in epiphany-d.c */ +extern void epiphany_d_target_versions (void); --- a/gcc/config/epiphany/epiphany.h +++ b/gcc/config/epiphany/epiphany.h @@ -41,6 +41,9 @@ along with GCC; see the file COPYING3. builtin_assert ("machine=epiphany"); \ } while (0) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS epiphany_d_target_versions + /* Pick up the libgloss library. One day we may do this by linker script, but for now its static. libgloss might use errno/__errno, which might not have been needed when we --- a/gcc/config/epiphany/t-epiphany +++ b/gcc/config/epiphany/t-epiphany @@ -36,3 +36,7 @@ specs: specs.install sed -e 's,epiphany_library_extra_spec,epiphany_library_stub_spec,' \ -e 's,epiphany_library_build_spec,epiphany_library_extra_spec,' \ < specs.install > $@ ; \ + +epiphany-d.o: $(srcdir)/config/epiphany/epiphany-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/freebsd-d.c @@ -0,0 +1,49 @@ +/* FreeBSD support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for FreeBSD targets. */ + +static void +freebsd_d_os_builtins (void) +{ + d_add_builtin_version ("FreeBSD"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for FreeBSD targets. */ + +static unsigned +freebsd_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t, an opaque pointer. */ + return POINTER_SIZE_UNITS; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS freebsd_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE freebsd_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- a/gcc/config/i386/cygwin.h +++ b/gcc/config/i386/cygwin.h @@ -29,6 +29,12 @@ along with GCC; see the file COPYING3. } \ while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("Cygwin"); \ + builtin_version ("Posix"); \ + } while (0) + #undef CPP_SPEC #define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} \ %{!ansi:-Dunix} \ --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -53,6 +53,16 @@ along with GCC; see the file COPYING3. } \ while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("MinGW"); \ + \ + if (TARGET_64BIT && ix86_abi == MS_ABI) \ + builtin_version ("Win64"); \ + else if (!TARGET_64BIT) \ + builtin_version ("Win32"); \ + } while (0) + #ifndef TARGET_USE_PTHREAD_BY_DEFAULT #define SPEC_PTHREAD1 "pthread" #define SPEC_PTHREAD2 "!no-pthread" --- a/gcc/config/i386/t-cygming +++ b/gcc/config/i386/t-cygming @@ -32,6 +32,9 @@ winnt-cxx.o: $(srcdir)/config/i386/winnt $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/i386/winnt-cxx.c +winnt-d.o: config/winnt-d.c + $(COMPILE) $< + $(POSTCOMPILE) winnt-stubs.o: $(srcdir)/config/i386/winnt-stubs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \ --- /dev/null +++ b/gcc/config/i386/winnt-d.c @@ -0,0 +1,60 @@ +/* Windows support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "d/d-target.h" +#include "d/d-target-def.h" +#include "tm_p.h" + +/* Implement TARGET_D_OS_VERSIONS for Windows targets. */ + +static void +winnt_d_os_builtins (void) +{ + d_add_builtin_version ("Windows"); + +#define builtin_version(TXT) d_add_builtin_version (TXT) + +#ifdef EXTRA_TARGET_D_OS_VERSIONS + EXTRA_TARGET_D_OS_VERSIONS (); +#endif +} + +/* Implement TARGET_D_CRITSEC_SIZE for Windows targets. */ + +static unsigned +winnt_d_critsec_size (void) +{ + /* This is the sizeof CRITICAL_SECTION. */ + if (TYPE_PRECISION (long_integer_type_node) == 64 + && POINTER_SIZE == 64 + && TYPE_PRECISION (integer_type_node) == 32) + return 40; + else + return 24; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS winnt_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE winnt_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/ia64/ia64-d.c @@ -0,0 +1,31 @@ +/* Subroutines for the D front end on the IA64 architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for IA64 targets. */ + +void +ia64_d_target_versions (void) +{ + d_add_builtin_version ("IA64"); + d_add_builtin_version ("D_HardFloat"); +} --- a/gcc/config/ia64/ia64-protos.h +++ b/gcc/config/ia64/ia64-protos.h @@ -92,6 +92,9 @@ extern void ia64_hpux_handle_builtin_pra extern void ia64_output_function_profiler (FILE *, int); extern void ia64_profile_hook (int); +/* Routines implemented in ia64-d.c */ +extern void ia64_d_target_versions (void); + extern void ia64_init_expanders (void); extern rtx ia64_dconst_0_5 (void); --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -40,6 +40,9 @@ do { \ builtin_define("__BIG_ENDIAN__"); \ } while (0) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS ia64_d_target_versions + #ifndef SUBTARGET_EXTRA_SPECS #define SUBTARGET_EXTRA_SPECS #endif --- a/gcc/config/ia64/t-ia64 +++ b/gcc/config/ia64/t-ia64 @@ -21,6 +21,10 @@ ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/ia64/ia64-c.c +ia64-d.o: $(srcdir)/config/ia64/ia64-d.c + $(COMPILE) $< + $(POSTCOMPILE) + # genattrtab generates very long string literals. insn-attrtab.o-warn = -Wno-error --- /dev/null +++ b/gcc/config/netbsd-d.c @@ -0,0 +1,49 @@ +/* NetBSD support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for NetBSD targets. */ + +static void +netbsd_d_os_builtins (void) +{ + d_add_builtin_version ("NetBSD"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for NetBSD targets. */ + +static unsigned +netbsd_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t. */ + return 48; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS netbsd_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE netbsd_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/nvptx/nvptx-d.c @@ -0,0 +1,34 @@ +/* Subroutines for the D front end on the NVPTX architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for NVPTX targets. */ + +void +nvptx_d_target_versions (void) +{ + if (TARGET_ABI64) + d_add_builtin_version ("NVPTX64"); + else + d_add_builtin_version ("NVPTX"); +} --- a/gcc/config/nvptx/nvptx-protos.h +++ b/gcc/config/nvptx/nvptx-protos.h @@ -43,6 +43,9 @@ extern void nvptx_output_ascii (FILE *, extern void nvptx_register_pragmas (void); extern unsigned int nvptx_data_alignment (const_tree, unsigned int); +/* Routines implemented in nvptx-d.c */ +extern void nvptx_d_target_versions (void); + #ifdef RTX_CODE extern void nvptx_expand_oacc_fork (unsigned); extern void nvptx_expand_oacc_join (unsigned); --- a/gcc/config/nvptx/nvptx.h +++ b/gcc/config/nvptx/nvptx.h @@ -37,6 +37,9 @@ builtin_define ("__nvptx_unisimt__"); \ } while (0) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS nvptx_d_target_versions + /* Avoid the default in ../../gcc.c, which adds "-pthread", which is not supported for nvptx. */ #define GOMP_SELF_SPECS "" --- a/gcc/config/nvptx/t-nvptx +++ b/gcc/config/nvptx/t-nvptx @@ -10,3 +10,7 @@ mkoffload$(exeext): mkoffload.o collect- mkoffload.o collect-utils.o libcommon-target.a $(LIBIBERTY) $(LIBS) MULTILIB_OPTIONS = mgomp + +nvptx-d.o: $(srcdir)/config/nvptx/nvptx-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/openbsd-d.c @@ -0,0 +1,49 @@ +/* OpenBSD support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for OpenBSD targets. */ + +static void +openbsd_d_os_builtins (void) +{ + d_add_builtin_version ("OpenBSD"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for OpenBSD targets. */ + +static unsigned +openbsd_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t, an opaque pointer. */ + return POINTER_SIZE_UNITS; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS openbsd_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE openbsd_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- /dev/null +++ b/gcc/config/pa/pa-d.c @@ -0,0 +1,39 @@ +/* Subroutines for the D front end on the HPPA architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for HPPA targets. */ + +void +pa_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("HPPA64"); + else + d_add_builtin_version("HPPA"); + + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("D_SoftFloat"); + else + d_add_builtin_version ("D_HardFloat"); +} --- a/gcc/config/pa/pa-linux.h +++ b/gcc/config/pa/pa-linux.h @@ -27,6 +27,8 @@ along with GCC; see the file COPYING3. } \ while (0) +#define GNU_USER_TARGET_D_CRITSEC_SIZE 48 + #undef CPP_SPEC #define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}" --- a/gcc/config/pa/pa-protos.h +++ b/gcc/config/pa/pa-protos.h @@ -110,3 +110,6 @@ extern HOST_WIDE_INT pa_initial_eliminat extern HOST_WIDE_INT pa_function_arg_size (machine_mode, const_tree); extern const int pa_magic_milli[]; + +/* Routines implemented in pa-d.c */ +extern void pa_d_target_versions (void); --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -196,6 +196,9 @@ do { \ } \ while (0) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS pa_d_target_versions + #define CC1_SPEC "%{pg:} %{p:}" #define LINK_SPEC "%{mlinker-opt:-O} %{!shared:-u main} %{shared:-b}" --- /dev/null +++ b/gcc/config/pa/t-pa @@ -0,0 +1,3 @@ +pa-d.o: $(srcdir)/config/pa/pa-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/riscv/riscv-d.c @@ -0,0 +1,39 @@ +/* Subroutines for the D front end on the RISC-V architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for RISC-V targets. */ + +void +riscv_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("RISCV64"); + else + d_add_builtin_version ("RISCV32"); + + if (TARGET_HARDFLOAT) + d_add_builtin_version ("D_HardFloat"); + else + d_add_builtin_version ("D_SoftFloat"); +} --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -74,6 +74,9 @@ extern bool riscv_expand_block_move (rtx /* Routines implemented in riscv-c.c. */ void riscv_cpu_cpp_builtins (cpp_reader *); +/* Routines implemented in riscv-d.c */ +extern void riscv_d_target_versions (void); + /* Routines implemented in riscv-builtins.c. */ extern void riscv_atomic_assign_expand_fenv (tree *, tree *, tree *); extern rtx riscv_expand_builtin (tree, rtx, rtx, machine_mode, int); --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS riscv_d_target_versions + /* Default target_flags if no switches are specified */ #ifndef TARGET_DEFAULT --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -9,3 +9,7 @@ riscv-c.o: $(srcdir)/config/riscv/riscv- coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-c.c + +riscv-d.o: $(srcdir)/config/riscv/riscv-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/sh/sh-d.c @@ -0,0 +1,36 @@ +/* Subroutines for the D front end on the SuperH architecture. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for SuperH targets. */ + +void +sh_d_target_versions (void) +{ + d_add_builtin_version ("SH"); + + if (TARGET_FPU_ANY) + d_add_builtin_version ("D_HardFloat"); + else + d_add_builtin_version ("D_SoftFloat"); +} --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -363,4 +363,7 @@ extern machine_mode sh_hard_regno_caller machine_mode); extern bool sh_can_use_simple_return_p (void); extern rtx sh_load_function_descriptor (rtx); + +/* Routines implemented in sh-d.c */ +extern void sh_d_target_versions (void); #endif /* ! GCC_SH_PROTOS_H */ --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -31,6 +31,9 @@ extern int code_for_indirect_jump_scratc #define TARGET_CPU_CPP_BUILTINS() sh_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS sh_d_target_versions + /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms may be accessed via the stack pointer) in functions that seem suitable. */ --- a/gcc/config/sh/t-sh +++ b/gcc/config/sh/t-sh @@ -25,6 +25,10 @@ sh-c.o: $(srcdir)/config/sh/sh-c.c \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/sh/sh-c.c +sh-d.o: $(srcdir)/config/sh/sh-d.c + $(COMPILE) $< + $(POSTCOMPILE) + sh_treg_combine.o: $(srcdir)/config/sh/sh_treg_combine.cc \ $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_H) $(TM_P_H) coretypes.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< --- /dev/null +++ b/gcc/config/sol2-d.c @@ -0,0 +1,49 @@ +/* Solaris support needed only by D front-end. + Copyright (C) 2017 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for Solaris targets. */ + +static void +solaris_d_os_builtins (void) +{ + d_add_builtin_version ("Solaris"); + d_add_builtin_version ("Posix"); +} + +/* Implement TARGET_D_CRITSEC_SIZE for Solaris targets. */ + +static unsigned +solaris_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t. */ + return 24; +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS solaris_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE solaris_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; --- a/gcc/config/t-darwin +++ b/gcc/config/t-darwin @@ -26,6 +26,9 @@ darwin-c.o: $(srcdir)/config/darwin-c.c $(COMPILE) $(PREPROCESSOR_DEFINES) $< $(POSTCOMPILE) +darwin-d.o: $(srcdir)/config/darwin-d.c + $(COMPILE) $< + $(POSTCOMPILE) darwin-f.o: $(srcdir)/config/darwin-f.c $(COMPILE) $< --- /dev/null +++ b/gcc/config/t-dragonfly @@ -0,0 +1,3 @@ +dragonfly-d.o: config/dragonfly-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- /dev/null +++ b/gcc/config/t-freebsd @@ -0,0 +1,3 @@ +freebsd-d.o: config/freebsd-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- a/gcc/config/t-netbsd +++ b/gcc/config/t-netbsd @@ -1,3 +1,6 @@ +netbsd-d.o: config/netbsd-d.c + $(COMPILE) $< + $(POSTCOMPILE) # Copyright (C) 2017-2018 Free Software Foundation, Inc. # # This file is part of GCC. --- a/gcc/config/t-openbsd +++ b/gcc/config/t-openbsd @@ -1,2 +1,6 @@ # We don't need GCC's own include files. USER_H = $(EXTRA_HEADERS) + +openbsd-d.o: config/openbsd-d.c + $(COMPILE) $< + $(POSTCOMPILE) --- a/gcc/config/t-sol2 +++ b/gcc/config/t-sol2 @@ -26,6 +26,11 @@ sol2-cxx.o: $(srcdir)/config/sol2-cxx.c $(COMPILE) $< $(POSTCOMPILE) +# Solaris-specific D support. +sol2-d.o: $(srcdir)/config/sol2-d.c + $(COMPILE) $< + $(POSTCOMPILE) + # Corresponding stub routines. sol2-stubs.o: $(srcdir)/config/sol2-stubs.c $(COMPILE) $< ================================================ FILE: gcc/d/patches/patch-toplev-9.patch ================================================ This implements building of libphobos library in GCC. --- --- a/Makefile.def +++ b/Makefile.def @@ -153,6 +153,8 @@ target_modules = { module= libgfortran; target_modules = { module= libobjc; }; target_modules = { module= libgo; }; target_modules = { module= libhsail-rt; }; +target_modules = { module= libphobos; + lib_path=src/.libs; }; target_modules = { module= libtermcap; no_check=true; missing=mostlyclean; missing=clean; @@ -265,6 +267,8 @@ flags_to_pass = { flag= STAGE1_CHECKING flags_to_pass = { flag= STAGE1_LANGUAGES ; }; flags_to_pass = { flag= GNATBIND ; }; flags_to_pass = { flag= GNATMAKE ; }; +flags_to_pass = { flag= GDC ; }; +flags_to_pass = { flag= GDCFLAGS ; }; // Target tools flags_to_pass = { flag= AR_FOR_TARGET ; }; @@ -278,6 +282,8 @@ flags_to_pass = { flag= FLAGS_FOR_TARGET flags_to_pass = { flag= GFORTRAN_FOR_TARGET ; }; flags_to_pass = { flag= GOC_FOR_TARGET ; }; flags_to_pass = { flag= GOCFLAGS_FOR_TARGET ; }; +flags_to_pass = { flag= GDC_FOR_TARGET ; }; +flags_to_pass = { flag= GDCFLAGS_FOR_TARGET ; }; flags_to_pass = { flag= LD_FOR_TARGET ; }; flags_to_pass = { flag= LIPO_FOR_TARGET ; }; flags_to_pass = { flag= LDFLAGS_FOR_TARGET ; }; @@ -544,6 +550,11 @@ dependencies = { module=configure-target dependencies = { module=all-target-libgo; on=all-target-libbacktrace; }; dependencies = { module=all-target-libgo; on=all-target-libffi; }; dependencies = { module=all-target-libgo; on=all-target-libatomic; }; +dependencies = { module=configure-target-libphobos; on=configure-target-libbacktrace; }; +dependencies = { module=configure-target-libphobos; on=configure-target-zlib; }; +dependencies = { module=all-target-libphobos; on=all-target-libbacktrace; }; +dependencies = { module=all-target-libphobos; on=all-target-zlib; }; +dependencies = { module=all-target-libphobos; on=all-target-libatomic; }; dependencies = { module=configure-target-libstdc++-v3; on=configure-target-libgomp; }; dependencies = { module=configure-target-liboffloadmic; on=configure-target-libgomp; }; dependencies = { module=configure-target-libsanitizer; on=all-target-libstdc++-v3; }; @@ -557,6 +568,7 @@ dependencies = { module=all-target-libof dependencies = { module=install-target-libgo; on=install-target-libatomic; }; dependencies = { module=install-target-libgfortran; on=install-target-libquadmath; }; dependencies = { module=install-target-libgfortran; on=install-target-libgcc; }; +dependencies = { module=install-target-libphobos; on=install-target-libatomic; }; dependencies = { module=install-target-libsanitizer; on=install-target-libstdc++-v3; }; dependencies = { module=install-target-libsanitizer; on=install-target-libgcc; }; dependencies = { module=install-target-libvtv; on=install-target-libstdc++-v3; }; @@ -598,6 +610,8 @@ languages = { language=go; gcc-check-tar lib-check-target=check-gotools; }; languages = { language=brig; gcc-check-target=check-brig; lib-check-target=check-target-libhsail-rt; }; +languages = { language=d; gcc-check-target=check-d; + lib-check-target=check-target-libphobos; }; // Toplevel bootstrap bootstrap_stage = { id=1 ; }; --- a/Makefile.in +++ b/Makefile.in @@ -156,6 +156,8 @@ BUILD_EXPORTS = \ GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ GOC="$(GOC_FOR_BUILD)"; export GOC; \ GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \ + GDC="$(GDC_FOR_BUILD)"; export GDC; \ + GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -192,6 +194,7 @@ HOST_EXPORTS = \ CXXFLAGS="$(CXXFLAGS)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \ GOC="$(GOC)"; export GOC; \ + GDC="$(GDC)"; export GDC; \ AR="$(AR)"; export AR; \ AS="$(AS)"; export AS; \ CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \ @@ -256,6 +259,15 @@ POSTSTAGE1_HOST_EXPORTS = \ CC_FOR_BUILD="$$CC"; export CC_FOR_BUILD; \ $(POSTSTAGE1_CXX_EXPORT) \ $(LTO_EXPORTS) \ + GDC="$$r/$(HOST_SUBDIR)/prev-gcc/gdc$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ \ + -B$(build_tooldir)/bin/ $(GDCFLAGS_FOR_TARGET) \ + -B$$r/prev-$(TARGET_SUBDIR)/libphobos/src \ + -I$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime -I$$s/libphobos/libdruntime \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libstdc++-v3/src/.libs"; \ + export GDC; \ + GDC_FOR_BUILD="$$GDC"; export GDC_FOR_BUILD; \ GNATBIND="$$r/$(HOST_SUBDIR)/prev-gcc/gnatbind"; export GNATBIND; \ LDFLAGS="$(POSTSTAGE1_LDFLAGS) $(BOOT_LDFLAGS)"; export LDFLAGS; \ HOST_LIBS="$(POSTSTAGE1_LIBS)"; export HOST_LIBS; @@ -278,6 +290,7 @@ BASE_TARGET_EXPORTS = \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GFORTRAN; \ GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GOC; \ + GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GDC; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -342,6 +355,7 @@ CXX_FOR_BUILD = @CXX_FOR_BUILD@ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@ GOC_FOR_BUILD = @GOC_FOR_BUILD@ +GDC_FOR_BUILD = @GDC_FOR_BUILD@ LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ LD_FOR_BUILD = @LD_FOR_BUILD@ NM_FOR_BUILD = @NM_FOR_BUILD@ @@ -399,6 +413,7 @@ STRIP = @STRIP@ WINDRES = @WINDRES@ WINDMC = @WINDMC@ +GDC = @GDC@ GNATBIND = @GNATBIND@ GNATMAKE = @GNATMAKE@ @@ -408,6 +423,7 @@ LIBCFLAGS = $(CFLAGS) CXXFLAGS = @CXXFLAGS@ LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates GOCFLAGS = $(CFLAGS) +GDCFLAGS = $(CFLAGS) CREATE_GCOV = create_gcov @@ -574,6 +590,7 @@ CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @CXX_ RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@ GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@ GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@ +GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@ DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ @@ -598,6 +615,7 @@ LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARG LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@ GOCFLAGS_FOR_TARGET = -O2 -g +GDCFLAGS_FOR_TARGET = -O2 -g FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ SYSROOT_CFLAGS_FOR_TARGET = @SYSROOT_CFLAGS_FOR_TARGET@ @@ -622,7 +640,7 @@ all: # This is the list of directories that may be needed in RPATH_ENVVAR # so that programs built for the target machine work. -TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_liboffloadmic)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc) +TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_liboffloadmic)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libphobos)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc) @if target-libstdc++-v3 TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs: @@ -644,6 +662,10 @@ TARGET_LIB_PATH_liboffloadmic = $$r/$(TA TARGET_LIB_PATH_libssp = $$r/$(TARGET_SUBDIR)/libssp/.libs: @endif target-libssp +@if target-libphobos +TARGET_LIB_PATH_libphobos = $$r/$(TARGET_SUBDIR)/libphobos/src/.libs: +@endif target-libphobos + @if target-libgomp TARGET_LIB_PATH_libgomp = $$r/$(TARGET_SUBDIR)/libgomp/.libs: @endif target-libgomp @@ -778,6 +800,8 @@ BASE_FLAGS_TO_PASS = \ "STAGE1_LANGUAGES=$(STAGE1_LANGUAGES)" \ "GNATBIND=$(GNATBIND)" \ "GNATMAKE=$(GNATMAKE)" \ + "GDC=$(GDC)" \ + "GDCFLAGS=$(GDCFLAGS)" \ "AR_FOR_TARGET=$(AR_FOR_TARGET)" \ "AS_FOR_TARGET=$(AS_FOR_TARGET)" \ "CC_FOR_TARGET=$(CC_FOR_TARGET)" \ @@ -789,6 +813,8 @@ BASE_FLAGS_TO_PASS = \ "GFORTRAN_FOR_TARGET=$(GFORTRAN_FOR_TARGET)" \ "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \ "GOCFLAGS_FOR_TARGET=$(GOCFLAGS_FOR_TARGET)" \ + "GDC_FOR_TARGET=$(GDC_FOR_TARGET)" \ + "GDCFLAGS_FOR_TARGET=$(GDCFLAGS_FOR_TARGET)" \ "LD_FOR_TARGET=$(LD_FOR_TARGET)" \ "LIPO_FOR_TARGET=$(LIPO_FOR_TARGET)" \ "LDFLAGS_FOR_TARGET=$(LDFLAGS_FOR_TARGET)" \ @@ -851,6 +877,7 @@ EXTRA_HOST_FLAGS = \ 'DLLTOOL=$(DLLTOOL)' \ 'GFORTRAN=$(GFORTRAN)' \ 'GOC=$(GOC)' \ + 'GDC=$(GDC)' \ 'LD=$(LD)' \ 'LIPO=$(LIPO)' \ 'NM=$(NM)' \ @@ -875,6 +902,7 @@ STAGE1_FLAGS_TO_PASS = \ POSTSTAGE1_FLAGS_TO_PASS = \ CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \ CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \ + GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \ GNATBIND="$${GNATBIND}" \ LDFLAGS="$${LDFLAGS}" \ HOST_LIBS="$${HOST_LIBS}" \ @@ -907,6 +935,8 @@ EXTRA_TARGET_FLAGS = \ 'GFORTRAN=$$(GFORTRAN_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOC=$$(GOC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \ + 'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ + 'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \ 'LD=$(COMPILER_LD_FOR_TARGET)' \ 'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \ 'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \ @@ -1008,6 +1038,7 @@ configure-target: \ maybe-configure-target-libobjc \ maybe-configure-target-libgo \ maybe-configure-target-libhsail-rt \ + maybe-configure-target-libphobos \ maybe-configure-target-libtermcap \ maybe-configure-target-winsup \ maybe-configure-target-libgloss \ @@ -1170,6 +1201,7 @@ all-target: maybe-all-target-libgfortran all-target: maybe-all-target-libobjc all-target: maybe-all-target-libgo all-target: maybe-all-target-libhsail-rt +all-target: maybe-all-target-libphobos all-target: maybe-all-target-libtermcap all-target: maybe-all-target-winsup all-target: maybe-all-target-libgloss @@ -1261,6 +1293,7 @@ info-target: maybe-info-target-libgfortr info-target: maybe-info-target-libobjc info-target: maybe-info-target-libgo info-target: maybe-info-target-libhsail-rt +info-target: maybe-info-target-libphobos info-target: maybe-info-target-libtermcap info-target: maybe-info-target-winsup info-target: maybe-info-target-libgloss @@ -1345,6 +1378,7 @@ dvi-target: maybe-dvi-target-libgfortran dvi-target: maybe-dvi-target-libobjc dvi-target: maybe-dvi-target-libgo dvi-target: maybe-dvi-target-libhsail-rt +dvi-target: maybe-dvi-target-libphobos dvi-target: maybe-dvi-target-libtermcap dvi-target: maybe-dvi-target-winsup dvi-target: maybe-dvi-target-libgloss @@ -1429,6 +1463,7 @@ pdf-target: maybe-pdf-target-libgfortran pdf-target: maybe-pdf-target-libobjc pdf-target: maybe-pdf-target-libgo pdf-target: maybe-pdf-target-libhsail-rt +pdf-target: maybe-pdf-target-libphobos pdf-target: maybe-pdf-target-libtermcap pdf-target: maybe-pdf-target-winsup pdf-target: maybe-pdf-target-libgloss @@ -1513,6 +1548,7 @@ html-target: maybe-html-target-libgfortr html-target: maybe-html-target-libobjc html-target: maybe-html-target-libgo html-target: maybe-html-target-libhsail-rt +html-target: maybe-html-target-libphobos html-target: maybe-html-target-libtermcap html-target: maybe-html-target-winsup html-target: maybe-html-target-libgloss @@ -1597,6 +1633,7 @@ TAGS-target: maybe-TAGS-target-libgfortr TAGS-target: maybe-TAGS-target-libobjc TAGS-target: maybe-TAGS-target-libgo TAGS-target: maybe-TAGS-target-libhsail-rt +TAGS-target: maybe-TAGS-target-libphobos TAGS-target: maybe-TAGS-target-libtermcap TAGS-target: maybe-TAGS-target-winsup TAGS-target: maybe-TAGS-target-libgloss @@ -1681,6 +1718,7 @@ install-info-target: maybe-install-info- install-info-target: maybe-install-info-target-libobjc install-info-target: maybe-install-info-target-libgo install-info-target: maybe-install-info-target-libhsail-rt +install-info-target: maybe-install-info-target-libphobos install-info-target: maybe-install-info-target-libtermcap install-info-target: maybe-install-info-target-winsup install-info-target: maybe-install-info-target-libgloss @@ -1765,6 +1803,7 @@ install-pdf-target: maybe-install-pdf-ta install-pdf-target: maybe-install-pdf-target-libobjc install-pdf-target: maybe-install-pdf-target-libgo install-pdf-target: maybe-install-pdf-target-libhsail-rt +install-pdf-target: maybe-install-pdf-target-libphobos install-pdf-target: maybe-install-pdf-target-libtermcap install-pdf-target: maybe-install-pdf-target-winsup install-pdf-target: maybe-install-pdf-target-libgloss @@ -1849,6 +1888,7 @@ install-html-target: maybe-install-html- install-html-target: maybe-install-html-target-libobjc install-html-target: maybe-install-html-target-libgo install-html-target: maybe-install-html-target-libhsail-rt +install-html-target: maybe-install-html-target-libphobos install-html-target: maybe-install-html-target-libtermcap install-html-target: maybe-install-html-target-winsup install-html-target: maybe-install-html-target-libgloss @@ -1933,6 +1973,7 @@ installcheck-target: maybe-installcheck- installcheck-target: maybe-installcheck-target-libobjc installcheck-target: maybe-installcheck-target-libgo installcheck-target: maybe-installcheck-target-libhsail-rt +installcheck-target: maybe-installcheck-target-libphobos installcheck-target: maybe-installcheck-target-libtermcap installcheck-target: maybe-installcheck-target-winsup installcheck-target: maybe-installcheck-target-libgloss @@ -2017,6 +2058,7 @@ mostlyclean-target: maybe-mostlyclean-ta mostlyclean-target: maybe-mostlyclean-target-libobjc mostlyclean-target: maybe-mostlyclean-target-libgo mostlyclean-target: maybe-mostlyclean-target-libhsail-rt +mostlyclean-target: maybe-mostlyclean-target-libphobos mostlyclean-target: maybe-mostlyclean-target-libtermcap mostlyclean-target: maybe-mostlyclean-target-winsup mostlyclean-target: maybe-mostlyclean-target-libgloss @@ -2101,6 +2143,7 @@ clean-target: maybe-clean-target-libgfor clean-target: maybe-clean-target-libobjc clean-target: maybe-clean-target-libgo clean-target: maybe-clean-target-libhsail-rt +clean-target: maybe-clean-target-libphobos clean-target: maybe-clean-target-libtermcap clean-target: maybe-clean-target-winsup clean-target: maybe-clean-target-libgloss @@ -2185,6 +2228,7 @@ distclean-target: maybe-distclean-target distclean-target: maybe-distclean-target-libobjc distclean-target: maybe-distclean-target-libgo distclean-target: maybe-distclean-target-libhsail-rt +distclean-target: maybe-distclean-target-libphobos distclean-target: maybe-distclean-target-libtermcap distclean-target: maybe-distclean-target-winsup distclean-target: maybe-distclean-target-libgloss @@ -2269,6 +2313,7 @@ maintainer-clean-target: maybe-maintaine maintainer-clean-target: maybe-maintainer-clean-target-libobjc maintainer-clean-target: maybe-maintainer-clean-target-libgo maintainer-clean-target: maybe-maintainer-clean-target-libhsail-rt +maintainer-clean-target: maybe-maintainer-clean-target-libphobos maintainer-clean-target: maybe-maintainer-clean-target-libtermcap maintainer-clean-target: maybe-maintainer-clean-target-winsup maintainer-clean-target: maybe-maintainer-clean-target-libgloss @@ -2409,6 +2454,7 @@ check-target: \ maybe-check-target-libobjc \ maybe-check-target-libgo \ maybe-check-target-libhsail-rt \ + maybe-check-target-libphobos \ maybe-check-target-libtermcap \ maybe-check-target-winsup \ maybe-check-target-libgloss \ @@ -2589,6 +2635,7 @@ install-target: \ maybe-install-target-libobjc \ maybe-install-target-libgo \ maybe-install-target-libhsail-rt \ + maybe-install-target-libphobos \ maybe-install-target-libtermcap \ maybe-install-target-winsup \ maybe-install-target-libgloss \ @@ -2693,6 +2740,7 @@ install-strip-target: \ maybe-install-strip-target-libobjc \ maybe-install-strip-target-libgo \ maybe-install-strip-target-libhsail-rt \ + maybe-install-strip-target-libphobos \ maybe-install-strip-target-libtermcap \ maybe-install-strip-target-winsup \ maybe-install-strip-target-libgloss \ @@ -46944,6 +46992,464 @@ maintainer-clean-target-libhsail-rt: +.PHONY: configure-target-libphobos maybe-configure-target-libphobos +maybe-configure-target-libphobos: +@if gcc-bootstrap +configure-target-libphobos: stage_current +@endif gcc-bootstrap +@if target-libphobos +maybe-configure-target-libphobos: configure-target-libphobos +configure-target-libphobos: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + echo "Checking multilib configuration for libphobos..."; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + $(NORMAL_TARGET_EXPORTS) \ + echo Configuring in $(TARGET_SUBDIR)/libphobos; \ + cd "$(TARGET_SUBDIR)/libphobos" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) \ + $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + || exit 1 +@endif target-libphobos + + + + + +.PHONY: all-target-libphobos maybe-all-target-libphobos +maybe-all-target-libphobos: +@if gcc-bootstrap +all-target-libphobos: stage_current +@endif gcc-bootstrap +@if target-libphobos +TARGET-target-libphobos=all +maybe-all-target-libphobos: all-target-libphobos +all-target-libphobos: configure-target-libphobos + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) \ + $(TARGET-target-libphobos)) +@endif target-libphobos + + + + + +.PHONY: check-target-libphobos maybe-check-target-libphobos +maybe-check-target-libphobos: +@if target-libphobos +maybe-check-target-libphobos: check-target-libphobos + +check-target-libphobos: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check) + +@endif target-libphobos + +.PHONY: install-target-libphobos maybe-install-target-libphobos +maybe-install-target-libphobos: +@if target-libphobos +maybe-install-target-libphobos: install-target-libphobos + +install-target-libphobos: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install) + +@endif target-libphobos + +.PHONY: install-strip-target-libphobos maybe-install-strip-target-libphobos +maybe-install-strip-target-libphobos: +@if target-libphobos +maybe-install-strip-target-libphobos: install-strip-target-libphobos + +install-strip-target-libphobos: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install-strip) + +@endif target-libphobos + +# Other targets (info, dvi, pdf, etc.) + +.PHONY: maybe-info-target-libphobos info-target-libphobos +maybe-info-target-libphobos: +@if target-libphobos +maybe-info-target-libphobos: info-target-libphobos + +info-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing info in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + info) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-dvi-target-libphobos dvi-target-libphobos +maybe-dvi-target-libphobos: +@if target-libphobos +maybe-dvi-target-libphobos: dvi-target-libphobos + +dvi-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing dvi in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + dvi) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-pdf-target-libphobos pdf-target-libphobos +maybe-pdf-target-libphobos: +@if target-libphobos +maybe-pdf-target-libphobos: pdf-target-libphobos + +pdf-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing pdf in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + pdf) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-html-target-libphobos html-target-libphobos +maybe-html-target-libphobos: +@if target-libphobos +maybe-html-target-libphobos: html-target-libphobos + +html-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing html in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + html) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-TAGS-target-libphobos TAGS-target-libphobos +maybe-TAGS-target-libphobos: +@if target-libphobos +maybe-TAGS-target-libphobos: TAGS-target-libphobos + +TAGS-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing TAGS in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + TAGS) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-info-target-libphobos install-info-target-libphobos +maybe-install-info-target-libphobos: +@if target-libphobos +maybe-install-info-target-libphobos: install-info-target-libphobos + +install-info-target-libphobos: \ + configure-target-libphobos \ + info-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-info in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-info) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-pdf-target-libphobos install-pdf-target-libphobos +maybe-install-pdf-target-libphobos: +@if target-libphobos +maybe-install-pdf-target-libphobos: install-pdf-target-libphobos + +install-pdf-target-libphobos: \ + configure-target-libphobos \ + pdf-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-pdf in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-pdf) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-html-target-libphobos install-html-target-libphobos +maybe-install-html-target-libphobos: +@if target-libphobos +maybe-install-html-target-libphobos: install-html-target-libphobos + +install-html-target-libphobos: \ + configure-target-libphobos \ + html-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-html in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-html) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-installcheck-target-libphobos installcheck-target-libphobos +maybe-installcheck-target-libphobos: +@if target-libphobos +maybe-installcheck-target-libphobos: installcheck-target-libphobos + +installcheck-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing installcheck in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + installcheck) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-mostlyclean-target-libphobos mostlyclean-target-libphobos +maybe-mostlyclean-target-libphobos: +@if target-libphobos +maybe-mostlyclean-target-libphobos: mostlyclean-target-libphobos + +mostlyclean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing mostlyclean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + mostlyclean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-clean-target-libphobos clean-target-libphobos +maybe-clean-target-libphobos: +@if target-libphobos +maybe-clean-target-libphobos: clean-target-libphobos + +clean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing clean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + clean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-distclean-target-libphobos distclean-target-libphobos +maybe-distclean-target-libphobos: +@if target-libphobos +maybe-distclean-target-libphobos: distclean-target-libphobos + +distclean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing distclean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + distclean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-maintainer-clean-target-libphobos maintainer-clean-target-libphobos +maybe-maintainer-clean-target-libphobos: +@if target-libphobos +maybe-maintainer-clean-target-libphobos: maintainer-clean-target-libphobos + +maintainer-clean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + maintainer-clean) \ + || exit 1 + +@endif target-libphobos + + + + + .PHONY: configure-target-libtermcap maybe-configure-target-libtermcap maybe-configure-target-libtermcap: @if gcc-bootstrap @@ -52329,6 +52835,14 @@ check-gcc-brig: (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-brig); check-brig: check-gcc-brig check-target-libhsail-rt +.PHONY: check-gcc-d check-d +check-gcc-d: + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-d); +check-d: check-gcc-d check-target-libphobos + # The gcc part of install-no-fixedincludes, which relies on an intimate # knowledge of how a number of gcc internal targets (inter)operate. Delegate. @@ -55521,6 +56035,7 @@ configure-target-libgfortran: stage_last configure-target-libobjc: stage_last configure-target-libgo: stage_last configure-target-libhsail-rt: stage_last +configure-target-libphobos: stage_last configure-target-libtermcap: stage_last configure-target-winsup: stage_last configure-target-libgloss: stage_last @@ -55555,6 +56070,7 @@ configure-target-libgfortran: maybe-all- configure-target-libobjc: maybe-all-gcc configure-target-libgo: maybe-all-gcc configure-target-libhsail-rt: maybe-all-gcc +configure-target-libphobos: maybe-all-gcc configure-target-libtermcap: maybe-all-gcc configure-target-winsup: maybe-all-gcc configure-target-libgloss: maybe-all-gcc @@ -56550,6 +57066,11 @@ configure-target-libgo: maybe-configure- all-target-libgo: maybe-all-target-libbacktrace all-target-libgo: maybe-all-target-libffi all-target-libgo: maybe-all-target-libatomic +configure-target-libphobos: maybe-configure-target-libbacktrace +configure-target-libphobos: maybe-configure-target-zlib +all-target-libphobos: maybe-all-target-libbacktrace +all-target-libphobos: maybe-all-target-zlib +all-target-libphobos: maybe-all-target-libatomic configure-target-libstdc++-v3: maybe-configure-target-libgomp configure-stage1-target-libstdc++-v3: maybe-configure-stage1-target-libgomp configure-stage2-target-libstdc++-v3: maybe-configure-stage2-target-libgomp @@ -56593,6 +57114,7 @@ all-stageautofeedback-target-libstdc++-v install-target-libgo: maybe-install-target-libatomic install-target-libgfortran: maybe-install-target-libquadmath install-target-libgfortran: maybe-install-target-libgcc +install-target-libphobos: maybe-install-target-libatomic install-target-libsanitizer: maybe-install-target-libstdc++-v3 install-target-libsanitizer: maybe-install-target-libgcc install-target-libvtv: maybe-install-target-libstdc++-v3 @@ -56717,6 +57239,7 @@ configure-target-libgfortran: maybe-all- configure-target-libobjc: maybe-all-target-libgcc configure-target-libgo: maybe-all-target-libgcc configure-target-libhsail-rt: maybe-all-target-libgcc +configure-target-libphobos: maybe-all-target-libgcc configure-target-libtermcap: maybe-all-target-libgcc configure-target-winsup: maybe-all-target-libgcc configure-target-libgloss: maybe-all-target-libgcc @@ -56755,6 +57278,8 @@ configure-target-libgo: maybe-all-target configure-target-libhsail-rt: maybe-all-target-newlib maybe-all-target-libgloss +configure-target-libphobos: maybe-all-target-newlib maybe-all-target-libgloss + configure-target-libtermcap: maybe-all-target-newlib maybe-all-target-libgloss configure-target-winsup: maybe-all-target-newlib maybe-all-target-libgloss --- a/Makefile.tpl +++ b/Makefile.tpl @@ -159,6 +159,8 @@ BUILD_EXPORTS = \ GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ GOC="$(GOC_FOR_BUILD)"; export GOC; \ GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \ + GDC="$(GDC_FOR_BUILD)"; export GDC; \ + GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -195,6 +197,7 @@ HOST_EXPORTS = \ CXXFLAGS="$(CXXFLAGS)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \ GOC="$(GOC)"; export GOC; \ + GDC="$(GDC)"; export GDC; \ AR="$(AR)"; export AR; \ AS="$(AS)"; export AS; \ CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \ @@ -259,6 +262,15 @@ POSTSTAGE1_HOST_EXPORTS = \ CC_FOR_BUILD="$$CC"; export CC_FOR_BUILD; \ $(POSTSTAGE1_CXX_EXPORT) \ $(LTO_EXPORTS) \ + GDC="$$r/$(HOST_SUBDIR)/prev-gcc/gdc$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ \ + -B$(build_tooldir)/bin/ $(GDCFLAGS_FOR_TARGET) \ + -B$$r/prev-$(TARGET_SUBDIR)/libphobos/src \ + -I$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime -I$$s/libphobos/libdruntime \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libstdc++-v3/src/.libs"; \ + export GDC; \ + GDC_FOR_BUILD="$$GDC"; export GDC_FOR_BUILD; \ GNATBIND="$$r/$(HOST_SUBDIR)/prev-gcc/gnatbind"; export GNATBIND; \ LDFLAGS="$(POSTSTAGE1_LDFLAGS) $(BOOT_LDFLAGS)"; export LDFLAGS; \ HOST_LIBS="$(POSTSTAGE1_LIBS)"; export HOST_LIBS; @@ -281,6 +293,7 @@ BASE_TARGET_EXPORTS = \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GFORTRAN; \ GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GOC; \ + GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GDC; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -345,6 +358,7 @@ CXX_FOR_BUILD = @CXX_FOR_BUILD@ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@ GOC_FOR_BUILD = @GOC_FOR_BUILD@ +GDC_FOR_BUILD = @GDC_FOR_BUILD@ LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ LD_FOR_BUILD = @LD_FOR_BUILD@ NM_FOR_BUILD = @NM_FOR_BUILD@ @@ -402,6 +416,7 @@ STRIP = @STRIP@ WINDRES = @WINDRES@ WINDMC = @WINDMC@ +GDC = @GDC@ GNATBIND = @GNATBIND@ GNATMAKE = @GNATMAKE@ @@ -411,6 +426,7 @@ LIBCFLAGS = $(CFLAGS) CXXFLAGS = @CXXFLAGS@ LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates GOCFLAGS = $(CFLAGS) +GDCFLAGS = $(CFLAGS) CREATE_GCOV = create_gcov @@ -497,6 +513,7 @@ CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @CXX_ RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@ GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@ GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@ +GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@ DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ @@ -521,6 +538,7 @@ LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARG LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@ GOCFLAGS_FOR_TARGET = -O2 -g +GDCFLAGS_FOR_TARGET = -O2 -g FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ SYSROOT_CFLAGS_FOR_TARGET = @SYSROOT_CFLAGS_FOR_TARGET@ @@ -622,6 +640,7 @@ EXTRA_HOST_FLAGS = \ 'DLLTOOL=$(DLLTOOL)' \ 'GFORTRAN=$(GFORTRAN)' \ 'GOC=$(GOC)' \ + 'GDC=$(GDC)' \ 'LD=$(LD)' \ 'LIPO=$(LIPO)' \ 'NM=$(NM)' \ @@ -646,6 +665,7 @@ STAGE1_FLAGS_TO_PASS = \ POSTSTAGE1_FLAGS_TO_PASS = \ CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \ CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \ + GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \ GNATBIND="$${GNATBIND}" \ LDFLAGS="$${LDFLAGS}" \ HOST_LIBS="$${HOST_LIBS}" \ @@ -678,6 +698,8 @@ EXTRA_TARGET_FLAGS = \ 'GFORTRAN=$$(GFORTRAN_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOC=$$(GOC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \ + 'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ + 'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \ 'LD=$(COMPILER_LD_FOR_TARGET)' \ 'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \ 'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \ --- a/config-ml.in +++ b/config-ml.in @@ -512,6 +512,7 @@ multi-do: prefix="$(prefix)" \ exec_prefix="$(exec_prefix)" \ GOCFLAGS="$(GOCFLAGS) $${flags}" \ + GDCFLAGS="$(GDCFLAGS) $${flags}" \ CXXFLAGS="$(CXXFLAGS) $${flags}" \ LIBCFLAGS="$(LIBCFLAGS) $${flags}" \ LIBCXXFLAGS="$(LIBCXXFLAGS) $${flags}" \ @@ -745,7 +746,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_n break fi done - ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" F77="${F77_}$flags" GFORTRAN="${GFORTRAN_}$flags" GOC="${GOC_}$flags"' + ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" F77="${F77_}$flags" GFORTRAN="${GFORTRAN_}$flags" GOC="${GOC_}$flags" GDC="${GDC_}$flags"' if [ "${with_target_subdir}" = "." ]; then CC_=$CC' ' @@ -753,6 +754,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_n F77_=$F77' ' GFORTRAN_=$GFORTRAN' ' GOC_=$GOC' ' + GDC_=$GDC' ' else # Create a regular expression that matches any string as long # as ML_POPDIR. @@ -817,6 +819,18 @@ if [ -n "${multidirs}" ] && [ -z "${ml_n esac done + GDC_= + for arg in ${GDC}; do + case $arg in + -[BIL]"${ML_POPDIR}"/*) + GDC_="${GDC_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\\1/p"`' ' ;; + "${ML_POPDIR}"/*) + GDC_="${GDC_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;; + *) + GDC_="${GDC_}${arg} " ;; + esac + done + if test "x${LD_LIBRARY_PATH+set}" = xset; then LD_LIBRARY_PATH_= for arg in `echo "$LD_LIBRARY_PATH" | tr ':' ' '`; do --- a/config/multi.m4 +++ b/config/multi.m4 @@ -64,4 +64,5 @@ multi_basedir="$multi_basedir" CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} CC="$CC" CXX="$CXX" -GFORTRAN="$GFORTRAN"])])dnl +GFORTRAN="$GFORTRAN" +GDC="$GDC"])])dnl --- a/configure +++ b/configure @@ -580,6 +580,7 @@ LD_FOR_TARGET DLLTOOL_FOR_TARGET AS_FOR_TARGET AR_FOR_TARGET +GDC_FOR_TARGET GOC_FOR_TARGET GFORTRAN_FOR_TARGET GCC_FOR_TARGET @@ -612,6 +613,7 @@ RANLIB_FOR_BUILD NM_FOR_BUILD LD_FOR_BUILD LDFLAGS_FOR_BUILD +GDC_FOR_BUILD GOC_FOR_BUILD GFORTRAN_FOR_BUILD DLLTOOL_FOR_BUILD @@ -830,6 +832,7 @@ CXX_FOR_TARGET GCC_FOR_TARGET GFORTRAN_FOR_TARGET GOC_FOR_TARGET +GDC_FOR_TARGET AR_FOR_TARGET AS_FOR_TARGET DLLTOOL_FOR_TARGET @@ -1613,6 +1616,8 @@ Some influential environment variables: GFORTRAN for the target GOC_FOR_TARGET GOC for the target + GDC_FOR_TARGET + GDC for the target AR_FOR_TARGET AR for the target AS_FOR_TARGET @@ -2764,7 +2769,8 @@ target_libraries="target-libgcc \ target-libffi \ target-libobjc \ target-libada \ - target-libgo" + target-libgo \ + target-libphobos" # these tools are built using the target libraries, and are intended to # run only in the target environment @@ -3920,6 +3926,7 @@ if test "${build}" != "${host}" ; then CXX_FOR_BUILD=${CXX_FOR_BUILD-g++} GFORTRAN_FOR_BUILD=${GFORTRAN_FOR_BUILD-gfortran} GOC_FOR_BUILD=${GOC_FOR_BUILD-gccgo} + GDC_FOR_BUILD=${GDC_FOR_BUILD-gdc} DLLTOOL_FOR_BUILD=${DLLTOOL_FOR_BUILD-dlltool} LD_FOR_BUILD=${LD_FOR_BUILD-ld} NM_FOR_BUILD=${NM_FOR_BUILD-nm} @@ -3933,6 +3940,7 @@ else CXX_FOR_BUILD="\$(CXX)" GFORTRAN_FOR_BUILD="\$(GFORTRAN)" GOC_FOR_BUILD="\$(GOC)" + GDC_FOR_BUILD="\$(GDC)" DLLTOOL_FOR_BUILD="\$(DLLTOOL)" LD_FOR_BUILD="\$(LD)" NM_FOR_BUILD="\$(NM)" @@ -6331,7 +6339,7 @@ $as_echo "$as_me: WARNING: ${language} n *) stage1_languages="${stage1_languages}${language}," ;; esac # We need to bootstrap any supporting libraries. - bootstrap_target_libs="${bootstrap_target_libs}${target_libs}," + bootstrap_target_libs=`echo "${bootstrap_target_libs}${target_libs}," | sed "s/ /,/g"` ;; esac ;; @@ -7650,6 +7658,7 @@ done + # Generate default definitions for YACC, M4, LEX and other programs that run # on the build machine. These are used if the Makefile can't locate these # programs in objdir. @@ -10704,6 +10713,167 @@ fi +if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET=$GDC_FOR_TARGET +elif test -n "$ac_cv_prog_GDC_FOR_TARGET"; then + GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +fi + +if test -n "$ac_cv_prog_GDC_FOR_TARGET"; then + for ncn_progname in gdc; do + # Extract the first word of "${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET" && test -n "$with_build_time_tools"; then + for ncn_progname in gdc; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ncn_progname} in $with_build_time_tools" >&5 +$as_echo_n "checking for ${ncn_progname} in $with_build_time_tools... " >&6; } + if test -x $with_build_time_tools/${ncn_progname}; then + ac_cv_prog_GDC_FOR_TARGET=$with_build_time_tools/${ncn_progname} + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET"; then + for ncn_progname in gdc; do + if test -n "$ncn_target_tool_prefix"; then + # Extract the first word of "${ncn_target_tool_prefix}${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_target_tool_prefix}${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_target_tool_prefix}${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test -z "$ac_cv_prog_GDC_FOR_TARGET" && test $build = $target ; then + # Extract the first word of "${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + test -n "$ac_cv_prog_GDC_FOR_TARGET" && break + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET" ; then + set dummy gdc + if test $build = $target ; then + GDC_FOR_TARGET="$2" + else + GDC_FOR_TARGET="${ncn_target_tool_prefix}$2" + fi +else + GDC_FOR_TARGET="$ac_cv_prog_GDC_FOR_TARGET" +fi + + + cat > conftest.c << \EOF #ifdef __GNUC__ gcc_yay; @@ -14094,6 +14264,51 @@ $as_echo "pre-installed in $ac_dir" >&6; { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5 $as_echo "host tool" >&6; } else + # We need a cross tool + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5 +$as_echo "pre-installed" >&6; } + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target gdc" >&5 +$as_echo_n "checking where to find the target gdc... " >&6; } +if test "x${build}" != "x${host}" ; then + if expr "x$GDC_FOR_TARGET" : "x/" > /dev/null; then + # We already found the complete path + ac_dir=`dirname $GDC_FOR_TARGET` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5 +$as_echo "pre-installed in $ac_dir" >&6; } + else + # Canadian cross, just use what we found + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5 +$as_echo "pre-installed" >&6; } + fi +else + ok=yes + case " ${configdirs} " in + *" gcc "*) ;; + *) ok=no ;; + esac + case ,${enable_languages}, in + *,d,*) ;; + *) ok=no ;; + esac + if test $ok = yes; then + # An in-tree tool is available and we can use it + GDC_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/' + { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5 +$as_echo "just compiled" >&6; } + elif expr "x$GDC_FOR_TARGET" : "x/" > /dev/null; then + # We already found the complete path + ac_dir=`dirname $GDC_FOR_TARGET` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5 +$as_echo "pre-installed in $ac_dir" >&6; } + elif test "x$target" = "x$host"; then + # We can use an host tool + GDC_FOR_TARGET='$(GDC)' + { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5 +$as_echo "host tool" >&6; } + else # We need a cross tool { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5 $as_echo "pre-installed" >&6; } --- a/configure.ac +++ b/configure.ac @@ -163,7 +163,8 @@ target_libraries="target-libgcc \ target-libffi \ target-libobjc \ target-libada \ - target-libgo" + target-libgo \ + target-libphobos" # these tools are built using the target libraries, and are intended to # run only in the target environment @@ -1235,6 +1236,7 @@ if test "${build}" != "${host}" ; then CXX_FOR_BUILD=${CXX_FOR_BUILD-g++} GFORTRAN_FOR_BUILD=${GFORTRAN_FOR_BUILD-gfortran} GOC_FOR_BUILD=${GOC_FOR_BUILD-gccgo} + GDC_FOR_BUILD=${GDC_FOR_BUILD-gdc} DLLTOOL_FOR_BUILD=${DLLTOOL_FOR_BUILD-dlltool} LD_FOR_BUILD=${LD_FOR_BUILD-ld} NM_FOR_BUILD=${NM_FOR_BUILD-nm} @@ -1248,6 +1250,7 @@ else CXX_FOR_BUILD="\$(CXX)" GFORTRAN_FOR_BUILD="\$(GFORTRAN)" GOC_FOR_BUILD="\$(GOC)" + GDC_FOR_BUILD="\$(GDC)" DLLTOOL_FOR_BUILD="\$(DLLTOOL)" LD_FOR_BUILD="\$(LD)" NM_FOR_BUILD="\$(NM)" @@ -2006,7 +2009,7 @@ directories, to avoid imposing the perfo *) stage1_languages="${stage1_languages}${language}," ;; esac # We need to bootstrap any supporting libraries. - bootstrap_target_libs="${bootstrap_target_libs}${target_libs}," + bootstrap_target_libs=`echo "${bootstrap_target_libs}${target_libs}," | sed "s/ /,/g"` ;; esac ;; @@ -3235,6 +3238,7 @@ AC_SUBST(CXX_FOR_BUILD) AC_SUBST(DLLTOOL_FOR_BUILD) AC_SUBST(GFORTRAN_FOR_BUILD) AC_SUBST(GOC_FOR_BUILD) +AC_SUBST(GDC_FOR_BUILD) AC_SUBST(LDFLAGS_FOR_BUILD) AC_SUBST(LD_FOR_BUILD) AC_SUBST(NM_FOR_BUILD) @@ -3344,6 +3348,7 @@ NCN_STRICT_CHECK_TARGET_TOOLS(CXX_FOR_TA NCN_STRICT_CHECK_TARGET_TOOLS(GCC_FOR_TARGET, gcc, ${CC_FOR_TARGET}) NCN_STRICT_CHECK_TARGET_TOOLS(GFORTRAN_FOR_TARGET, gfortran) NCN_STRICT_CHECK_TARGET_TOOLS(GOC_FOR_TARGET, gccgo) +NCN_STRICT_CHECK_TARGET_TOOLS(GDC_FOR_TARGET, gdc) ACX_CHECK_INSTALLED_TARGET_TOOL(AR_FOR_TARGET, ar) ACX_CHECK_INSTALLED_TARGET_TOOL(AS_FOR_TARGET, as) @@ -3377,6 +3382,8 @@ GCC_TARGET_TOOL(gfortran, GFORTRAN_FOR_T [gcc/gfortran -B$$r/$(HOST_SUBDIR)/gcc/], fortran) GCC_TARGET_TOOL(gccgo, GOC_FOR_TARGET, GOC, [gcc/gccgo -B$$r/$(HOST_SUBDIR)/gcc/], go) +GCC_TARGET_TOOL(gdc, GDC_FOR_TARGET, GDC, + [gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/], d) GCC_TARGET_TOOL(ld, LD_FOR_TARGET, LD, [ld/ld-new]) GCC_TARGET_TOOL(lipo, LIPO_FOR_TARGET, LIPO) GCC_TARGET_TOOL(nm, NM_FOR_TARGET, NM, [binutils/nm-new]) ================================================ FILE: gcc/d/patches/patch-toplev-ddmd-9.patch ================================================ This implements building of self hosted D compiler in GCC. --- --- a/Makefile.def +++ b/Makefile.def @@ -147,13 +147,14 @@ target_modules = { module= liboffloadmic target_modules = { module= libssp; lib_path=.libs; }; target_modules = { module= newlib; }; target_modules = { module= libgcc; bootstrap=true; no_check=true; }; -target_modules = { module= libbacktrace; }; +target_modules = { module= libbacktrace; bootstrap=true; }; target_modules = { module= libquadmath; }; target_modules = { module= libgfortran; }; target_modules = { module= libobjc; }; target_modules = { module= libgo; }; target_modules = { module= libhsail-rt; }; target_modules = { module= libphobos; + bootstrap=true; lib_path=src/.libs; }; target_modules = { module= libtermcap; no_check=true; missing=mostlyclean; @@ -168,7 +169,7 @@ target_modules = { module= rda; }; target_modules = { module= libada; }; target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; }; target_modules = { module= libitm; lib_path=.libs; }; -target_modules = { module= libatomic; lib_path=.libs; }; +target_modules = { module= libatomic; bootstrap=true; lib_path=.libs; }; // These are (some of) the make targets to be done in each subdirectory. // Not all; these are the ones which don't have special options. --- a/Makefile.in +++ b/Makefile.in @@ -1195,13 +1195,17 @@ all-target: maybe-all-target-newlib @if target-libgcc-no-bootstrap all-target: maybe-all-target-libgcc @endif target-libgcc-no-bootstrap +@if target-libbacktrace-no-bootstrap all-target: maybe-all-target-libbacktrace +@endif target-libbacktrace-no-bootstrap all-target: maybe-all-target-libquadmath all-target: maybe-all-target-libgfortran all-target: maybe-all-target-libobjc all-target: maybe-all-target-libgo all-target: maybe-all-target-libhsail-rt +@if target-libphobos-no-bootstrap all-target: maybe-all-target-libphobos +@endif target-libphobos-no-bootstrap all-target: maybe-all-target-libtermcap all-target: maybe-all-target-winsup all-target: maybe-all-target-libgloss @@ -1213,7 +1217,9 @@ all-target: maybe-all-target-libada all-target: maybe-all-target-libgomp @endif target-libgomp-no-bootstrap all-target: maybe-all-target-libitm +@if target-libatomic-no-bootstrap all-target: maybe-all-target-libatomic +@endif target-libatomic-no-bootstrap # Do a target for all the subdirectories. A ``make do-X'' will do a # ``make X'' in all subdirectories (because, in general, there is a @@ -44252,7 +44258,6 @@ configure-target-libbacktrace: stage_cur @if target-libbacktrace maybe-configure-target-libbacktrace: configure-target-libbacktrace configure-target-libbacktrace: - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ echo "Checking multilib configuration for libbacktrace..."; \ @@ -44290,6 +44295,412 @@ configure-target-libbacktrace: +.PHONY: configure-stage1-target-libbacktrace maybe-configure-stage1-target-libbacktrace +maybe-configure-stage1-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stage1-target-libbacktrace: configure-stage1-target-libbacktrace +configure-stage1-target-libbacktrace: + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 1 in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + \ + $(STAGE1_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stage2-target-libbacktrace maybe-configure-stage2-target-libbacktrace +maybe-configure-stage2-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stage2-target-libbacktrace: configure-stage2-target-libbacktrace +configure-stage2-target-libbacktrace: + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 2 in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE2_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stage3-target-libbacktrace maybe-configure-stage3-target-libbacktrace +maybe-configure-stage3-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stage3-target-libbacktrace: configure-stage3-target-libbacktrace +configure-stage3-target-libbacktrace: + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 3 in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE3_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stage4-target-libbacktrace maybe-configure-stage4-target-libbacktrace +maybe-configure-stage4-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stage4-target-libbacktrace: configure-stage4-target-libbacktrace +configure-stage4-target-libbacktrace: + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 4 in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE4_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stageprofile-target-libbacktrace maybe-configure-stageprofile-target-libbacktrace +maybe-configure-stageprofile-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stageprofile-target-libbacktrace: configure-stageprofile-target-libbacktrace +configure-stageprofile-target-libbacktrace: + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage profile in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEprofile_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stagetrain-target-libbacktrace maybe-configure-stagetrain-target-libbacktrace +maybe-configure-stagetrain-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stagetrain-target-libbacktrace: configure-stagetrain-target-libbacktrace +configure-stagetrain-target-libbacktrace: + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage train in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEtrain_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stagefeedback-target-libbacktrace maybe-configure-stagefeedback-target-libbacktrace +maybe-configure-stagefeedback-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stagefeedback-target-libbacktrace: configure-stagefeedback-target-libbacktrace +configure-stagefeedback-target-libbacktrace: + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage feedback in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEfeedback_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stageautoprofile-target-libbacktrace maybe-configure-stageautoprofile-target-libbacktrace +maybe-configure-stageautoprofile-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stageautoprofile-target-libbacktrace: configure-stageautoprofile-target-libbacktrace +configure-stageautoprofile-target-libbacktrace: + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autoprofile in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautoprofile_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + +.PHONY: configure-stageautofeedback-target-libbacktrace maybe-configure-stageautofeedback-target-libbacktrace +maybe-configure-stageautofeedback-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-configure-stageautofeedback-target-libbacktrace: configure-stageautofeedback-target-libbacktrace +configure-stageautofeedback-target-libbacktrace: + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libbacktrace..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libbacktrace/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libbacktrace/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libbacktrace/Makefile; \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libbacktrace/multilib.tmp $(TARGET_SUBDIR)/libbacktrace/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libbacktrace/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autofeedback in $(TARGET_SUBDIR)/libbacktrace; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libbacktrace; \ + cd $(TARGET_SUBDIR)/libbacktrace || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libbacktrace/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libbacktrace; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautofeedback_CONFIGURE_FLAGS) +@endif target-libbacktrace-bootstrap + + + .PHONY: all-target-libbacktrace maybe-all-target-libbacktrace @@ -44301,7 +44712,6 @@ all-target-libbacktrace: stage_current TARGET-target-libbacktrace=all maybe-all-target-libbacktrace: all-target-libbacktrace all-target-libbacktrace: configure-target-libbacktrace - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(NORMAL_TARGET_EXPORTS) \ @@ -44312,6 +44722,387 @@ all-target-libbacktrace: configure-targe +.PHONY: all-stage1-target-libbacktrace maybe-all-stage1-target-libbacktrace +.PHONY: clean-stage1-target-libbacktrace maybe-clean-stage1-target-libbacktrace +maybe-all-stage1-target-libbacktrace: +maybe-clean-stage1-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stage1-target-libbacktrace: all-stage1-target-libbacktrace +all-stage1: all-stage1-target-libbacktrace +TARGET-stage1-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stage1-target-libbacktrace: configure-stage1-target-libbacktrace + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + \ + TFLAGS="$(STAGE1_TFLAGS)" \ + $(TARGET-stage1-target-libbacktrace) + +maybe-clean-stage1-target-libbacktrace: clean-stage1-target-libbacktrace +clean-stage1: clean-stage1-target-libbacktrace +clean-stage1-target-libbacktrace: + @if [ $(current_stage) = stage1 ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage1-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stage1-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stage2-target-libbacktrace maybe-all-stage2-target-libbacktrace +.PHONY: clean-stage2-target-libbacktrace maybe-clean-stage2-target-libbacktrace +maybe-all-stage2-target-libbacktrace: +maybe-clean-stage2-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stage2-target-libbacktrace: all-stage2-target-libbacktrace +all-stage2: all-stage2-target-libbacktrace +TARGET-stage2-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stage2-target-libbacktrace: configure-stage2-target-libbacktrace + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE2_TFLAGS)" \ + $(TARGET-stage2-target-libbacktrace) + +maybe-clean-stage2-target-libbacktrace: clean-stage2-target-libbacktrace +clean-stage2: clean-stage2-target-libbacktrace +clean-stage2-target-libbacktrace: + @if [ $(current_stage) = stage2 ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage2-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stage2-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stage3-target-libbacktrace maybe-all-stage3-target-libbacktrace +.PHONY: clean-stage3-target-libbacktrace maybe-clean-stage3-target-libbacktrace +maybe-all-stage3-target-libbacktrace: +maybe-clean-stage3-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stage3-target-libbacktrace: all-stage3-target-libbacktrace +all-stage3: all-stage3-target-libbacktrace +TARGET-stage3-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stage3-target-libbacktrace: configure-stage3-target-libbacktrace + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE3_TFLAGS)" \ + $(TARGET-stage3-target-libbacktrace) + +maybe-clean-stage3-target-libbacktrace: clean-stage3-target-libbacktrace +clean-stage3: clean-stage3-target-libbacktrace +clean-stage3-target-libbacktrace: + @if [ $(current_stage) = stage3 ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage3-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stage3-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stage4-target-libbacktrace maybe-all-stage4-target-libbacktrace +.PHONY: clean-stage4-target-libbacktrace maybe-clean-stage4-target-libbacktrace +maybe-all-stage4-target-libbacktrace: +maybe-clean-stage4-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stage4-target-libbacktrace: all-stage4-target-libbacktrace +all-stage4: all-stage4-target-libbacktrace +TARGET-stage4-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stage4-target-libbacktrace: configure-stage4-target-libbacktrace + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE4_TFLAGS)" \ + $(TARGET-stage4-target-libbacktrace) + +maybe-clean-stage4-target-libbacktrace: clean-stage4-target-libbacktrace +clean-stage4: clean-stage4-target-libbacktrace +clean-stage4-target-libbacktrace: + @if [ $(current_stage) = stage4 ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage4-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stage4-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stageprofile-target-libbacktrace maybe-all-stageprofile-target-libbacktrace +.PHONY: clean-stageprofile-target-libbacktrace maybe-clean-stageprofile-target-libbacktrace +maybe-all-stageprofile-target-libbacktrace: +maybe-clean-stageprofile-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stageprofile-target-libbacktrace: all-stageprofile-target-libbacktrace +all-stageprofile: all-stageprofile-target-libbacktrace +TARGET-stageprofile-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stageprofile-target-libbacktrace: configure-stageprofile-target-libbacktrace + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEprofile_TFLAGS)" \ + $(TARGET-stageprofile-target-libbacktrace) + +maybe-clean-stageprofile-target-libbacktrace: clean-stageprofile-target-libbacktrace +clean-stageprofile: clean-stageprofile-target-libbacktrace +clean-stageprofile-target-libbacktrace: + @if [ $(current_stage) = stageprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageprofile-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stageprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stagetrain-target-libbacktrace maybe-all-stagetrain-target-libbacktrace +.PHONY: clean-stagetrain-target-libbacktrace maybe-clean-stagetrain-target-libbacktrace +maybe-all-stagetrain-target-libbacktrace: +maybe-clean-stagetrain-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stagetrain-target-libbacktrace: all-stagetrain-target-libbacktrace +all-stagetrain: all-stagetrain-target-libbacktrace +TARGET-stagetrain-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stagetrain-target-libbacktrace: configure-stagetrain-target-libbacktrace + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEtrain_TFLAGS)" \ + $(TARGET-stagetrain-target-libbacktrace) + +maybe-clean-stagetrain-target-libbacktrace: clean-stagetrain-target-libbacktrace +clean-stagetrain: clean-stagetrain-target-libbacktrace +clean-stagetrain-target-libbacktrace: + @if [ $(current_stage) = stagetrain ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagetrain-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stagetrain-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stagefeedback-target-libbacktrace maybe-all-stagefeedback-target-libbacktrace +.PHONY: clean-stagefeedback-target-libbacktrace maybe-clean-stagefeedback-target-libbacktrace +maybe-all-stagefeedback-target-libbacktrace: +maybe-clean-stagefeedback-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stagefeedback-target-libbacktrace: all-stagefeedback-target-libbacktrace +all-stagefeedback: all-stagefeedback-target-libbacktrace +TARGET-stagefeedback-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stagefeedback-target-libbacktrace: configure-stagefeedback-target-libbacktrace + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEfeedback_TFLAGS)" \ + $(TARGET-stagefeedback-target-libbacktrace) + +maybe-clean-stagefeedback-target-libbacktrace: clean-stagefeedback-target-libbacktrace +clean-stagefeedback: clean-stagefeedback-target-libbacktrace +clean-stagefeedback-target-libbacktrace: + @if [ $(current_stage) = stagefeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagefeedback-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stagefeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stageautoprofile-target-libbacktrace maybe-all-stageautoprofile-target-libbacktrace +.PHONY: clean-stageautoprofile-target-libbacktrace maybe-clean-stageautoprofile-target-libbacktrace +maybe-all-stageautoprofile-target-libbacktrace: +maybe-clean-stageautoprofile-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stageautoprofile-target-libbacktrace: all-stageautoprofile-target-libbacktrace +all-stageautoprofile: all-stageautoprofile-target-libbacktrace +TARGET-stageautoprofile-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stageautoprofile-target-libbacktrace: configure-stageautoprofile-target-libbacktrace + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $$s/gcc/config/i386/$(AUTO_PROFILE) \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautoprofile_TFLAGS)" \ + $(TARGET-stageautoprofile-target-libbacktrace) + +maybe-clean-stageautoprofile-target-libbacktrace: clean-stageautoprofile-target-libbacktrace +clean-stageautoprofile: clean-stageautoprofile-target-libbacktrace +clean-stageautoprofile-target-libbacktrace: + @if [ $(current_stage) = stageautoprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautoprofile-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stageautoprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + +.PHONY: all-stageautofeedback-target-libbacktrace maybe-all-stageautofeedback-target-libbacktrace +.PHONY: clean-stageautofeedback-target-libbacktrace maybe-clean-stageautofeedback-target-libbacktrace +maybe-all-stageautofeedback-target-libbacktrace: +maybe-clean-stageautofeedback-target-libbacktrace: +@if target-libbacktrace-bootstrap +maybe-all-stageautofeedback-target-libbacktrace: all-stageautofeedback-target-libbacktrace +all-stageautofeedback: all-stageautofeedback-target-libbacktrace +TARGET-stageautofeedback-target-libbacktrace = $(TARGET-target-libbacktrace) +all-stageautofeedback-target-libbacktrace: configure-stageautofeedback-target-libbacktrace + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \ + $(TARGET-stageautofeedback-target-libbacktrace) + +maybe-clean-stageautofeedback-target-libbacktrace: clean-stageautofeedback-target-libbacktrace +clean-stageautofeedback: clean-stageautofeedback-target-libbacktrace +clean-stageautofeedback-target-libbacktrace: + @if [ $(current_stage) = stageautofeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libbacktrace/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautofeedback-libbacktrace/Makefile ] || exit 0; \ + $(MAKE) stageautofeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libbacktrace && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libbacktrace-bootstrap + + + + .PHONY: check-target-libbacktrace maybe-check-target-libbacktrace @@ -47000,7 +47791,6 @@ configure-target-libphobos: stage_curren @if target-libphobos maybe-configure-target-libphobos: configure-target-libphobos configure-target-libphobos: - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ echo "Checking multilib configuration for libphobos..."; \ @@ -47038,6 +47828,412 @@ configure-target-libphobos: +.PHONY: configure-stage1-target-libphobos maybe-configure-stage1-target-libphobos +maybe-configure-stage1-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stage1-target-libphobos: configure-stage1-target-libphobos +configure-stage1-target-libphobos: + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 1 in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + \ + $(STAGE1_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stage2-target-libphobos maybe-configure-stage2-target-libphobos +maybe-configure-stage2-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stage2-target-libphobos: configure-stage2-target-libphobos +configure-stage2-target-libphobos: + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 2 in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE2_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stage3-target-libphobos maybe-configure-stage3-target-libphobos +maybe-configure-stage3-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stage3-target-libphobos: configure-stage3-target-libphobos +configure-stage3-target-libphobos: + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 3 in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE3_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stage4-target-libphobos maybe-configure-stage4-target-libphobos +maybe-configure-stage4-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stage4-target-libphobos: configure-stage4-target-libphobos +configure-stage4-target-libphobos: + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 4 in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE4_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stageprofile-target-libphobos maybe-configure-stageprofile-target-libphobos +maybe-configure-stageprofile-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stageprofile-target-libphobos: configure-stageprofile-target-libphobos +configure-stageprofile-target-libphobos: + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage profile in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEprofile_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stagetrain-target-libphobos maybe-configure-stagetrain-target-libphobos +maybe-configure-stagetrain-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stagetrain-target-libphobos: configure-stagetrain-target-libphobos +configure-stagetrain-target-libphobos: + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage train in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEtrain_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stagefeedback-target-libphobos maybe-configure-stagefeedback-target-libphobos +maybe-configure-stagefeedback-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stagefeedback-target-libphobos: configure-stagefeedback-target-libphobos +configure-stagefeedback-target-libphobos: + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage feedback in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEfeedback_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stageautoprofile-target-libphobos maybe-configure-stageautoprofile-target-libphobos +maybe-configure-stageautoprofile-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stageautoprofile-target-libphobos: configure-stageautoprofile-target-libphobos +configure-stageautoprofile-target-libphobos: + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autoprofile in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautoprofile_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + +.PHONY: configure-stageautofeedback-target-libphobos maybe-configure-stageautofeedback-target-libphobos +maybe-configure-stageautofeedback-target-libphobos: +@if target-libphobos-bootstrap +maybe-configure-stageautofeedback-target-libphobos: configure-stageautofeedback-target-libphobos +configure-stageautofeedback-target-libphobos: + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libphobos..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autofeedback in $(TARGET_SUBDIR)/libphobos; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + cd $(TARGET_SUBDIR)/libphobos || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautofeedback_CONFIGURE_FLAGS) +@endif target-libphobos-bootstrap + + + .PHONY: all-target-libphobos maybe-all-target-libphobos @@ -47049,7 +48245,6 @@ all-target-libphobos: stage_current TARGET-target-libphobos=all maybe-all-target-libphobos: all-target-libphobos all-target-libphobos: configure-target-libphobos - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(NORMAL_TARGET_EXPORTS) \ @@ -47060,6 +48255,387 @@ all-target-libphobos: configure-target-l +.PHONY: all-stage1-target-libphobos maybe-all-stage1-target-libphobos +.PHONY: clean-stage1-target-libphobos maybe-clean-stage1-target-libphobos +maybe-all-stage1-target-libphobos: +maybe-clean-stage1-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stage1-target-libphobos: all-stage1-target-libphobos +all-stage1: all-stage1-target-libphobos +TARGET-stage1-target-libphobos = $(TARGET-target-libphobos) +all-stage1-target-libphobos: configure-stage1-target-libphobos + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + \ + TFLAGS="$(STAGE1_TFLAGS)" \ + $(TARGET-stage1-target-libphobos) + +maybe-clean-stage1-target-libphobos: clean-stage1-target-libphobos +clean-stage1: clean-stage1-target-libphobos +clean-stage1-target-libphobos: + @if [ $(current_stage) = stage1 ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage1-libphobos/Makefile ] || exit 0; \ + $(MAKE) stage1-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stage2-target-libphobos maybe-all-stage2-target-libphobos +.PHONY: clean-stage2-target-libphobos maybe-clean-stage2-target-libphobos +maybe-all-stage2-target-libphobos: +maybe-clean-stage2-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stage2-target-libphobos: all-stage2-target-libphobos +all-stage2: all-stage2-target-libphobos +TARGET-stage2-target-libphobos = $(TARGET-target-libphobos) +all-stage2-target-libphobos: configure-stage2-target-libphobos + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE2_TFLAGS)" \ + $(TARGET-stage2-target-libphobos) + +maybe-clean-stage2-target-libphobos: clean-stage2-target-libphobos +clean-stage2: clean-stage2-target-libphobos +clean-stage2-target-libphobos: + @if [ $(current_stage) = stage2 ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage2-libphobos/Makefile ] || exit 0; \ + $(MAKE) stage2-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stage3-target-libphobos maybe-all-stage3-target-libphobos +.PHONY: clean-stage3-target-libphobos maybe-clean-stage3-target-libphobos +maybe-all-stage3-target-libphobos: +maybe-clean-stage3-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stage3-target-libphobos: all-stage3-target-libphobos +all-stage3: all-stage3-target-libphobos +TARGET-stage3-target-libphobos = $(TARGET-target-libphobos) +all-stage3-target-libphobos: configure-stage3-target-libphobos + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE3_TFLAGS)" \ + $(TARGET-stage3-target-libphobos) + +maybe-clean-stage3-target-libphobos: clean-stage3-target-libphobos +clean-stage3: clean-stage3-target-libphobos +clean-stage3-target-libphobos: + @if [ $(current_stage) = stage3 ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage3-libphobos/Makefile ] || exit 0; \ + $(MAKE) stage3-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stage4-target-libphobos maybe-all-stage4-target-libphobos +.PHONY: clean-stage4-target-libphobos maybe-clean-stage4-target-libphobos +maybe-all-stage4-target-libphobos: +maybe-clean-stage4-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stage4-target-libphobos: all-stage4-target-libphobos +all-stage4: all-stage4-target-libphobos +TARGET-stage4-target-libphobos = $(TARGET-target-libphobos) +all-stage4-target-libphobos: configure-stage4-target-libphobos + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE4_TFLAGS)" \ + $(TARGET-stage4-target-libphobos) + +maybe-clean-stage4-target-libphobos: clean-stage4-target-libphobos +clean-stage4: clean-stage4-target-libphobos +clean-stage4-target-libphobos: + @if [ $(current_stage) = stage4 ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage4-libphobos/Makefile ] || exit 0; \ + $(MAKE) stage4-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stageprofile-target-libphobos maybe-all-stageprofile-target-libphobos +.PHONY: clean-stageprofile-target-libphobos maybe-clean-stageprofile-target-libphobos +maybe-all-stageprofile-target-libphobos: +maybe-clean-stageprofile-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stageprofile-target-libphobos: all-stageprofile-target-libphobos +all-stageprofile: all-stageprofile-target-libphobos +TARGET-stageprofile-target-libphobos = $(TARGET-target-libphobos) +all-stageprofile-target-libphobos: configure-stageprofile-target-libphobos + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEprofile_TFLAGS)" \ + $(TARGET-stageprofile-target-libphobos) + +maybe-clean-stageprofile-target-libphobos: clean-stageprofile-target-libphobos +clean-stageprofile: clean-stageprofile-target-libphobos +clean-stageprofile-target-libphobos: + @if [ $(current_stage) = stageprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageprofile-libphobos/Makefile ] || exit 0; \ + $(MAKE) stageprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stagetrain-target-libphobos maybe-all-stagetrain-target-libphobos +.PHONY: clean-stagetrain-target-libphobos maybe-clean-stagetrain-target-libphobos +maybe-all-stagetrain-target-libphobos: +maybe-clean-stagetrain-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stagetrain-target-libphobos: all-stagetrain-target-libphobos +all-stagetrain: all-stagetrain-target-libphobos +TARGET-stagetrain-target-libphobos = $(TARGET-target-libphobos) +all-stagetrain-target-libphobos: configure-stagetrain-target-libphobos + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEtrain_TFLAGS)" \ + $(TARGET-stagetrain-target-libphobos) + +maybe-clean-stagetrain-target-libphobos: clean-stagetrain-target-libphobos +clean-stagetrain: clean-stagetrain-target-libphobos +clean-stagetrain-target-libphobos: + @if [ $(current_stage) = stagetrain ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagetrain-libphobos/Makefile ] || exit 0; \ + $(MAKE) stagetrain-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stagefeedback-target-libphobos maybe-all-stagefeedback-target-libphobos +.PHONY: clean-stagefeedback-target-libphobos maybe-clean-stagefeedback-target-libphobos +maybe-all-stagefeedback-target-libphobos: +maybe-clean-stagefeedback-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stagefeedback-target-libphobos: all-stagefeedback-target-libphobos +all-stagefeedback: all-stagefeedback-target-libphobos +TARGET-stagefeedback-target-libphobos = $(TARGET-target-libphobos) +all-stagefeedback-target-libphobos: configure-stagefeedback-target-libphobos + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEfeedback_TFLAGS)" \ + $(TARGET-stagefeedback-target-libphobos) + +maybe-clean-stagefeedback-target-libphobos: clean-stagefeedback-target-libphobos +clean-stagefeedback: clean-stagefeedback-target-libphobos +clean-stagefeedback-target-libphobos: + @if [ $(current_stage) = stagefeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagefeedback-libphobos/Makefile ] || exit 0; \ + $(MAKE) stagefeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stageautoprofile-target-libphobos maybe-all-stageautoprofile-target-libphobos +.PHONY: clean-stageautoprofile-target-libphobos maybe-clean-stageautoprofile-target-libphobos +maybe-all-stageautoprofile-target-libphobos: +maybe-clean-stageautoprofile-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stageautoprofile-target-libphobos: all-stageautoprofile-target-libphobos +all-stageautoprofile: all-stageautoprofile-target-libphobos +TARGET-stageautoprofile-target-libphobos = $(TARGET-target-libphobos) +all-stageautoprofile-target-libphobos: configure-stageautoprofile-target-libphobos + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + $$s/gcc/config/i386/$(AUTO_PROFILE) \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautoprofile_TFLAGS)" \ + $(TARGET-stageautoprofile-target-libphobos) + +maybe-clean-stageautoprofile-target-libphobos: clean-stageautoprofile-target-libphobos +clean-stageautoprofile: clean-stageautoprofile-target-libphobos +clean-stageautoprofile-target-libphobos: + @if [ $(current_stage) = stageautoprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautoprofile-libphobos/Makefile ] || exit 0; \ + $(MAKE) stageautoprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + +.PHONY: all-stageautofeedback-target-libphobos maybe-all-stageautofeedback-target-libphobos +.PHONY: clean-stageautofeedback-target-libphobos maybe-clean-stageautofeedback-target-libphobos +maybe-all-stageautofeedback-target-libphobos: +maybe-clean-stageautofeedback-target-libphobos: +@if target-libphobos-bootstrap +maybe-all-stageautofeedback-target-libphobos: all-stageautofeedback-target-libphobos +all-stageautofeedback: all-stageautofeedback-target-libphobos +TARGET-stageautofeedback-target-libphobos = $(TARGET-target-libphobos) +all-stageautofeedback-target-libphobos: configure-stageautofeedback-target-libphobos + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libphobos && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \ + $(TARGET-stageautofeedback-target-libphobos) + +maybe-clean-stageautofeedback-target-libphobos: clean-stageautofeedback-target-libphobos +clean-stageautofeedback: clean-stageautofeedback-target-libphobos +clean-stageautofeedback-target-libphobos: + @if [ $(current_stage) = stageautofeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautofeedback-libphobos/Makefile ] || exit 0; \ + $(MAKE) stageautofeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libphobos-bootstrap + + + + .PHONY: check-target-libphobos maybe-check-target-libphobos @@ -52285,7 +53861,6 @@ configure-target-libatomic: stage_curren @if target-libatomic maybe-configure-target-libatomic: configure-target-libatomic configure-target-libatomic: - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ echo "Checking multilib configuration for libatomic..."; \ @@ -52323,6 +53898,412 @@ configure-target-libatomic: +.PHONY: configure-stage1-target-libatomic maybe-configure-stage1-target-libatomic +maybe-configure-stage1-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stage1-target-libatomic: configure-stage1-target-libatomic +configure-stage1-target-libatomic: + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 1 in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + \ + $(STAGE1_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stage2-target-libatomic maybe-configure-stage2-target-libatomic +maybe-configure-stage2-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stage2-target-libatomic: configure-stage2-target-libatomic +configure-stage2-target-libatomic: + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 2 in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE2_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stage3-target-libatomic maybe-configure-stage3-target-libatomic +maybe-configure-stage3-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stage3-target-libatomic: configure-stage3-target-libatomic +configure-stage3-target-libatomic: + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 3 in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE3_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stage4-target-libatomic maybe-configure-stage4-target-libatomic +maybe-configure-stage4-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stage4-target-libatomic: configure-stage4-target-libatomic +configure-stage4-target-libatomic: + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 4 in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE4_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stageprofile-target-libatomic maybe-configure-stageprofile-target-libatomic +maybe-configure-stageprofile-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stageprofile-target-libatomic: configure-stageprofile-target-libatomic +configure-stageprofile-target-libatomic: + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage profile in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEprofile_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stagetrain-target-libatomic maybe-configure-stagetrain-target-libatomic +maybe-configure-stagetrain-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stagetrain-target-libatomic: configure-stagetrain-target-libatomic +configure-stagetrain-target-libatomic: + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage train in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEtrain_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stagefeedback-target-libatomic maybe-configure-stagefeedback-target-libatomic +maybe-configure-stagefeedback-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stagefeedback-target-libatomic: configure-stagefeedback-target-libatomic +configure-stagefeedback-target-libatomic: + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage feedback in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEfeedback_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stageautoprofile-target-libatomic maybe-configure-stageautoprofile-target-libatomic +maybe-configure-stageautoprofile-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stageautoprofile-target-libatomic: configure-stageautoprofile-target-libatomic +configure-stageautoprofile-target-libatomic: + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autoprofile in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautoprofile_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + +.PHONY: configure-stageautofeedback-target-libatomic maybe-configure-stageautofeedback-target-libatomic +maybe-configure-stageautofeedback-target-libatomic: +@if target-libatomic-bootstrap +maybe-configure-stageautofeedback-target-libatomic: configure-stageautofeedback-target-libatomic +configure-stageautofeedback-target-libatomic: + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libatomic..."; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libatomic/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libatomic/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libatomic/Makefile; \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libatomic/multilib.tmp $(TARGET_SUBDIR)/libatomic/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libatomic/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage autofeedback in $(TARGET_SUBDIR)/libatomic; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libatomic; \ + cd $(TARGET_SUBDIR)/libatomic || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libatomic/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libatomic; \ + $(SHELL) $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEautofeedback_CONFIGURE_FLAGS) +@endif target-libatomic-bootstrap + + + .PHONY: all-target-libatomic maybe-all-target-libatomic @@ -52334,7 +54315,6 @@ all-target-libatomic: stage_current TARGET-target-libatomic=all maybe-all-target-libatomic: all-target-libatomic all-target-libatomic: configure-target-libatomic - @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(NORMAL_TARGET_EXPORTS) \ @@ -52345,6 +54325,387 @@ all-target-libatomic: configure-target-l +.PHONY: all-stage1-target-libatomic maybe-all-stage1-target-libatomic +.PHONY: clean-stage1-target-libatomic maybe-clean-stage1-target-libatomic +maybe-all-stage1-target-libatomic: +maybe-clean-stage1-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stage1-target-libatomic: all-stage1-target-libatomic +all-stage1: all-stage1-target-libatomic +TARGET-stage1-target-libatomic = $(TARGET-target-libatomic) +all-stage1-target-libatomic: configure-stage1-target-libatomic + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + \ + TFLAGS="$(STAGE1_TFLAGS)" \ + $(TARGET-stage1-target-libatomic) + +maybe-clean-stage1-target-libatomic: clean-stage1-target-libatomic +clean-stage1: clean-stage1-target-libatomic +clean-stage1-target-libatomic: + @if [ $(current_stage) = stage1 ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage1-libatomic/Makefile ] || exit 0; \ + $(MAKE) stage1-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stage2-target-libatomic maybe-all-stage2-target-libatomic +.PHONY: clean-stage2-target-libatomic maybe-clean-stage2-target-libatomic +maybe-all-stage2-target-libatomic: +maybe-clean-stage2-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stage2-target-libatomic: all-stage2-target-libatomic +all-stage2: all-stage2-target-libatomic +TARGET-stage2-target-libatomic = $(TARGET-target-libatomic) +all-stage2-target-libatomic: configure-stage2-target-libatomic + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE2_TFLAGS)" \ + $(TARGET-stage2-target-libatomic) + +maybe-clean-stage2-target-libatomic: clean-stage2-target-libatomic +clean-stage2: clean-stage2-target-libatomic +clean-stage2-target-libatomic: + @if [ $(current_stage) = stage2 ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage2-libatomic/Makefile ] || exit 0; \ + $(MAKE) stage2-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stage3-target-libatomic maybe-all-stage3-target-libatomic +.PHONY: clean-stage3-target-libatomic maybe-clean-stage3-target-libatomic +maybe-all-stage3-target-libatomic: +maybe-clean-stage3-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stage3-target-libatomic: all-stage3-target-libatomic +all-stage3: all-stage3-target-libatomic +TARGET-stage3-target-libatomic = $(TARGET-target-libatomic) +all-stage3-target-libatomic: configure-stage3-target-libatomic + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE3_TFLAGS)" \ + $(TARGET-stage3-target-libatomic) + +maybe-clean-stage3-target-libatomic: clean-stage3-target-libatomic +clean-stage3: clean-stage3-target-libatomic +clean-stage3-target-libatomic: + @if [ $(current_stage) = stage3 ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage3-libatomic/Makefile ] || exit 0; \ + $(MAKE) stage3-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stage4-target-libatomic maybe-all-stage4-target-libatomic +.PHONY: clean-stage4-target-libatomic maybe-clean-stage4-target-libatomic +maybe-all-stage4-target-libatomic: +maybe-clean-stage4-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stage4-target-libatomic: all-stage4-target-libatomic +all-stage4: all-stage4-target-libatomic +TARGET-stage4-target-libatomic = $(TARGET-target-libatomic) +all-stage4-target-libatomic: configure-stage4-target-libatomic + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE4_TFLAGS)" \ + $(TARGET-stage4-target-libatomic) + +maybe-clean-stage4-target-libatomic: clean-stage4-target-libatomic +clean-stage4: clean-stage4-target-libatomic +clean-stage4-target-libatomic: + @if [ $(current_stage) = stage4 ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage4-libatomic/Makefile ] || exit 0; \ + $(MAKE) stage4-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stageprofile-target-libatomic maybe-all-stageprofile-target-libatomic +.PHONY: clean-stageprofile-target-libatomic maybe-clean-stageprofile-target-libatomic +maybe-all-stageprofile-target-libatomic: +maybe-clean-stageprofile-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stageprofile-target-libatomic: all-stageprofile-target-libatomic +all-stageprofile: all-stageprofile-target-libatomic +TARGET-stageprofile-target-libatomic = $(TARGET-target-libatomic) +all-stageprofile-target-libatomic: configure-stageprofile-target-libatomic + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEprofile_TFLAGS)" \ + $(TARGET-stageprofile-target-libatomic) + +maybe-clean-stageprofile-target-libatomic: clean-stageprofile-target-libatomic +clean-stageprofile: clean-stageprofile-target-libatomic +clean-stageprofile-target-libatomic: + @if [ $(current_stage) = stageprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageprofile-libatomic/Makefile ] || exit 0; \ + $(MAKE) stageprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stagetrain-target-libatomic maybe-all-stagetrain-target-libatomic +.PHONY: clean-stagetrain-target-libatomic maybe-clean-stagetrain-target-libatomic +maybe-all-stagetrain-target-libatomic: +maybe-clean-stagetrain-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stagetrain-target-libatomic: all-stagetrain-target-libatomic +all-stagetrain: all-stagetrain-target-libatomic +TARGET-stagetrain-target-libatomic = $(TARGET-target-libatomic) +all-stagetrain-target-libatomic: configure-stagetrain-target-libatomic + @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEtrain_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEtrain_TFLAGS)" \ + $(TARGET-stagetrain-target-libatomic) + +maybe-clean-stagetrain-target-libatomic: clean-stagetrain-target-libatomic +clean-stagetrain: clean-stagetrain-target-libatomic +clean-stagetrain-target-libatomic: + @if [ $(current_stage) = stagetrain ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagetrain-libatomic/Makefile ] || exit 0; \ + $(MAKE) stagetrain-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stagefeedback-target-libatomic maybe-all-stagefeedback-target-libatomic +.PHONY: clean-stagefeedback-target-libatomic maybe-clean-stagefeedback-target-libatomic +maybe-all-stagefeedback-target-libatomic: +maybe-clean-stagefeedback-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stagefeedback-target-libatomic: all-stagefeedback-target-libatomic +all-stagefeedback: all-stagefeedback-target-libatomic +TARGET-stagefeedback-target-libatomic = $(TARGET-target-libatomic) +all-stagefeedback-target-libatomic: configure-stagefeedback-target-libatomic + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEfeedback_TFLAGS)" \ + $(TARGET-stagefeedback-target-libatomic) + +maybe-clean-stagefeedback-target-libatomic: clean-stagefeedback-target-libatomic +clean-stagefeedback: clean-stagefeedback-target-libatomic +clean-stagefeedback-target-libatomic: + @if [ $(current_stage) = stagefeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagefeedback-libatomic/Makefile ] || exit 0; \ + $(MAKE) stagefeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stageautoprofile-target-libatomic maybe-all-stageautoprofile-target-libatomic +.PHONY: clean-stageautoprofile-target-libatomic maybe-clean-stageautoprofile-target-libatomic +maybe-all-stageautoprofile-target-libatomic: +maybe-clean-stageautoprofile-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stageautoprofile-target-libatomic: all-stageautoprofile-target-libatomic +all-stageautoprofile: all-stageautoprofile-target-libatomic +TARGET-stageautoprofile-target-libatomic = $(TARGET-target-libatomic) +all-stageautoprofile-target-libatomic: configure-stageautoprofile-target-libatomic + @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + $$s/gcc/config/i386/$(AUTO_PROFILE) \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautoprofile_TFLAGS)" \ + $(TARGET-stageautoprofile-target-libatomic) + +maybe-clean-stageautoprofile-target-libatomic: clean-stageautoprofile-target-libatomic +clean-stageautoprofile: clean-stageautoprofile-target-libatomic +clean-stageautoprofile-target-libatomic: + @if [ $(current_stage) = stageautoprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautoprofile-libatomic/Makefile ] || exit 0; \ + $(MAKE) stageautoprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + +.PHONY: all-stageautofeedback-target-libatomic maybe-all-stageautofeedback-target-libatomic +.PHONY: clean-stageautofeedback-target-libatomic maybe-clean-stageautofeedback-target-libatomic +maybe-all-stageautofeedback-target-libatomic: +maybe-clean-stageautofeedback-target-libatomic: +@if target-libatomic-bootstrap +maybe-all-stageautofeedback-target-libatomic: all-stageautofeedback-target-libatomic +all-stageautofeedback: all-stageautofeedback-target-libatomic +TARGET-stageautofeedback-target-libatomic = $(TARGET-target-libatomic) +all-stageautofeedback-target-libatomic: configure-stageautofeedback-target-libatomic + @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libatomic && \ + \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \ + $(TARGET-stageautofeedback-target-libatomic) + +maybe-clean-stageautofeedback-target-libatomic: clean-stageautofeedback-target-libatomic +clean-stageautofeedback: clean-stageautofeedback-target-libatomic +clean-stageautofeedback-target-libatomic: + @if [ $(current_stage) = stageautofeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libatomic/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageautofeedback-libatomic/Makefile ] || exit 0; \ + $(MAKE) stageautofeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libatomic && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) clean +@endif target-libatomic-bootstrap + + + + .PHONY: check-target-libatomic maybe-check-target-libatomic @@ -56029,13 +58390,29 @@ configure-stagetrain-target-libgcc: mayb configure-stagefeedback-target-libgcc: maybe-all-stagefeedback-gcc configure-stageautoprofile-target-libgcc: maybe-all-stageautoprofile-gcc configure-stageautofeedback-target-libgcc: maybe-all-stageautofeedback-gcc -configure-target-libbacktrace: stage_last +configure-stage1-target-libbacktrace: maybe-all-stage1-gcc +configure-stage2-target-libbacktrace: maybe-all-stage2-gcc +configure-stage3-target-libbacktrace: maybe-all-stage3-gcc +configure-stage4-target-libbacktrace: maybe-all-stage4-gcc +configure-stageprofile-target-libbacktrace: maybe-all-stageprofile-gcc +configure-stagetrain-target-libbacktrace: maybe-all-stagetrain-gcc +configure-stagefeedback-target-libbacktrace: maybe-all-stagefeedback-gcc +configure-stageautoprofile-target-libbacktrace: maybe-all-stageautoprofile-gcc +configure-stageautofeedback-target-libbacktrace: maybe-all-stageautofeedback-gcc configure-target-libquadmath: stage_last configure-target-libgfortran: stage_last configure-target-libobjc: stage_last configure-target-libgo: stage_last configure-target-libhsail-rt: stage_last -configure-target-libphobos: stage_last +configure-stage1-target-libphobos: maybe-all-stage1-gcc +configure-stage2-target-libphobos: maybe-all-stage2-gcc +configure-stage3-target-libphobos: maybe-all-stage3-gcc +configure-stage4-target-libphobos: maybe-all-stage4-gcc +configure-stageprofile-target-libphobos: maybe-all-stageprofile-gcc +configure-stagetrain-target-libphobos: maybe-all-stagetrain-gcc +configure-stagefeedback-target-libphobos: maybe-all-stagefeedback-gcc +configure-stageautoprofile-target-libphobos: maybe-all-stageautoprofile-gcc +configure-stageautofeedback-target-libphobos: maybe-all-stageautofeedback-gcc configure-target-libtermcap: stage_last configure-target-winsup: stage_last configure-target-libgloss: stage_last @@ -56053,7 +58430,15 @@ configure-stagefeedback-target-libgomp: configure-stageautoprofile-target-libgomp: maybe-all-stageautoprofile-gcc configure-stageautofeedback-target-libgomp: maybe-all-stageautofeedback-gcc configure-target-libitm: stage_last -configure-target-libatomic: stage_last +configure-stage1-target-libatomic: maybe-all-stage1-gcc +configure-stage2-target-libatomic: maybe-all-stage2-gcc +configure-stage3-target-libatomic: maybe-all-stage3-gcc +configure-stage4-target-libatomic: maybe-all-stage4-gcc +configure-stageprofile-target-libatomic: maybe-all-stageprofile-gcc +configure-stagetrain-target-libatomic: maybe-all-stagetrain-gcc +configure-stagefeedback-target-libatomic: maybe-all-stagefeedback-gcc +configure-stageautoprofile-target-libatomic: maybe-all-stageautoprofile-gcc +configure-stageautofeedback-target-libatomic: maybe-all-stageautofeedback-gcc @endif gcc-bootstrap @if gcc-no-bootstrap @@ -57063,14 +59448,39 @@ all-m4: maybe-all-build-texinfo configure-target-fastjar: maybe-configure-target-zlib all-target-fastjar: maybe-all-target-zlib configure-target-libgo: maybe-configure-target-libffi -all-target-libgo: maybe-all-target-libbacktrace all-target-libgo: maybe-all-target-libffi -all-target-libgo: maybe-all-target-libatomic configure-target-libphobos: maybe-configure-target-libbacktrace +configure-stage1-target-libphobos: maybe-configure-stage1-target-libbacktrace +configure-stage2-target-libphobos: maybe-configure-stage2-target-libbacktrace +configure-stage3-target-libphobos: maybe-configure-stage3-target-libbacktrace +configure-stage4-target-libphobos: maybe-configure-stage4-target-libbacktrace +configure-stageprofile-target-libphobos: maybe-configure-stageprofile-target-libbacktrace +configure-stagetrain-target-libphobos: maybe-configure-stagetrain-target-libbacktrace +configure-stagefeedback-target-libphobos: maybe-configure-stagefeedback-target-libbacktrace +configure-stageautoprofile-target-libphobos: maybe-configure-stageautoprofile-target-libbacktrace +configure-stageautofeedback-target-libphobos: maybe-configure-stageautofeedback-target-libbacktrace configure-target-libphobos: maybe-configure-target-zlib all-target-libphobos: maybe-all-target-libbacktrace +all-stage1-target-libphobos: maybe-all-stage1-target-libbacktrace +all-stage2-target-libphobos: maybe-all-stage2-target-libbacktrace +all-stage3-target-libphobos: maybe-all-stage3-target-libbacktrace +all-stage4-target-libphobos: maybe-all-stage4-target-libbacktrace +all-stageprofile-target-libphobos: maybe-all-stageprofile-target-libbacktrace +all-stagetrain-target-libphobos: maybe-all-stagetrain-target-libbacktrace +all-stagefeedback-target-libphobos: maybe-all-stagefeedback-target-libbacktrace +all-stageautoprofile-target-libphobos: maybe-all-stageautoprofile-target-libbacktrace +all-stageautofeedback-target-libphobos: maybe-all-stageautofeedback-target-libbacktrace all-target-libphobos: maybe-all-target-zlib all-target-libphobos: maybe-all-target-libatomic +all-stage1-target-libphobos: maybe-all-stage1-target-libatomic +all-stage2-target-libphobos: maybe-all-stage2-target-libatomic +all-stage3-target-libphobos: maybe-all-stage3-target-libatomic +all-stage4-target-libphobos: maybe-all-stage4-target-libatomic +all-stageprofile-target-libphobos: maybe-all-stageprofile-target-libatomic +all-stagetrain-target-libphobos: maybe-all-stagetrain-target-libatomic +all-stagefeedback-target-libphobos: maybe-all-stagefeedback-target-libatomic +all-stageautoprofile-target-libphobos: maybe-all-stageautoprofile-target-libatomic +all-stageautofeedback-target-libphobos: maybe-all-stageautofeedback-target-libatomic configure-target-libstdc++-v3: maybe-configure-target-libgomp configure-stage1-target-libstdc++-v3: maybe-configure-stage1-target-libgomp configure-stage2-target-libstdc++-v3: maybe-configure-stage2-target-libgomp @@ -57127,7 +59537,6 @@ install-target-libstdc++-v3: maybe-insta all-target-libgloss: maybe-all-target-newlib all-target-winsup: maybe-all-target-libtermcap configure-target-libgfortran: maybe-all-target-libquadmath -configure-target-libgfortran: maybe-all-target-libbacktrace @if gcc-bootstrap @@ -57176,10 +59585,13 @@ all-bison: maybe-all-intl all-flex: maybe-all-intl all-m4: maybe-all-intl configure-target-libgo: maybe-all-target-libstdc++-v3 +all-target-libgo: maybe-all-target-libbacktrace +all-target-libgo: maybe-all-target-libatomic configure-target-liboffloadmic: maybe-configure-target-libgomp all-target-liboffloadmic: maybe-all-target-libgomp configure-target-newlib: maybe-all-binutils configure-target-newlib: maybe-all-ld +configure-target-libgfortran: maybe-all-target-libbacktrace @endunless gcc-bootstrap # Dependencies for target modules on other target modules are @@ -57215,6 +59627,24 @@ configure-stagetrain-target-libvtv: mayb configure-stagefeedback-target-libvtv: maybe-all-stagefeedback-target-libgcc configure-stageautoprofile-target-libvtv: maybe-all-stageautoprofile-target-libgcc configure-stageautofeedback-target-libvtv: maybe-all-stageautofeedback-target-libgcc +configure-stage1-target-libbacktrace: maybe-all-stage1-target-libgcc +configure-stage2-target-libbacktrace: maybe-all-stage2-target-libgcc +configure-stage3-target-libbacktrace: maybe-all-stage3-target-libgcc +configure-stage4-target-libbacktrace: maybe-all-stage4-target-libgcc +configure-stageprofile-target-libbacktrace: maybe-all-stageprofile-target-libgcc +configure-stagetrain-target-libbacktrace: maybe-all-stagetrain-target-libgcc +configure-stagefeedback-target-libbacktrace: maybe-all-stagefeedback-target-libgcc +configure-stageautoprofile-target-libbacktrace: maybe-all-stageautoprofile-target-libgcc +configure-stageautofeedback-target-libbacktrace: maybe-all-stageautofeedback-target-libgcc +configure-stage1-target-libphobos: maybe-all-stage1-target-libgcc +configure-stage2-target-libphobos: maybe-all-stage2-target-libgcc +configure-stage3-target-libphobos: maybe-all-stage3-target-libgcc +configure-stage4-target-libphobos: maybe-all-stage4-target-libgcc +configure-stageprofile-target-libphobos: maybe-all-stageprofile-target-libgcc +configure-stagetrain-target-libphobos: maybe-all-stagetrain-target-libgcc +configure-stagefeedback-target-libphobos: maybe-all-stagefeedback-target-libgcc +configure-stageautoprofile-target-libphobos: maybe-all-stageautoprofile-target-libgcc +configure-stageautofeedback-target-libphobos: maybe-all-stageautofeedback-target-libgcc configure-stage1-target-libgomp: maybe-all-stage1-target-libgcc configure-stage2-target-libgomp: maybe-all-stage2-target-libgcc configure-stage3-target-libgomp: maybe-all-stage3-target-libgcc @@ -57224,6 +59654,15 @@ configure-stagetrain-target-libgomp: may configure-stagefeedback-target-libgomp: maybe-all-stagefeedback-target-libgcc configure-stageautoprofile-target-libgomp: maybe-all-stageautoprofile-target-libgcc configure-stageautofeedback-target-libgomp: maybe-all-stageautofeedback-target-libgcc +configure-stage1-target-libatomic: maybe-all-stage1-target-libgcc +configure-stage2-target-libatomic: maybe-all-stage2-target-libgcc +configure-stage3-target-libatomic: maybe-all-stage3-target-libgcc +configure-stage4-target-libatomic: maybe-all-stage4-target-libgcc +configure-stageprofile-target-libatomic: maybe-all-stageprofile-target-libgcc +configure-stagetrain-target-libatomic: maybe-all-stagetrain-target-libgcc +configure-stagefeedback-target-libatomic: maybe-all-stagefeedback-target-libgcc +configure-stageautoprofile-target-libatomic: maybe-all-stageautoprofile-target-libgcc +configure-stageautofeedback-target-libatomic: maybe-all-stageautofeedback-target-libgcc @endif gcc-bootstrap @if gcc-no-bootstrap --- a/config/acx.m4 +++ b/config/acx.m4 @@ -420,6 +420,18 @@ else fi ]) +# Test for D. +AC_DEFUN([ACX_PROG_GDC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX]) +AC_REQUIRE([AC_PROG_CC]) +AC_CHECK_TOOL(GDC, gdc, no) +if test "x$GDC" != xno; then + have_gdc=yes +else + have_gdc=no +fi +]) + dnl 'make compare' can be significantly faster, if cmp itself can dnl skip bytes instead of using tail. The test being performed is dnl "if cmp --ignore-initial=2 t1 t2 && ! cmp --ignore-initial=1 t1 t2" --- a/configure +++ b/configure @@ -662,6 +662,7 @@ extra_mpfr_configure_flags gmpinc gmplibs do_compare +GDC GNATMAKE GNATBIND ac_ct_CXX @@ -5252,6 +5253,106 @@ else have_gnat=no fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gdc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gdc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC"; then + ac_cv_prog_GDC="$GDC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC="${ac_tool_prefix}gdc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC=$ac_cv_prog_GDC +if test -n "$GDC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5 +$as_echo "$GDC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_GDC"; then + ac_ct_GDC=$GDC + # Extract the first word of "gdc", so it can be a program name with args. +set dummy gdc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_GDC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_GDC"; then + ac_cv_prog_ac_ct_GDC="$ac_ct_GDC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_GDC="gdc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_GDC=$ac_cv_prog_ac_ct_GDC +if test -n "$ac_ct_GDC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GDC" >&5 +$as_echo "$ac_ct_GDC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_GDC" = x; then + GDC="no" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + GDC=$ac_ct_GDC + fi +else + GDC="$ac_cv_prog_GDC" +fi + +if test "x$GDC" != xno; then + have_gdc=yes +else + have_gdc=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to compare bootstrapped objects" >&5 $as_echo_n "checking how to compare bootstrapped objects... " >&6; } if test "${gcc_cv_prog_cmp_skip+set}" = set; then : @@ -6277,6 +6378,23 @@ $as_echo "$as_me: WARNING: GNAT is requi ;; esac + # Disable D if no preexisting GDC is available. + case ${add_this_lang}:${language}:${have_gdc} in + yes:d:no) + # Specifically requested language; tell them. + as_fn_error "GDC is required to build $language" "$LINENO" 5 + ;; + all:d:no) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GDC is required to build $language" >&5 +$as_echo "$as_me: WARNING: GDC is required to build $language" >&2;} + add_this_lang=unsupported + ;; + *:d:no) + # Silently disable. + add_this_lang=unsupported + ;; + esac + # Disable jit if -enable-host-shared not specified case ${add_this_lang}:${language}:${host_shared} in yes:jit:no) @@ -7098,6 +7216,16 @@ if echo " ${target_configdirs} " | grep bootstrap_target_libs=${bootstrap_target_libs}target-libvtv, fi +# If we are building libatomic and the list of enabled languages includes the +# D frontend, bootstrap it. +if echo " ${target_configdirs} " | grep " libatomic " > /dev/null 2>&1; then + case ,${enable_languages}, in + *,d,*) + bootstrap_target_libs=${bootstrap_target_libs}target-libatomic, + ;; + esac +fi + # Determine whether gdb needs tk/tcl or not. # Use 'maybe' since enable_gdbtk might be true even if tk isn't available # and in that case we want gdb to be built without tk. Ugh! --- a/configure.ac +++ b/configure.ac @@ -1302,6 +1302,7 @@ int main() {}], fi ACX_PROG_GNAT +ACX_PROG_GDC ACX_PROG_CMP_IGNORE_INITIAL AC_ARG_ENABLE([bootstrap], @@ -1949,6 +1950,22 @@ if test -d ${srcdir}/gcc; then ;; esac + # Disable D if no preexisting GDC is available. + case ${add_this_lang}:${language}:${have_gdc} in + yes:d:no) + # Specifically requested language; tell them. + AC_MSG_ERROR([GDC is required to build $language]) + ;; + all:d:no) + AC_MSG_WARN([GDC is required to build $language]) + add_this_lang=unsupported + ;; + *:d:no) + # Silently disable. + add_this_lang=unsupported + ;; + esac + # Disable jit if -enable-host-shared not specified case ${add_this_lang}:${language}:${host_shared} in yes:jit:no) @@ -2682,6 +2699,16 @@ if echo " ${target_configdirs} " | grep bootstrap_target_libs=${bootstrap_target_libs}target-libvtv, fi +# If we are building libatomic and the list of enabled languages includes the +# D frontend, bootstrap it. +if echo " ${target_configdirs} " | grep " libatomic " > /dev/null 2>&1; then + case ,${enable_languages}, in + *,d,*) + bootstrap_target_libs=${bootstrap_target_libs}target-libatomic, + ;; + esac +fi + # Determine whether gdb needs tk/tcl or not. # Use 'maybe' since enable_gdbtk might be true even if tk isn't available # and in that case we want gdb to be built without tk. Ugh! ================================================ FILE: gcc/d/runtime.cc ================================================ /* runtime.cc -- D runtime functions called by generated code. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/mtype.h" #include "tree.h" #include "fold-const.h" #include "stringpool.h" #include "d-tree.h" /* During the codegen pass, the compiler may do lowering of expressions to call various runtime library functions. Most are implemented in the `rt' package. We represent them in the frontend here, however there's no guarantee that the compiler implementation actually matches the actual implementation. */ enum libcall_type { LCT_VOID, /* void */ LCT_BYTE, /* byte */ LCT_INT, /* int */ LCT_UINT, /* uint */ LCT_BOOL, /* bool */ LCT_DCHAR, /* dchar */ LCT_VOIDPTR, /* void* */ LCT_STRING, /* string */ LCT_WSTRING, /* wstring */ LCT_DSTRING, /* dstring */ LCT_SIZE_T, /* size_t */ LCT_ASSOCARRAY, /* void[void] */ LCT_ARRAY_VOID, /* void[] */ LCT_ARRAY_SIZE_T, /* size_t[] */ LCT_ARRAY_BYTE, /* byte[] */ LCT_ARRAY_STRING, /* string[] */ LCT_ARRAY_WSTRING, /* wstring[] */ LCT_ARRAY_DSTRING, /* dstring[] */ LCT_ARRAYARRAY_BYTE, /* byte[][] */ LCT_POINTER_ASSOCARRAY, /* void[void]* */ LCT_POINTER_VOIDPTR, /* void** */ LCT_ARRAYPTR_VOID, /* void[]* */ LCT_ARRAYPTR_BYTE, /* byte[]* */ LCT_TYPEINFO, /* TypeInfo */ LCT_CLASSINFO, /* TypeInfo_Class */ LCT_OBJECT, /* Object */ LCT_CONST_TYPEINFO, /* const(TypeInfo) */ LCT_CONST_CLASSINFO, /* const(ClassInfo) */ LCT_END }; /* An array of all types that are used by the runtime functions we need. */ static Type *libcall_types[LCT_END]; /* Our internal list of library functions. */ static tree libcall_decls[LIBCALL_LAST]; /* Return the frontend Type that is described by TYPE. Most are readily cached by the frontend proper, and likewise the use of pointerTo(), constOf(), and arrayOf() will return cached types if they have been requested before. */ static Type * get_libcall_type (libcall_type type) { if (libcall_types[type]) return libcall_types[type]; switch (type) { case LCT_VOID: libcall_types[type] = Type::tvoid; break; case LCT_BYTE: libcall_types[type] = Type::tint8; break; case LCT_INT: libcall_types[type] = Type::tint32; break; case LCT_UINT: libcall_types[type] = Type::tuns32; break; case LCT_BOOL: libcall_types[type] = Type::tbool; break; case LCT_DCHAR: libcall_types[type] = Type::tdchar; break; case LCT_VOIDPTR: libcall_types[type] = Type::tvoidptr; break; case LCT_STRING: libcall_types[type] = Type::tstring; break; case LCT_WSTRING: libcall_types[type] = Type::twstring; break; case LCT_DSTRING: libcall_types[type] = Type::tdstring; break; case LCT_SIZE_T: libcall_types[type] = Type::tsize_t; break; case LCT_ASSOCARRAY: libcall_types[type] = TypeAArray::create (Type::tvoid, Type::tvoid); break; case LCT_TYPEINFO: libcall_types[type] = Type::dtypeinfo->type; break; case LCT_CLASSINFO: libcall_types[type] = Type::typeinfoclass->type; break; case LCT_OBJECT: libcall_types[type] = get_object_type (); break; case LCT_CONST_TYPEINFO: libcall_types[type] = Type::dtypeinfo->type->constOf (); break; case LCT_CONST_CLASSINFO: libcall_types[type] = Type::typeinfoclass->type->constOf (); break; case LCT_ARRAY_VOID: libcall_types[type] = Type::tvoid->arrayOf (); break; case LCT_ARRAY_SIZE_T: libcall_types[type] = Type::tsize_t->arrayOf (); break; case LCT_ARRAY_BYTE: libcall_types[type] = Type::tint8->arrayOf (); break; case LCT_ARRAY_STRING: libcall_types[type] = Type::tstring->arrayOf (); break; case LCT_ARRAY_WSTRING: libcall_types[type] = Type::twstring->arrayOf (); break; case LCT_ARRAY_DSTRING: libcall_types[type] = Type::tdstring->arrayOf (); break; case LCT_ARRAYARRAY_BYTE: libcall_types[type] = Type::tint8->arrayOf ()->arrayOf (); break; case LCT_POINTER_ASSOCARRAY: libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo (); break; case LCT_POINTER_VOIDPTR: libcall_types[type] = Type::tvoidptr->arrayOf (); break; case LCT_ARRAYPTR_VOID: libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo (); break; case LCT_ARRAYPTR_BYTE: libcall_types[type] = Type::tint8->arrayOf ()->pointerTo (); break; default: gcc_unreachable (); } return libcall_types[type]; } /* Builds and returns function declaration named NAME. The RETURN_TYPE is the type returned, FLAGS are the expression call flags, and NPARAMS is the number of arguments, the types of which are provided in `...'. */ static tree build_libcall_decl (const char *name, libcall_type return_type, int flags, int nparams, ...) { tree *args = XALLOCAVEC (tree, nparams); bool varargs = false; tree fntype; /* Add parameter types, using 'void' as the last parameter type to mean this function accepts a variable list of arguments. */ va_list ap; va_start (ap, nparams); for (int i = 0; i < nparams; i++) { libcall_type ptype = (libcall_type) va_arg (ap, int); Type *type = get_libcall_type (ptype); if (type == Type::tvoid) { varargs = true; nparams = i; } else args[i] = build_ctype (type); } va_end (ap); /* Build the function. */ tree tret = build_ctype (get_libcall_type (return_type)); if (varargs) fntype = build_varargs_function_type_array (tret, nparams, args); else fntype = build_function_type_array (tret, nparams, args); tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, get_identifier (name), fntype); DECL_EXTERNAL (decl) = 1; TREE_PUBLIC (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; DECL_VISIBILITY_SPECIFIED (decl) = 1; /* Set any attributes on the function, such as malloc or noreturn. */ set_call_expr_flags (decl, flags); return decl; } /* Return or create the runtime library function declaration for LIBCALL. Library functions are generated as needed. This could probably be changed in the future to be done in the compiler init stage, like GCC builtin trees are, however we depend on run-time initialization of types whose definitions are in the library such as `Object' or `TypeInfo'. */ static tree get_libcall (libcall_fn libcall) { if (libcall_decls[libcall]) return libcall_decls[libcall]; switch (libcall) { #define DEF_D_RUNTIME(CODE, NAME, TYPE, PARAMS, FLAGS) \ case LIBCALL_ ## CODE: \ libcall_decls[libcall] = build_libcall_decl (NAME, TYPE, FLAGS, PARAMS); \ break; #include "runtime.def" #undef DEF_D_RUNTIME default: gcc_unreachable (); } return libcall_decls[libcall]; } /* Generate a call to LIBCALL, returning the result as TYPE. NARGS is the number of call arguments, the expressions of which are provided in `...'. This does not perform conversions or promotions on the arguments. */ tree build_libcall (libcall_fn libcall, Type *type, int nargs, ...) { /* Build the call expression to the runtime function. */ tree decl = get_libcall (libcall); tree *args = XALLOCAVEC (tree, nargs); va_list ap; va_start (ap, nargs); for (int i = 0; i < nargs; i++) args[i] = va_arg (ap, tree); va_end (ap); tree result = build_call_expr_loc_array (input_location, decl, nargs, args); /* Assumes caller knows what it is doing. */ return convert (build_ctype (type), result); } ================================================ FILE: gcc/d/runtime.def ================================================ /* runtime.def -- Definitions for D runtime functions. Copyright (C) 2014-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* D runtime library functions. */ /* DEF_D_RUNTIME (CODE, NAME, FLAGS) CODE The enum code used to refer to this function. NAME The name of this function as a string. FLAGS ECF flags to describe attributes of the function. Used for declaring functions that are called by generated code. Most are extern(C) - for those that are not, ensure to use correct mangling. */ /* Helper macros for parameter building. */ #define P0() 0 #define P1(T1) 1, LCT_ ## T1 #define P2(T1, T2) 2, LCT_ ## T1, LCT_ ## T2 #define P3(T1, T2, T3) 3, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3 #define P4(T1, T2, T3, T4) 4, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3, LCT_ ## T4 #define RT(T1) LCT_ ## T1 /* Used when an assert() contract fails. */ DEF_D_RUNTIME (ASSERT, "_d_assert", RT(VOID), P2(STRING, UINT), ECF_NORETURN) DEF_D_RUNTIME (ASSERT_MSG, "_d_assert_msg", RT(VOID), P3(STRING, STRING, UINT), ECF_NORETURN) /* Used when an assert() contract fails in a unittest function. */ DEF_D_RUNTIME (UNITTEST, "_d_unittest", RT(VOID), P2(STRING, UINT), ECF_NORETURN) DEF_D_RUNTIME (UNITTEST_MSG, "_d_unittest_msg", RT(VOID), P3(STRING, STRING, UINT), ECF_NORETURN) /* Used when an array index outside the bounds of its range. */ DEF_D_RUNTIME (ARRAY_BOUNDS, "_d_arraybounds", RT(VOID), P2(STRING, UINT), ECF_NORETURN) /* Used when calling new on a class. */ DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0) /* Used when calling delete on a class or interface. */ DEF_D_RUNTIME (DELCLASS, "_d_delclass", RT(VOID), P1(VOIDPTR), 0) DEF_D_RUNTIME (DELINTERFACE, "_d_delinterface", RT(VOID), P1(VOIDPTR), 0) /* Same as deleting a class, but used for stack-allocated classes. */ DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0) DEF_D_RUNTIME (CALLINTERFACEFINALIZER, "_d_callinterfacefinalizer", RT(VOID), P1(VOIDPTR), 0) /* Used for casting to a class or interface. */ DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT), P2(OBJECT, CLASSINFO), 0) DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT), P2(OBJECT, CLASSINFO), 0) /* Used when calling new on a pointer. The `i' variant is for when the initializer is nonzero. */ DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0) /* Used when calling delete on a pointer. */ DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0) DEF_D_RUNTIME (DELSTRUCT, "_d_delstruct", RT(VOID), P2(POINTER_VOIDPTR, TYPEINFO), 0) /* Used when calling new on an array. The `i' variant is for when the initializer is nonzero, and the `m' variant is when initializing a multi-dimensional array. */ DEF_D_RUNTIME (NEWARRAYT, "_d_newarrayT", RT(ARRAY_VOID), P2(CONST_TYPEINFO, SIZE_T), 0) DEF_D_RUNTIME (NEWARRAYIT, "_d_newarrayiT", RT(ARRAY_VOID), P2(CONST_TYPEINFO, SIZE_T), 0) DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID), P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID), P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) /* Used for allocating an array literal on the GC heap. */ DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR), P2(CONST_TYPEINFO, SIZE_T), 0) /* Used when calling delete on an array. */ DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID), P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0) /* Used for value equality (x == y) and comparisons (x < y) of non-trivial arrays. Such as an array of structs or classes. */ DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT), P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0) /* Used when casting from one array type to another where the index type sizes differ. Such as from int[] to short[]. */ DEF_D_RUNTIME (ARRAYCAST, "_d_arraycast", RT(ARRAY_VOID), P3(SIZE_T, SIZE_T, ARRAY_VOID), 0) /* Used for (array.length = n) expressions. The `i' variant is for when the initializer is nonzero. */ DEF_D_RUNTIME (ARRAYSETLENGTHT, "_d_arraysetlengthT", RT(ARRAY_VOID), P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0) DEF_D_RUNTIME (ARRAYSETLENGTHIT, "_d_arraysetlengthiT", RT(ARRAY_VOID), P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0) /* Used for allocating closures on the GC heap. */ DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T), ECF_MALLOC) /* Used for copying an array into a slice, adds an enforcment that the source and destination are equal in size and do not overlap. */ DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID), P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0) /* Used for array assignments from an existing array. The `set' variant is for when the assignment value is a single element. */ DEF_D_RUNTIME (ARRAYASSIGN, "_d_arrayassign", RT(ARRAY_VOID), P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) DEF_D_RUNTIME (ARRAYASSIGN_L, "_d_arrayassign_l", RT(ARRAY_VOID), P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0) DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID), P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0) DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR), P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) /* Used for constructing a new array from an existing array. The `set' variant is for when the constructor value is a single element. */ DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID), P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR), P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) /* Used for concatenating two or more arrays together. Then `n' variant is for when there is more than two arrays to handle. */ DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE), P3(CONST_TYPEINFO, ARRAY_BYTE, ARRAY_BYTE), 0) DEF_D_RUNTIME (ARRAYCATNTX, "_d_arraycatnTX", RT(ARRAY_VOID), P2(CONST_TYPEINFO, ARRAYARRAY_BYTE), 0) /* Used for appending a single element to an array. */ DEF_D_RUNTIME (ARRAYAPPENDCTX, "_d_arrayappendcTX", RT(ARRAY_BYTE), P3(CONST_TYPEINFO, ARRAYPTR_BYTE, SIZE_T), 0) /* Same as appending a single element to an array, but specific for when the source is a UTF-32 character, and the destination is a UTF-8 or 16 array. */ DEF_D_RUNTIME (ARRAYAPPENDCD, "_d_arrayappendcd", RT(ARRAY_VOID), P2(ARRAYPTR_BYTE, DCHAR), 0) DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID), P2(ARRAYPTR_BYTE, DCHAR), 0) /* Used for appending an existing array to another. */ DEF_D_RUNTIME (ARRAYAPPENDT, "_d_arrayappendT", RT(ARRAY_VOID), P3(TYPEINFO, ARRAYPTR_BYTE, ARRAY_BYTE), 0) /* Used for allocating a new associative array. */ DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR), P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) /* Used for value equality of two associative arrays. */ DEF_D_RUNTIME (AAEQUAL, "_aaEqual", RT(INT), P3(CONST_TYPEINFO, ASSOCARRAY, ASSOCARRAY), 0) /* Used to determine is a key exists in an associative array. */ DEF_D_RUNTIME (AAINX, "_aaInX", RT(VOIDPTR), P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0) /* Used to retrieve a value from an associative array index by a key. The `Rvalue' variant returns null if the key is not found, where as aaGetY will create new key entry for assignment. */ DEF_D_RUNTIME (AAGETY, "_aaGetY", RT(VOIDPTR), P4(POINTER_ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0) DEF_D_RUNTIME (AAGETRVALUEX, "_aaGetRvalueX", RT(VOIDPTR), P4(ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0) /* Used when calling delete on a key entry in an associative array. */ DEF_D_RUNTIME (AADELX, "_aaDelX", RT(BOOL), P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0) /* Used for throw() expressions. */ DEF_D_RUNTIME (THROW, "_d_throw", RT(VOID), P1(OBJECT), ECF_NORETURN) DEF_D_RUNTIME (BEGIN_CATCH, "__gdc_begin_catch", RT(VOIDPTR), P1(VOIDPTR), 0) /* C++ exception handlers. */ DEF_D_RUNTIME (CXA_BEGIN_CATCH, "__cxa_begin_catch", RT(VOIDPTR), P1(VOIDPTR), ECF_NOTHROW) DEF_D_RUNTIME (CXA_END_CATCH, "__cxa_end_catch", RT(VOID), P0(), 0) /* When invariant() contracts are turned on, used after testing whether a class != null for validating the state of a class. */ DEF_D_RUNTIME (INVARIANT, "_D9invariant12_d_invariantFC6ObjectZv", RT(VOID), P1(OBJECT), 0) #undef P0 #undef P1 #undef P2 #undef P3 #undef P4 #undef RT ================================================ FILE: gcc/d/toir.cc ================================================ /* toir.cc -- Lower D frontend statements to GCC trees. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/declaration.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/init.h" #include "dmd/statement.h" #include "tree.h" #include "tree-iterator.h" #include "options.h" #include "stmt.h" #include "fold-const.h" #include "diagnostic.h" #include "stringpool.h" #include "function.h" #include "toplev.h" #include "d-tree.h" /* Update data for defined and undefined labels when leaving a scope. */ bool pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl) { binding_level *obl = bl->level_chain; if (ent->level == bl) { if (bl->kind == level_try) ent->in_try_scope = true; else if (bl->kind == level_catch) ent->in_catch_scope = true; ent->level = obl; } else if (ent->fwdrefs) { for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next) ref->level = obl; } return true; } /* At the end of a function, all labels declared within the function go out of scope. BLOCK is the top-level block for the function. */ bool pop_label (Statement * const &s, d_label_entry *ent, tree block) { if (!ent->bc_label) { /* Put the labels into the "variables" of the top-level block, so debugger can see them. */ if (DECL_NAME (ent->label)) { gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE); DECL_CHAIN (ent->label) = BLOCK_VARS (block); BLOCK_VARS (block) = ent->label; } } d_function_chain->labels->remove (s); return true; } /* The D front-end does not use the 'binding level' system for a symbol table, however it has been the goto structure for tracking code flow. Primarily it is only needed to get debugging information for local variables and otherwise support the back-end. */ void push_binding_level (level_kind kind) { /* Add it to the front of currently active scopes stack. */ binding_level *new_level = ggc_cleared_alloc (); new_level->level_chain = current_binding_level; new_level->kind = kind; current_binding_level = new_level; } tree pop_binding_level (void) { binding_level *level = current_binding_level; current_binding_level = level->level_chain; tree block = make_node (BLOCK); BLOCK_VARS (block) = level->names; BLOCK_SUBBLOCKS (block) = level->blocks; /* In each subblock, record that this is its superior. */ for (tree t = level->blocks; t; t = BLOCK_CHAIN (t)) BLOCK_SUPERCONTEXT (t) = block; if (level->kind == level_function) { /* Dispose of the block that we just made inside some higher level. */ DECL_INITIAL (current_function_decl) = block; BLOCK_SUPERCONTEXT (block) = current_function_decl; /* Pop all the labels declared in the function. */ if (d_function_chain->labels) d_function_chain->labels->traverse (block); } else { /* Any uses of undefined labels, and any defined labels, now operate under constraints of next binding contour. */ if (d_function_chain && d_function_chain->labels) { language_function *f = d_function_chain; f->labels->traverse (level); } current_binding_level->blocks = block_chainon (current_binding_level->blocks, block); } TREE_USED (block) = 1; return block; } /* Create an empty statement tree rooted at T. */ void push_stmt_list (void) { tree t = alloc_stmt_list (); vec_safe_push (d_function_chain->stmt_list, t); d_keep (t); } /* Finish the statement tree rooted at T. */ tree pop_stmt_list (void) { tree t = d_function_chain->stmt_list->pop (); /* If the statement list is completely empty, just return it. This is just as good as build_empty_stmt, with the advantage that statement lists are merged when they are appended to one another. So using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements. */ if (TREE_SIDE_EFFECTS (t)) { /* If the statement list contained exactly one statement, then extract it immediately. */ tree_stmt_iterator i = tsi_start (t); if (tsi_one_before_end_p (i)) { tree u = tsi_stmt (i); tsi_delink (&i); free_stmt_list (t); t = u; } } return t; } /* T is an expression statement. Add it to the statement-tree. */ void add_stmt (tree t) { /* Ignore (void) 0; expression statements received from the frontend. Likewise void_node is used when contracts become nops in release code. */ if (t == void_node || IS_EMPTY_STMT (t)) return; /* At this point, we no longer care about the value of expressions, so if there's no side-effects, then don't add it. */ if (!TREE_SIDE_EFFECTS (t)) return; if (TREE_CODE (t) == COMPOUND_EXPR) { /* Push out each comma expressions as separate statements. */ add_stmt (TREE_OPERAND (t, 0)); add_stmt (TREE_OPERAND (t, 1)); } else { /* Force the type to be void so we don't need to create a temporary variable to hold the inner expression. */ if (TREE_CODE (t) == CLEANUP_POINT_EXPR) TREE_TYPE (t) = void_type_node; /* Append the expression to the statement list. Make sure it has a proper location. */ if (EXPR_P (t) && !EXPR_HAS_LOCATION (t)) SET_EXPR_LOCATION (t, input_location); tree stmt_list = d_function_chain->stmt_list->last (); append_to_statement_list_force (t, &stmt_list); } } /* Implements the visitor interface to build the GCC trees of all Statement AST classes emitted from the D Front-end. All visit methods accept one parameter S, which holds the frontend AST of the statement to compile. They also don't return any value, instead generated code are pushed to add_stmt(), which appends them to the statement list in the current_binding_level. */ class IRVisitor : public Visitor { using Visitor::visit; FuncDeclaration *func_; /* Stack of labels which are targets for "break" and "continue", linked through TREE_CHAIN. */ tree break_label_; tree continue_label_; public: IRVisitor (FuncDeclaration *fd) { this->func_ = fd; this->break_label_ = NULL_TREE; this->continue_label_ = NULL_TREE; } /* Helper for generating code for the statement AST class S. Sets up the location of the statement before lowering. */ void build_stmt (Statement *s) { location_t saved_location = input_location; input_location = make_location_t (s->loc); s->accept (this); input_location = saved_location; } /* Start a new scope for a KIND statement. Each user-declared variable will have a binding contour that begins where the variable is declared and ends at its containing scope. */ void start_scope (level_kind kind) { push_binding_level (kind); push_stmt_list (); } /* Leave scope pushed by start_scope, returning a new bind_expr if any variables where declared in the scope. */ tree end_scope (void) { tree block = pop_binding_level (); tree body = pop_stmt_list (); if (! BLOCK_VARS (block)) return body; tree bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block), body, block); TREE_SIDE_EFFECTS (bind) = 1; return bind; } /* Like end_scope, but also push it into the outer statement-tree. */ void finish_scope (void) { tree scope = this->end_scope (); add_stmt (scope); } /* Return TRUE if IDENT is the current function return label. */ bool is_return_label (Identifier *ident) { if (this->func_->returnLabel) return this->func_->returnLabel->ident == ident; return false; } /* Define a label, specifying the location in the source file. Return the LABEL_DECL node for the label. */ tree define_label (Statement *s, Identifier *ident = NULL) { tree label = this->lookup_label (s, ident); gcc_assert (DECL_INITIAL (label) == NULL_TREE); d_label_entry *ent = d_function_chain->labels->get (s); gcc_assert (ent != NULL); /* Mark label as having been defined. */ DECL_INITIAL (label) = error_mark_node; ent->level = current_binding_level; for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next) this->check_previous_goto (ent->statement, ref); ent->fwdrefs = NULL; return label; } /* Emit a LABEL expression. */ void do_label (tree label) { /* Don't write out label unless it is marked as used by the frontend. This makes auto-vectorization possible in conditional loops. The only excemption to this is in the LabelStatement visitor, in which all computed labels are marked regardless. */ if (TREE_USED (label)) add_stmt (build1 (LABEL_EXPR, void_type_node, label)); } /* Emit a goto expression to LABEL. */ void do_jump (tree label) { add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label)); TREE_USED (label) = 1; } /* Check that a new jump at statement scope FROM to a label declared in statement scope TO is valid. */ void check_goto (Statement *from, Statement *to) { d_label_entry *ent = d_function_chain->labels->get (to); gcc_assert (ent != NULL); /* If the label hasn't been defined yet, defer checking. */ if (! DECL_INITIAL (ent->label)) { d_label_use_entry *fwdref = ggc_alloc (); fwdref->level = current_binding_level; fwdref->statement = from; fwdref->next = ent->fwdrefs; ent->fwdrefs = fwdref; return; } if (ent->in_try_scope) error_at (make_location_t (from->loc), "cannot goto into try block"); else if (ent->in_catch_scope) error_at (make_location_t (from->loc), "cannot goto into catch block"); } /* Check that a previously seen jump to a newly defined label is valid. S is the label statement; FWDREF is the jump context. This is called for both user-defined and case labels. */ void check_previous_goto (Statement *s, d_label_use_entry *fwdref) { for (binding_level *b = current_binding_level; b ; b = b->level_chain) { if (b == fwdref->level) break; if (b->kind == level_try || b->kind == level_catch) { location_t location; if (s->isLabelStatement ()) { location = make_location_t (fwdref->statement->loc); if (b->kind == level_try) error_at (location, "cannot goto into try block"); else error_at (location, "cannot goto into catch block"); } else if (s->isCaseStatement ()) { location = make_location_t (s->loc); error_at (location, "case cannot be in different " "try block level from switch"); } else if (s->isDefaultStatement ()) { location = make_location_t (s->loc); error_at (location, "default cannot be in different " "try block level from switch"); } else gcc_unreachable (); } } } /* Get or build LABEL_DECL using the IDENT and statement block S given. */ tree lookup_label (Statement *s, Identifier *ident = NULL) { /* You can't use labels at global scope. */ if (d_function_chain == NULL) { error ("label %s referenced outside of any function", ident ? ident->toChars () : "(unnamed)"); return NULL_TREE; } /* Create the label htab for the function on demand. */ if (!d_function_chain->labels) { d_function_chain->labels = hash_map::create_ggc (13); } d_label_entry *ent = d_function_chain->labels->get (s); if (ent != NULL) return ent->label; else { tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE; tree decl = build_decl (make_location_t (s->loc), LABEL_DECL, name, void_type_node); DECL_CONTEXT (decl) = current_function_decl; DECL_MODE (decl) = VOIDmode; /* Create new empty slot. */ ent = ggc_cleared_alloc (); ent->statement = s; ent->label = decl; bool existed = d_function_chain->labels->put (s, *ent); gcc_assert (!existed); return decl; } } /* Get the LABEL_DECL to represent a break or continue for the statement S given. BC indicates which. */ tree lookup_bc_label (Statement *s, bc_kind bc) { tree vec = this->lookup_label (s); /* The break and continue labels are put into a TREE_VEC. */ if (TREE_CODE (vec) == LABEL_DECL) { d_label_entry *ent = d_function_chain->labels->get (s); gcc_assert (ent != NULL); vec = make_tree_vec (2); TREE_VEC_ELT (vec, bc_break) = ent->label; /* Build the continue label. */ tree label = build_decl (make_location_t (s->loc), LABEL_DECL, NULL_TREE, void_type_node); DECL_CONTEXT (label) = current_function_decl; DECL_MODE (label) = VOIDmode; TREE_VEC_ELT (vec, bc_continue) = label; ent->label = vec; ent->bc_label = true; } return TREE_VEC_ELT (vec, bc); } /* Set and return the current break label for the current block. */ tree push_break_label (Statement *s) { tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break); DECL_CHAIN (label) = this->break_label_; this->break_label_ = label; return label; } /* Finish with the current break label. */ void pop_break_label (tree label) { gcc_assert (this->break_label_ == label); this->break_label_ = DECL_CHAIN (this->break_label_); this->do_label (label); } /* Set and return the continue label for the current block. */ tree push_continue_label (Statement *s) { tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue); DECL_CHAIN (label) = this->continue_label_; this->continue_label_ = label; return label; } /* Finish with the current continue label. */ void pop_continue_label (tree label) { gcc_assert (this->continue_label_ == label); this->continue_label_ = DECL_CHAIN (this->continue_label_); this->do_label (label); } /* Visitor interfaces. */ /* This should be overridden by each statement class. */ void visit (Statement *) { gcc_unreachable (); } /* The frontend lowers `scope (exit/failure/success)' statements as try/catch/finally. At this point, this statement is just an empty placeholder. Maybe the frontend shouldn't leak these. */ void visit (OnScopeStatement *) { } /* If statements provide simple conditional execution of statements. */ void visit (IfStatement *s) { this->start_scope (level_cond); /* Build the outer 'if' condition, which may produce temporaries requiring scope destruction. */ tree ifcond = convert_for_condition (build_expr_dtor (s->condition), s->condition->type); tree ifbody = void_node; tree elsebody = void_node; /* Build the 'then' branch. */ if (s->ifbody) { push_stmt_list (); this->build_stmt (s->ifbody); ifbody = pop_stmt_list (); } /* Now build the 'else' branch, which may have nested 'else if' parts. */ if (s->elsebody) { push_stmt_list (); this->build_stmt (s->elsebody); elsebody = pop_stmt_list (); } /* Wrap up our constructed if condition into a COND_EXPR. */ tree cond = build_vcondition (ifcond, ifbody, elsebody); add_stmt (cond); /* Finish the if-then scope. */ this->finish_scope (); } /* Should there be any `pragma (...)' statements requiring code generation, here would be the place to do it. For now, all pragmas are handled by the frontend. */ void visit (PragmaStatement *) { } /* The frontend lowers `while (...)' statements as `for (...)' loops. This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ void visit (WhileStatement *) { gcc_unreachable (); } /* Do while statments implement simple loops. The body is executed, then the condition is evaluated. */ void visit (DoStatement *s) { tree lbreak = this->push_break_label (s); this->start_scope (level_loop); if (s->_body) { tree lcontinue = this->push_continue_label (s); this->build_stmt (s->_body); this->pop_continue_label (lcontinue); } /* Build the outer 'while' condition, which may produce temporaries requiring scope destruction. */ tree exitcond = convert_for_condition (build_expr_dtor (s->condition), s->condition->type); add_stmt (build_vcondition (exitcond, void_node, build1 (GOTO_EXPR, void_type_node, lbreak))); TREE_USED (lbreak) = 1; tree body = this->end_scope (); add_stmt (build1 (LOOP_EXPR, void_type_node, body)); this->pop_break_label (lbreak); } /* For statements implement loops with initialization, test, and increment clauses. */ void visit (ForStatement *s) { tree lbreak = this->push_break_label (s); this->start_scope (level_loop); if (s->_init) this->build_stmt (s->_init); if (s->condition) { tree exitcond = convert_for_condition (build_expr_dtor (s->condition), s->condition->type); add_stmt (build_vcondition (exitcond, void_node, build1 (GOTO_EXPR, void_type_node, lbreak))); TREE_USED (lbreak) = 1; } if (s->_body) { tree lcontinue = this->push_continue_label (s); this->build_stmt (s->_body); this->pop_continue_label (lcontinue); } if (s->increment) { /* Force side effects? */ add_stmt (build_expr_dtor (s->increment)); } tree body = this->end_scope (); add_stmt (build1 (LOOP_EXPR, void_type_node, body)); this->pop_break_label (lbreak); } /* The frontend lowers `foreach (...)' statements as `for (...)' loops. This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ void visit (ForeachStatement *) { gcc_unreachable (); } /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)' loops. This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ void visit (ForeachRangeStatement *) { gcc_unreachable (); } /* Jump to the associated exit label for the current loop. If IDENT for the Statement is not null, then the label is user defined. */ void visit (BreakStatement *s) { if (s->ident) { /* The break label may actually be some levels up. eg: on a try/finally wrapping a loop. */ LabelStatement *label = this->func_->searchLabel (s->ident)->statement; gcc_assert (label != NULL); Statement *stmt = label->statement->getRelatedLabeled (); this->do_jump (this->lookup_bc_label (stmt, bc_break)); } else this->do_jump (this->break_label_); } /* Jump to the associated continue label for the current loop. If IDENT for the Statement is not null, then the label is user defined. */ void visit (ContinueStatement *s) { if (s->ident) { LabelStatement *label = this->func_->searchLabel (s->ident)->statement; gcc_assert (label != NULL); this->do_jump (this->lookup_bc_label (label->statement, bc_continue)); } else this->do_jump (this->continue_label_); } /* A goto statement jumps to the statement identified by the given label. */ void visit (GotoStatement *s) { gcc_assert (s->label->statement != NULL); gcc_assert (s->tf == s->label->statement->tf); /* If no label found, there was an error. */ tree label = this->lookup_label (s->label->statement, s->label->ident); this->do_jump (label); /* Need to error if the goto is jumping into a try or catch block. */ this->check_goto (s, s->label->statement); } /* Statements can be labeled. A label is an identifier that precedes a statement. */ void visit (LabelStatement *s) { LabelDsymbol *sym; if (this->is_return_label (s->ident)) sym = this->func_->returnLabel; else sym = this->func_->searchLabel (s->ident); /* If no label found, there was an error. */ tree label = this->define_label (sym->statement, sym->ident); TREE_USED (label) = 1; this->do_label (label); if (this->is_return_label (s->ident) && this->func_->fensure != NULL) this->build_stmt (this->func_->fensure); else if (s->statement) this->build_stmt (s->statement); } /* A switch statement goes to one of a collection of case statements depending on the value of the switch expression. */ void visit (SwitchStatement *s) { this->start_scope (level_switch); tree lbreak = this->push_break_label (s); tree condition = build_expr_dtor (s->condition); Type *condtype = s->condition->type->toBasetype (); /* A switch statement on a string gets turned into a library call. It is not lowered during codegen. */ if (!condtype->isscalar ()) { error ("cannot handle switch condition of type %s", condtype->toChars ()); gcc_unreachable (); } condition = fold (condition); /* Build LABEL_DECLs now so they can be refered to by goto case. Also checking the jump from the switch to the label is allowed. */ if (s->cases) { for (size_t i = 0; i < s->cases->dim; i++) { CaseStatement *cs = (*s->cases)[i]; tree caselabel = this->lookup_label (cs); /* Write cases as a series of if-then-else blocks. if (condition == case) goto caselabel; */ if (s->hasVars) { tree ifcase = build2 (EQ_EXPR, build_ctype (condtype), condition, build_expr_dtor (cs->exp)); tree ifbody = fold_build1 (GOTO_EXPR, void_type_node, caselabel); tree cond = build_vcondition (ifcase, ifbody, void_node); TREE_USED (caselabel) = 1; LABEL_VARIABLE_CASE (caselabel) = 1; add_stmt (cond); } this->check_goto (s, cs); } if (s->sdefault) { tree defaultlabel = this->lookup_label (s->sdefault); /* The default label is the last 'else' block. */ if (s->hasVars) { this->do_jump (defaultlabel); LABEL_VARIABLE_CASE (defaultlabel) = 1; } this->check_goto (s, s->sdefault); } } /* Switch body goes in its own statement list. */ push_stmt_list (); if (s->_body) this->build_stmt (s->_body); tree casebody = pop_stmt_list (); /* Wrap up constructed body into a switch_expr, unless it was converted to an if-then-else expression. */ if (s->hasVars) add_stmt (casebody); else { tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition), condition, casebody); add_stmt (switchexpr); SWITCH_ALL_CASES_P (switchexpr) = 1; } SWITCH_BREAK_LABEL_P (lbreak) = 1; /* If the switch had any 'break' statements, emit the label now. */ this->pop_break_label (lbreak); this->finish_scope (); } /* Declare the case label associated with the current SwitchStatement. */ void visit (CaseStatement *s) { /* Emit the case label. */ tree label = this->define_label (s); if (LABEL_VARIABLE_CASE (label)) this->do_label (label); else { tree casevalue; if (s->exp->type->isscalar ()) casevalue = build_expr (s->exp); else casevalue = build_integer_cst (s->index, build_ctype (Type::tint32)); tree caselabel = build_case_label (casevalue, NULL_TREE, label); add_stmt (caselabel); } /* Now do the body. */ if (s->statement) this->build_stmt (s->statement); } /* Declare the default label associated with the current SwitchStatement. */ void visit (DefaultStatement *s) { /* Emit the default case label. */ tree label = this->define_label (s); if (LABEL_VARIABLE_CASE (label)) this->do_label (label); else { tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label); add_stmt (caselabel); } /* Now do the body. */ if (s->statement) this->build_stmt (s->statement); } /* Implements 'goto default' by jumping to the label associated with the DefaultStatement in a switch block. */ void visit (GotoDefaultStatement *s) { tree label = this->lookup_label (s->sw->sdefault); this->do_jump (label); } /* Implements 'goto case' by jumping to the label associated with the CaseStatement in a switch block. */ void visit (GotoCaseStatement *s) { tree label = this->lookup_label (s->cs); this->do_jump (label); } /* Throw a SwitchError exception, called when a switch statement has no DefaultStatement, yet none of the cases match. */ void visit (SwitchErrorStatement *s) { /* A throw SwitchError statement gets turned into a library call. The call is wrapped in the enclosed expression. */ gcc_assert (s->exp != NULL); add_stmt (build_expr (s->exp)); } /* A return statement exits the current function and supplies its return value, if the return type is not void. */ void visit (ReturnStatement *s) { if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid) { /* Return has no value. */ add_stmt (return_expr (NULL_TREE)); return; } TypeFunction *tf = (TypeFunction *)this->func_->type; Type *type = this->func_->tintro != NULL ? this->func_->tintro->nextOf () : tf->nextOf (); if ((this->func_->isMain () || this->func_->isCMain ()) && type->toBasetype ()->ty == Tvoid) type = Type::tint32; if (this->func_->nrvo_can && this->func_->nrvo_var) { /* Just refer to the DECL_RESULT; this differs from using NULL_TREE in that it indicates that we care about the value of the DECL_RESULT. */ tree decl = DECL_RESULT (get_symbol_decl (this->func_)); add_stmt (return_expr (decl)); } else { /* Convert for initializing the DECL_RESULT. */ tree expr = build_return_dtor (s->exp, type, tf); add_stmt (expr); } } /* Evaluate the enclosed expression, and add it to the statement list. */ void visit (ExpStatement *s) { if (s->exp) { /* Expression may produce temporaries requiring scope destruction. */ tree exp = build_expr_dtor (s->exp); add_stmt (exp); } } /* Evaluate all enclosed statements. */ void visit (CompoundStatement *s) { if (s->statements == NULL) return; for (size_t i = 0; i < s->statements->dim; i++) { Statement *statement = (*s->statements)[i]; if (statement != NULL) this->build_stmt (statement); } } /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop. These are compiled down as a `do ... while (0)', where each unrolled loop is nested inside and given their own continue label to jump to. */ void visit (UnrolledLoopStatement *s) { if (s->statements == NULL) return; tree lbreak = this->push_break_label (s); this->start_scope (level_loop); for (size_t i = 0; i < s->statements->dim; i++) { Statement *statement = (*s->statements)[i]; if (statement != NULL) { tree lcontinue = this->push_continue_label (statement); this->build_stmt (statement); this->pop_continue_label (lcontinue); } } this->do_jump (this->break_label_); tree body = this->end_scope (); add_stmt (build1 (LOOP_EXPR, void_type_node, body)); this->pop_break_label (lbreak); } /* Start a new scope and visit all nested statements, wrapping them up into a BIND_EXPR at the end of the scope. */ void visit (ScopeStatement *s) { if (s->statement == NULL) return; this->start_scope (level_block); this->build_stmt (s->statement); this->finish_scope (); } /* A with statement is a way to simplify repeated references to the same object, where the handle is either a class or struct instance. */ void visit (WithStatement *s) { this->start_scope (level_with); if (s->wthis) { /* Perform initialisation of the 'with' handle. */ ExpInitializer *ie = s->wthis->_init->isExpInitializer (); gcc_assert (ie != NULL); declare_local_var (s->wthis); tree init = build_expr_dtor (ie->exp); add_stmt (init); } if (s->_body) this->build_stmt (s->_body); this->finish_scope (); } /* Implements 'throw Object'. Frontend already checks that the object thrown is a class type, but does not check if it is derived from Object. Foreign objects are not currently supported at run-time. */ void visit (ThrowStatement *s) { ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle (); InterfaceDeclaration *id = cd->isInterfaceDeclaration (); tree arg = build_expr_dtor (s->exp); if (!global.params.useExceptions) { static int warned = 0; if (!warned) { error_at (make_location_t (s->loc), "exception handling disabled, " "use -fexceptions to enable"); warned = 1; } } if (cd->isCPPclass () || (id != NULL && id->isCPPclass ())) error_at (make_location_t (s->loc), "cannot throw C++ classes"); else if (cd->com || (id != NULL && id->com)) error_at (make_location_t (s->loc), "cannot throw COM objects"); else arg = build_nop (build_ctype (get_object_type ()), arg); add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg)); } /* Build a try-catch statement, one of the building blocks for exception handling generated by the frontend. This is also used to implement `scope (failure)' statements. */ void visit (TryCatchStatement *s) { this->start_scope (level_try); if (s->_body) this->build_stmt (s->_body); tree trybody = this->end_scope (); /* Try handlers go in their own statement list. */ push_stmt_list (); if (s->catches) { for (size_t i = 0; i < s->catches->dim; i++) { Catch *vcatch = (*s->catches)[i]; this->start_scope (level_catch); tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER); tree catchtype = build_ctype (vcatch->type); tree object = NULL_TREE; ehptr = build_call_expr (ehptr, 1, integer_zero_node); /* Retrieve the internal exception object, which could be for a D or C++ catch handler. This is different from the generic exception pointer returned from gcc runtime. */ Type *tcatch = vcatch->type->toBasetype (); ClassDeclaration *cd = tcatch->isClassHandle (); libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH : LIBCALL_BEGIN_CATCH; object = build_libcall (libcall, vcatch->type, 1, ehptr); if (vcatch->var) { tree var = get_symbol_decl (vcatch->var); tree init = build_assign (INIT_EXPR, var, object); declare_local_var (vcatch->var); add_stmt (init); } else { /* Still need to emit a call to __gdc_begin_catch() to remove the object from the uncaught exceptions list. */ add_stmt (object); } if (vcatch->handler) this->build_stmt (vcatch->handler); tree catchbody = this->end_scope (); /* Need to wrap C++ handlers in a try/finally block to signal the end catch callback. */ if (cd->isCPPclass ()) { tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH, Type::tvoid, 0); catchbody = build2 (TRY_FINALLY_EXPR, void_type_node, catchbody, endcatch); } add_stmt (build2 (CATCH_EXPR, void_type_node, catchtype, catchbody)); } } tree catches = pop_stmt_list (); /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a statement list, however pop_stmt_list may optimize away the list if there is only a single catch to push. */ if (TREE_CODE (catches) != STATEMENT_LIST) { tree stmt_list = alloc_stmt_list (); append_to_statement_list_force (catches, &stmt_list); catches = stmt_list; } add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches)); } /* Build a try-finally statement, one of the building blocks for exception handling generated by the frontend. This is also used to implement `scope (exit)' statements. */ void visit (TryFinallyStatement *s) { this->start_scope (level_try); if (s->_body) this->build_stmt (s->_body); tree trybody = this->end_scope (); this->start_scope (level_finally); if (s->finalbody) this->build_stmt (s->finalbody); tree finally = this->end_scope (); add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally)); } /* The frontend lowers `synchronized (...)' statements as a call to monitor/critical enter and exit wrapped around try/finally. This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ void visit (SynchronizedStatement *) { gcc_unreachable (); } /* D Inline Assembler is not implemented, as it would require writing an assembly parser for each supported target. Instead we leverage GCC extended assembler using the GccAsmStatement class. */ void visit (AsmStatement *) { sorry ("D inline assembler statements are not supported in GDC."); } /* Build a GCC extended assembler expression, whose components are an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */ void visit (GccAsmStatement *s) { StringExp *insn = (StringExp *)s->insn; tree outputs = NULL_TREE; tree inputs = NULL_TREE; tree clobbers = NULL_TREE; tree labels = NULL_TREE; /* Collect all arguments, which may be input or output operands. */ if (s->args) { for (size_t i = 0; i < s->args->dim; i++) { Identifier *name = (*s->names)[i]; const char *sname = name ? name->toChars () : NULL; tree id = name ? build_string (strlen (sname), sname) : NULL_TREE; StringExp *constr = (StringExp *)(*s->constraints)[i]; const char *cstring = (const char *)(constr->len ? constr->string : ""); tree str = build_string (constr->len, cstring); Expression *earg = (*s->args)[i]; tree val = build_expr (earg); if (i < s->outputargs) { tree arg = build_tree_list (id, str); outputs = chainon (outputs, build_tree_list (arg, val)); } else { tree arg = build_tree_list (id, str); inputs = chainon (inputs, build_tree_list (arg, val)); } } } /* Collect all clobber arguments. */ if (s->clobbers) { for (size_t i = 0; i < s->clobbers->dim; i++) { StringExp *clobber = (StringExp *)(*s->clobbers)[i]; const char *cstring = (const char *)(clobber->len ? clobber->string : ""); tree val = build_string (clobber->len, cstring); clobbers = chainon (clobbers, build_tree_list (0, val)); } } /* Collect all goto labels, these should have been already checked by the front-end, so pass down the label symbol to the back-end. */ if (s->labels) { for (size_t i = 0; i < s->labels->dim; i++) { Identifier *ident = (*s->labels)[i]; GotoStatement *gs = (*s->gotos)[i]; gcc_assert (gs->label->statement != NULL); gcc_assert (gs->tf == gs->label->statement->tf); const char *sident = ident->toChars (); tree name = build_string (strlen (sident), sident); tree label = this->lookup_label (gs->label->statement, gs->label->ident); TREE_USED (label) = 1; labels = chainon (labels, build_tree_list (name, label)); } } /* Do some extra validation on all input and output operands. */ const char *insnstring = (const char *)(insn->len ? insn->string : ""); tree string = build_string (insn->len, insnstring); string = resolve_asm_operand_names (string, outputs, inputs, labels); if (s->args) { unsigned noutputs = s->outputargs; unsigned ninputs = (s->args->dim - noutputs); const char **oconstraints = XALLOCAVEC (const char *, noutputs); bool allows_mem, allows_reg, is_inout; size_t i; tree t; for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++) { tree output = TREE_VALUE (t); const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); oconstraints[i] = constraint; if (parse_output_constraint (&constraint, i, ninputs, noutputs, &allows_mem, &allows_reg, &is_inout)) { /* If the output argument is going to end up in memory. */ if (!allows_reg) d_mark_addressable (output); } else output = error_mark_node; TREE_VALUE (t) = output; } for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++) { tree input = TREE_VALUE (t); const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, oconstraints, &allows_mem, &allows_reg)) { /* If the input argument is going to end up in memory. */ if (!allows_reg && allows_mem) d_mark_addressable (input); } else input = error_mark_node; TREE_VALUE (t) = input; } } tree exp = build5 (ASM_EXPR, void_type_node, string, outputs, inputs, clobbers, labels); SET_EXPR_LOCATION (exp, make_location_t (s->loc)); /* If the extended syntax was not used, mark the ASM_EXPR. */ if (s->args == NULL && s->clobbers == NULL) ASM_INPUT_P (exp) = 1; /* Asm statements are treated as volatile unless 'pure'. */ ASM_VOLATILE_P (exp) = !(s->stc & STCpure); add_stmt (exp); } /* Import symbols from another module. */ void visit (ImportStatement *s) { if (s->imports == NULL) return; for (size_t i = 0; i < s->imports->dim; i++) { Dsymbol *dsym = (*s->imports)[i]; if (dsym != NULL) build_decl_tree (dsym); } } }; /* Main entry point for the IRVisitor interface to generate code for the body of function FD. */ void build_function_body (FuncDeclaration *fd) { IRVisitor v = IRVisitor (fd); location_t saved_location = input_location; input_location = make_location_t (fd->loc); v.build_stmt (fd->fbody); input_location = saved_location; } ================================================ FILE: gcc/d/typeinfo.cc ================================================ /* typeinfo.cc -- D runtime type identification. Copyright (C) 2013-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/aggregate.h" #include "dmd/enum.h" #include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/globals.h" #include "dmd/identifier.h" #include "dmd/module.h" #include "dmd/mtype.h" #include "dmd/template.h" #include "dmd/target.h" #include "tree.h" #include "options.h" #include "fold-const.h" #include "diagnostic.h" #include "stringpool.h" #include "toplev.h" #include "stor-layout.h" #include "d-tree.h" #include "d-target.h" /* D returns type information to the user as TypeInfo class objects, and can be retrieved for any type using `typeid()'. We also use type information to implement many runtime library helpers, including `new', `delete', most dynamic array operations, and all associative array operations. Type information for a particular type is indicated with an ABI defined structure derived from TypeInfo. This would all be very straight forward, but for the fact that the runtime library provides the definitions of the TypeInfo structure and the ABI defined derived classes in `object.d', as well as having specific implementations of TypeInfo for built-in types in `rt/typeinfo`. We cannot build declarations of these directly in the compiler, but we need to layout objects of their type. To get around this, we define layout compatible POD-structs and generate the appropriate initializations for them. When we have to provide a TypeInfo to the user, we cast the internal compiler type to TypeInfo. It is only required that TypeInfo has a definition in `object.d'. It could happen that we are generating a type information for a TypeInfo object that has no declaration. We however only need the addresses of such incomplete TypeInfo objects for static initialization. */ enum tinfo_kind { TK_TYPEINFO_TYPE, /* object.TypeInfo */ TK_CLASSINFO_TYPE, /* object.TypeInfo_Class */ TK_INTERFACE_TYPE, /* object.TypeInfo_Interface */ TK_STRUCT_TYPE, /* object.TypeInfo_Struct */ TK_POINTER_TYPE, /* object.TypeInfo_Pointer */ TK_ARRAY_TYPE, /* object.TypeInfo_Array */ TK_STATICARRAY_TYPE, /* object.TypeInfo_StaticArray */ TK_ASSOCIATIVEARRAY_TYPE, /* object.TypeInfo_AssociativeArray */ TK_VECTOR_TYPE, /* object.TypeInfo_Vector */ TK_ENUMERAL_TYPE, /* object.TypeInfo_Enum */ TK_FUNCTION_TYPE, /* object.TypeInfo_Function */ TK_DELEGATE_TYPE, /* object.TypeInfo_Delegate */ TK_TYPELIST_TYPE, /* object.TypeInfo_Tuple */ TK_CONST_TYPE, /* object.TypeInfo_Const */ TK_IMMUTABLE_TYPE, /* object.TypeInfo_Invariant */ TK_SHARED_TYPE, /* object.TypeInfo_Shared */ TK_INOUT_TYPE, /* object.TypeInfo_Inout */ TK_CPPTI_TYPE, /* object.__cpp_type_info_ptr */ TK_END }; /* An array of all internal TypeInfo derived types we need. The TypeInfo and ClassInfo types are created early, the remainder are generated as needed. */ static GTY(()) tree tinfo_types[TK_END]; /* Return the kind of TypeInfo used to describe TYPE. */ static tinfo_kind get_typeinfo_kind (Type *type) { /* Check head shared/const modifiers first. */ if (type->isShared ()) return TK_SHARED_TYPE; else if (type->isConst ()) return TK_CONST_TYPE; else if (type->isImmutable ()) return TK_IMMUTABLE_TYPE; else if (type->isWild ()) return TK_INOUT_TYPE; switch (type->ty) { case Tpointer: return TK_POINTER_TYPE; case Tarray: return TK_ARRAY_TYPE; case Tsarray: return TK_STATICARRAY_TYPE; case Taarray: return TK_ASSOCIATIVEARRAY_TYPE; case Tstruct: return TK_STRUCT_TYPE; case Tvector: return TK_VECTOR_TYPE; case Tenum: return TK_ENUMERAL_TYPE; case Tfunction: return TK_FUNCTION_TYPE; case Tdelegate: return TK_DELEGATE_TYPE; case Ttuple: return TK_TYPELIST_TYPE; case Tclass: if (((TypeClass *) type)->sym->isInterfaceDeclaration ()) return TK_INTERFACE_TYPE; else return TK_CLASSINFO_TYPE; default: return TK_TYPEINFO_TYPE; } } /* Generate the RECORD_TYPE containing the data layout of a TypeInfo derivative as used by the runtime. This layout must be consistent with that defined in the `object.d' module. */ static void make_internal_typeinfo (tinfo_kind tk, Identifier *ident, ...) { va_list ap; va_start (ap, ident); /* First two fields are from the TypeInfo base class. Note, finish_builtin_struct() expects these fields in reverse order. */ tree fields = create_field_decl (ptr_type_node, NULL, 1, 1); DECL_CHAIN (fields) = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1); /* Now add the derived fields. */ tree field_type = va_arg (ap, tree); while (field_type != NULL_TREE) { tree field = create_field_decl (field_type, NULL, 1, 1); DECL_CHAIN (field) = fields; fields = field; field_type = va_arg (ap, tree); } /* Create the TypeInfo type. */ tree type = make_node (RECORD_TYPE); finish_builtin_struct (type, ident->toChars (), fields, NULL_TREE); tinfo_types[tk] = type; va_end (ap); } /* Helper for create_tinfo_types. Creates a typeinfo class declaration incase one wasn't supplied by reading `object.d'. */ static void make_frontend_typeinfo (Module *mod, Identifier *ident, ClassDeclaration *base = NULL) { if (!base) base = Type::dtypeinfo; /* Create object module in order to complete the semantic. */ if (!mod->_scope) mod->importAll (NULL); /* Assignment of global typeinfo variables is managed by the ClassDeclaration constructor, so only need to new the declaration here. */ Loc loc = (mod->md) ? mod->md->loc : mod->loc; ClassDeclaration *tinfo = ClassDeclaration::create (loc, ident, NULL, NULL, true); tinfo->parent = mod; tinfo->members = new Dsymbols; dsymbolSemantic (tinfo, mod->_scope); tinfo->baseClass = base; /* This is a compiler generated class, and shouldn't be mistaken for being the type declared in the runtime library. */ tinfo->storage_class |= STCtemp; } /* Make sure the required builtin types exist for generating the TypeInfo variable definitions. */ void create_tinfo_types (Module *mod) { /* Build the internal TypeInfo and ClassInfo types. See TypeInfoVisitor for documentation of field layout. */ make_internal_typeinfo (TK_TYPEINFO_TYPE, Identifier::idPool ("TypeInfo"), NULL); make_internal_typeinfo (TK_CLASSINFO_TYPE, Identifier::idPool ("TypeInfo_Class"), array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, array_type_node, ptr_type_node, ptr_type_node, NULL); /* Create all frontend TypeInfo classes declarations. We rely on all existing, even if only just as stubs. */ if (!Type::dtypeinfo) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo"), ClassDeclaration::object); if (!Type::typeinfoclass) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Class")); if (!Type::typeinfointerface) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Interface")); if (!Type::typeinfostruct) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Struct")); if (!Type::typeinfopointer) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Pointer")); if (!Type::typeinfoarray) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Array")); if (!Type::typeinfostaticarray) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_StaticArray")); if (!Type::typeinfoassociativearray) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_AssociativeArray")); if (!Type::typeinfoenum) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Enum")); if (!Type::typeinfofunction) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Function")); if (!Type::typeinfodelegate) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Delegate")); if (!Type::typeinfotypelist) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Tuple")); if (!Type::typeinfoconst) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Const")); if (!Type::typeinfoinvariant) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Invariant"), Type::typeinfoconst); if (!Type::typeinfoshared) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Shared"), Type::typeinfoconst); if (!Type::typeinfowild) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Wild"), Type::typeinfoconst); if (!Type::typeinfovector) make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Vector")); if (!ClassDeclaration::cpp_type_info_ptr) make_frontend_typeinfo (mod, Identifier::idPool ("__cpp_type_info_ptr"), ClassDeclaration::object); } /* Return true if TypeInfo class TINFO is available in the runtime library. */ bool have_typeinfo_p (ClassDeclaration *tinfo) { /* Run-time typeinfo disabled on command line. */ if (!global.params.useTypeInfo) return false; /* Can't layout TypeInfo if type is not declared, or is an opaque declaration in the object module. */ if (!tinfo || !tinfo->members) return false; /* Typeinfo is compiler-generated. */ if (tinfo->storage_class & STCtemp) return false; return true; } /* Implements the visitor interface to build the TypeInfo layout of all TypeInfoDeclaration AST classes emitted from the D Front-end. All visit methods accept one parameter D, which holds the frontend AST of the TypeInfo class. They also don't return any value, instead the generated symbol is cached internally and returned from the caller. */ class TypeInfoVisitor : public Visitor { using Visitor::visit; tree type_; vec *init_; /* Add VALUE to the constructor values list. */ void layout_field (tree value) { CONSTRUCTOR_APPEND_ELT (this->init_, NULL_TREE, value); } /* Write out STR as a static D string literal. */ void layout_string (const char *str) { unsigned len = strlen (str); tree value = build_string (len, str); TREE_TYPE (value) = make_array_type (Type::tchar, len); TREE_CONSTANT (value) = 1; TREE_READONLY (value) = 1; TREE_STATIC (value) = 1; /* Taking the address, so assign the literal to a static var. */ tree decl = build_artificial_decl (TREE_TYPE (value), value); TREE_READONLY (decl) = 1; DECL_EXTERNAL (decl) = 0; d_pushdecl (decl); value = d_array_value (build_ctype (Type::tchar->arrayOf ()), size_int (len), build_address (decl)); this->layout_field (value); } /* Write out the __vptr and __monitor fields of class CD. */ void layout_base (ClassDeclaration *cd) { gcc_assert (cd != NULL); if (have_typeinfo_p (cd)) this->layout_field (build_address (get_vtable_decl (cd))); else this->layout_field (null_pointer_node); this->layout_field (null_pointer_node); } /* Write out the interfaces field of class CD. Returns the array of interfaces that the field is pointing to. */ tree layout_interfaces (ClassDeclaration *cd) { size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]); tree csym = build_address (get_classinfo_decl (cd)); /* Put out the offset to where vtblInterfaces are written. */ tree value = d_array_value (array_type_node, size_int (cd->vtblInterfaces->dim), build_offset (csym, size_int (offset))); this->layout_field (value); /* Internally, the compiler sees Interface as: void*[4] interface; The run-time layout of Interface is: TypeInfo_Class classinfo; void*[] vtbl; size_t offset; */ vec *elms = NULL; for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; vec *v = NULL; /* Fill in the vtbl[]. */ if (!cd->isInterfaceDeclaration ()) b->fillVtbl (cd, &b->vtbl, 1); /* ClassInfo for the interface. */ value = build_address (get_classinfo_decl (id)); CONSTRUCTOR_APPEND_ELT (v, size_int (0), value); if (!cd->isInterfaceDeclaration ()) { /* The vtable of the interface length and ptr. */ unsigned voffset = base_vtable_offset (cd, b); gcc_assert (voffset != 0u); value = build_offset (csym, size_int (voffset)); CONSTRUCTOR_APPEND_ELT (v, size_int (1), size_int (id->vtbl.dim)); CONSTRUCTOR_APPEND_ELT (v, size_int (2), value); } /* The 'this' offset. */ CONSTRUCTOR_APPEND_ELT (v, size_int (3), size_int (b->offset)); /* Add to the array of interfaces. */ value = build_constructor (vtbl_interface_type_node, v); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } tree domain = size_int (cd->vtblInterfaces->dim - 1); tree arrtype = build_array_type (vtbl_interface_type_node, build_index_type (domain)); return build_constructor (arrtype, elms); } /* Write out the interfacing vtable[] of base class BCD that will be accessed from the overriding class CD. If both are the same class, then this will be its own vtable. INDEX is the offset in the interfaces array of the base class where the Interface reference can be found. This must be mirrored with base_vtable_offset(). */ void layout_base_vtable (ClassDeclaration *cd, ClassDeclaration *bcd, size_t index) { BaseClass *bs = (*bcd->vtblInterfaces)[index]; ClassDeclaration *id = bs->sym; vec *elms = NULL; FuncDeclarations bvtbl; if (id->vtbl.dim == 0 || base_vtable_offset (cd, bs) == ~0u) return; /* Fill bvtbl with the functions we want to put out. */ if (cd != bcd && !bs->fillVtbl (cd, &bvtbl, 0)) return; /* First entry is struct Interface reference. */ if (id->vtblOffset ()) { size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]); offset += (index * int_size_in_bytes (vtbl_interface_type_node)); tree value = build_offset (build_address (get_classinfo_decl (bcd)), size_int (offset)); CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, value); } for (size_t i = id->vtblOffset () ? 1 : 0; i < id->vtbl.dim; i++) { FuncDeclaration *fd = (cd == bcd) ? bs->vtbl[i] : bvtbl[i]; if (fd != NULL) { tree value = build_address (make_thunk (fd, bs->offset)); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } } tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1)); tree vtbltype = build_array_type (vtable_entry_type, vtbldomain); tree value = build_constructor (vtbltype, elms); this->layout_field (value); } public: TypeInfoVisitor (tree type) { this->type_ = type; this->init_ = NULL; } /* Return the completed constructor for the TypeInfo record. */ tree result (void) { return build_struct_literal (this->type_, this->init_); } /* Layout of TypeInfo is: void **__vptr; void *__monitor; */ void visit (TypeInfoDeclaration *) { /* The vtable for TypeInfo. */ this->layout_base (Type::dtypeinfo); } /* Layout of TypeInfo_Const is: void **__vptr; void *__monitor; TypeInfo base; */ void visit (TypeInfoConstDeclaration *d) { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); /* The vtable for TypeInfo_Const. */ this->layout_base (Type::typeinfoconst); /* TypeInfo for the mutable type. */ this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Immutable is: void **__vptr; void *__monitor; TypeInfo base; */ void visit (TypeInfoInvariantDeclaration *d) { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); /* The vtable for TypeInfo_Invariant. */ this->layout_base (Type::typeinfoinvariant); /* TypeInfo for the mutable type. */ this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Shared is: void **__vptr; void *__monitor; TypeInfo base; */ void visit (TypeInfoSharedDeclaration *d) { Type *tm = d->tinfo->unSharedOf (); tm = tm->merge2 (); /* The vtable for TypeInfo_Shared. */ this->layout_base (Type::typeinfoshared); /* TypeInfo for the unshared type. */ this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Inout is: void **__vptr; void *__monitor; TypeInfo base; */ void visit (TypeInfoWildDeclaration *d) { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); /* The vtable for TypeInfo_Inout. */ this->layout_base (Type::typeinfowild); /* TypeInfo for the mutable type. */ this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Enum is: void **__vptr; void *__monitor; TypeInfo base; string name; void[] m_init; */ void visit (TypeInfoEnumDeclaration *d) { gcc_assert (d->tinfo->ty == Tenum); TypeEnum *ti = (TypeEnum *) d->tinfo; EnumDeclaration *ed = ti->sym; /* The vtable for TypeInfo_Enum. */ this->layout_base (Type::typeinfoenum); /* TypeInfo for enum members. */ tree memtype = (ed->memtype) ? build_typeinfo (d->loc, ed->memtype) : null_pointer_node; this->layout_field (memtype); /* Name of the enum declaration. */ this->layout_string (ed->toPrettyChars ()); /* Default initializer for enum. */ if (ed->members && !d->tinfo->isZeroInit ()) { tree length = size_int (ed->type->size ()); tree ptr = build_address (enum_initializer_decl (ed)); this->layout_field (d_array_value (array_type_node, length, ptr)); } else this->layout_field (null_array_node); } /* Layout of TypeInfo_Pointer is: void **__vptr; void *__monitor; TypeInfo m_next; */ void visit (TypeInfoPointerDeclaration *d) { gcc_assert (d->tinfo->ty == Tpointer); TypePointer *ti = (TypePointer *) d->tinfo; /* The vtable for TypeInfo_Pointer. */ this->layout_base (Type::typeinfopointer); /* TypeInfo for pointer-to type. */ this->layout_field (build_typeinfo (d->loc, ti->next)); } /* Layout of TypeInfo_Array is: void **__vptr; void *__monitor; TypeInfo value; */ void visit (TypeInfoArrayDeclaration *d) { gcc_assert (d->tinfo->ty == Tarray); TypeDArray *ti = (TypeDArray *) d->tinfo; /* The vtable for TypeInfo_Array. */ this->layout_base (Type::typeinfoarray); /* TypeInfo for array of type. */ this->layout_field (build_typeinfo (d->loc, ti->next)); } /* Layout of TypeInfo_StaticArray is: void **__vptr; void *__monitor; TypeInfo value; size_t len; */ void visit (TypeInfoStaticArrayDeclaration *d) { gcc_assert (d->tinfo->ty == Tsarray); TypeSArray *ti = (TypeSArray *) d->tinfo; /* The vtable for TypeInfo_StaticArray. */ this->layout_base (Type::typeinfostaticarray); /* TypeInfo for array of type. */ this->layout_field (build_typeinfo (d->loc, ti->next)); /* Static array length. */ this->layout_field (size_int (ti->dim->toInteger ())); } /* Layout of TypeInfo_AssociativeArray is: void **__vptr; void *__monitor; TypeInfo value; TypeInfo key; */ void visit (TypeInfoAssociativeArrayDeclaration *d) { gcc_assert (d->tinfo->ty == Taarray); TypeAArray *ti = (TypeAArray *) d->tinfo; /* The vtable for TypeInfo_AssociativeArray. */ this->layout_base (Type::typeinfoassociativearray); /* TypeInfo for value of type. */ this->layout_field (build_typeinfo (d->loc, ti->next)); /* TypeInfo for index of type. */ this->layout_field (build_typeinfo (d->loc, ti->index)); } /* Layout of TypeInfo_Vector is: void **__vptr; void *__monitor; TypeInfo base; */ void visit (TypeInfoVectorDeclaration *d) { gcc_assert (d->tinfo->ty == Tvector); TypeVector *ti = (TypeVector *) d->tinfo; /* The vtable for TypeInfo_Vector. */ this->layout_base (Type::typeinfovector); /* TypeInfo for equivalent static array. */ this->layout_field (build_typeinfo (d->loc, ti->basetype)); } /* Layout of TypeInfo_Function is: void **__vptr; void *__monitor; TypeInfo next; string deco; */ void visit (TypeInfoFunctionDeclaration *d) { gcc_assert (d->tinfo->ty == Tfunction && d->tinfo->deco != NULL); TypeFunction *ti = (TypeFunction *) d->tinfo; /* The vtable for TypeInfo_Function. */ this->layout_base (Type::typeinfofunction); /* TypeInfo for function return value. */ this->layout_field (build_typeinfo (d->loc, ti->next)); /* Mangled name of function declaration. */ this->layout_string (d->tinfo->deco); } /* Layout of TypeInfo_Delegate is: void **__vptr; void *__monitor; TypeInfo next; string deco; */ void visit (TypeInfoDelegateDeclaration *d) { gcc_assert (d->tinfo->ty == Tdelegate && d->tinfo->deco != NULL); TypeDelegate *ti = (TypeDelegate *) d->tinfo; /* The vtable for TypeInfo_Delegate. */ this->layout_base (Type::typeinfodelegate); /* TypeInfo for delegate return value. */ this->layout_field (build_typeinfo (d->loc, ti->next)); /* Mangled name of delegate declaration. */ this->layout_string (d->tinfo->deco); } /* Layout of ClassInfo/TypeInfo_Class is: void **__vptr; void *__monitor; byte[] m_init; string name; void*[] vtbl; Interface[] interfaces; TypeInfo_Class base; void *destructor; void function(Object) classInvariant; ClassFlags m_flags; void *deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; immutable(void)* m_RTInfo; Information relating to interfaces, and their vtables are laid out immediately after the named fields, if there is anything to write. */ void visit (TypeInfoClassDeclaration *d) { gcc_assert (d->tinfo->ty == Tclass); TypeClass *ti = (TypeClass *) d->tinfo; ClassDeclaration *cd = ti->sym; /* The vtable for ClassInfo. */ this->layout_base (Type::typeinfoclass); if (!cd->members) return; tree interfaces = NULL_TREE; if (!cd->isInterfaceDeclaration ()) { /* Default initializer for class. */ tree init = aggregate_initializer_decl (cd); tree value = d_array_value (array_type_node, size_int (cd->structsize), build_address (init)); this->layout_field (value); /* Name of the class declaration. */ const char *name = cd->ident->toChars (); if (!(strlen (name) > 9 && memcmp (name, "TypeInfo_", 9) == 0)) name = cd->toPrettyChars (); this->layout_string (name); /* The vtable of the class declaration. */ value = d_array_value (array_type_node, size_int (cd->vtbl.dim), build_address (get_vtable_decl (cd))); this->layout_field (value); /* Array of base interfaces that have their own vtable. */ if (cd->vtblInterfaces->dim) interfaces = this->layout_interfaces (cd); else this->layout_field (null_array_node); /* TypeInfo_Class base; */ tree base = (cd->baseClass) ? build_address (get_classinfo_decl (cd->baseClass)) : null_pointer_node; this->layout_field (base); /* void *destructor; */ tree dtor = (cd->tidtor) ? build_address (get_symbol_decl (cd->tidtor)) : null_pointer_node; this->layout_field (dtor); /* void function(Object) classInvariant; */ tree inv = (cd->inv) ? build_address (get_symbol_decl (cd->inv)) : null_pointer_node; this->layout_field (inv); /* ClassFlags m_flags; */ int flags = ClassFlags::hasOffTi; if (cd->isCOMclass ()) flags |= ClassFlags::isCOMclass; if (cd->isCPPclass ()) flags |= ClassFlags::isCPPclass; flags |= ClassFlags::hasGetMembers; flags |= ClassFlags::hasTypeInfo; if (cd->ctor) flags |= ClassFlags::hasCtor; for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass) { if (bcd->dtor) { flags |= ClassFlags::hasDtor; break; } } if (cd->isAbstract ()) flags |= ClassFlags::isAbstract; for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass) { if (!bcd->members) continue; for (size_t i = 0; i < bcd->members->dim; i++) { Dsymbol *sm = (*bcd->members)[i]; if (sm->hasPointers ()) goto Lhaspointers; } } flags |= ClassFlags::noPointers; Lhaspointers: this->layout_field (size_int (flags)); /* void *deallocator; */ tree ddtor = (cd->aggDelete) ? build_address (get_symbol_decl (cd->aggDelete)) : null_pointer_node; this->layout_field (ddtor); /* OffsetTypeInfo[] m_offTi; (not implemented) */ this->layout_field (null_array_node); /* void function(Object) defaultConstructor; */ if (cd->defaultCtor && !(cd->defaultCtor->storage_class & STCdisable)) { tree dctor = get_symbol_decl (cd->defaultCtor); this->layout_field (build_address (dctor)); } else this->layout_field (null_pointer_node); /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); else if (!(flags & ClassFlags::noPointers)) this->layout_field (size_one_node); else this->layout_field (null_pointer_node); } else { /* No initializer for interface. */ this->layout_field (null_array_node); /* Name of the interface declaration. */ this->layout_string (cd->toPrettyChars ()); /* No vtable for interface declaration. */ this->layout_field (null_array_node); /* Array of base interfaces that have their own vtable. */ if (cd->vtblInterfaces->dim) interfaces = this->layout_interfaces (cd); else this->layout_field (null_array_node); /* TypeInfo_Class base; void *destructor; void function(Object) classInvariant; */ this->layout_field (null_pointer_node); this->layout_field (null_pointer_node); this->layout_field (null_pointer_node); /* ClassFlags m_flags; */ int flags = ClassFlags::hasOffTi; flags |= ClassFlags::hasTypeInfo; if (cd->isCOMinterface ()) flags |= ClassFlags::isCOMclass; this->layout_field (size_int (flags)); /* void *deallocator; OffsetTypeInfo[] m_offTi; (not implemented) void function(Object) defaultConstructor; */ this->layout_field (null_pointer_node); this->layout_field (null_array_node); this->layout_field (null_pointer_node); /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); else this->layout_field (null_pointer_node); } /* Put out array of Interfaces. */ if (interfaces != NULL_TREE) this->layout_field (interfaces); if (!cd->isInterfaceDeclaration ()) { /* Put out this class' interface vtables[]. */ for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) this->layout_base_vtable (cd, cd, i); /* Put out the overriding interface vtables[]. */ for (ClassDeclaration *bcd = cd->baseClass; bcd; bcd = bcd->baseClass) { for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++) this->layout_base_vtable (cd, bcd, i); } } } /* Layout of TypeInfo_Interface is: void **__vptr; void *__monitor; TypeInfo_Class info; */ void visit (TypeInfoInterfaceDeclaration *d) { gcc_assert (d->tinfo->ty == Tclass); TypeClass *ti = (TypeClass *) d->tinfo; if (!ti->sym->vclassinfo) ti->sym->vclassinfo = TypeInfoClassDeclaration::create (ti); /* The vtable for TypeInfo_Interface. */ this->layout_base (Type::typeinfointerface); /* TypeInfo for class inheriting the interface. */ tree tidecl = get_typeinfo_decl (ti->sym->vclassinfo); this->layout_field (build_address (tidecl)); } /* Layout of TypeInfo_Struct is: void **__vptr; void *__monitor; string name; void[] m_init; hash_t function(in void*) xtoHash; bool function(in void*, in void*) xopEquals; int function(in void*, in void*) xopCmp; string function(const(void)*) xtoString; StructFlags m_flags; void function(void*) xdtor; void function(void*) xpostblit; uint m_align; version (X86_64) TypeInfo m_arg1; TypeInfo m_arg2; immutable(void)* xgetRTInfo; */ void visit (TypeInfoStructDeclaration *d) { gcc_assert (d->tinfo->ty == Tstruct); TypeStruct *ti = (TypeStruct *) d->tinfo; StructDeclaration *sd = ti->sym; /* The vtable for TypeInfo_Struct. */ this->layout_base (Type::typeinfostruct); if (!sd->members) return; /* Name of the struct declaration. */ this->layout_string (sd->toPrettyChars ()); /* Default initializer for struct. */ tree ptr = (sd->zeroInit) ? null_pointer_node : build_address (aggregate_initializer_decl (sd)); this->layout_field (d_array_value (array_type_node, size_int (sd->structsize), ptr)); /* hash_t function (in void*) xtoHash; */ tree xhash = (sd->xhash) ? build_address (get_symbol_decl (sd->xhash)) : null_pointer_node; this->layout_field (xhash); if (sd->xhash) { TypeFunction *tf = (TypeFunction *) sd->xhash->type; gcc_assert (tf->ty == Tfunction); if (!tf->isnothrow || tf->trust == TRUSTsystem) { warning (sd->xhash->loc, "toHash() must be declared as " "extern (D) size_t toHash() const nothrow @safe, " "not %s", tf->toChars ()); } } /* bool function(in void*, in void*) xopEquals; */ tree xeq = (sd->xeq) ? build_address (get_symbol_decl (sd->xeq)) : null_pointer_node; this->layout_field (xeq); /* int function(in void*, in void*) xopCmp; */ tree xcmp = (sd->xcmp) ? build_address (get_symbol_decl (sd->xcmp)) : null_pointer_node; this->layout_field (xcmp); /* string function(const(void)*) xtoString; */ FuncDeclaration *fdx = search_toString (sd); if (fdx) this->layout_field (build_address (get_symbol_decl (fdx))); else this->layout_field (null_pointer_node); /* StructFlags m_flags; */ int m_flags = StructFlags::none; if (ti->hasPointers ()) m_flags |= StructFlags::hasPointers; this->layout_field (size_int (m_flags)); /* void function(void*) xdtor; */ tree dtor = (sd->tidtor) ? build_address (get_symbol_decl (sd->tidtor)) : null_pointer_node; this->layout_field (dtor); /* void function(void*) xpostblit; */ if (sd->postblit && !(sd->postblit->storage_class & STCdisable)) this->layout_field (build_address (get_symbol_decl (sd->postblit))); else this->layout_field (null_pointer_node); /* uint m_align; */ this->layout_field (size_int (ti->alignsize ())); if (global.params.is64bit) { /* TypeInfo m_arg1; */ tree arg1type = (sd->arg1type) ? build_typeinfo (d->loc, sd->arg1type) : null_pointer_node; this->layout_field (arg1type); /* TypeInfo m_arg2; */ tree arg2type = (sd->arg2type) ? build_typeinfo (d->loc, sd->arg2type) : null_pointer_node; this->layout_field (arg2type); } /* immutable(void)* xgetRTInfo; */ if (sd->getRTInfo) this->layout_field (build_expr (sd->getRTInfo, true)); else if (m_flags & StructFlags::hasPointers) this->layout_field (size_one_node); } /* Layout of TypeInfo_Tuple is: void **__vptr; void *__monitor; TypeInfo[] elements; */ void visit (TypeInfoTupleDeclaration *d) { gcc_assert (d->tinfo->ty == Ttuple); TypeTuple *ti = (TypeTuple *) d->tinfo; /* The vtable for TypeInfo_Tuple. */ this->layout_base (Type::typeinfotypelist); /* TypeInfo[] elements; */ Type *satype = Type::tvoidptr->sarrayOf (ti->arguments->dim); vec *elms = NULL; for (size_t i = 0; i < ti->arguments->dim; i++) { Parameter *arg = (*ti->arguments)[i]; CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_typeinfo (d->loc, arg->type)); } tree ctor = build_constructor (build_ctype (satype), elms); tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor); /* The internal pointer reference should be public, but not visible outside the compilation unit, as it's referencing COMDAT decls. */ TREE_PUBLIC (decl) = 1; DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL; DECL_COMDAT (decl) = 1; tree length = size_int (ti->arguments->dim); tree ptr = build_address (decl); this->layout_field (d_array_value (array_type_node, length, ptr)); d_pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } }; /* Main entry point for TypeInfoVisitor interface to generate TypeInfo constructor for the TypeInfoDeclaration AST class D. */ tree layout_typeinfo (TypeInfoDeclaration *d) { tree type = TREE_TYPE (get_typeinfo_decl (d)); TypeInfoVisitor v = TypeInfoVisitor (type); d->accept (&v); return v.result (); } /* Like layout_typeinfo, but generates the TypeInfo_Class for the class or interface declaration CD. */ tree layout_classinfo (ClassDeclaration *cd) { TypeInfoClassDeclaration *d = TypeInfoClassDeclaration::create (cd->type); tree type = TREE_TYPE (get_classinfo_decl (cd)); TypeInfoVisitor v = TypeInfoVisitor (type); d->accept (&v); return v.result (); } /* Layout fields that immediately come after the classinfo type for DECL if there's any interfaces or interface vtables to be added. This must be mirrored with base_vtable_offset(). */ static tree layout_classinfo_interfaces (ClassDeclaration *decl) { tree type = tinfo_types[TK_CLASSINFO_TYPE]; size_t structsize = int_size_in_bytes (type); if (decl->vtblInterfaces->dim) { size_t interfacesize = int_size_in_bytes (vtbl_interface_type_node); tree field; type = copy_aggregate_type (type); /* First layout the static array of Interface, which provides information about the vtables that follow. */ tree domain = size_int (decl->vtblInterfaces->dim - 1); tree arrtype = build_array_type (vtbl_interface_type_node, build_index_type (domain)); field = create_field_decl (arrtype, NULL, 1, 1); insert_aggregate_field (type, field, structsize); structsize += decl->vtblInterfaces->dim * interfacesize; /* For each interface, layout each vtable. */ for (size_t i = 0; i < decl->vtblInterfaces->dim; i++) { BaseClass *b = (*decl->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; unsigned offset = base_vtable_offset (decl, b); if (id->vtbl.dim && offset != ~0u) { tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1)); tree vtbltype = build_array_type (vtable_entry_type, vtbldomain); field = create_field_decl (vtbltype, NULL, 1, 1); insert_aggregate_field (type, field, offset); structsize += id->vtbl.dim * Target::ptrsize; } } } /* Layout the arrays of overriding interface vtables. */ for (ClassDeclaration *bcd = decl->baseClass; bcd; bcd = bcd->baseClass) { for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++) { BaseClass *b = (*bcd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; unsigned offset = base_vtable_offset (decl, b); if (id->vtbl.dim && offset != ~0u) { if (type == tinfo_types[TK_CLASSINFO_TYPE]) type = copy_aggregate_type (type); tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1)); tree vtbltype = build_array_type (vtable_entry_type, vtbldomain); tree field = create_field_decl (vtbltype, NULL, 1, 1); insert_aggregate_field (type, field, offset); structsize += id->vtbl.dim * Target::ptrsize; } } } /* Update the type size and record mode for the classinfo type. */ if (type != tinfo_types[TK_CLASSINFO_TYPE]) finish_aggregate_type (structsize, TYPE_ALIGN_UNIT (type), type, NULL); return type; } /* Returns true if the TypeInfo for TYPE should be placed in the runtime library. */ static bool builtin_typeinfo_p (Type *type) { if (type->isTypeBasic () || type->ty == Tclass || type->ty == Tnull) return !type->mod; if (type->ty == Tarray) { /* Strings are so common, make them builtin. */ Type *next = type->nextOf (); return !type->mod && ((next->isTypeBasic () != NULL && !next->mod) || (next->ty == Tchar && next->mod == MODimmutable) || (next->ty == Tchar && next->mod == MODconst)); } return false; } /* Implements a visitor interface to create the decl tree for TypeInfo decls. TypeInfo_Class objects differ in that they also have information about the class type packed immediately after the TypeInfo symbol. If the frontend had an interface to allow distinguishing being these two AST types, then that would be better for us. */ class TypeInfoDeclVisitor : public Visitor { using Visitor::visit; public: TypeInfoDeclVisitor (void) { } void visit (TypeInfoDeclaration *tid) { tree ident = get_identifier (tid->ident->toChars ()); tree type = tinfo_types[get_typeinfo_kind (tid->tinfo)]; gcc_assert (type != NULL_TREE); tid->csym = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (tid->csym) = build_lang_decl (tid); DECL_CONTEXT (tid->csym) = d_decl_context (tid); TREE_READONLY (tid->csym) = 1; /* Built-in typeinfo will be referenced as one-only. */ gcc_assert (!tid->isInstantiated ()); if (builtin_typeinfo_p (tid->tinfo)) d_linkonce_linkage (tid->csym); else d_comdat_linkage (tid->csym); } void visit (TypeInfoClassDeclaration *tid) { gcc_assert (tid->tinfo->ty == Tclass); TypeClass *tc = (TypeClass *) tid->tinfo; tid->csym = get_classinfo_decl (tc->sym); } }; /* Get the VAR_DECL of the TypeInfo for DECL. If this does not yet exist, create it. The TypeInfo decl provides information about the type of a given expression or object. */ tree get_typeinfo_decl (TypeInfoDeclaration *decl) { if (decl->csym) return decl->csym; gcc_assert (decl->tinfo->ty != Terror); TypeInfoDeclVisitor v = TypeInfoDeclVisitor (); decl->accept (&v); gcc_assert (decl->csym != NULL_TREE); return decl->csym; } /* Get the VAR_DECL of the ClassInfo for DECL. If this does not yet exist, create it. The ClassInfo decl provides information about the dynamic type of a given class type or object. */ tree get_classinfo_decl (ClassDeclaration *decl) { if (decl->csym) return decl->csym; InterfaceDeclaration *id = decl->isInterfaceDeclaration (); tree ident = mangle_internal_decl (decl, id ? "__Interface" : "__Class", "Z"); tree type = layout_classinfo_interfaces (decl); decl->csym = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL); /* Class is a reference, want the record type. */ DECL_CONTEXT (decl->csym) = TREE_TYPE (build_ctype (decl->type)); /* ClassInfo cannot be const data, because we use the monitor on it. */ TREE_READONLY (decl->csym) = 0; return decl->csym; } /* Returns typeinfo reference for TYPE. */ tree build_typeinfo (const Loc& loc, Type *type) { if (!global.params.useTypeInfo) { static int warned = 0; if (!warned) { error_at (make_location_t (loc), "% cannot be used with -fno-rtti"); warned = 1; } } gcc_assert (type->ty != Terror); create_typeinfo (type, NULL); return build_address (get_typeinfo_decl (type->vtinfo)); } /* Like layout_classinfo, but generates an Object that wraps around a pointer to C++ type_info so it can be distinguished from D TypeInfo. */ void layout_cpp_typeinfo (ClassDeclaration *cd) { gcc_assert (cd->isCPPclass ()); tree decl = get_cpp_typeinfo_decl (cd); vec *init = NULL; /* Use the vtable of __cpp_type_info_ptr, the EH personality routine expects this, as it uses .classinfo identity comparison to test for C++ catch handlers. */ tree vptr = get_vtable_decl (ClassDeclaration::cpp_type_info_ptr); CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (vptr)); CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, null_pointer_node); /* Let C++ do the RTTI generation, and just reference the symbol as extern, knowing the underlying type is not required. */ const char *ident = Target::cppTypeInfoMangle (cd); tree typeinfo = declare_extern_var (get_identifier (ident), unknown_type_node); TREE_READONLY (typeinfo) = 1; CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (typeinfo)); /* Build the initializer and emit. */ DECL_INITIAL (decl) = build_struct_literal (TREE_TYPE (decl), init); DECL_EXTERNAL (decl) = 0; d_pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } /* Get the VAR_DECL of the __cpp_type_info_ptr for DECL. If this does not yet exist, create it. The __cpp_type_info_ptr decl is then initialized with a pointer to the C++ type_info for the given class. */ tree get_cpp_typeinfo_decl (ClassDeclaration *decl) { gcc_assert (decl->isCPPclass ()); if (decl->cpp_type_info_ptr_sym) return decl->cpp_type_info_ptr_sym; if (!tinfo_types[TK_CPPTI_TYPE]) make_internal_typeinfo (TK_CPPTI_TYPE, Identifier::idPool ("__cpp_type_info_ptr"), ptr_type_node, NULL); tree ident = mangle_internal_decl (decl, "_cpp_type_info_ptr", ""); tree type = tinfo_types[TK_CPPTI_TYPE]; decl->cpp_type_info_ptr_sym = declare_extern_var (ident, type); DECL_LANG_SPECIFIC (decl->cpp_type_info_ptr_sym) = build_lang_decl (NULL); /* Class is a reference, want the record type. */ DECL_CONTEXT (decl->cpp_type_info_ptr_sym) = TREE_TYPE (build_ctype (decl->type)); TREE_READONLY (decl->cpp_type_info_ptr_sym) = 1; d_comdat_linkage (decl->cpp_type_info_ptr_sym); /* Layout the initializer and emit the symbol. */ layout_cpp_typeinfo (decl); return decl->cpp_type_info_ptr_sym; } /* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. */ void create_typeinfo (Type *type, Module *mod) { /* Do this since not all Type's are merged. */ Type *t = type->merge2 (); Identifier *ident; if (!t->vtinfo) { tinfo_kind tk = get_typeinfo_kind (t); switch (tk) { case TK_SHARED_TYPE: case TK_CONST_TYPE: case TK_IMMUTABLE_TYPE: case TK_INOUT_TYPE: case TK_POINTER_TYPE: case TK_ARRAY_TYPE: case TK_VECTOR_TYPE: case TK_INTERFACE_TYPE: /* Kinds of TypeInfo that add one extra pointer field. */ if (tk == TK_SHARED_TYPE) { /* Does both 'shared' and 'shared const'. */ t->vtinfo = TypeInfoSharedDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Shared"); } else if (tk == TK_CONST_TYPE) { t->vtinfo = TypeInfoConstDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Const"); } else if (tk == TK_IMMUTABLE_TYPE) { t->vtinfo = TypeInfoInvariantDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Invariant"); } else if (tk == TK_INOUT_TYPE) { t->vtinfo = TypeInfoWildDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Wild"); } else if (tk == TK_POINTER_TYPE) { t->vtinfo = TypeInfoPointerDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Pointer"); } else if (tk == TK_ARRAY_TYPE) { t->vtinfo = TypeInfoArrayDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Array"); } else if (tk == TK_VECTOR_TYPE) { t->vtinfo = TypeInfoVectorDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Vector"); } else if (tk == TK_INTERFACE_TYPE) { t->vtinfo = TypeInfoInterfaceDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Interface"); } else gcc_unreachable (); if (!tinfo_types[tk]) make_internal_typeinfo (tk, ident, ptr_type_node, NULL); break; case TK_STATICARRAY_TYPE: if (!tinfo_types[tk]) { ident = Identifier::idPool ("TypeInfo_StaticArray"); make_internal_typeinfo (tk, ident, ptr_type_node, size_type_node, NULL); } t->vtinfo = TypeInfoStaticArrayDeclaration::create (t); break; case TK_ASSOCIATIVEARRAY_TYPE: if (!tinfo_types[tk]) { ident = Identifier::idPool ("TypeInfo_AssociativeArray"); make_internal_typeinfo (tk, ident, ptr_type_node, ptr_type_node, NULL); } t->vtinfo = TypeInfoAssociativeArrayDeclaration::create (t); break; case TK_STRUCT_TYPE: if (!tinfo_types[tk]) { /* Some ABIs add extra TypeInfo fields on the end. */ tree argtype = global.params.is64bit ? ptr_type_node : NULL_TREE; ident = Identifier::idPool ("TypeInfo_Struct"); make_internal_typeinfo (tk, ident, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, ptr_type_node, size_type_node, ptr_type_node, ptr_type_node, size_type_node, ptr_type_node, argtype, argtype, NULL); } t->vtinfo = TypeInfoStructDeclaration::create (t); break; case TK_ENUMERAL_TYPE: if (!tinfo_types[tk]) { ident = Identifier::idPool ("TypeInfo_Enum"); make_internal_typeinfo (tk, ident, ptr_type_node, array_type_node, array_type_node, NULL); } t->vtinfo = TypeInfoEnumDeclaration::create (t); break; case TK_FUNCTION_TYPE: case TK_DELEGATE_TYPE: /* Functions and delegates share a common TypeInfo layout. */ if (tk == TK_FUNCTION_TYPE) { t->vtinfo = TypeInfoFunctionDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Function"); } else if (tk == TK_DELEGATE_TYPE) { t->vtinfo = TypeInfoDelegateDeclaration::create (t); ident = Identifier::idPool ("TypeInfo_Delegate"); } else gcc_unreachable (); if (!tinfo_types[tk]) make_internal_typeinfo (tk, ident, ptr_type_node, array_type_node, NULL); break; case TK_TYPELIST_TYPE: if (!tinfo_types[tk]) { ident = Identifier::idPool ("TypeInfo_Tuple"); make_internal_typeinfo (tk, ident, array_type_node, NULL); } t->vtinfo = TypeInfoTupleDeclaration::create (t); break; case TK_CLASSINFO_TYPE: t->vtinfo = TypeInfoClassDeclaration::create (t); break; default: t->vtinfo = TypeInfoDeclaration::create (t); } gcc_assert (t->vtinfo); /* If this has a custom implementation in rt/typeinfo, then do not generate a COMDAT for it. */ if (!builtin_typeinfo_p (t)) { /* Find module that will go all the way to an object file. */ if (mod) mod->members->push (t->vtinfo); else build_decl_tree (t->vtinfo); } } /* Types aren't merged, but we can share the vtinfo's. */ if (!type->vtinfo) type->vtinfo = t->vtinfo; gcc_assert (type->vtinfo != NULL); } /* Implements a visitor interface to check whether a type is speculative. TypeInfo_Struct would reference the members of the struct it is representing (e.g: opEquals via xopEquals field), so if it's instantiated in speculative context, TypeInfo creation should also be stopped to avoid possible `unresolved symbol' linker errors. */ class SpeculativeTypeVisitor : public Visitor { using Visitor::visit; bool result_; public: SpeculativeTypeVisitor (void) { this->result_ = false; } bool result (void) { return this->result_; } void visit (Type *t) { Type *tb = t->toBasetype (); if (tb != t) tb->accept (this); } void visit (TypeNext *t) { if (t->next) t->next->accept (this); } void visit (TypeBasic *) { } void visit (TypeVector *t) { t->basetype->accept (this); } void visit (TypeAArray *t) { t->index->accept (this); visit ((TypeNext *)t); } void visit (TypeFunction *t) { visit ((TypeNext *)t); } void visit (TypeStruct *t) { StructDeclaration *sd = t->sym; if (TemplateInstance *ti = sd->isInstantiated ()) { if (!ti->needsCodegen ()) { if (ti->minst || sd->requestTypeInfo) return; this->result_ |= true; } } } void visit (TypeClass *t) { ClassDeclaration *cd = t->sym; if (TemplateInstance *ti = cd->isInstantiated ()) { if (!ti->needsCodegen () && !ti->minst) { this->result_ |= true; } } } void visit (TypeTuple *t) { if (!t->arguments) return; for (size_t i = 0; i < t->arguments->dim; i++) { Type *tprm = (*t->arguments)[i]->type; if (tprm) tprm->accept (this); if (this->result_) return; } } }; /* Return true if type was instantiated in a speculative context. */ bool speculative_type_p (Type *t) { SpeculativeTypeVisitor v = SpeculativeTypeVisitor (); t->accept (&v); return v.result (); } #include "gt-d-typeinfo.h" ================================================ FILE: gcc/d/types.cc ================================================ /* types.cc -- Lower D frontend types to GCC trees. Copyright (C) 2006-2018 Free Software Foundation, Inc. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/attrib.h" #include "dmd/aggregate.h" #include "dmd/enum.h" #include "dmd/expression.h" #include "dmd/identifier.h" #include "dmd/mtype.h" #include "dmd/target.h" #include "tree.h" #include "fold-const.h" #include "diagnostic.h" #include "langhooks.h" #include "tm.h" #include "function.h" #include "toplev.h" #include "target.h" #include "stringpool.h" #include "stor-layout.h" #include "attribs.h" #include "d-tree.h" /* Return TRUE if TYPE is a static array va_list. This is for compatibility with the C ABI, where va_list static arrays are passed by reference. However for every other case in D, static arrays are passed by value. */ bool valist_array_p (Type *type) { if (Type::tvalist->ty == Tsarray) { Type *tb = type->toBasetype (); if (same_type_p (tb, Type::tvalist)) return true; } return false; } /* Returns true if TYPE contains no actual data, just various possible combinations of empty aggregates. */ bool empty_aggregate_p (tree type) { if (!AGGREGATE_TYPE_P (type)) return false; /* Want the element type for arrays. */ if (TREE_CODE (type) == ARRAY_TYPE) return empty_aggregate_p (TREE_TYPE (type)); /* Recursively check all fields. */ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) { if (TREE_CODE (field) == FIELD_DECL && !empty_aggregate_p (TREE_TYPE (field))) return false; } return true; } /* Returns true if T1 and T2 are related to each other. */ bool same_type_p (Type *t1, Type *t2) { /* Types are equal. */ if (t1 == t2) return true; /* Types derive from the same base. */ Type *tb1 = t1->toBasetype (); Type *tb2 = t2->toBasetype (); if (tb1 == tb2) return true; /* Types are mutably the same type. */ if (tb1->ty == tb2->ty && tb1->equivalent (tb2)) return true; return false; } /* Returns 'Object' type which all D classes are derived from. */ Type * get_object_type (void) { if (ClassDeclaration::object) return ClassDeclaration::object->type; error ("missing or corrupt object.d"); return Type::terror; } /* Returns a static array of TYPE which has SIZE number of elements. */ tree make_array_type (Type *type, unsigned HOST_WIDE_INT size) { /* In [arrays/void-arrays], void arrays can also be static, the length is specified in bytes. */ if (type->toBasetype ()->ty == Tvoid) type = Type::tuns8; /* In [arrays/static-arrays], a static array with a dimension of 0 is allowed, but no space is allocated for it. */ if (size == 0) { tree range = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype), TYPE_UNSIGNED (sizetype)); tree index = build_range_type (range, size_zero_node, NULL_TREE); tree t = build_array_type (build_ctype (type), index); TYPE_SIZE (t) = bitsize_zero_node; TYPE_SIZE_UNIT (t) = size_zero_node; return t; } return build_array_type (build_ctype (type), build_index_type (size_int (size - 1))); } /* Builds a record type whose name is NAME. NFIELDS is the number of fields, provided as field ident/type pairs. */ tree make_struct_type (const char *name, int nfields, ...) { tree fields = NULL_TREE; va_list ap; va_start (ap, nfields); for (int i = 0; i < nfields; i++) { tree ident = va_arg (ap, tree); tree type = va_arg (ap, tree); tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, ident, type); DECL_CHAIN (field) = fields; fields = field; } va_end (ap); tree type = make_node (RECORD_TYPE); finish_builtin_struct (type, name, fields, NULL_TREE); return type; } /* Return qualified type variant of TYPE determined by modifier value MOD. */ tree insert_type_modifiers (tree type, unsigned mod) { int quals = 0; switch (mod) { case MODconst: case MODwild: case MODwildconst: case MODimmutable: case MODshared | MODconst: case MODshared | MODwild: case MODshared | MODwildconst: quals |= TYPE_QUAL_CONST; break; case 0: case MODshared: break; default: gcc_unreachable (); } tree qualtype = build_qualified_type (type, quals); /* Mark whether the type is qualified 'shared'. */ if (mod & MODshared) TYPE_SHARED (qualtype) = 1; return qualtype; } /* Adds FIELD into the aggregate TYPE at OFFSET. */ void insert_aggregate_field (tree type, tree field, size_t offset) { DECL_FIELD_CONTEXT (field) = type; SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field))); DECL_FIELD_OFFSET (field) = size_int (offset); DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; TREE_ADDRESSABLE (field) = TYPE_SHARED (TREE_TYPE (field)); layout_decl (field, 0); TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field); } /* For all decls in the FIELDS chain, adjust their field offset by OFFSET. This is done as the frontend puts fields into the outer struct, and so their offset is from the beginning of the aggregate. We want the offset to be from the beginning of the anonymous aggregate. */ static void fixup_anonymous_offset (tree fields, tree offset) { while (fields != NULL_TREE) { /* Traverse all nested anonymous aggregates to update their offset. Set the anonymous decl offset to its first member. */ tree ftype = TREE_TYPE (fields); if (TYPE_NAME (ftype) && anon_aggrname_p (TYPE_IDENTIFIER (ftype))) { tree vfields = TYPE_FIELDS (ftype); fixup_anonymous_offset (vfields, offset); DECL_FIELD_OFFSET (fields) = DECL_FIELD_OFFSET (vfields); } else { tree voffset = DECL_FIELD_OFFSET (fields); DECL_FIELD_OFFSET (fields) = size_binop (MINUS_EXPR, voffset, offset); } fields = DECL_CHAIN (fields); } } /* Iterate over all MEMBERS of an aggregate, and add them as fields to CONTEXT. If INHERITED_P is true, then the members derive from a base class. Returns the number of fields found. */ static size_t layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) { size_t fields = 0; for (size_t i = 0; i < members->dim; i++) { Dsymbol *sym = (*members)[i]; VarDeclaration *var = sym->isVarDeclaration (); if (var != NULL) { /* Skip fields that have already been added. */ if (!inherited_p && var->csym != NULL) continue; /* If this variable was really a tuple, add all tuple fields. */ if (var->aliassym) { TupleDeclaration *td = var->aliassym->isTupleDeclaration (); Dsymbols tmembers; /* No other way to coerce the underlying type out of the tuple. Frontend should have already validated this. */ for (size_t j = 0; j < td->objects->dim; j++) { RootObject *ro = (*td->objects)[j]; gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); Expression *e = (Expression *) ro; gcc_assert (e->op == TOKdsymbol); DsymbolExp *se = (DsymbolExp *) e; tmembers.push (se->s); } fields += layout_aggregate_members (&tmembers, context, inherited_p); continue; } /* Insert the field declaration at its given offset. */ if (var->isField ()) { const char *ident = var->ident ? var->ident->toChars () : NULL; tree field = create_field_decl (declaration_type (var), ident, inherited_p, inherited_p); insert_aggregate_field (context, field, var->offset); /* Because the front-end shares field decls across classes, don't create the corresponding back-end symbol unless we are adding it to the aggregate it is defined in. */ if (!inherited_p) { DECL_LANG_SPECIFIC (field) = build_lang_decl (var); var->csym = field; } fields += 1; continue; } } /* Anonymous struct/union are flattened by the frontend. However, we want to keep the record layout in-tact when building the type. */ AnonDeclaration *ad = sym->isAnonDeclaration (); if (ad != NULL) { /* Use a counter to create anonymous type names. */ static int anon_cnt = 0; char buf[32]; sprintf (buf, anon_aggrname_format (), anon_cnt++); tree ident = get_identifier (buf); tree type = make_node (ad->isunion ? UNION_TYPE : RECORD_TYPE); ANON_AGGR_TYPE_P (type) = 1; d_keep (type); /* Build the type declaration. */ tree decl = build_decl (make_location_t (ad->loc), TYPE_DECL, ident, type); DECL_CONTEXT (decl) = context; DECL_ARTIFICIAL (decl) = 1; TYPE_CONTEXT (type) = context; TYPE_NAME (type) = decl; TYPE_STUB_DECL (type) = decl; /* Recursively iterator over the anonymous members. */ fields += layout_aggregate_members (ad->decl, type, inherited_p); /* Remove from the anon fields the base offset of this anonymous aggregate. Undoes what is set-up in setFieldOffset, but doesn't affect field accesses. */ tree offset = size_int (ad->anonoffset); fixup_anonymous_offset (TYPE_FIELDS (type), offset); finish_aggregate_type (ad->anonstructsize, ad->anonalignsize, type, NULL); /* And make the corresponding data member. */ tree field = create_field_decl (type, NULL, 0, 0); insert_aggregate_field (context, field, ad->anonoffset); continue; } /* Other kinds of attributes don't create a scope. */ AttribDeclaration *attrib = sym->isAttribDeclaration (); if (attrib != NULL) { Dsymbols *decls = attrib->include (NULL); if (decls != NULL) { fields += layout_aggregate_members (decls, context, inherited_p); continue; } } /* Same with template mixins and namespaces. */ if (sym->isTemplateMixin () || sym->isNspace ()) { ScopeDsymbol *scopesym = sym->isScopeDsymbol (); if (scopesym->members) { fields += layout_aggregate_members (scopesym->members, context, inherited_p); continue; } } } return fields; } /* Write out all fields for aggregate BASE. For classes, write out all interfaces first, then the base class fields. */ static void layout_aggregate_type (AggregateDeclaration *decl, tree type, AggregateDeclaration *base) { ClassDeclaration *cd = base->isClassDeclaration (); bool inherited_p = (decl != base); if (cd != NULL) { if (cd->baseClass) layout_aggregate_type (decl, type, cd->baseClass); else { /* This is the base class (Object) or interface. */ tree objtype = TREE_TYPE (build_ctype (cd->type)); /* Add the vtable pointer, and optionally the monitor fields. */ InterfaceDeclaration *id = cd->isInterfaceDeclaration (); if (!id || id->vtblInterfaces->dim == 0) { tree field = create_field_decl (vtbl_ptr_type_node, "__vptr", 1, inherited_p); DECL_VIRTUAL_P (field) = 1; TYPE_VFIELD (type) = field; DECL_FCONTEXT (field) = objtype; insert_aggregate_field (type, field, 0); } if (!id && !cd->isCPPclass ()) { tree field = create_field_decl (ptr_type_node, "__monitor", 1, inherited_p); insert_aggregate_field (type, field, Target::ptrsize); } } if (cd->vtblInterfaces) { for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *bc = (*cd->vtblInterfaces)[i]; tree field = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1); insert_aggregate_field (type, field, bc->offset); } } } if (base->members) { size_t fields = layout_aggregate_members (base->members, type, inherited_p); gcc_assert (fields == base->fields.dim); /* Make sure that all fields have been created. */ if (!inherited_p) { for (size_t i = 0; i < base->fields.dim; i++) { VarDeclaration *var = base->fields[i]; gcc_assert (var->csym != NULL); } } } } /* Given a record type TYPE, whose size and alignment are determined by STRUCTSIZE and ALIGNSIZE. Apply any type attributes ATTRS and compute the finalized record mode. */ void finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type, UserAttributeDeclaration *attrs) { TYPE_SIZE (type) = NULL_TREE; /* Write out any GCC attributes that were applied to the type declaration. */ if (attrs) { Expressions *eattrs = attrs->getAttributes (); decl_attributes (&type, build_attributes (eattrs), ATTR_FLAG_TYPE_IN_PLACE); } /* Set size and alignment as requested by frontend. */ TYPE_SIZE (type) = bitsize_int (structsize * BITS_PER_UNIT); TYPE_SIZE_UNIT (type) = size_int (structsize); SET_TYPE_ALIGN (type, alignsize * BITS_PER_UNIT); TYPE_PACKED (type) = (alignsize == 1); /* Set the back-end type mode. */ compute_record_mode (type); /* Fix up all variants of this aggregate type. */ for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) { if (t == type) continue; TYPE_FIELDS (t) = TYPE_FIELDS (type); TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type); SET_TYPE_ALIGN (t, TYPE_ALIGN (type)); TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type); gcc_assert (TYPE_MODE (t) == TYPE_MODE (type)); } } /* Implements the visitor interface to build the GCC trees of all Type AST classes emitted from the D Front-end, where CTYPE holds the cached back-end representation to be returned. */ class TypeVisitor : public Visitor { using Visitor::visit; public: TypeVisitor (void) { } /* This should be overridden by each type class. */ void visit (Type *) { gcc_unreachable (); } /* Type assigned to erroneous expressions or constructs that failed during the semantic stage. */ void visit (TypeError *t) { t->ctype = error_mark_node; } /* Type assigned to generic nullable types. */ void visit (TypeNull *t) { t->ctype = ptr_type_node; } /* Basic Data Types. */ void visit (TypeBasic *t) { /* [type/basic-data-types] void no type. bool 8-bit boolean value. byte 8-bit signed value. ubyte 8-bit unsigned value. short 16-bit signed value. ushort 16-bit unsigned value. int 32-bit signed value. uint 32-bit unsigned value. long 64-bit signed value. ulong 64-bit unsigned value. cent 128-bit signed value. ucent 128-bit unsigned value. float 32-bit IEEE 754 floating-point value. double 64-bit IEEE 754 floating-point value. real largest FP size implemented in hardware. ifloat imaginary float. idouble imaginary double. ireal imaginary real. cfloat complex float. cdouble complex double. creal complex real. char UTF-8 code unit. wchar UTF-16 code unit. dchar UTF-32 code unit. */ switch (t->ty) { case Tvoid: t->ctype = void_type_node; break; case Tbool: t->ctype = d_bool_type; break; case Tint8: t->ctype = d_byte_type; break; case Tuns8: t->ctype = d_ubyte_type; break; case Tint16: t->ctype = d_short_type; break; case Tuns16: t->ctype = d_ushort_type; break; case Tint32: t->ctype = d_int_type; break; case Tuns32: t->ctype = d_uint_type; break; case Tint64: t->ctype = d_long_type; break; case Tuns64: t->ctype = d_ulong_type; break; case Tint128: t->ctype = d_cent_type; break; case Tuns128: t->ctype = d_ucent_type; break; case Tfloat32: t->ctype = float_type_node; break; case Tfloat64: t->ctype = double_type_node; break; case Tfloat80: t->ctype = long_double_type_node; break; case Timaginary32: t->ctype = ifloat_type_node; break; case Timaginary64: t->ctype = idouble_type_node; break; case Timaginary80: t->ctype = ireal_type_node; break; case Tcomplex32: t->ctype = complex_float_type_node; break; case Tcomplex64: t->ctype = complex_double_type_node; break; case Tcomplex80: t->ctype = complex_long_double_type_node; break; case Tchar: t->ctype = char8_type_node; break; case Twchar: t->ctype = char16_type_node; break; case Tdchar: t->ctype = char32_type_node; break; default: gcc_unreachable (); } TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); } /* Derived Data Types. */ /* Build a simple pointer to data type, analogous to C pointers. */ void visit (TypePointer *t) { t->ctype = build_pointer_type (build_ctype (t->next)); } /* Build a dynamic array type, consisting of a length and a pointer to the array data. */ void visit (TypeDArray *t) { /* In [abi/arrays], dynamic array layout is: .length array dimension. .ptr pointer to array data. */ t->ctype = make_struct_type (t->toChars (), 2, get_identifier ("length"), build_ctype (Type::tsize_t), get_identifier ("ptr"), build_pointer_type (build_ctype (t->next))); TYPE_DYNAMIC_ARRAY (t->ctype) = 1; TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); d_keep (t->ctype); } /* Build a static array type, distinguished from dynamic arrays by having a length fixed at compile-time, analogous to C arrays. */ void visit (TypeSArray *t) { if (t->dim->isConst () && t->dim->type->isintegral ()) { uinteger_t size = t->dim->toUInteger (); t->ctype = make_array_type (t->next, size); } else { error ("invalid expression for static array dimension: %s", t->dim->toChars ()); gcc_unreachable (); } } /* Build a vector type, a fixed array of floating or integer types. */ void visit (TypeVector *t) { int nunits = ((TypeSArray *) t->basetype)->dim->toUInteger (); tree inner = build_ctype (t->elementType ()); /* Same rationale as void static arrays. */ if (inner == void_type_node) inner = build_ctype (Type::tuns8); t->ctype = build_vector_type (inner, nunits); TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); layout_type (t->ctype); } /* Build an associative array type, distinguished from arrays by having an index that's not necessarily an integer, and can be sparsely populated. */ void visit (TypeAArray *t) { /* In [abi/associative-arrays], associative arrays are a struct that only consist of a pointer to an opaque, implementation defined type. */ t->ctype = make_struct_type (t->toChars (), 1, get_identifier ("ptr"), ptr_type_node); TYPE_ASSOCIATIVE_ARRAY (t->ctype) = 1; TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); d_keep (t->ctype); } /* Build type for a function declaration, which consists of a return type, and a list of parameter types, and a linkage attribute. */ void visit (TypeFunction *t) { tree fnparams = NULL_TREE; tree fntype; /* [function/variadic] Variadic functions with D linkage have an additional hidden argument with the name _arguments passed to the function. */ if (t->varargs == 1 && t->linkage == LINKd) { tree type = build_ctype (Type::typeinfotypelist->type); fnparams = chainon (fnparams, build_tree_list (0, type)); } if (t->parameters) { size_t n_args = Parameter::dim (t->parameters); for (size_t i = 0; i < n_args; i++) { tree type = type_passed_as (Parameter::getNth (t->parameters, i)); fnparams = chainon (fnparams, build_tree_list (0, type)); } } /* When the last parameter is void_list_node, that indicates a fixed length parameter list, otherwise function is treated as variadic. */ if (t->varargs != 1) fnparams = chainon (fnparams, void_list_node); if (t->next != NULL) { fntype = build_ctype (t->next); if (t->isref) fntype = build_reference_type (fntype); } else fntype = void_type_node; /* Could the function type be self referenced by parameters? */ t->ctype = build_function_type (fntype, fnparams); TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); d_keep (t->ctype); /* Handle any special support for calling conventions. */ switch (t->linkage) { case LINKpascal: case LINKwindows: /* [attribute/linkage] The Windows convention is distinct from the C convention only on Win32, where it is equivalent to the stdcall convention. */ if (!global.params.is64bit) t->ctype = insert_type_attribute (t->ctype, "stdcall"); break; case LINKc: case LINKcpp: case LINKd: case LINKobjc: /* [abi/function-calling-conventions] The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system. */ break; default: gcc_unreachable (); } } /* Build a delegate type, an aggregate of two pieces of data, an object reference and a pointer to a non-static member function, or a pointer to a closure and a pointer to a nested function. */ void visit (TypeDelegate *t) { /* In [abi/delegates], delegate layout is: .ptr context pointer. .funcptr pointer to function. */ tree fntype = build_ctype (t->next); tree dgtype = build_vthis_function (void_type_node, fntype); TYPE_ATTRIBUTES (dgtype) = TYPE_ATTRIBUTES (fntype); TYPE_LANG_SPECIFIC (dgtype) = TYPE_LANG_SPECIFIC (fntype); t->ctype = make_struct_type (t->toChars (), 2, get_identifier ("ptr"), build_ctype (Type::tvoidptr), get_identifier ("funcptr"), build_pointer_type (dgtype)); TYPE_DELEGATE (t->ctype) = 1; TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); d_keep (t->ctype); } /* User Defined Types. */ /* Build a named enum type, a distinct value whose values are restrict to a group of constants of the same underlying base type. */ void visit (TypeEnum *t) { tree basetype = (t->sym->memtype) ? build_ctype (t->sym->memtype) : void_type_node; if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE) { /* Enums in D2 can have a base type that is not necessarily integral. For these, we simplify this a little by using the base type directly instead of building an ENUMERAL_TYPE. */ t->ctype = build_variant_type_copy (basetype); } else { t->ctype = make_node (ENUMERAL_TYPE); ENUM_IS_SCOPED (t->ctype) = 1; TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); d_keep (t->ctype); if (flag_short_enums) TYPE_PACKED (t->ctype) = 1; TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8; TYPE_SIZE (t->ctype) = 0; TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype); TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype); layout_type (t->ctype); tree values = NULL_TREE; if (t->sym->members) { for (size_t i = 0; i < t->sym->members->dim; i++) { EnumMember *member = (*t->sym->members)[i]->isEnumMember (); /* Templated functions can seep through to the back-end just ignore for now. */ if (member == NULL) continue; tree ident = get_identifier (member->ident->toChars ()); tree value = build_integer_cst (member->value ()->toInteger (), basetype); /* Build an identifier for the enumeration constant. */ tree decl = build_decl (make_location_t (member->loc), CONST_DECL, ident, basetype); DECL_CONTEXT (decl) = t->ctype; TREE_CONSTANT (decl) = 1; TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = value; /* Add this enumeration constant to the list for this type. */ values = chainon (values, build_tree_list (ident, decl)); } } TYPE_VALUES (t->ctype) = values; TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype); build_type_decl (t->ctype, t->sym); } if (t->sym->userAttribDecl) { Expressions *eattrs = t->sym->userAttribDecl->getAttributes (); decl_attributes (&t->ctype, build_attributes (eattrs), ATTR_FLAG_TYPE_IN_PLACE); } } /* Build a struct or union type. Layout should be exactly represented as an equivalent C struct, except for non-POD or nested structs. */ void visit (TypeStruct *t) { /* Merge types in the back-end if the frontend did not itself do so. */ tree deco = get_identifier (mangle_decl (t->sym)); if (IDENTIFIER_DAGGREGATE (deco)) { AggregateDeclaration *ad = IDENTIFIER_DAGGREGATE (deco); gcc_assert (ad->isStructDeclaration ()); /* Non-templated variables shouldn't be defined twice. */ if (!t->sym->isInstantiated ()) ScopeDsymbol::multiplyDefined (t->sym->loc, t->sym, ad); t->ctype = build_ctype (ad->type); return; } /* Need to set this right away in case of self-references. */ t->ctype = make_node (t->sym->isUnionDeclaration () ? UNION_TYPE : RECORD_TYPE); d_keep (t->ctype); IDENTIFIER_DAGGREGATE (deco) = t->sym; TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); if (t->sym->members) { /* Must set up the overall size and alignment before determining the context or laying out fields as those types may make recursive references to this type. */ unsigned structsize = t->sym->structsize; unsigned alignsize = (t->sym->alignment != STRUCTALIGN_DEFAULT) ? t->sym->alignment : t->sym->alignsize; TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT); TYPE_SIZE_UNIT (t->ctype) = size_int (structsize); SET_TYPE_ALIGN (t->ctype, alignsize * BITS_PER_UNIT); TYPE_PACKED (t->ctype) = (alignsize == 1); compute_record_mode (t->ctype); /* Put out all fields. */ layout_aggregate_type (t->sym, t->ctype, t->sym); finish_aggregate_type (structsize, alignsize, t->ctype, t->sym->userAttribDecl); } TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym); build_type_decl (t->ctype, t->sym); /* For structs with a user defined postblit or a destructor, also set TREE_ADDRESSABLE on the type and all variants. This will make the struct be passed around by reference. */ if (t->sym->postblit || t->sym->dtor) { for (tree tv = t->ctype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) TREE_ADDRESSABLE (tv) = 1; } } /* Build a class type. Whereas structs are value types, classes are reference types, with all the object-orientated features. */ void visit (TypeClass *t) { /* Merge types in the back-end if the frontend did not itself do so. */ tree deco = get_identifier (mangle_decl (t->sym)); if (IDENTIFIER_DAGGREGATE (deco)) { AggregateDeclaration *ad = IDENTIFIER_DAGGREGATE (deco); gcc_assert (ad->isClassDeclaration ()); /* Non-templated variables shouldn't be defined twice. */ if (!t->sym->isInstantiated ()) ScopeDsymbol::multiplyDefined (t->sym->loc, t->sym, ad); t->ctype = build_ctype (ad->type); return; } /* Need to set ctype right away in case of self-references to the type during this call. */ tree basetype = make_node (RECORD_TYPE); t->ctype = build_pointer_type (basetype); d_keep (t->ctype); IDENTIFIER_DAGGREGATE (deco) = t->sym; /* Note that lang_specific data is assigned to both the reference and the underlying record type. */ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); TYPE_LANG_SPECIFIC (basetype) = TYPE_LANG_SPECIFIC (t->ctype); CLASS_TYPE_P (basetype) = 1; /* Put out all fields, including from each base class. */ layout_aggregate_type (t->sym, basetype, t->sym); finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype, t->sym->userAttribDecl); /* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */ for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) TREE_ADDRESSABLE (tv) = 1; /* Type is final, there are no derivations. */ if (t->sym->storage_class & STCfinal) TYPE_FINAL_P (basetype) = 1; /* Create BINFO even if debugging is off. This is needed to keep references to inherited types. */ if (!t->sym->isInterfaceDeclaration ()) TYPE_BINFO (basetype) = build_class_binfo (NULL_TREE, t->sym); else { unsigned offset = 0; TYPE_BINFO (basetype) = build_interface_binfo (NULL_TREE, t->sym, offset); } /* Associate all virtual methods with the class too. */ for (size_t i = 0; i < t->sym->vtbl.dim; i++) { FuncDeclaration *fd = t->sym->vtbl[i]->isFuncDeclaration (); tree method = fd ? get_symbol_decl (fd) : error_mark_node; if (!error_operand_p (method) && DECL_CONTEXT (method) == basetype && !chain_member (method, TYPE_FIELDS (basetype))) TYPE_FIELDS (basetype) = chainon (TYPE_FIELDS (basetype), method); } TYPE_CONTEXT (basetype) = d_decl_context (t->sym); build_type_decl (basetype, t->sym); } }; /* Build a tree from a frontend Type. */ tree build_ctype (Type *t) { if (!t->ctype) { TypeVisitor v; /* Strip const modifiers from type before building. This is done to ensure that back-end treats e.g: const (T) as a variant of T, and not as two distinct types. */ if (t->isNaked ()) t->accept (&v); else { Type *tb = t->castMod (0); if (!tb->ctype) tb->accept (&v); t->ctype = insert_type_modifiers (tb->ctype, t->mod); } } return t->ctype; } ================================================ FILE: gcc/d/verstr.h ================================================ "2.083.0" ================================================ FILE: gcc/testsuite/gdc.dg/asan/asan.exp ================================================ # Copyright (C) 2017 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # Load support procs. load_lib gdc-dg.exp load_lib asan-dg.exp # Initialize `dg'. dg-init asan_init # Main loop. if [check_effective_target_fsanitize_address] { gdc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.d]] "" "" } # All done. asan_finish dg-finish ================================================ FILE: gcc/testsuite/gdc.dg/asan/gdc272.d ================================================ /* { dg-options "-fsanitize=address" } */ /* { dg-do compile } */ module asantests; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=272 extern(C) void my_memcmp(const(void) *s1, const(void) *s2); void bug(const(char)* p) { my_memcmp(p, "__FILE__".ptr); } ================================================ FILE: gcc/testsuite/gdc.dg/compilable.d ================================================ // { dg-options "-I $srcdir/gdc.dg -I $srcdir/gdc.dg/imports" } // { dg-additional-sources "imports/gdc27.d imports/gdc231.d" } // { dg-do compile } import core.simd; import gcc.attribute; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=27 import imports.gdc27; interface I_B : I_A { void b(); } abstract class C_B : C_A, I_B { abstract void b(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=108 @attribute("forceinline") void forceinline108() { } @attribute("noinline") void noinline108() { } @attribute("flatten") void flatten108() { } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=170 import imports.gdc170; void test170() { foo!void.foo1!void(); foo!void.foo2!void(); foo!void.foo3(); foo!void.foo3!void(); foo!void.foo4(); foo!void.foo4!void(); foo!void.foo5!void(null); foo!void.foo6!void(null); foo!void.foo7(null); foo!void.foo7!void(null); foo!void.foo8(null); foo!void.foo8!void(null); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=212 template hasElaborateAssign212(S) { enum hasElaborateAssign212 = is(typeof(S.init.opAssign(rvalueOf212!S))) || is(typeof(lvalueOf212!S)) ; } T rvalueOf212(T)(); T lvalueOf212(T)(); template TypeTuple212(TList...) { alias TypeTuple212 = TList; } template Tuple212() { struct Tuple212 { void opAssign(R)(R) { if (hasElaborateAssign212!R) { } } } } ref emplaceRef212() { static if (!hasElaborateAssign212!(Tuple212!())) chunk; } class TaskPool212 { void reduce() { Tuple212!() seed = void; Tuple212!()[] results; foreach(i; TypeTuple212!(0, 1)) results[i] = seed; } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=213 struct S213 { int4 vec; } void test213() { S213 s, b; assert(s == b); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=218 struct S218a { this(int* pdata_) { pdata = pdata_; } void opIndexAssign(int, size_t) { } int* pdata; }; struct S218 { S218a getS218a() { return S218a(data.ptr); } int[] data; int[] tab2; }; S218 f() { S218 r; for(int i = 0; i < 1; ++i) r.getS218a()[0] = 0; return r; } S218 var; static this() { var = f(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=223 struct S223 { long[8] field; } class C223 { long[8] field; } S223 test223_1(); real test223_2(); string[long[8]] test223_3(); C223 test223_4(); long test223_5(); long[] test223_6(); long[8] test223_7(); C223[8] test223_8(); void delegate() test223_9(); bool test223() { return test223_1() == test223_1() && test223_1() is test223_1() && test223_2() == test223_2() && test223_2() is test223_2() && test223_3() == test223_3() && test223_3() is test223_3() && test223_4() == test223_4() && test223_4() is test223_4() && test223_5() == test223_5() && test223_5() is test223_5() && test223_6() == test223_6() && test223_6() is test223_6() && test223_7() == test223_7() && test223_7() is test223_7() && test223_8() == test223_8() && test223_8() is test223_8() && test223_9() == test223_9() && test223_9() is test223_9(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=231 import imports.gdc231; class Range231 : Widget231 { override void* getStruct() { return null; } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=239 import imports.gdc239; class C239 { C239a *foo; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=240 interface I204 { void f(); } class C204 : I204 { void f(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=241 import imports.gdc241a; import imports.gdc241b : S241, C241, E241, N241; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=242 struct S242a { enum M = S242a(); void iter() { } } void test242a() { return S242a.M.iter; } struct S242b { enum M = S242b(); void iter() { } } void test242b() { S242b.M.iter; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=251 import imports.gdc251a; import imports.gdc251b : C251; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=253 import imports.gdc253; class C253 : C253a { void test253() { } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=255 class C255 { void f2() { class C1 { void f1() { void f0() { class C0 { void test255() { f2(); } } } } } } } class C255a { void f3() { class C1 { void f2() { void f1() { void f0() { class C0 { void test255a() { f3(); } } } } } } } } class C255b { void f4() { class C2 { void f3() { void f2() { class C1 { void f1() { void f0() { class C0 { void test255b() { f4(); } } } } } } } } } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=256 import imports.gdcpkg256 : gdc256; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=261 void test261() { class C1 { void f1() { class C2 { void f2() { auto v = &f1; } } } } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=280 struct RBNode280 { RBNode280* _parent; @property left(RBNode280*) { _parent = &this; } } class RedBlackTree280 { RBNode280* _end; RBNode280* _begin; this(int[] elems...) { _end = new RBNode280; foreach (e; elems) { _end.left = _begin; } } } __gshared s = new RedBlackTree280('h'); /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=284 alias v284 = __vector(int[2]); v284 test284(v284 a, ...) { return a + a; } ================================================ FILE: gcc/testsuite/gdc.dg/dg.exp ================================================ # Copyright (C) 2017 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # GCC testsuite that uses the `dg.exp' driver. # Load support procs. load_lib gdc-dg.exp # The default option list can be overridden by # TORTURE_OPTIONS="{ { list1 } ... { listN } }" if ![info exists TORTURE_OPTIONS] { set TORTURE_OPTIONS [list \ { -O0 } { -O1 } { -O2 } { -O3 } { -Os } \ { -O0 -frelease } { -O0 -g } { -O0 -frelease -g } \ { -O1 -frelease } { -O1 -g } { -O1 -frelease -g } \ { -O2 -frelease } { -O2 -g } { -O2 -frelease -g } \ { -O3 -frelease } { -O3 -g } { -O3 -frelease -g } \ { -Os -frelease } { -Os -g } { -Os -frelease -g }] } # Initialize `dg'. dg-init # Initialize use of torture lists. torture-init set-torture-options $TORTURE_OPTIONS # Main loop. gdc-dg-runtest [lsort \ [glob -nocomplain $srcdir/$subdir/*.d ] ] "" "" # Finalize use of torture lists. torture-finish # All done. dg-finish ================================================ FILE: gcc/testsuite/gdc.dg/gdc254.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=254 // { dg-options "-I $srcdir/gdc.dg" } // { dg-shouldfail "interface function is not implemented" } // { dg-do compile } import imports.gdc254a; interface A254 { void F(); } class C254 : B254, A254 // { dg-error "interface function '\[^\n\r]*' is not implemented" } { } ================================================ FILE: gcc/testsuite/gdc.dg/gdc260.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=260 // { dg-options "-Wall -Werror" } // { dg-do compile } import gcc.builtins; char *bug260(char *buffer) { return __builtin_strcat(&buffer[0], "Li"); } ================================================ FILE: gcc/testsuite/gdc.dg/gdc270a.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=270 // { dg-do compile } module gdc270; void foo() { } /* { dg-final { scan-assembler "_GLOBAL__D_6gdc270" } } */ /* { dg-final { scan-assembler "_GLOBAL__I_6gdc270" } } */ ================================================ FILE: gcc/testsuite/gdc.dg/gdc270b.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=270 // { dg-do compile } module gdc270; /* { dg-final { scan-assembler "_GLOBAL__D_6gdc270" } } */ /* { dg-final { scan-assembler "_GLOBAL__I_6gdc270" } } */ ================================================ FILE: gcc/testsuite/gdc.dg/gdc282.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=282 // { dg-shouldfail "conflicting methods in class" } // { dg-do compile } class C282a { void fun() { } void f282() { } void f282() // { dg-error "conflicts with 'gdc282.C282a.f282'" } { } } class C282b { struct S282b { } void f282() { } void f282() // { dg-error "conflicts with 'gdc282.C282b.f282'" } { } } class C282c { class C282c { } void f282() { } void f282() // { dg-error "conflicts with 'gdc282.C282c.f282'" } { } } ================================================ FILE: gcc/testsuite/gdc.dg/gdc283.d ================================================ // https://bugzilla.gdcproject.org/show_bug.cgi?id=283 // { dg-do run { target hw } } struct Impl { size_t _count; } struct RefCountedStore { Impl* _store; void initialize() { import core.stdc.stdlib : malloc; _store = cast(Impl*) malloc(Impl.sizeof); _store._count = 1; } bool isInitialized() { return _store !is null; } void ensureInitialized() { if (!isInitialized) initialize(); } } struct RefCounted14443 { RefCountedStore _refCounted; this(int) { _refCounted.initialize(); } this(this) { ++_refCounted._store._count; } ~this() { if (--_refCounted._store._count) return; import core.stdc.stdlib : free; free(_refCounted._store); _refCounted._store = null; } int refCountedPayload() { _refCounted.ensureInitialized(); return 1; } } struct PathRange14443 { RefCounted14443 path; @property PathElement14443 front() { return PathElement14443(this, path.refCountedPayload()); } } struct PathElement14443 { PathRange14443 range; this(PathRange14443 range, int) { this.range = range; } } void main() { auto path = RefCounted14443(12); if (path._refCounted._store._count != 1) assert(0); { auto _r = PathRange14443(path); if (path._refCounted._store._count != 2) assert(0); { auto element = _r.front; if (path._refCounted._store._count != 3) assert(0); } if (path._refCounted._store._count != 2) assert(0); } if (path._refCounted._store._count != 1) assert(0); } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc170.d ================================================ module imports.gdc170; class bar(T) { void undefined_reference() {} } template foo(T) { bar!T foo1(T2)() if (true) body { return null; } bar!T foo2(T2)() { return null; } bar!T foo3(T2 = void)() if (true) body { return null; } bar!T foo4(T2 = void)() { return null; } void foo5(T2)(bar!T x) if (true) body {} void foo6(T2)(bar!T x) {} void foo7(T2 = void)(bar!T x) if (true) body {} void foo8(T2 = void)(bar!T x) {} } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc231.d ================================================ module imports.gdc231; interface ImplementorIF { void* getImplementorStruct(); void* getStruct(); } template ImplementorT() { void* getImplementorStruct() { return null; } } class Widget231 : ImplementorIF { mixin ImplementorT; void* getStruct() { return null; } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc239.d ================================================ import std.path : buildNormalizedPath; class C239a { auto bar() { auto path = buildNormalizedPath("/", "foo"); } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc241a.d ================================================ import compilable; S241 *s241; // Use indirectly imported struct C241 *c241; // Use indirectly imported class E241 *e241; // Use indirectly imported enum N241.T *n241; // Use indirectly imported namespace ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc241b.d ================================================ class C241 { } enum E241 { a } struct S241 { } extern(C++, N241) { struct T { } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc251a.d ================================================ module imports.gdc251a; import imports.gdc251b; import compilable; C251 config; ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc251b.d ================================================ module imports.gdc251b; class C251 { } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc253.d ================================================ module imports.gdc253; interface I253a { } interface I253b { size_t printf(...); void flush(); } class C253a : I253a , I253b { size_t printf(...) { return 0; } void flush() { } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc254a.d ================================================ module imports.gdc254a; class B254 { void F() { if (Error) return; } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc256.d ================================================ module gdc256; ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdc27.d ================================================ module imports.gdc27; interface I_A { bool a(); } class C_A : I_A { bool a() { return false; } } ================================================ FILE: gcc/testsuite/gdc.dg/imports/gdcpkg256/package.d ================================================ module imports.gdcpkg256; public import gdc256; ================================================ FILE: gcc/testsuite/gdc.dg/imports/runnable.d ================================================ module imports.runnable; private import runnable; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=36 void test36d_1() { auto parser = Parser!(char[])(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=253 class B253 : A253 { void test253(int[int] a) { if (a.get(0, 1)) return; } } ================================================ FILE: gcc/testsuite/gdc.dg/link.d ================================================ // { dg-do link { target arm*-*-* i?86-*-* x86_64-*-* } } /******************************************/ class C1() { static struct S1 { A1 a; } } enum E1 = is(C1!()); /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=300 struct S300(Range) { double test(size_t remaining) { double r; return r ^^ remaining; } } auto link300a(Range)(Range) { return S300!(Range)(); } void link300() { struct I {} static assert(is(typeof(link300a(I())) == struct)); auto sample = link300a(I()); sample.test(5); } /******************************************/ void main() {} ================================================ FILE: gcc/testsuite/gdc.dg/lto/lto.exp ================================================ # Copyright (C) 2017 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # Test link-time optimization across multiple files. # # Programs are broken into multiple files. Each one is compiled # separately with LTO information. The final executable is generated # by collecting all the generated object files using regular LTO or WHOPR. if $tracelevel then { strace $tracelevel } # Load procedures from common libraries. load_lib standard.exp load_lib gdc-dg.exp # Load the language-independent compabibility support procedures. load_lib lto.exp # If LTO has not been enabled, bail. if { ![check_effective_target_lto] } { return } lto_init no-mathlib # Define an identifier for use with this suite to avoid name conflicts # with other lto tests running at the same time. set sid "d_lto" # Main loop. foreach src [lsort [find $srcdir/$subdir *_0.d]] { # If we're only testing specific files and this isn't one of them, skip it. if ![runtest_file_p $runtests $src] then { continue } lto-execute $src $sid } lto_finish ================================================ FILE: gcc/testsuite/gdc.dg/lto/ltotests_0.d ================================================ // { dg-lto-do link } module ltotests_0; import core.stdc.stdio; /******************************************/ interface I284 { void m284(); } class C284 : I284 { void m284() { } } /******************************************/ class C304 { } C304 c304; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=61 struct S61a { void a() { } void b() { } } struct S61b { S61a other; void foo() { bar(); } void bar() { try other.a(); catch (Exception) other.b(); } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=88 extern(C) int test88a(); void test88() { test88a(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=252 class C252 { struct S252 { int i; ubyte u; } S252 s; } void test252() { C252 c = new C252(); } /******************************************/ void main(string[]) { test88(); test252(); printf("Success!\n"); } ================================================ FILE: gcc/testsuite/gdc.dg/lto/ltotests_1.d ================================================ module ltotests_1; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=88 extern(C) int test88a() { return 0; } ================================================ FILE: gcc/testsuite/gdc.dg/runnable.d ================================================ // { dg-additional-sources "imports/runnable.d" } // { dg-do run { target hw } } module runnable; import imports.runnable; import core.stdc.stdio; import gcc.attribute; /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=2 struct S { string toString() { return "foo"; } } void test2() { import std.string : format; assert(format("%s", S()) == "foo"); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=4 void test4() { string str = "allo"; static assert(!__traits(compiles, str.reverse)); static assert(!__traits(compiles, str.sort)); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=15 class B { class A { } A a; } class C { void visit(B b) { import std.algorithm : map; auto as = [b.a]; as.map!(d => d); } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=16 void test16() { import std.parallelism : taskPool; taskPool.reduce!"a+b"([0, 1, 2, 3]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=17 /** * Parameters are not copied into a frame to be accessed from * the method's __require function. */ void contractTest(string path) { assert(path[0] == 't'); assert(path.length == 9); assert(path[8] == 'i'); } interface ModuleSaver { void save(string str) in { contractTest(str); } } class ModuleWriter : ModuleSaver { void save (string str) in {} body { } } void test17() { (new ModuleWriter()).save ("test.0.mci"); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=18 class C18 { struct Link { int x; int y; } void sort_links() { import std.algorithm : sort; import std.array : empty; import std.exception : enforce; enforce(!_link.empty); bool lt(Link a, Link b) { if(a.x > b.x) return false; if(a.x < b.x) return true; if(a.y >= b.y) return false; else return true; } sort!(lt)(_link); } this() { _link ~= Link(8, 3); _link ~= Link(4, 7); _link ~= Link(4, 6); _link ~= Link(3, 7); _link ~= Link(2, 7); _link ~= Link(2, 2); _link ~= Link(4, 1); } Link[] _link; } void test18() { C18 foo = new C18; foo.sort_links(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=19 void test19() { byte b; --b = b; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=24 void test24() { struct S24 { char[1] b; } S24 a; if (*a.b.ptr) return; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=29 void test29() { import std.string : format; import std.conv : text; string s; for (auto i = 0; i < 100000; i++) { s = format("%d", i); s = text(i); } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=31 class RedBlackTree(T, alias less) { struct Range { @property empty() { } } Range opSlice() { return Range(); } } auto redBlackTree(alias less, E)() { return new RedBlackTree!(E, less); } void test31() { redBlackTree!((a){}, double)(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=35 /** * Here the BinaryHeap instance uses an alias parameter and therefore * the instance's functions (percolateDown) need to be generated in * topNIndex->BinaryHeap scope and not in the declaration scope * (module->BinaryHeap). */ void topNIndex()() { bool indirectLess(int a, int b) { return a > b; } auto a = BinaryHeap!(indirectLess)(); } struct BinaryHeap(alias less) { void percolateDown() { less(0, 1); } } void test35a() { topNIndex(); } /* * Similar as test35a but with an additional indirection. * The nested function chain for percolateDown should look like this: * topNIndex2->BinaryHeap2->percolateDown. */ void topNIndex2()() { bool indirectLess(int a, int b) { return a > b; } auto a = BinaryHeap2!(S35b!(indirectLess)())(); } struct S35b(alias a) { void foo() { a(0, 0); } } struct BinaryHeap2(alias less) { void percolateDown() { less.foo(); } } void test35b() { topNIndex2(); } void test35() { test35a(); test35b(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=36 /** * Here getChar is a function in a template where template.isnested == false * but getChar still is a nested function and needs to get a static chain * containing test36a. */ void test36a()(char val) { void error() { } void getChar()() { error(); } void parseString() { getChar(); } } /** * Similar as test36a, but a little more complicated: * Here getChar is nested in a struct template which is nested in a function. * getChar's static chain still needs to contain test36b. */ void test36b()(char val) { void error() { } struct S(T) { void getChar() { error(); } } void parseString() { S!(int)().getChar(); } } /** * If g had accessed a, the frontend would have generated a closure. * * As we do not access it, there's no closure. We have to be careful * not to set a static chain for g containing test36c_1 though, * as g can be called from outside (here from test1c). In the end * we have to treat this as if everything in test36c_1 was declared * at module scope. */ auto test36c_1() { int a; void c() {}; class Result { int b; void g() { c(); /*a = 42;*/ } } return new Result(); } void test36c() { test36c_1().g(); } /** * empty is a (private) function which is nested in lightPostprocess. * At the same time it's a template instance, so it has to be declared as * weak or otherwise one-only. imports/runnable.d creates another instance * of Regex!char to verify that. */ struct Parser(R) { @property program() { return Regex!char(); } } struct Regex(Char) { @trusted lightPostprocess() { struct FixedStack(T) { @property empty() { return false; } } auto counterRange = FixedStack!uint(); } } void test36d() { auto parser = Parser!(char[])(); imports.runnable.test36d_1; } void test36() { test36a('n'); test36b('n'); test36c(); test36d(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=37 struct S37 { int bar(const S37 s) { return 0; } } int test37() { S37 s; return s.bar(s); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=43 void test43() { import core.vararg; import core.stdc.stdio; void formatArray(ref va_list argptr) { auto a = va_arg!(const(float)[])(argptr); foreach(f; a) { printf("%f\n", f); } } void doFormat(TypeInfo[] arguments, va_list argptr) { formatArray(argptr); } void format(...) { doFormat(_arguments, _argptr); } format([1.0f, 2.0f, 3.0f]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=47 template Foo47() { void test47() { asm { "nop"; } } } mixin Foo47!(); /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=51 struct S51 { int x; int pad; this(this) { ++x; } } void test51() { S51 s; auto sarr = new S51[1]; auto sarr2 = sarr; // postblit all fields. sarr2 ~= s; assert (sarr2[0].x == 1); assert (sarr2[1].x == 1); assert (sarr[0].x == 0); assert (s.x == 0); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=52 class C52 { C52 a; this() { printf("Construct: this=%p\n", cast(void*)this); a = this; } bool check() { printf("Check: this=%p a=%p\n", cast(void*)this, cast(void*)a); return this is a; } } auto test52a() { import std.conv, std.traits; struct Scoped { void[__traits (classInstanceSize, C52) ] Scoped_store = void; inout(C52) Scoped_payload() inout { void* alignedStore = cast(void*) Scoped_store.ptr; return cast(inout (C52)) alignedStore; } alias Scoped_payload this; } Scoped result; emplace!(Unqual!C52)(result.Scoped_store); assert(result.Scoped_payload().check); return result; } void test52() { auto a1 = test52a(); assert(a1.Scoped_payload().check); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=57 struct S57 { int a; long b; // Doesn't happen for bigger structs } S57 bar57() { return S57(4, 42); } void test57() { S57 s = bar57(); assert (s is S57(4, 42)); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=66 void test66() { int pos = 0; foreach(x; 0 .. 64) { ++pos %= 4; assert (pos != 4); } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=67 __vector(float[4])[2] d; // ICE /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=71 struct Leaf { ubyte symbol; ubyte codeLen; } struct CanonicalHuffman { Leaf[] table; void print() { import std.algorithm; import std.range; auto list = zip(iota(table.length), table.dup).array .sort!((a, b) => a[1].symbol < b[1].symbol) .uniq!((a, b) => (a[0] & (1 << a[1].codeLen) - 1) == (b[0] & (1 << b[1].codeLen) - 1)); } } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=77 void fun(ubyte[3] buf) { import std.bitmanip : bigEndianToNative; bigEndianToNative!ushort(buf[0..2]); } void test77() { fun([1,2,3]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=108 @attribute("forceinline") void test108() { import std.stdio : writeln; writeln("Here"); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=115 void test115() { union U { float f; uint i; } float a = 123.0; const l = U(a); assert(l.i == U(a).i); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=121 immutable char C121 = void; // ICE /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=122 void test122() { import std.algorithm : map; import std.parallelism : taskPool; import std.range : iota; immutable n = 10000; enum delta = 1.0 / n; // XBUG: was 'immutable delta' https://issues.dlang.org/show_bug.cgi?id=17092 immutable pi = 4.0 * delta * taskPool.reduce!"a + b"( map!((int i) { immutable x = (i - 0.5) * delta; return 1.0 / (1.0 + x * x); })(iota(n))); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=127 int[0] test127a; // OK int[1][0] test127b; // OK int[0][1] test127c; // ICE /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=131 struct S131 { this(string ) { } string opAssign(string v) { return v; } } void test131() { S131[string] s; s["foo"] = "bar"; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=133 void delegate()[] D133; void test133a(void delegate() dg) { D133 ~= dg; } void test133() { void nested() {} test133a(&nested); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=141 bool test141a(int a) { return a > (a + 1); } void test141() { assert(test141a(int.min) == false); assert(test141a(int.max) == true); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=142 @attribute("noinline") int test142a()() { return 142; } void test142() { enum E142 = test142a(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=171 void test171a() { int count = 0; short a = -1; while (a != 0) { a >>>= 1; count++; assert(count <= 16); } } void test171b() { uint[3] lhs = [99, 201, 300], rhs = [-1, 0, 0]; long t = 0; for (int i = 0; i < 3; i++) { t += lhs[i]; t -= rhs[i]; lhs[i] = cast(uint) t; t >>= uint.sizeof * 8; } assert(lhs == [100, 200, 300]); } void test171() { test171a(); test171b(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=179 struct S179a { @disable this(this); } struct S179b { S179a s1; void connect() { printf("this=%p\n", &this); } } class C179 { private S179b s2; ref S179b value() @property { printf("this=%p\n", &s2); return s2; } } void test179() { C179 a = new C179; a.value.connect(); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=183 struct S183a { union I183a { struct { double x, y, z; } struct { double a, b, c; } } I183a inner; this(double x, double y, double z) { this.inner.x = x; this.inner.y = y; this.inner.z = z; } } struct S183b { @property get() { union Buf { void[0] result; } const Buf buf = { }; return buf.result; } } struct S183c { @property get() { union Buf { TypeInfo info; void[0] result; } const Buf buf = { }; return buf.result; } } void test183() { auto v1 = S183a(0, 0, 0); auto v2 = S183b().get; auto v3 = S183c().get; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=186 struct S186 { union { struct { ubyte fieldA; byte fieldB = -1; byte fieldC = -1; } size_t _complete; } this(size_t complete) { this._complete = complete; } } void check186(in S186 obj, byte fieldB) { assert(obj.fieldA == 2); assert(obj.fieldB == 0); assert(obj.fieldC == 0); assert(obj._complete == 2); assert(fieldB == 0); } void test186a(size_t val) { S186 obj = S186(val); check186(obj, obj.fieldB); assert(obj.fieldA == 2); assert(obj.fieldB == 0); assert(obj.fieldC == 0); assert(obj._complete == 2); obj = S186(val); check186(obj, obj.fieldB); assert(obj.fieldA == 2); assert(obj.fieldB == 0); assert(obj.fieldC == 0); assert(obj._complete == 2); } void test186() { test186a(2); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=187 align(1) struct S187b { align(1) { uint unpaddedA; ushort unpaddedB; } } struct S187a { S187b[3] unpaddedArray; ubyte wontInitialize = ubyte.init; } struct S187 { S187a interesting; } void prepareStack() { byte[255] stackGarbage; foreach(i, ref b; stackGarbage) { b = cast(byte)(-i); } } void test187() { prepareStack(); auto a = S187(S187a()); assert(a.interesting.wontInitialize == 0); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=191 class C191 { int count = 0; void testA() { class Inner { void test() { void localFunction() { if (++count != 5) testA(); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testB() { class Inner { void test() { void localFunction() { void anotherLocalFunction() { if (++count != 10) testB(); } anotherLocalFunction(); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testC() { class Inner { int a = 1; void test() { void localFunction() { count += a; if (count != 15) testC(); assert(a == 1); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testD() { class Inner { void test() { int a = 1; void localFunction() { count += a; if (count != 20) testD(); assert(a == 1); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testE() { class Inner { int a = 1; void test() { void localFunction() { void anotherLocalFunction() { count += a; if (count != 25) testE(); assert(a == 1); } anotherLocalFunction(); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testF() { class Inner { void test() { int a = 1; void localFunction() { void anotherLocalFunction() { count += a; if (count != 30) testF(); assert(a == 1); } anotherLocalFunction(); } localFunction(); } } scope ic = new Inner(); ic.test(); } void testG() { class Inner { void test() { void localFunction() { int a = 1; void anotherLocalFunction() { count += a; if (count != 35) testG(); assert(a == 1); } anotherLocalFunction(); } localFunction(); } } scope ic = new Inner(); ic.test(); } } void test191() { scope oc = new C191(); oc.testA(); assert(oc.count == 5); oc.testB(); assert(oc.count == 10); oc.testC(); assert(oc.count == 15); oc.testD(); assert(oc.count == 20); oc.testE(); assert(oc.count == 25); oc.testF(); assert(oc.count == 30); oc.testG(); assert(oc.count == 35); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=194 auto test194(ref bool overflow) { import core.checkedint; return adds(1, 1, overflow); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=196 class C196 { int a; } struct S196 { int a; } void test196() { __gshared c = new C196(); __gshared s = new S196(0); c.a = 1; s.a = 1; } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=198 struct S198a { union { float[3] v; struct { float x; float y; float z; } } this(float x_, float y_, float z_) { x = x_; y = y_; z = z_; } ref S198a opOpAssign(string op)(S198a operand) if (op == "+") { x += operand.x; y += operand.y; z += operand.z; return this; } } struct S198b { @property get() { union Buf { void[0] result; } const Buf buf = { }; return buf.result; } } struct S198c { @property get() { union Buf { TypeInfo info; void[0] result; } const Buf buf = { }; return buf.result; } } auto test198() { S198a sum = S198a(0, 0, 0); foreach(size_t v; 0 .. 3) sum += S198a(1, 2, 3); assert(sum.v == [3, 6, 9]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=200 void test200a(double x, double y) { const double y2 = x + 1.0; assert(y == y2); } void test200() { const double x = .012; const double y = x + 1.0; test200a(x, y); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=210 struct S210 { ubyte a; uint b; } union U210 { S210 a; uint b; } S210 test210a() { S210 s = S210(1, 2); return s; } S210[2] test210b() { S210[2] s = [S210(1, 2), S210(3, 4)]; return s; } U210 test210c() { U210 s = U210(S210(1, 2)); return s; } U210[2] test210d() { U210[2] s = [U210(S210(1, 2)), U210(S210(3, 4))]; return s; } void test210() { S210 a = S210(1, 2); assert(a == S210(1, 2)); assert(a == test210a()); assert(a != S210(2, 1)); S210[2] b = [S210(1, 2), S210(3, 4)]; assert(b == [S210(1, 2), S210(3, 4)]); assert(b == test210b()); assert(b != [S210(2, 1), S210(3, 4)]); U210 c = U210(S210(1, 2)); assert(c == U210(S210(1, 2))); assert(c == test210c()); assert(c != U210(S210(2, 1))); U210[2] d = [U210(S210(1, 2)), U210(S210(3, 4))]; assert(d == [U210(S210(1, 2)), U210(S210(3, 4))]); assert(d == test210d()); assert(d != [U210(S210(2, 1)), U210(S210(3, 4))]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=240 void test240a(int a, int b) { assert(a == 0); assert(b == 0); } void test240() { int a = 0; test240a(a, a++); assert(a == 1); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=242 struct S242 { enum M = S242(); int a = 42; auto iter() { this.a = 24; return this; } } S242 test242a() { return S242.M.iter; } void test242() { assert(test242a() == S242(24)); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=248 class C248b { bool isintegral() { return false; } } class C248a { int count = 0; C248b getMemtype() { count++; return new C248b(); } } class C248 { C248a sym; this() { this.sym = new C248a(); } bool isintegral() { return sym.getMemtype().isintegral(); } } void test248() { C248 e = new C248(); e.isintegral(); assert(e.sym.count == 1); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=250 void test250() { struct S { string data; } auto a = S("hello"); auto b = S("hello".dup); assert(a.data == b.data); assert(a == b); assert([a] == [b]); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=253 interface A253 { void test253(int[int]); } interface C253 : A253 { } class D253 : B253, C253 { } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=273 class B273 { B273[] members; } class D273 : B273 { } void test273() { auto noPointers = ClassInfo.ClassFlags.noPointers; assert((B273.classinfo.m_flags & noPointers) == 0); assert((D273.classinfo.m_flags & noPointers) == 0); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=285 inout(char)[] test285a(inout(char)* s) @nogc @system pure nothrow { import core.stdc.string : strlen; return s ? s[0 .. strlen(s)] : null; } void test285() { assert(test285a(null) == null); assert(test285a("foo") == "foo"); } /******************************************/ // https://bugzilla.gdcproject.org/show_bug.cgi?id=286 void test286() { struct K286 { int count; this(this) { count++; } } struct S286 { int data; this(K286 key) { data = key.count; } } S286 getData(K286 key) { static S286[K286] getCache; auto p = key in getCache; if (p) return *p; return (getCache[key] = S286(key)); } auto s = getData(K286()); if (s.data == 0) assert(0); } /******************************************/ void main() { test2(); test4(); test16(); test17(); test18(); test35(); test36(); test43(); test51(); test52(); test57(); test66(); test77(); test108(); test115(); test131(); test133(); test141(); test179(); test186(); test187(); test191(); test196(); test198(); test200(); test210(); test240(); test242(); test248(); test250(); test273(); test285(); test286(); printf("Success!\n"); } ================================================ FILE: gcc/testsuite/gdc.dg/simd.d ================================================ // { dg-do run { target hw } } import core.simd; import core.stdc.string; import std.stdio; alias TypeTuple(T...) = T; /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16087 static assert(void8.sizeof == 8); static assert(float2.sizeof == 8); static assert(byte8.sizeof == 8); static assert(ubyte8.sizeof == 8); static assert(short4.sizeof == 8); static assert(ushort4.sizeof == 8); static assert(int2.sizeof == 8); static assert(uint2.sizeof == 8); static assert(void16.alignof == 16); static assert(double2.alignof == 16); static assert(float4.alignof == 16); static assert(byte16.alignof == 16); static assert(ubyte16.alignof == 16); static assert(short8.alignof == 16); static assert(ushort8.alignof == 16); static assert(int4.alignof == 16); static assert(uint4.alignof == 16); static assert(long2.alignof == 16); static assert(ulong2.alignof == 16); static assert(void16.sizeof == 16); static assert(double2.sizeof == 16); static assert(float4.sizeof == 16); static assert(byte16.sizeof == 16); static assert(ubyte16.sizeof == 16); static assert(short8.sizeof == 16); static assert(ushort8.sizeof == 16); static assert(int4.sizeof == 16); static assert(uint4.sizeof == 16); static assert(long2.sizeof == 16); static assert(ulong2.sizeof == 16); static assert(void32.alignof == 32); static assert(double4.alignof == 32); static assert(float8.alignof == 32); static assert(byte32.alignof == 32); static assert(ubyte32.alignof == 32); static assert(short16.alignof == 32); static assert(ushort16.alignof == 32); static assert(int8.alignof == 32); static assert(uint8.alignof == 32); static assert(long4.alignof == 32); static assert(ulong4.alignof == 32); static assert(void32.sizeof == 32); static assert(double4.sizeof == 32); static assert(float8.sizeof == 32); static assert(byte32.sizeof == 32); static assert(ubyte32.sizeof == 32); static assert(short16.sizeof == 32); static assert(ushort16.sizeof == 32); static assert(int8.sizeof == 32); static assert(uint8.sizeof == 32); static assert(long4.sizeof == 32); static assert(ulong4.sizeof == 32); /*****************************************/ void test1() { void16 v1 = void,v2 = void; byte16 b; v2 = b; v1 = v2; static assert(!__traits(compiles, v1 + v2)); static assert(!__traits(compiles, v1 - v2)); static assert(!__traits(compiles, v1 * v2)); static assert(!__traits(compiles, v1 / v2)); static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); static assert(!__traits(compiles, -v1)); static assert(!__traits(compiles, +v1)); static assert(!__traits(compiles, !v1)); static assert(!__traits(compiles, v1 += v2)); static assert(!__traits(compiles, v1 -= v2)); static assert(!__traits(compiles, v1 *= v2)); static assert(!__traits(compiles, v1 /= v2)); static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2() { byte16 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2b() { ubyte16 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2c() { short8 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; v1 = v1 * 3; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2d() { ushort8 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2e() { int4 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2f() { uint4 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2g() { long2 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2h() { ulong2 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; v1 = v2 % v3; v1 = v2 & v3; v1 = v2 | v3; v1 = v2 ^ v3; static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); v1 = v2 << 1; v1 = v2 >> 1; v1 = v2 >>> 1; static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); v1 = ~v2; v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; v1 %= v2; v1 &= v2; v1 |= v2; v1 ^= v2; static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); v1 <<= 1; v1 >>= 1; v1 >>>= 1; // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2i() { float4 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test2j() { double2 v1, v2 = 1, v3 = 1; v1 = v2; v1 = v2 + v3; v1 = v2 - v3; v1 = v2 * v3; v1 = v2 / v3; static assert(!__traits(compiles, v1 % v2)); static assert(!__traits(compiles, v1 & v2)); static assert(!__traits(compiles, v1 | v2)); static assert(!__traits(compiles, v1 ^ v2)); static assert(!__traits(compiles, v1 ~ v2)); static assert(!__traits(compiles, v1 ^^ v2)); static assert(!__traits(compiles, v1 is v2)); static assert(!__traits(compiles, v1 !is v2)); static assert(!__traits(compiles, v1 == v2)); static assert(!__traits(compiles, v1 != v2)); static assert(!__traits(compiles, v1 < v2)); static assert(!__traits(compiles, v1 > v2)); static assert(!__traits(compiles, v1 <= v2)); static assert(!__traits(compiles, v1 >= v2)); static assert(!__traits(compiles, v1 << 1)); static assert(!__traits(compiles, v1 >> 1)); static assert(!__traits(compiles, v1 >>> 1)); static assert(!__traits(compiles, v1 && v2)); static assert(!__traits(compiles, v1 || v2)); static assert(!__traits(compiles, ~v1)); v1 = -v2; v1 = +v2; static assert(!__traits(compiles, !v1)); v1 += v2; v1 -= v2; v1 *= v2; v1 /= v2; static assert(!__traits(compiles, v1 %= v2)); static assert(!__traits(compiles, v1 &= v2)); static assert(!__traits(compiles, v1 |= v2)); static assert(!__traits(compiles, v1 ^= v2)); static assert(!__traits(compiles, v1 ~= v2)); static assert(!__traits(compiles, v1 ^^= v2)); static assert(!__traits(compiles, v1 <<= 1)); static assert(!__traits(compiles, v1 >>= 1)); static assert(!__traits(compiles, v1 >>>= 1)); // A cast from vector to non-vector is allowed only when the target is same size Tsarray. static assert(!__traits(compiles, cast(byte)v1)); // 1byte static assert(!__traits(compiles, cast(short)v1)); // 2byte static assert(!__traits(compiles, cast(int)v1)); // 4byte static assert(!__traits(compiles, cast(long)v1)); // 8byte static assert(!__traits(compiles, cast(float)v1)); // 4byte static assert(!__traits(compiles, cast(double)v1)); // 8byte static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK } /*****************************************/ void test4() { int4 c = 7; (cast(int[4])c)[3] = 4; (cast(int*)&c)[2] = 4; c.array[1] = 4; c.ptr[3] = 4; assert(c.length == 4); } /*****************************************/ void BaseTypeOfVector(T : __vector(T[N]), size_t N)(int i) { assert(is(T == int)); assert(N == 4); } void test7411() { BaseTypeOfVector!(__vector(int[4]))(3); } /*****************************************/ // 7951 float[4] test7951() { float4 v1; float4 v2; return cast(float[4])(v1+v2); } /*****************************************/ void test7951_2() { float[4] v1 = [1,2,3,4]; float[4] v2 = [1,2,3,4]; float4 f1, f2, f3; f1.array = v1; f2.array = v2; f3 = f1 + f2; } /*****************************************/ immutable ulong2 gulong2 = 0x8000_0000_0000_0000; immutable uint4 guint4 = 0x8000_0000; immutable ushort8 gushort8 = 0x8000; immutable ubyte16 gubyte16 = 0x80; immutable long2 glong2 = 0x7000_0000_0000_0000; immutable int4 gint4 = 0x7000_0000; immutable short8 gshort8 = 0x7000; immutable byte16 gbyte16 = 0x70; immutable float4 gfloat4 = 4.0; immutable double2 gdouble2 = 8.0; void test7414() { immutable ulong2 lulong2 = 0x8000_0000_0000_0000; assert(memcmp(&lulong2, &gulong2, gulong2.sizeof) == 0); immutable uint4 luint4 = 0x8000_0000; assert(memcmp(&luint4, &guint4, guint4.sizeof) == 0); immutable ushort8 lushort8 = 0x8000; assert(memcmp(&lushort8, &gushort8, gushort8.sizeof) == 0); immutable ubyte16 lubyte16 = 0x80; assert(memcmp(&lubyte16, &gubyte16, gubyte16.sizeof) == 0); immutable long2 llong2 = 0x7000_0000_0000_0000; assert(memcmp(&llong2, &glong2, glong2.sizeof) == 0); immutable int4 lint4 = 0x7000_0000; assert(memcmp(&lint4, &gint4, gint4.sizeof) == 0); immutable short8 lshort8 = 0x7000; assert(memcmp(&lshort8, &gshort8, gshort8.sizeof) == 0); immutable byte16 lbyte16 = 0x70; assert(memcmp(&lbyte16, &gbyte16, gbyte16.sizeof) == 0); immutable float4 lfloat4 = 4.0; assert(memcmp(&lfloat4, &gfloat4, gfloat4.sizeof) == 0); immutable double2 ldouble2 = 8.0; assert(memcmp(&ldouble2, &gdouble2, gdouble2.sizeof) == 0); } /*****************************************/ void test7413() { byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; assert(b.array[0] == 1); assert(b.array[1] == 2); assert(b.array[2] == 3); assert(b.array[3] == 4); assert(b.array[4] == 5); assert(b.array[5] == 6); assert(b.array[6] == 7); assert(b.array[7] == 8); assert(b.array[8] == 9); assert(b.array[9] == 10); assert(b.array[10] == 11); assert(b.array[11] == 12); assert(b.array[12] == 13); assert(b.array[13] == 14); assert(b.array[14] == 15); assert(b.array[15] == 16); ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; assert(ub.array[0] == 1); assert(ub.array[1] == 2); assert(ub.array[2] == 3); assert(ub.array[3] == 4); assert(ub.array[4] == 5); assert(ub.array[5] == 6); assert(ub.array[6] == 7); assert(ub.array[7] == 8); assert(ub.array[8] == 9); assert(ub.array[9] == 10); assert(ub.array[10] == 11); assert(ub.array[11] == 12); assert(ub.array[12] == 13); assert(ub.array[13] == 14); assert(ub.array[14] == 15); assert(ub.array[15] == 16); short8 s = [1,2,3,4,5,6,7,8]; assert(s.array[0] == 1); assert(s.array[1] == 2); assert(s.array[2] == 3); assert(s.array[3] == 4); assert(s.array[4] == 5); assert(s.array[5] == 6); assert(s.array[6] == 7); assert(s.array[7] == 8); ushort8 us = [1,2,3,4,5,6,7,8]; assert(us.array[0] == 1); assert(us.array[1] == 2); assert(us.array[2] == 3); assert(us.array[3] == 4); assert(us.array[4] == 5); assert(us.array[5] == 6); assert(us.array[6] == 7); assert(us.array[7] == 8); int4 i = [1,2,3,4]; assert(i.array[0] == 1); assert(i.array[1] == 2); assert(i.array[2] == 3); assert(i.array[3] == 4); uint4 ui = [1,2,3,4]; assert(ui.array[0] == 1); assert(ui.array[1] == 2); assert(ui.array[2] == 3); assert(ui.array[3] == 4); long2 l = [1,2]; assert(l.array[0] == 1); assert(l.array[1] == 2); ulong2 ul = [1,2]; assert(ul.array[0] == 1); assert(ul.array[1] == 2); float4 f = [1,2,3,4]; assert(f.array[0] == 1); assert(f.array[1] == 2); assert(f.array[2] == 3); assert(f.array[3] == 4); double2 d = [1,2]; assert(d.array[0] == 1); assert(d.array[1] == 2); } /*****************************************/ byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; short8 s = [1,2,3,4,5,6,7,8]; ushort8 us = [1,2,3,4,5,6,7,8]; int4 i = [1,2,3,4]; uint4 ui = [1,2,3,4]; long2 l = [1,2]; ulong2 ul = [1,2]; float4 f = [1,2,3,4]; double2 d = [1,2]; void test7413_2() { assert(b.array[0] == 1); assert(b.array[1] == 2); assert(b.array[2] == 3); assert(b.array[3] == 4); assert(b.array[4] == 5); assert(b.array[5] == 6); assert(b.array[6] == 7); assert(b.array[7] == 8); assert(b.array[8] == 9); assert(b.array[9] == 10); assert(b.array[10] == 11); assert(b.array[11] == 12); assert(b.array[12] == 13); assert(b.array[13] == 14); assert(b.array[14] == 15); assert(b.array[15] == 16); assert(ub.array[0] == 1); assert(ub.array[1] == 2); assert(ub.array[2] == 3); assert(ub.array[3] == 4); assert(ub.array[4] == 5); assert(ub.array[5] == 6); assert(ub.array[6] == 7); assert(ub.array[7] == 8); assert(ub.array[8] == 9); assert(ub.array[9] == 10); assert(ub.array[10] == 11); assert(ub.array[11] == 12); assert(ub.array[12] == 13); assert(ub.array[13] == 14); assert(ub.array[14] == 15); assert(ub.array[15] == 16); assert(s.array[0] == 1); assert(s.array[1] == 2); assert(s.array[2] == 3); assert(s.array[3] == 4); assert(s.array[4] == 5); assert(s.array[5] == 6); assert(s.array[6] == 7); assert(s.array[7] == 8); assert(us.array[0] == 1); assert(us.array[1] == 2); assert(us.array[2] == 3); assert(us.array[3] == 4); assert(us.array[4] == 5); assert(us.array[5] == 6); assert(us.array[6] == 7); assert(us.array[7] == 8); assert(i.array[0] == 1); assert(i.array[1] == 2); assert(i.array[2] == 3); assert(i.array[3] == 4); assert(ui.array[0] == 1); assert(ui.array[1] == 2); assert(ui.array[2] == 3); assert(ui.array[3] == 4); assert(l.array[0] == 1); assert(l.array[1] == 2); assert(ul.array[0] == 1); assert(ul.array[1] == 2); assert(f.array[0] == 1); assert(f.array[1] == 2); assert(f.array[2] == 3); assert(f.array[3] == 4); assert(d.array[0] == 1); assert(d.array[1] == 2); } /*****************************************/ float bug8060(float x) { int i = *cast(int*)&x; ++i; return *cast(float*)&i; } /*****************************************/ /+ // 9200 void bar9200(double[2] a) { assert(a[0] == 1); assert(a[1] == 2); } double2 * v9200(double2* a) { return a; } void test9200() { double2 a = [1, 2]; *v9200(&a) = a; bar9200(a.array); } +/ /*****************************************/ // 9304 and 9322 float4 foo9304(float4 a) { return -a; } void test9304() { auto a = foo9304([0, 1, 2, 3]); //writeln(a.array); assert(a.array == [0,-1,-2,-3]); } /*****************************************/ void test9910() { float4 f = [1, 1, 1, 1]; auto works = f + 3; auto bug = 3 + f; assert (works.array == [4,4,4,4]); assert (bug.array == [4,4,4,4]); // no property 'array' for type 'int' } /*****************************************/ bool normalize(double[] range, double sum = 1) { double s = 0; const length = range.length; foreach (e; range) { s += e; } if (s == 0) { return false; } return true; } void test12852() { double[3] range = [0.0, 0.0, 0.0]; assert(normalize(range[]) == false); range[1] = 3.0; assert(normalize(range[]) == true); } /*****************************************/ void test9449() { ubyte16[1] table; } /*****************************************/ void test9449_2() { float[4][2] m = [[2.0, 1, 3, 4], [5.0, 6, 7, 8]]; // segfault assert(m[0][0] == 2.0); assert(m[0][1] == 1); assert(m[0][2] == 3); assert(m[0][3] == 4); assert(m[1][0] == 5.0); assert(m[1][1] == 6); assert(m[1][2] == 7); assert(m[1][3] == 8); } /*****************************************/ // 13841 void test13841() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V1; Vector16s) { foreach (V2; Vector16s) { V1 v1 = void; V2 v2 = void; static if (is(V1 == V2)) { static assert( is(typeof(true ? v1 : v2) == V1)); } else { static assert(!is(typeof(true ? v1 : v2))); } } } } /*****************************************/ // 12776 void test12776() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V; Vector16s) { static assert(is(typeof( V .init) == V )); static assert(is(typeof( const(V).init) == const(V))); static assert(is(typeof( inout( V).init) == inout( V))); static assert(is(typeof( inout(const V).init) == inout(const V))); static assert(is(typeof(shared( V).init) == shared( V))); static assert(is(typeof(shared( const V).init) == shared( const V))); static assert(is(typeof(shared(inout V).init) == shared(inout V))); static assert(is(typeof(shared(inout const V).init) == shared(inout const V))); static assert(is(typeof( immutable(V).init) == immutable(V))); } } /*****************************************/ void foo13988(double[] arr) { static ulong repr(double d) { return *cast(ulong*)&d; } foreach (x; arr) assert(repr(arr[0]) == *cast(ulong*)&(arr[0])); } void test13988() { double[] arr = [3.0]; foo13988(arr); } /*****************************************/ // 15123 void test15123() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); foreach (V; Vector16s) { auto x = V.init; } } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15144 void test15144() { enum ubyte16 csXMM1 = ['a','b','c',0,0,0,0,0]; __gshared ubyte16 csXMM2 = ['a','b','c',0,0,0,0,0]; immutable ubyte16 csXMM3 = ['a','b','c',0,0,0,0,0]; } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=13927 void test13927(ulong2 a) { ulong2 b = [long.min, long.min]; auto tmp = a - b; } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16488 void foo_byte16(byte t, byte s) { byte16 f = s; auto p = cast(byte*)&f; foreach (i; 0 .. 16) assert(p[i] == s); } void foo_ubyte16(ubyte t, ubyte s) { ubyte16 f = s; auto p = cast(ubyte*)&f; foreach (i; 0 .. 16) assert(p[i] == s); } void foo_short8(short t, short s) { short8 f = s; auto p = cast(short*)&f; foreach (i; 0 .. 8) assert(p[i] == s); } void foo_ushort8(ushort t, ushort s) { ushort8 f = s; auto p = cast(ushort*)&f; foreach (i; 0 .. 8) assert(p[i] == s); } void foo_int4(int t, int s) { int4 f = s; auto p = cast(int*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void foo_uint4(uint t, uint s, uint u) { uint4 f = s; auto p = cast(uint*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void foo_long2(long t, long s, long u) { long2 f = s; auto p = cast(long*)&f; foreach (i; 0 .. 2) assert(p[i] == s); } void foo_ulong2(ulong t, ulong s) { ulong2 f = s; auto p = cast(ulong*)&f; foreach (i; 0 .. 2) assert(p[i] == s); } void foo_float4(float t, float s) { float4 f = s; auto p = cast(float*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void foo_double2(double t, double s, double u) { double2 f = s; auto p = cast(double*)&f; foreach (i; 0 .. 2) assert(p[i] == s); } void test16448() { foo_byte16(5, -10); foo_ubyte16(5, 11); foo_short8(5, -6); foo_short8(5, 7); foo_int4(5, -6); foo_uint4(5, 0x12345678, 22); foo_long2(5, -6, 1); foo_ulong2(5, 0x12345678_87654321L); foo_float4(5, -6); foo_double2(5, -6, 2); } /*****************************************/ void foo_byte32(byte t, byte s) { byte32 f = s; auto p = cast(byte*)&f; foreach (i; 0 .. 32) assert(p[i] == s); } void foo_ubyte32(ubyte t, ubyte s) { ubyte32 f = s; auto p = cast(ubyte*)&f; foreach (i; 0 .. 32) assert(p[i] == s); } void foo_short16(short t, short s) { short16 f = s; auto p = cast(short*)&f; foreach (i; 0 .. 16) assert(p[i] == s); } void foo_ushort16(ushort t, ushort s) { ushort16 f = s; auto p = cast(ushort*)&f; foreach (i; 0 .. 16) assert(p[i] == s); } void foo_int8(int t, int s) { int8 f = s; auto p = cast(int*)&f; foreach (i; 0 .. 8) assert(p[i] == s); } void foo_uint8(uint t, uint s, uint u) { uint8 f = s; auto p = cast(uint*)&f; foreach (i; 0 .. 8) assert(p[i] == s); } void foo_long4(long t, long s, long u) { long4 f = s; auto p = cast(long*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void foo_ulong4(ulong t, ulong s) { ulong4 f = s; auto p = cast(ulong*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void foo_float8(float t, float s) { float8 f = s; auto p = cast(float*)&f; foreach (i; 0 .. 8) assert(p[i] == s); } void foo_double4(double t, double s, double u) { double4 f = s; auto p = cast(double*)&f; foreach (i; 0 .. 4) assert(p[i] == s); } void test16448_32() { import core.cpuid; if (!core.cpuid.avx) return; foo_byte32(5, -10); foo_ubyte32(5, 11); foo_short16(5, -6); foo_short16(5, 7); foo_int8(5, -6); foo_uint8(5, 0x12345678, 22); foo_long4(5, -6, 1); foo_ulong4(5, 0x12345678_87654321L); foo_float8(5, -6); foo_double4(5, -6, 2); } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16703 float index(float4 f4, size_t i) { return f4[i]; //return (*cast(float[4]*)&f4)[2]; } float[4] slice(float4 f4) { return f4[]; } float slice2(float4 f4, size_t lwr, size_t upr, size_t i) { float[] fa = f4[lwr .. upr]; return fa[i]; } void test16703() { float4 f4 = [1,2,3,4]; assert(index(f4, 0) == 1); assert(index(f4, 1) == 2); assert(index(f4, 2) == 3); assert(index(f4, 3) == 4); float[4] fsa = slice(f4); assert(fsa == [1.0f,2,3,4]); assert(slice2(f4, 1, 3, 0) == 2); assert(slice2(f4, 1, 3, 1) == 3); } /*****************************************/ struct Sunsto { align (1): // make sure f4 is misaligned byte b; union { float4 f4; ubyte[16] a; } } ubyte[16] foounsto() { float4 vf = 6; Sunsto s; s.f4 = vf * 2; vf = s.f4; return s.a; } void testOPvecunsto() { auto a = foounsto(); assert(a == [0, 0, 64, 65, 0, 0, 64, 65, 0, 0, 64, 65, 0, 0, 64, 65]); } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=10447 void test10447() { immutable __vector(double[2]) a = [1.0, 2.0]; __vector(double[2]) r; r += a; r = r * a; } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=17237 struct S17237 { bool a; struct { bool b; int8 c; } } static assert(S17237.a.offsetof == 0); static assert(S17237.b.offsetof == 32); static assert(S17237.c.offsetof == 64); /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16697 static assert(!is(float == __vector)); static assert(!is(float[1] == __vector)); static assert(!is(float[4] == __vector)); static assert( is(__vector(float[4]) == __vector)); static assert(!is(__vector(float[3]) == __vector)); static assert(!is(__vector(float[5]) == __vector)); static assert( is(__vector(float[4]) X == __vector) && is(X == float[4])); static assert( is(__vector(byte[16]) X == __vector) && is(X == byte[16])); /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=17720 void test17720() { alias Vector16s = TypeTuple!( void16, byte16, short8, int4, long2, ubyte16, ushort8, uint4, ulong2, float4, double2); alias Vector32s = TypeTuple!( void32, byte32, short16, int8, long4, ubyte32, ushort16, uint8, ulong4, float8, double4); // OK: __vector(T) -> __vector(void[]) of same size. // NG: __vector(T) -> __vector(void[]) of different size. // NG: explicit cast __vector(T) -> __vector(void[]) of different size. foreach (V; Vector16s) { static assert( __traits(compiles, { void16 v = V.init; })); static assert(!__traits(compiles, { void32 v = V.init; })); static assert(!__traits(compiles, { void32 v = cast(void32)V.init; })); } foreach (V; Vector32s) { static assert( __traits(compiles, { void32 v = V.init; })); static assert(!__traits(compiles, { void16 v = V.init; })); static assert(!__traits(compiles, { void16 v = cast(void16)V.init; })); } // NG: __vector(T) -> __vector(T) of same size. // OK: explicit cast __vector(T) -> __vector(T) of same size. // NG: __vector(T) -> __vector(T) of different size. // NG: explicit cast __vector(T) -> __vector(T) of different size. foreach (V; Vector16s) { static if (is(V == double2)) { static assert(!__traits(compiles, { long2 v = V.init; })); static assert( __traits(compiles, { long2 v = cast(long2)V.init; })); } else { static assert(!__traits(compiles, { double2 v = V.init; })); static assert( __traits(compiles, { double2 v = cast(double2)V.init; })); } static assert(!__traits(compiles, { double4 v = V.init; })); static assert(!__traits(compiles, { double4 v = cast(double4)V.init; })); } foreach (V; Vector32s) { static if (is(V == double4)) { static assert(!__traits(compiles, { long4 v = V.init; })); static assert( __traits(compiles, { long4 v = cast(long4)V.init; })); } else { static assert(!__traits(compiles, { double4 v = V.init; })); static assert( __traits(compiles, { double4 v = cast(double4)V.init; })); } static assert(!__traits(compiles, { double2 v = V.init; })); static assert(!__traits(compiles, { double2 v = cast(double2)V.init; })); } } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=17695 void test17695(__vector(ubyte[16]) a) { auto b = -a; } /*****************************************/ int main() { test1(); test2(); test2b(); test2c(); test2d(); test2e(); test2f(); test2g(); test2h(); test2i(); test2j(); test4(); test7411(); test7951(); test7951_2(); test7414(); test7413(); test7413_2(); // test9200(); test9304(); test9910(); test12852(); test9449(); test9449_2(); test13988(); test16448(); test16448_32(); test16703(); testOPvecunsto(); test10447(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/99bottles.d ================================================ // written by Don Clugston: // http://www.digitalmars.com/d/archives/digitalmars/D/announce/4374.html // http://www.99-bottles-of-beer.net/language-d-1212.html // Displays the "99 bottles of beer" song at compile time, // using the template metaprograming facilities of D. // No executable is generated. No libraries are used. // Illustrates template default values, template string value parameters, // compile-time concatenation of constant strings, static if. module bottles99; template decimaldigit(int n) { const string decimaldigit = "0123456789"[n..n+1]; } template itoa(ulong n) { static if ( n < 10L ) const string itoa = decimaldigit!(n); else const string itoa = itoa!( n / 10L ) ~ decimaldigit!( n % 10L ); } template showHowMany(int n, string where, bool needcapital = false) { static if ( n > 1 ) const string showHowMany = itoa!(n) ~ " bottles of beer" ~ where ~ "\n"; else static if ( n == 1 ) const string showHowMany = "1 bottle of beer" ~ where ~ "\n"; else static if ( needcapital ) const string showHowMany = "No more bottles of beer" ~ where ~ "\n"; else const string showHowMany = "no more bottles of beer" ~ where ~ "\n"; } template beer(int maxbeers, int n = maxbeers) { static if ( n > 0 ) const string beer = showHowMany!(n, " on the wall,", true) ~ showHowMany!(n, ".") ~ "Take one down and pass it around, " ~ "\n" ~ showHowMany!( n - 1 , " on the wall.") ~ "\n" ~ beer!(maxbeers, n - 1); // recurse for subsequent verses. else const string beer = showHowMany!(n, " on the wall,", true) ~ showHowMany!(n, ".") ~ "Go to the store and buy some more, " ~ "\n" ~ showHowMany!( maxbeers, " on the wall."); } pragma(msg, beer!(99)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/Test16206.d ================================================ struct S { static int foo()() { return 0; } static int foo()(int n) { return 1; } static int foo(string s) { return 2; } enum foo(int[] arr) = arr.length; } alias AliasSeq(T...) = T; alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", true)); static assert(allFoos.length == 4); static assert(allFoos[0]("") == 2); static assert(allFoos[1]() == 0); static assert(allFoos[2](1) == 1); alias foo3 = allFoos[3]; static assert(foo3!([]) == 0); static assert(S.foo() == 0); static assert(S.foo(1) == 1); static assert(S.foo("") == 2); static assert(S.foo!([]) == 0); alias fooFuns = AliasSeq!(__traits(getOverloads, S, "foo")); static assert(fooFuns.length == 1); static assert(fooFuns[0]("") == 2); ================================================ FILE: gcc/testsuite/gdc.test/compilable/a3682.d ================================================ // COMPILED_IMPORTS: imports/b3682.d // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=3682 struct Tuple(Types...) { Tuple!(Types[0..1]) slice()() { Tuple!(Types[0..1]) x; return x; } void fail() { Tuple!(float, double, int) a; auto s = a.slice(); static assert(is(typeof(s) == Tuple!(float))); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/aggr_alignment.d ================================================ struct S1 // overall alignment: max(1, 1) = 1 { byte[5] bytes; struct // overall alignment: max(1, 1) = 1 { byte byte1; align(1) int int1; } } static assert(S1.int1.offsetof == 6); static assert(S1.alignof == 1); static assert(S1.sizeof == 10); class C2 // overall alignment: max(vtbl.alignof, monitor.alignof, 1, 2) { byte[5] bytes; struct // overall alignment: max(1, 2) = 2 { byte byte1; align(2) int int1; } } enum payloadOffset = C2.bytes.offsetof; static assert(C2.int1.offsetof == payloadOffset + 8); static assert(C2.alignof == size_t.sizeof); static assert(__traits(classInstanceSize, C2) == payloadOffset + 12); align(8) struct PaddedStruct { bool flag; align(2) S1 s1; } static assert(PaddedStruct.s1.offsetof == 2); static assert(PaddedStruct.alignof == 8); static assert(PaddedStruct.sizeof == 16); align(1) struct UglyStruct { bool flag; int i; ubyte u; } static assert(UglyStruct.i.offsetof == 4); static assert(UglyStruct.alignof == 1); static assert(UglyStruct.sizeof == 9); ================================================ FILE: gcc/testsuite/gdc.test/compilable/aliasdecl.d ================================================ template Test(T){ alias Type = T; } alias X1 = int; static assert(is(X1 == int)); alias X2 = immutable(long)[], X3 = shared const double[int]; static assert(is(X2 == immutable(long)[])); static assert(is(X3 == shared const double[int])); alias X4 = void delegate() const, X5 = Test!int; static assert(is(X4 == void delegate() const)); static assert(is(X5.Type == int)); alias FP5 = extern(C) pure nothrow @safe @nogc void function(), DG5 = extern(D) pure nothrow @safe @nogc void delegate(); static assert(FP5.stringof == "extern (C) void function() pure nothrow " /* ~ "@safe " */ ~ "@nogc"); static assert(DG5.stringof == "void delegate() pure nothrow " /* ~ "@safe " */ ~ "@nogc"); void main() { alias Y1 = int; static assert(is(Y1 == int)); alias Y2 = immutable(long)[], Y3 = shared const double[int]; static assert(is(Y2 == immutable(long)[])); static assert(is(Y3 == shared const double[int])); alias Y4 = void delegate() const, Y5 = Test!int; static assert(is(Y4 == void delegate() const)); static assert(is(Y5.Type == int)); // https://issues.dlang.org/show_bug.cgi?id=18429 struct S { alias a this; enum a = 1; } /+ struct S { int value; alias this = value; } auto s = S(10); int n = s; assert(n == 10); +/ } ================================================ FILE: gcc/testsuite/gdc.test/compilable/alignment.d ================================================ /* Test alignment of stack variables. * * This test should be moved to "runnable" once DMD implements alignment of stack variables. */ void main() { byte dummy; align(32) int align32; assert((cast(size_t)&align32 & cast(size_t)0b11111) == 0); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/art4769.d ================================================ // http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.bugs&article_id=4769 // COMPILED_IMPORTS: imports/art4769a.d imports/art4769b.d // PERMUTE_ARGS: module art4769; private import imports.art4769a; struct Vector(T) { DataStreamability!(T).footype f; static if (DataStreamability!(T).isStreamable) void writeTo() { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b11118.d ================================================ struct X(size_t Z) { void set(T)(T[Z] v...) { } } void main() { X!3 a; a.set(1,2,3); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b1215.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -o- struct A(Args...) { enum i = 1; // base use case. Args[0].T mBase; static assert(is(typeof(mBase) == B.T)); // chained types Args[0].T.TT mChain; static assert(is(typeof(mChain) == B.T.TT)); // chained packs Args[1+1].FArgs[0] mChainPack; static assert(is(typeof(mChainPack) == B)); // expr enum mExpr = Args[1].i; static assert(mExpr == B.i); // Nested + index eval Args[Args[0].i2].T mNested; static assert(is(typeof(mNested) == B.T)); // index with constexpr Args[i].T mCEIndex; static assert(is(typeof(mCEIndex) == B.T)); // Nested + index with constexpr Args[Args[i].i2].T mNestedCE; static assert(is(typeof(mNestedCE) == B.T)); // alias, base use case alias UBase = Args[0].T; static assert(is(UBase == B.T)); // alias, chained types alias UChain = Args[0].T.TT; static assert(is(UChain == B.T.TT)); // alias, chained packs alias UChainPack = Args[1+1].FArgs[0]; static assert(is(UChainPack == B)); // alias, expr alias uExpr = Args[1].i; static assert(uExpr == B.i); // alias, Nested + index eval alias UNested = Args[Args[0].i2].T; static assert(is(UNested == B.T)); // alias, index with constexpr alias UCEIndex = Args[i].T; static assert(is(UCEIndex == B.T)); // alias, Nested + index with constexpr alias UNextedCE = Args[Args[i].i2].T; static assert(is(UNextedCE == B.T)); } struct B { struct T { struct TT { } } enum i = 6; enum i2 = 0; } struct C(Args...) { alias FArgs = Args; } alias Z = A!(B,B,C!(B,B)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14889 struct A14889(alias Exc) { alias ExceptionType = Exc; } alias TT14889(Args...) = Args; alias X14889a = TT14889!(A14889!Throwable()); alias Y14889a = X14889a[0].ExceptionType; alias X14889b = TT14889!(A14889!Throwable); alias Y14889b = X14889b[0].ExceptionType; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14889 alias TypeTuple14900(T...) = T; struct S14900 { alias T = int; alias U = TypeTuple14900!(long,string); } alias Types14900 = TypeTuple14900!(S14900, S14900); Types14900[0].T a14900; // Types[0] == S, then typeof(a) == S.T == int Types14900[0].U[1] b14900; // Types[0].U == S.U, then typeof(b) == S.U[1] == string void test14900() { Types14900[0].T a; // Types[0] == S, then typeof(a) == S.T == int Types14900[0].U[1] b; // Types[0].U == S.U, then typeof(b) == S.U[1] == string } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14911 void test14911() { struct S {} int* buf1 = new int[2].ptr; // OK S* buf2 = (new S[2]).ptr; // OK S* buf3 = new S[2].ptr; // OK <- broken } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14986 alias Id14986(alias a) = a; struct Foo14986 { int tsize; } struct Bar14986 { enum Foo14986[] arr = [Foo14986()]; } Bar14986 test14986() { Foo14986[] types; auto a1 = new void[types[0].tsize]; // TypeIdentifier::toExpression auto a2 = new void[Id14986!types[0].tsize]; // TypeInstance::toExpression Bar14986 bar; auto a3 = Id14986!(typeof(bar).arr[0].tsize); // TypeTypeof::resolve auto a4 = Id14986!(typeof(return).arr[0].tsize); // TypeReturn::resolve return Bar14986(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b15428.d ================================================ class A { this() {} } class B : A { this() { static if (__traits(compiles, super())) super(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16244.d ================================================ struct Foo { void bar()(typeof(cast()this) x) { } } void main() { Foo x; x.bar(x); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16346.d ================================================ enum A { B } static assert(is(typeof(A.B) == A)); static assert(is(typeof(A(A.B)) == A)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16355.d ================================================ // REQUIRED_ARGS: -c struct S0 { this(this) {} } struct S1 { S0[2] x; } struct S2 { S0[0] x; } // S0 has an explicit and a compiler-generated postblit static assert( __traits(hasMember, S0, "__postblit")); static assert( __traits(hasMember, S0, "__xpostblit")); // S1 has only the compiler-generated postblit static assert(!__traits(hasMember, S1, "__postblit")); static assert( __traits(hasMember, S1, "__xpostblit")); // S2 has no postblit at all since the x array has zero length static assert(!__traits(hasMember, S2, "__postblit")); static assert(!__traits(hasMember, S2, "__xpostblit")); ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16382.d ================================================ // REQUIRED_ARGS: -c struct S0 { void foo() { pragma(msg, &this); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16483.d ================================================ struct S { enum a = is(typeof(false.bar!(x => x))); // The lambda compiles enum b = is(typeof(false.bar!(x => y))); // The lambda doesn't compile } auto bar(alias foo)(bool var) { return foo(var); } static assert(is(typeof(S.a) == bool)); static assert(S.a == true); static assert(S.b == false); ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16598.d ================================================ struct S { this(int) {} ~this() {} } int g(S a, S b) { return 1; } void main() { true ? g(S(), S(1)) : {}(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16697.d ================================================ version(D_SIMD) { static assert(!is( float == __vector)); static assert(!is( float[1] == __vector)); static assert(!is( float[4] == __vector)); static assert( is(__vector(float[4]) == __vector)); static assert(!is(__vector(float[3]) == __vector)); static assert(!is(__vector(float[5]) == __vector)); static assert( is(__vector(float[4]) X == __vector) && is(X == float[4])); static assert( is(__vector(byte[16]) X == __vector) && is(X == byte[16])); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b16967.d ================================================ /* * REQUIRED_ARGS: -c * TEST_OUTPUT: --- compilable/b16967.d(16): Deprecation: switch case fallthrough - use 'goto default;' if intended compilable/b16967.d(26): Deprecation: switch case fallthrough - use 'goto default;' if intended --- */ int foo(int x) in { switch (x) { case 1: assert(x != 0); default: break; } } out(v) { switch(v) { case 42: assert(x != 0); default: break; } } body { return 42; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b17111.d ================================================ alias TestType = ubyte; void test() { TestType a,b,c; switch(c) { case a: break; case (cast(ushort)b): break; default: assert(false); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b18197.d ================================================ // REQUIRED_ARGS: -c -m32 -O -inline struct A { double a; } A makeA(double value) { return A(value); } double test(double x) { ulong p = *cast(ulong *)&x; return makeA(x).a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b18242.d ================================================ // REQUIRED_ARGS: -c // PERMUTE_ARGS: module object; class Object { } class TypeInfo { } class TypeInfo_Class : TypeInfo { version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; } } class Throwable { } int _d_run_main() { try { } catch(Throwable e) { return 1; } return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b18489.d ================================================ // REQUIRED_ARGS: -O -m64 import core.simd; double dot (double2 a) { return a.ptr[0] * a.ptr[1]; } void main () { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b33.d ================================================ // COMPILED_IMPORTS: imports/b33a.d // PERMUTE_ARGS: module b33; private import imports.b33a; size_t fn() { return find( "123" ); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/b6227.d ================================================ enum X { O, R } enum Y { U } static assert( (X.O == cast(const)X.O)); static assert( (X.O == X.O)); static assert( (X.O != X.R)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/b6395.d ================================================ // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_FILES: extra-files/c6395.d // https://issues.dlang.org/show_bug.cgi?id=6395 import c6395; int regex(string pattern) { return 0; } bool match(string r) { return true; } void applyNoRemoveRegex() { void scan(string[] noRemoveStr, string e) { auto a = find!((a){return match(e);})(map!regex(noRemoveStr)); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/betterCarray.d ================================================ /* REQUIRED_ARGS: -betterC PERMUTE_ARGS: */ import core.stdc.stdio; extern (C) int main(char** argv, int argc) { printf("hello world\n"); int[3] a; foo(a[], 3); return 0; } int foo(int[] a, int i) { return a[i]; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/betterCswitch.d ================================================ import core.stdc.stdio; extern (C) int main(char** argv, int argc) { printf("hello world\n"); foo(3); return 0; } int foo(int i) { final switch (i) { case 1: break; } return i; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/betterc.d ================================================ /* REQUIRED_ARGS: -betterC */ // https://issues.dlang.org/show_bug.cgi?id=17787 version (D_BetterC) { } else { static assert(0); } // -betterC does not support `ModuleInfo`, `TypeInfo`, or exception handling version (D_ModuleInfo) { static assert(0); } version (D_Exceptions) { static assert(0); } version (D_TypeInfo) { static assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/bug11735.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: /* TEST_OUTPUT: --- print string print wstring print dstring يطبع الترميز الموحد يطبع الترميز الموحد يطبع الترميز الموحد foo_str foo_wstr foo_dstr --- */ pragma(msg, "print string"); pragma(msg, "print wstring"w); pragma(msg, "print dstring"d); pragma(msg, "يطبع الترميز الموحد"); pragma(msg, "يطبع الترميز الموحد"w); pragma(msg, "يطبع الترميز الموحد"d); void main() { enum a = "foo_str"; enum b = "foo_wstr"w; enum c = "foo_dstr"d; pragma(msg, a); pragma(msg, b); pragma(msg, c); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/bug6963.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: /* TEST_OUTPUT: --- output foo: 1e: pure nothrow @nogc @safe void(int x) output foo: 3e: pure nothrow @nogc @safe void(int x) --- */ alias void function(int) pure nothrow @safe @nogc FuncPtrType; void foo1a(X)(X x) {} void foo1b(X)(X x) {} void foo1c(X)(X x) {} void foo1d(X)(X x) {} void foo1e(X)(X x) {} // module level declaration with type inference auto fptr1 = &foo1a!int; static assert(is(typeof(fptr1) == FuncPtrType)); // array initializer auto fptrlist1 = [&foo1b!int]; static assert(is(typeof(fptrlist1) == FuncPtrType[])); // static assert static assert(is(typeof(&foo1c!int) == FuncPtrType)); // static if static if(is(typeof(&foo1d!int) PF)) static assert(is(PF == FuncPtrType)); else static assert(0); // pragma test pragma(msg, "output foo: 1e: ", typeof(foo1e!int).stringof); void foo2a(X)(X x) {} void foo2b(X)(X x) {} void foo2c(X)(X x) {} FuncPtrType fptr3 = &foo2a!int; // most similar to original issue FuncPtrType[] fptrlist3 = [&foo2b!int]; struct S{ FuncPtrType fp; } S s = { &foo2c!int }; void foo3a(X)(X x) {} void foo3b(X)(X x) {} void foo3c(X)(X x) {} void foo3d(X)(X x) {} void foo3e(X)(X x) {} void main() { auto fptr2 = &foo3a!int; static assert(is(typeof(fptr2) == FuncPtrType)); auto fptrlist2 = [&foo3b!int]; static assert(is(typeof(fptrlist2) == FuncPtrType[])); static assert(is(typeof(&foo1c!int) == FuncPtrType)); static if(is(typeof(&foo1d!int) PF)) static assert(is(PF == FuncPtrType)); else static assert(0); pragma(msg, "output foo: 3e: ", typeof(foo3e!int)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/callconv.d ================================================ // PERMUTE_ARGS: import core.stdc.stdarg; struct ABC { int[4] x; } ABC abc; int x,y,z; extern (Pascal): ABC test1(int xx, int yy, int zz) { x = xx; y = yy; z = zz; return abc; } extern (Pascal): ABC test1v(int xx, int yy, int zz, ...) { x = xx; y = yy; z = zz; return abc; } extern (C): ABC test2v(int xx, int yy, int zz, ...) { x = xx; y = yy; z = zz; return abc; } extern (C++): ABC test3(int xx, int yy, int zz) { x = xx; y = yy; z = zz; return abc; } ABC test3v(int xx, int yy, int zz, ...) { x = xx; y = yy; z = zz; return abc; } extern (D): ABC test4(int xx, int yy, int zz) { x = xx; y = yy; z = zz; return abc; } ABC test4v(int xx, int yy, int zz, ...) { x = xx; y = yy; z = zz; return abc; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/checkimports3.d ================================================ /* REQUIRED_ARGS: -transition=checkimports -de */ import imports.checkimports3a; import imports.checkimports3b; import imports.checkimports3c; void test() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/compile1.d ================================================ // PERMUTE_ARGS: /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=1748 // class template with stringof struct S1748(T) {} static assert(S1748!int.stringof == "S1748!int"); class C1748(T) {} static assert(C1748!int.stringof == "C1748!int"); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=2354 // pragma + single semicolon DeclarationBlock version(all) pragma(msg, "true"); else pragma(msg, "false"); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=2438 alias void delegate() Dg2438; alias typeof(Dg2438.ptr) CP2438a; alias typeof(Dg2438.funcptr) FP2438a; static assert(is(CP2438a == void*)); static assert(is(FP2438a == void function())); alias typeof(Dg2438.init.ptr) CP2438b; alias typeof(Dg2438.init.funcptr) FP2438b; static assert(is(CP2438b == void*)); static assert(is(FP2438b == void function())); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4225 struct Foo4225 { enum x = Foo4225(); static Foo4225 opCall() { return Foo4225.init; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5996 // ICE(expression.c) template T5996(T) { auto bug5996() { if (anyOldGarbage) {} return 2; } } static assert(!is(typeof(T5996!(int).bug5996()))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8532 // segfault(mtype.c) - type inference + pure auto segfault8532(Y, R ...)(R r, Y val) pure { return segfault8532(r, val); } static assert(!is(typeof( segfault8532(1,2,3)))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8982 // ICE(ctfeexpr.c) __parameters with error in default value template ice8982(T) { void bug8982(ref const int v = 7){} static if (is(typeof(bug8982) P == __parameters)) { pragma(msg, ((P[0..1] g) => g[0])()); } } static assert(!is(ice8982!(int))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8801 // ICE assigning to __ctfe static assert(!is(typeof( { bool __ctfe= true; }))); static assert(!is(typeof( { __ctfe |= true; }))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5932 // https://issues.dlang.org/show_bug.cgi?id=6675 // ICE(s2ir.c), ICE(glue.c) void bug3932(T)() { static assert( 0 ); func5932( 7 ); } void func5932(T)( T val ) { void onStandardMsg() { foreach( t; T ) { } } } static assert(!is(typeof( { bug3932!(int)(); }() ))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6650 // ICE(glue.c) or wrong-code auto bug6650(X)(X y) { X q; q = "abc"; return y; } static assert(!is(typeof(bug6650!(int)(6)))); static assert(!is(typeof(bug6650!(int)(18)))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14710 // VC-built DMD crashes on templated variadic function IFTI void bug14710a(T)(T val, T[] arr...) { } void bug14710b() { bug14710a("", ""); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6661 // Templates instantiated only through is(typeof()) shouldn't cause errors template bug6661(Q) { int qutz(Q y) { Q q = "abc"; return 67; } static assert(qutz(13).sizeof!=299); const Q blaz = 6; } static assert(!is(typeof(bug6661!(int).blaz))); template bug6661x(Q) { int qutz(Q y) { Q q = "abc"; return 67; } } // should pass, but doesn't in current //static assert(!is(typeof(bug6661x!(int)))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6599 // ICE(constfold.c) or segfault string bug6599extraTest(string x) { return x ~ "abc"; } template Bug6599(X) { class Orbit { Repository repository = Repository(); } struct Repository { string fileProtocol = "file://"; string blah = bug6599extraTest("abc"); string source = fileProtocol ~ "/usr/local/orbit/repository"; } } static assert(!is(typeof(Bug6599!int))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8422 // TypeTuple of tuples can't be read at compile time template TypeTuple8422(TList...) { alias TList TypeTuple8422; } struct S8422 { int x; } void test8422() { enum a = S8422(1); enum b = S8422(2); enum c = [1,2,3]; foreach(t; TypeTuple8422!(b, a)) { enum u = t; } foreach(t; TypeTuple8422!(c)) { enum v = t; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6096 // ICE(el.c) with -O cdouble c6096; int bug6096() { if (c6096) return 0; return 1; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7681 // Segfault static assert( !is(typeof( (){ undefined ~= delegate(){}; return 7; }()))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8639 // Buffer overflow void t8639(alias a)() {} void bug8639() { t8639!({auto r = -real.max;})(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7751 // Segfault static assert( !is(typeof( (){ bar[]r; r ~= []; return 7; }()))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7639 // Segfault static assert( !is(typeof( (){ enum foo = [ str : "functions", ]; }))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11991 void main() { int Throwable; int object; try { } catch(.object.Throwable) { } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11939 void test11939() { scope(failure) { import object : Object; } throw new Exception(""); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5796 template A(B) { pragma(msg, "missing ;") enum X = 0; } static assert(!is(typeof(A!(int)))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6720 void bug6720() { } static assert(!is(typeof( cast(bool)bug6720() ))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=1099 template Mix1099(int a) { alias typeof(this) ThisType; static assert (ThisType.init.tupleof.length == 2); } struct Foo1099 { mixin Mix1099!(0); int foo; mixin Mix1099!(1); int bar; mixin Mix1099!(2); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8788 // super() and return class B8788 { this ( ) { } } class C8788(int test) : B8788 { this ( int y ) { // TESTS WHICH SHOULD PASS static if (test == 1) { if (y == 3) { super(); return; } super(); return; } else static if (test == 2) { if (y == 3) { super(); return; } super(); } else static if (test == 3) { if (y > 3) { if (y == 7) { super(); return; } super(); return; } super(); } else static if (test == 4) { if (y > 3) { if (y == 7) { super(); return; } else if (y> 5) super(); else super(); return; } super(); } // TESTS WHICH SHOULD FAIL else static if (test == 5) { if (y == 3) { super(); return; } return; // no super } else static if (test == 6) { if (y > 3) { if (y == 7) { super(); return; } super(); } super(); // two calls } else static if (test == 7) { if (y == 3) { return; // no super } super(); } else static if (test == 8) { if (y > 3) { if (y == 7) { return; // no super } super(); return; } super(); } else static if (test == 9) { if (y > 3) { if (y == 7) { super(); return; } else if (y> 5) super(); else return; // no super return; } super(); } } } static assert( is(typeof( { new C8788!(1)(0); } ))); static assert( is(typeof( { new C8788!(2)(0); } ))); static assert( is(typeof( { new C8788!(3)(0); } ))); static assert( is(typeof( { new C8788!(4)(0); } ))); static assert(!is(typeof( { new C8788!(5)(0); } ))); static assert(!is(typeof( { new C8788!(6)(0); } ))); static assert(!is(typeof( { new C8788!(7)(0); } ))); static assert(!is(typeof( { new C8788!(8)(0); } ))); static assert(!is(typeof( { new C8788!(9)(0); } ))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4967 // https://issues.dlang.org/show_bug.cgi?id=7058 enum Bug7058 bug7058 = { 1.5f, 2}; static assert(bug7058.z == 99); struct Bug7058 { float x = 0; float y = 0; float z = 99; } /***************************************************/ void test12094() { auto n = null; int *a; int[int] b; int[] c; auto u = true ? null : a; auto v = true ? null : b; auto w = true ? null : c; auto x = true ? n : a; auto y = true ? n : b; auto z = true ? n : c; a = n; b = n; c = n; } /***************************************************/ template test8163(T...) { struct Point { T fields; } enum N = 2; // N>=2 triggers the bug extern Point[N] bar(); void foo() { Point[N] _ = bar(); } } alias test8163!(long) _l; alias test8163!(double) _d; alias test8163!(float, float) _ff; alias test8163!(int, int) _ii; alias test8163!(int, float) _if; alias test8163!(ushort, ushort, ushort, ushort) _SSSS; alias test8163!(ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte) _BBBBBBBB; alias test8163!(ubyte, ubyte, ushort, float) _BBSf; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4757 auto foo4757(T)(T) { static struct Bar(T) { void spam() { foo4757(1); } } return Bar!T(); } void test4757() { foo4757(1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9348 void test9348() { @property Object F(int E)() { return null; } assert(F!0 !is null); assert(F!0 !in [new Object():1]); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9690 @disable { void dep9690() {} void test9690() { dep9690(); // OK void inner() { dep9690(); // OK <- NG } } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9987 static if (is(object.ModuleInfo == struct)) { struct ModuleInfo {} static assert(!is(object.ModuleInfo == ModuleInfo)); static assert(object.ModuleInfo.sizeof != ModuleInfo.sizeof); } static if (is(object.ModuleInfo == class)) { class ModuleInfo {} static assert(!is(object.ModuleInfo == ModuleInfo)); static assert(__traits(classInstanceSize, object.ModuleInfo) != __traits(classInstanceSize, ModuleInfo)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10158 class Outer10158 { static struct Inner { int f; } void test() { static assert( Inner.f .offsetof == 0); // OK <- NG static assert((Inner.f).offsetof == 0); // OK } } void test10158() { static assert(Outer10158.Inner.f.offsetof == 0); // OK } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10326 class C10326 { int val; invariant { assert(val == 0); } invariant() { assert(val == 0); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11042 static if ((true || error) == true ) {} else { static assert(0); } static if ((false && error) == false) {} else { static assert(0); } static assert ((true || error) == true ); static assert ((false && error) == false); int f11042a1()() if ((true || error) == true ) { return 0; } enum x11042a1 = f11042a1(); int f11042b1()() if ((false && error) == false) { return 0; } enum x11042b1 = f11042b1(); static if (is(typeof(true || error)) == false) {} else { static assert(0); } static if (is(typeof(false && error)) == false) {} else { static assert(0); } static assert (is(typeof(true || error)) == false); static assert (is(typeof(false && error)) == false); int f11042a2()() if (is(typeof(true || error)) == false) { return 0; } enum x11042a2 = f11042a2(); int f11042b2()() if (is(typeof(false && error)) == false) { return 0; } enum x11042b2 = f11042b2(); static if (__traits(compiles, true || error) == false) {} else { static assert(0); } static if (__traits(compiles, false && error) == false) {} else { static assert(0); } static assert (__traits(compiles, true || error) == false); static assert (__traits(compiles, false && error) == false); int f11042a3()() if (__traits(compiles, true || error) == false) { return 0; } enum x11042a3 = f11042a3(); int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; } enum x11042b3 = f11042b3(); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11554 enum E11554; static assert(is(E11554 == enum)); struct Bro11554(N...) {} static assert(!is(E11554 unused : Bro11554!M, M...)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12302 template isCallable12302(T...) if (T.length == 1) { static if (is(typeof(& T[0].opCall) == delegate)) enum bool isCallable12302 = true; else static if (is(typeof(& T[0].opCall) V : V*) && is(V == function)) enum bool isCallable12302 = true; else enum bool isCallable12302 = true; } class A12302 { struct X {} X x; auto opDispatch(string s, TArgs...)(TArgs args) { mixin("return x."~s~"(args);"); } } A12302 func12302() { return null; } enum b12302 = isCallable12302!func12302; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12476 template A12476(T) { } struct S12476(T) { alias B = A12476!T; } class C12476(T) { alias B = A12476!T; } struct Bar12476(alias Foo) { Foo!int baz; alias baz this; } alias Identity12476(alias A) = A; alias sb12476 = Identity12476!(Bar12476!S12476.B); alias cb12476 = Identity12476!(Bar12476!C12476.B); static assert(__traits(isSame, sb12476, A12476!int)); static assert(__traits(isSame, cb12476, A12476!int)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12506 import imports.a12506; private bool[9] r12506a = f12506!(i => true)(); // OK private immutable bool[9] r12506b = f12506!(i => true)(); // OK <- error /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12555 class A12555(T) { Undef12555 error; } static assert(!__traits(compiles, { class C : A12555!C { } })); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11622 class A11622(T) { B11622!T foo() { return new B11622!T; } } class B11622(T) : T { } static assert(!__traits(compiles, { class C : A11622!C { } })); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12688 void writeln12688(A...)(A) {} struct S12688 { int foo() @property { return 1; } } void test12688() { S12688 s; s.foo.writeln12688; // ok (s.foo).writeln12688; // ok <- ng } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12703 struct S12703 { this(int) {} } final class C12703 { S12703 s = S12703(1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12799 struct A12799 { int a; enum C = A12799.sizeof; enum D = C; // OK <- Error } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13236 pragma(msg, is(typeof({ struct S { S x; } }))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13280 struct S13280 { alias U = ubyte; alias T1 = ubyte[this.sizeof]; // ok alias T2 = const U[this.sizeof]; // ok alias T3 = const ubyte[this.sizeof]; // ok <- error } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13481 mixin template Mix13481(void function() callback) { static this() { callback(); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13564 class E13564(T) { int pos; } class C13564(T) { struct S { ~this() { C13564!int c; c.element.pos = 0; } } E13564!T element; } void test13564() { auto c = new C13564!int(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14166 struct Proxy14166(T) { T* ptr; ref deref() { return *ptr; } alias deref this; } struct Test14166 { auto opIndex() { return this; } auto opIndex(int) { return 1; } } template Elem14166a(R) { alias Elem14166a = typeof(R.init[][0]); } template Elem14166b(R) { alias Elem14166b = typeof(R.init[0]); } void test14166() { alias T = Proxy14166!Test14166; static assert(is(Elem14166a!T == int)); // rejects-valid case static assert(is(Elem14166b!T == int)); // regression case } // other related cases struct S14166 { int x; double y; int[] a; S14166 opUnary(string op : "++")() { return this; } } S14166 s14166; struct X14166 { this(int) { } X14166 opAssign(int) { return this; } } X14166[int] aa14166; X14166[int] makeAA14166() { return aa14166; } struct Tup14166(T...) { T field; alias field this; } Tup14166!(int, int) tup14166; Tup14166!(int, int) makeTup14166() { return tup14166; } pragma(msg, typeof((s14166.x += 1) = 2)); // ok <- error pragma(msg, typeof(s14166.a.length += 2)); // ok <- error pragma(msg, typeof(s14166++)); // ok <- error pragma(msg, typeof(s14166.x ^^ 2)); // ok <- error pragma(msg, typeof(s14166.y ^^= 2.5)); // ok <- error pragma(msg, typeof(makeAA14166()[0] = 1)); // ok <- error pragma(msg, typeof(tup14166.field = makeTup14166())); // ok <- error /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14388 @property immutable(T)[] idup14388(T)(T[] a) { alias U = immutable(T); U[] res; foreach (ref e; a) res ~= e; return res; } struct Data14388(A14388 a) { auto foo() { return Data14388!a.init; // [B] } } struct A14388 { struct Item {} immutable(Item)[] items; this(int dummy) { items = [Item()].idup14388; } } void test14388() { auto test = Data14388!(A14388(42)).init.foo(); // [A] /* * A(42) is interpreter to a struct literal A([immutable(Item)()]). * The internal VarDeclaration with STCmanifest for the Data's template parameteter 'a' * calls syntaxCopy() on its ((ExpInitializer *)init)->exp in VarDeclaration::semantic(), * and 'immutable(Item)()'->syntaxCopy() had incorrectly removed the qualifier. * Then, the arguments of two Data template instances at [A] and [B] had become unmatch, * and the second instantiation had created the AST duplication. */ } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15163 void function() func15164(int[] arr) { return () { }; } void test15163() { auto arr = [[0]]; func15164(arr[0])(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3438 import core.vararg; struct S3438_1 { this(int x, int y = 1) { } } struct S3438_2 { this(int x, ...) { } } struct S3438_3 { this(int x, int[] arr...) { } } struct S3438_4 { this(...) { } } struct S3438_5 { this(int[] arr...) { } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15362 void func15362() { assert(true); assert(true,); assert(true, "So true"); assert(true, "Very, very true",); static assert(true); static assert(true,); static assert(true, "So true"); static assert(true, "Very, very true",); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15799 interface I15799 { void funA(); void funB(int n) in { assert(n); }; // Semicolon is not a part of function declaration. It's an empty declaration. } ================================================ FILE: gcc/testsuite/gdc.test/compilable/const.d ================================================ static assert(2.0 * 3.0 == 6 ); static assert(2.0 * 3.0i == 6i); static assert(2.0i * 3.0 == 6i); static assert(2.0i * 3.0i == -6 ); static assert(2.0 * (4.0 + 3.0i) == 8 + 6i); static assert(2.0i * (4.0 + 3.0i) == 8i - 6 ); static assert((4.0 + 3.0i) * 2.0 == 8 + 6i); static assert((4.0 + 3.0i) * 2.0i == 8i - 6 ); static assert((4.0 + 3.0i) * (5 + 7i) == -1 + 43i ); static assert((2.0).re == 2); static assert((2.0i).re == 0); static assert((3+2.0i).re == 3); static assert((4.0i).im == 4); static assert((2.0i).im == 2); static assert((3+2.0i).im == 2); static assert(6.0 / 2.0 == 3); static assert(6i / 2i == 3); static assert(6 / 2i == -3i); static assert(6i / 2 == 3i); static assert((6 + 4i) / 2 == 3 + 2i); static assert((6 + 4i) / 2i == -3i + 2); //static assert(2 / (6 + 4i) == -3i); //static assert(2i / (6 + 4i) == 3i); //static assert((1 + 2i) / (6 + 4i) == 3i); static assert(6.0 % 2.0 == 0); static assert(6.0 % 3.0 == 0); static assert(6.0 % 4.0 == 2); static assert(6.0i % 2.0i == 0); static assert(6.0i % 3.0i == 0); static assert(6.0i % 4.0i == 2i); ================================================ FILE: gcc/testsuite/gdc.test/compilable/cppmangle.d ================================================ // Test C++ name mangling. // https://issues.dlang.org/show_bug.cgi?id=4059 // https://issues.dlang.org/show_bug.cgi?id=5148 // https://issues.dlang.org/show_bug.cgi?id=7024 // https://issues.dlang.org/show_bug.cgi?id=10058 import core.stdc.stdio; extern (C++) int foob(int i, int j, int k); class C { extern (C++) int bar(int i, int j, int k) { printf("this = %p\n", this); printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); return 1; } } extern (C++) int foo(int i, int j, int k) { printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); assert(i == 1); assert(j == 2); assert(k == 3); return 1; } void test1() { foo(1, 2, 3); auto i = foob(1, 2, 3); assert(i == 7); C c = new C(); c.bar(4, 5, 6); } version (linux) { static assert(foo.mangleof == "_Z3fooiii"); static assert(foob.mangleof == "_Z4foobiii"); static assert(C.bar.mangleof == "_ZN1C3barEiii"); } version (Win32) { static assert(foo.mangleof == "?foo@@YAHHHH@Z"); static assert(foob.mangleof == "?foob@@YAHHHH@Z"); static assert(C.bar.mangleof == "?bar@C@@UAEHHHH@Z"); } version (Win64) { static assert(foo.mangleof == "?foo@@YAHHHH@Z"); static assert(foob.mangleof == "?foob@@YAHHHH@Z"); static assert(C.bar.mangleof == "?bar@C@@UEAAHHHH@Z"); } /****************************************/ extern (C++) interface D { int bar(int i, int j, int k); } extern (C++) D getD(); void test2() { D d = getD(); int i = d.bar(9,10,11); assert(i == 8); } version (linux) { static assert (getD.mangleof == "_Z4getDv"); static assert (D.bar.mangleof == "_ZN1D3barEiii"); } /****************************************/ extern (C++) int callE(E); extern (C++) interface E { int bar(int i, int j, int k); } class F : E { extern (C++) int bar(int i, int j, int k) { printf("F.bar: i = %d\n", i); printf("F.bar: j = %d\n", j); printf("F.bar: k = %d\n", k); assert(i == 11); assert(j == 12); assert(k == 13); return 8; } } void test3() { F f = new F(); int i = callE(f); assert(i == 8); } version (linux) { static assert (callE.mangleof == "_Z5callEP1E"); static assert (E.bar.mangleof == "_ZN1E3barEiii"); static assert (F.bar.mangleof == "_ZN1F3barEiii"); } /****************************************/ extern (C++) void foo4(char* p); void test4() { foo4(null); } version (linux) { static assert(foo4.mangleof == "_Z4foo4Pc"); } /****************************************/ extern(C++) { struct foo5 { int i; int j; void* p; } interface bar5{ foo5 getFoo(int i); } bar5 newBar(); } void test5() { bar5 b = newBar(); foo5 f = b.getFoo(4); printf("f.p = %p, b = %p\n", f.p, cast(void*)b); assert(f.p == cast(void*)b); } version (linux) { static assert(bar5.getFoo.mangleof == "_ZN4bar56getFooEi"); static assert (newBar.mangleof == "_Z6newBarv"); } /****************************************/ extern(C++) { struct S6 { int i; double d; } S6 foo6(); } extern (C) int foosize6(); void test6() { S6 f = foo6(); printf("%d %d\n", foosize6(), S6.sizeof); assert(foosize6() == S6.sizeof); assert(f.i == 42); printf("f.d = %g\n", f.d); assert(f.d == 2.5); } version (linux) { static assert (foo6.mangleof == "_Z4foo6v"); } /****************************************/ extern (C) int foo7(); struct S { int i; long l; } void test7() { printf("%d %d\n", foo7(), S.sizeof); assert(foo7() == S.sizeof); } /****************************************/ extern (C++) void foo8(const char *); void test8() { char c; foo8(&c); } version (linux) { static assert(foo8.mangleof == "_Z4foo8PKc"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=4059 struct elem9 { } extern(C++) void foobar9(elem9*, elem9*); void test9() { elem9 *a; foobar9(a, a); } version (linux) { static assert(foobar9.mangleof == "_Z7foobar9P5elem9S0_"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=5148 extern (C++) { void foo10(const char*, const char*); void foo10(const int, const int); void foo10(const char, const char); struct MyStructType { } void foo10(const MyStructType s, const MyStructType t); enum MyEnumType { onemember } void foo10(const MyEnumType s, const MyEnumType t); } void test10() { char* p; foo10(p, p); foo10(1,2); foo10('c','d'); MyStructType s; foo10(s,s); MyEnumType e; foo10(e,e); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=10058 extern (C++) { void test10058a(void*) { } void test10058b(void function(void*)) { } void test10058c(void* function(void*)) { } void test10058d(void function(void*), void*) { } void test10058e(void* function(void*), void*) { } void test10058f(void* function(void*), void* function(void*)) { } void test10058g(void function(void*), void*, void*) { } void test10058h(void* function(void*), void*, void*) { } void test10058i(void* function(void*), void* function(void*), void*) { } void test10058j(void* function(void*), void* function(void*), void* function(void*)) { } void test10058k(void* function(void*), void* function(const (void)*)) { } void test10058l(void* function(void*), void* function(const (void)*), const(void)* function(void*)) { } } version (linux) { static assert(test10058a.mangleof == "_Z10test10058aPv"); static assert(test10058b.mangleof == "_Z10test10058bPFvPvE"); static assert(test10058c.mangleof == "_Z10test10058cPFPvS_E"); static assert(test10058d.mangleof == "_Z10test10058dPFvPvES_"); static assert(test10058e.mangleof == "_Z10test10058ePFPvS_ES_"); static assert(test10058f.mangleof == "_Z10test10058fPFPvS_ES1_"); static assert(test10058g.mangleof == "_Z10test10058gPFvPvES_S_"); static assert(test10058h.mangleof == "_Z10test10058hPFPvS_ES_S_"); static assert(test10058i.mangleof == "_Z10test10058iPFPvS_ES1_S_"); static assert(test10058j.mangleof == "_Z10test10058jPFPvS_ES1_S1_"); static assert(test10058k.mangleof == "_Z10test10058kPFPvS_EPFS_PKvE"); static assert(test10058l.mangleof == "_Z10test10058lPFPvS_EPFS_PKvEPFS3_S_E"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=11696 class Expression; struct Loc {} extern(C++) class CallExp { static void test11696a(Loc, Expression, Expression); static void test11696b(Loc, Expression, Expression*); static void test11696c(Loc, Expression*, Expression); static void test11696d(Loc, Expression*, Expression*); } version (linux) { static assert(CallExp.test11696a.mangleof == "_ZN7CallExp10test11696aE3LocP10ExpressionS2_"); static assert(CallExp.test11696b.mangleof == "_ZN7CallExp10test11696bE3LocP10ExpressionPS2_"); static assert(CallExp.test11696c.mangleof == "_ZN7CallExp10test11696cE3LocPP10ExpressionS2_"); static assert(CallExp.test11696d.mangleof == "_ZN7CallExp10test11696dE3LocPP10ExpressionS3_"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=13337 extern(C++, N13337a.N13337b.N13337c) { struct S13337{} void foo13337(S13337 s); } version (linux) { static assert(foo13337.mangleof == "_ZN7N13337a7N13337b7N13337c8foo13337ENS1_6S13337E"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=15789 extern (C++) void test15789a(T...)(T args); void test15789() { test15789a(0); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=7030 extern(C++) { struct T { void foo(int) const; void bar(int); static __gshared int boo; } } version (Posix) { static assert(T.foo.mangleof == "_ZNK1T3fooEi"); static assert(T.bar.mangleof == "_ZN1T3barEi"); static assert(T.boo.mangleof == "_ZN1T3booE"); } /****************************************/ // Special cases of Itanium mangling extern (C++, std) { struct pair(T1, T2) { void swap(ref pair other); } struct allocator(T) { uint fooa() const; uint foob(); } struct basic_string(T1, T2, T3) { uint fooa(); } struct basic_istream(T1, T2) { uint fooc(); } struct basic_ostream(T1, T2) { uint food(); } struct basic_iostream(T1, T2) { uint fooe(); } struct char_traits(T) { uint foof(); } struct vector (T); struct test18957 {} } version (linux) { // https://issues.dlang.org/show_bug.cgi?id=17947 static assert(std.pair!(void*, void*).swap.mangleof == "_ZNSt4pairIPvS0_E4swapERS1_"); static assert(std.allocator!int.fooa.mangleof == "_ZNKSaIiE4fooaEv"); static assert(std.allocator!int.foob.mangleof == "_ZNSaIiE4foobEv"); static assert(std.basic_string!(char,int,uint).fooa.mangleof == "_ZNSbIcijE4fooaEv"); static assert(std.basic_string!(char, std.char_traits!char, std.allocator!char).fooa.mangleof == "_ZNSs4fooaEv"); static assert(std.basic_istream!(char, std.char_traits!char).fooc.mangleof == "_ZNSi4foocEv"); static assert(std.basic_ostream!(char, std.char_traits!char).food.mangleof == "_ZNSo4foodEv"); static assert(std.basic_iostream!(char, std.char_traits!char).fooe.mangleof == "_ZNSd4fooeEv"); } /**************************************/ alias T36 = int ********** ********** ********** **********; extern (C++) void test36(T36, T36*) { } version (linux) { static assert(test36.mangleof == "_Z6test36PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPiPS12_"); } /*****************************************/ // https://issues.dlang.org/show_bug.cgi?id=17772 extern(C++, SPACE) int test37(T)(){ return 0;} version (Posix) // all non-Windows machines { static assert(test37!int.mangleof == "_ZN5SPACE6test37IiEEiv"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=15388 extern (C++) void test15388(typeof(null)); version (Posix) { static assert(test15388.mangleof == "_Z9test15388Dn"); } version (Windows) { static assert(test15388.mangleof == "?test15388@@YAX$$T@Z"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=14086 extern (C++) class Test14086 { this(); ~this(); } extern (C++) class Test14086_2 { final ~this(); } extern (C++) struct Test14086_S { this(int); ~this(); } version(Posix) { static assert(Test14086.__ctor.mangleof == "_ZN9Test14086C1Ev"); static assert(Test14086.__dtor.mangleof == "_ZN9Test14086D1Ev"); static assert(Test14086_2.__dtor.mangleof == "_ZN11Test14086_2D1Ev"); static assert(Test14086_S.__ctor.mangleof == "_ZN11Test14086_SC1Ei"); static assert(Test14086_S.__dtor.mangleof == "_ZN11Test14086_SD1Ev"); } version(Win32) { static assert(Test14086.__ctor.mangleof == "??0Test14086@@QAE@XZ"); static assert(Test14086.__dtor.mangleof == "??1Test14086@@UAE@XZ"); static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QAE@XZ"); static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QAE@H@Z"); static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QAE@XZ"); } version(Win64) { static assert(Test14086.__ctor.mangleof == "??0Test14086@@QEAA@XZ"); static assert(Test14086.__dtor.mangleof == "??1Test14086@@UEAA@XZ"); static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QEAA@XZ"); static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QEAA@H@Z"); static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QEAA@XZ"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=18888 extern (C++) struct T18888(T) { void fun(); } extern (C++) struct S18888(alias arg = T18888) { alias I = T18888!(arg!int); } version(Posix) { static assert(S18888!().I.fun.mangleof == "_ZN6T18888IS_IiEE3funEv"); } version(Win32) { static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QAEXXZ"); } version(Win64) { static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QEAAXXZ"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=18890 extern (C++) class C18890 { ~this() {} } extern (C++) class C18890_2 { ~this() {} extern (C++) struct Agg { ~this() {} } Agg s; } version (Posix) { static assert(C18890.__dtor.mangleof == "_ZN6C18890D1Ev"); static assert(C18890.__xdtor.mangleof == "_ZN6C18890D1Ev"); static assert(C18890_2.__dtor.mangleof == "_ZN8C18890_26__dtorEv"); static assert(C18890_2.__xdtor.mangleof == "_ZN8C18890_2D1Ev"); } version (Win32) { static assert(C18890.__dtor.mangleof == "??1C18890@@UAE@XZ"); static assert(C18890.__xdtor.mangleof == "??_GC18890@@UAEPAXI@Z"); static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UAEXXZ"); static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UAEPAXI@Z"); } version (Win64) { static assert(C18890.__dtor.mangleof == "??1C18890@@UEAA@XZ"); static assert(C18890.__xdtor.mangleof == "??_GC18890@@UEAAPEAXI@Z"); static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UEAAXXZ"); static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UEAAPEAXI@Z"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=18891 extern (C++) class C18891 { ~this(); extern (C++) struct Agg { ~this() {} } Agg s; } version (Posix) { static assert(C18891.__dtor.mangleof == "_ZN6C18891D1Ev"); static assert(C18891.__xdtor.mangleof == "_ZN6C18891D1Ev"); } version (Win32) { static assert(C18891.__dtor.mangleof == "??1C18891@@UAE@XZ"); static assert(C18891.__xdtor.mangleof == "??_GC18891@@UAEPAXI@Z"); } version (Win64) { static assert(C18891.__dtor.mangleof == "??1C18891@@UEAA@XZ"); static assert(C18891.__xdtor.mangleof == "??_GC18891@@UEAAPEAXI@Z"); } /**************************************/ // Test C++ operator mangling extern (C++) struct TestOperators { int opCast(T)(); int opBinary(string op)(int x); int opUnary(string op)(); int opOpAssign(string op)(int x); int opIndex(int x); bool opEquals(int x); int opCall(int, float); int opAssign(int); } version (Posix) { static assert(TestOperators.opUnary!"*".mangleof == "_ZN13TestOperatorsdeEv"); static assert(TestOperators.opUnary!"++".mangleof == "_ZN13TestOperatorsppEv"); static assert(TestOperators.opUnary!"--".mangleof == "_ZN13TestOperatorsmmEv"); static assert(TestOperators.opUnary!"-".mangleof == "_ZN13TestOperatorsngEv"); static assert(TestOperators.opUnary!"+".mangleof == "_ZN13TestOperatorspsEv"); static assert(TestOperators.opUnary!"~".mangleof == "_ZN13TestOperatorscoEv"); static assert(TestOperators.opBinary!">>".mangleof == "_ZN13TestOperatorsrsEi"); static assert(TestOperators.opBinary!"<<".mangleof == "_ZN13TestOperatorslsEi"); static assert(TestOperators.opBinary!"*".mangleof == "_ZN13TestOperatorsmlEi"); static assert(TestOperators.opBinary!"-".mangleof == "_ZN13TestOperatorsmiEi"); static assert(TestOperators.opBinary!"+".mangleof == "_ZN13TestOperatorsplEi"); static assert(TestOperators.opBinary!"&".mangleof == "_ZN13TestOperatorsanEi"); static assert(TestOperators.opBinary!"/".mangleof == "_ZN13TestOperatorsdvEi"); static assert(TestOperators.opBinary!"%".mangleof == "_ZN13TestOperatorsrmEi"); static assert(TestOperators.opBinary!"^".mangleof == "_ZN13TestOperatorseoEi"); static assert(TestOperators.opBinary!"|".mangleof == "_ZN13TestOperatorsorEi"); static assert(TestOperators.opOpAssign!"*".mangleof == "_ZN13TestOperatorsmLEi"); static assert(TestOperators.opOpAssign!"+".mangleof == "_ZN13TestOperatorspLEi"); static assert(TestOperators.opOpAssign!"-".mangleof == "_ZN13TestOperatorsmIEi"); static assert(TestOperators.opOpAssign!"/".mangleof == "_ZN13TestOperatorsdVEi"); static assert(TestOperators.opOpAssign!"%".mangleof == "_ZN13TestOperatorsrMEi"); static assert(TestOperators.opOpAssign!">>".mangleof == "_ZN13TestOperatorsrSEi"); static assert(TestOperators.opOpAssign!"<<".mangleof == "_ZN13TestOperatorslSEi"); static assert(TestOperators.opOpAssign!"&".mangleof == "_ZN13TestOperatorsaNEi"); static assert(TestOperators.opOpAssign!"|".mangleof == "_ZN13TestOperatorsoREi"); static assert(TestOperators.opOpAssign!"^".mangleof == "_ZN13TestOperatorseOEi"); static assert(TestOperators.opCast!int.mangleof == "_ZN13TestOperatorscviEv"); static assert(TestOperators.opAssign.mangleof == "_ZN13TestOperatorsaSEi"); static assert(TestOperators.opEquals.mangleof == "_ZN13TestOperatorseqEi"); static assert(TestOperators.opIndex.mangleof == "_ZN13TestOperatorsixEi"); static assert(TestOperators.opCall.mangleof == "_ZN13TestOperatorsclEif"); } version (Win32) { static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QAEHXZ"); static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QAEHXZ"); static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QAEHXZ"); static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QAEHXZ"); static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QAEHXZ"); static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QAEHXZ"); static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QAEHH@Z"); static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QAEHH@Z"); static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QAEHH@Z"); static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QAEHXZ"); static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QAEHH@Z"); static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QAE_NH@Z"); static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QAEHH@Z"); static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QAEHHM@Z"); } version (Win64) { static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QEAAHXZ"); static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QEAAHXZ"); static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QEAAHXZ"); static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QEAAHXZ"); static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QEAAHXZ"); static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QEAAHXZ"); static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QEAAHH@Z"); static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QEAAHH@Z"); static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QEAAHH@Z"); static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QEAAHXZ"); static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QEAAHH@Z"); static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QEAA_NH@Z"); static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QEAAHH@Z"); static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QEAAHHM@Z"); } extern(C++, Namespace18922) { import cppmangle2; void func18922(Struct18922) {} version (Posix) static assert(func18922.mangleof == "_ZN14Namespace189229func18922ENS_11Struct18922E"); else version(Windows) static assert(func18922.mangleof == "?func18922@Namespace18922@@YAXUStruct18922@1@@Z"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=18957 // extern(C++) doesn't mangle 'std' correctly on posix systems version (Posix) { // https://godbolt.org/z/C5T2LQ /+ namespace std { struct test18957 {}; } void test18957(const std::test18957& t) {} +/ extern (C++) void test18957(ref const(std.test18957) t) {} static assert(test18957.mangleof == "_Z9test18957RKSt9test18957"); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=19043 // Incorrect mangling for extern(C++) const template parameter on windows extern(C++) struct test19043(T) {} extern(C++) void test19043a(test19043!(const(char)) a) {} extern(C++) void test19043b(T)(T a) {} version(Windows) { static assert(test19043a.mangleof == "?test19043a@@YAXU?$test19043@$$CBD@@@Z"); static assert(test19043b!(test19043!(const(char))).mangleof == "??$test19043b@U?$test19043@$$CBD@@@@YAXU?$test19043@$$CBD@@@Z"); } // https://issues.dlang.org/show_bug.cgi?id=16479 // Missing substitution while mangling C++ template parameter for functions version (Posix) extern (C++) { // Make sure aliases are still resolved alias Alias16479 = int; Alias16479 func16479_0 (FuncT1) (FuncT1, Alias16479); static assert(func16479_0!(int).mangleof == `_Z11func16479_0IiEiT_i`); // Simple substitution on return type FuncT1* func16479_1 (FuncT1) (); static assert(func16479_1!(int).mangleof == `_Z11func16479_1IiEPT_v`); // Simple substitution on parameter void func16479_2 (FuncT1) (FuncT1); static assert(func16479_2!(int).mangleof == `_Z11func16479_2IiEvT_`); // Make sure component substition is prefered over template parameter FuncT1* func16479_3 (FuncT1) (FuncT1); static assert(func16479_3!(int).mangleof == `_Z11func16479_3IiEPT_S0_`); struct Array16479 (Arg) { Arg* data; } struct Array16479_2 (Arg, int Size) { Arg[Size] data; } struct Value16479 (int Value1, int Value2) { int data; } // Make sure template parameter substitution happens on templated return Array16479!(FuncT2) func16479_4 (FuncT1, FuncT2) (FuncT1); static assert(func16479_4!(int, float).mangleof == `_Z11func16479_4IifE10Array16479IT0_ET_`); // Make sure template parameter substitution happens with values Value16479!(Value2, Value1)* func16479_5 (int Value1, int Value2) (); static assert(func16479_5!(1, 1).mangleof == `_Z11func16479_5ILi1ELi1EEP10Value16479IXT0_EXT_EEv`); // But make sure it's not substituting *too many* values Value16479!(1, 1)* func16479_6 (int Value1, int Value2) (); static assert(func16479_6!(1, 1).mangleof == `_Z11func16479_6ILi1ELi1EEP10Value16479ILi1ELi1EEv`); // Or too many types Array16479!(int) func16479_7 (FuncT1, FuncT2) (FuncT1); static assert(func16479_7!(int, int).mangleof == `_Z11func16479_7IiiE10Array16479IiET_`); // Also must check the parameters for template param substitution void func16479_8 (FuncT1) (Array16479!(FuncT1)); static assert(func16479_8!(int).mangleof == `_Z11func16479_8IiEv10Array16479IT_E`); // And non-substitution void func16479_9 (FuncT1) (Array16479!(int)); static assert(func16479_9!(int).mangleof == `_Z11func16479_9IiEv10Array16479IiE`); // Now let's have a bit of fun with alias parameters, // starting with C functions // TODO: Why is this mangled by g++: /* extern "C" { void externC16479 (int); } template void func16479_10 (); void foo () { func16479_10(); } */ extern (C) void externC16479 (int); void func16479_10 (alias Print) (); static assert(func16479_10!(externC16479).mangleof == `_Z12func16479_10IXadL_Z12externC16479EEEvv`); /** * Let's not exclude C++ functions * Note: * Passing a function as template parameter has an implicit * `&` operator prepended to it, so the following code: * --- * void CPPPrinter16479(const char*); * template void func16479_11 (); * void foo () { func16479_11(); } * --- * Gets mangled as `func16479_11<&CPPPrinter16479>()` would, * which means the expression part of the template argument is * mangled as `XadL_Z[...]E` not `XL_Z[...]E` * (expressions always begin with a code anyway). */ extern(C++) void CPPPrinter16479(const(char)*); extern(C++, Namespace16479) void CPPPrinterNS16479(const(char)*); void func16479_11 (alias Print) (); static assert(func16479_11!(CPPPrinter16479).mangleof == `_Z12func16479_11IXadL_Z15CPPPrinter16479PKcEEEvv`); static assert(func16479_11!(CPPPrinterNS16479).mangleof == `_Z12func16479_11IXadL_ZN14Namespace1647917CPPPrinterNS16479EPKcEEEvv`); // Functions are fine, but templates are finer // --- // template class Container, typename T, int Val> // Container func16479_12 (); // --- Container!(T, Val) func16479_12 (alias Container, T, int Val) (); static assert(func16479_12!(Array16479_2, int, 42).mangleof == `_Z12func16479_12I12Array16479_2iLi42EET_IT0_XT1_EEv`); // Substitution needs to happen on the most specialized type // Iow, `ref T identity (T) (ref T v);` should be mangled as // `_Z8identityIiET_*S1_*`, not as `_Z8identityIiET_*RS0_*` ref FuncT1 func16479_13_1 (FuncT1) (ref FuncT1); FuncT1* func16479_13_2 (FuncT1) (FuncT1*); void func16479_13_3 (FuncT1) (FuncT1*, FuncT1*); FuncT1** func16479_13_4 (FuncT1) (FuncT1*, FuncT1); FuncT1 func16479_13_5 (FuncT1) (FuncT1*, FuncT1**); static assert(func16479_13_1!(int).mangleof == `_Z14func16479_13_1IiERT_S1_`); static assert(func16479_13_2!(float).mangleof == `_Z14func16479_13_2IfEPT_S1_`); static assert(func16479_13_3!(int).mangleof == `_Z14func16479_13_3IiEvPT_S1_`); static assert(func16479_13_4!(int).mangleof == `_Z14func16479_13_4IiEPPT_S1_S0_`); static assert(func16479_13_5!(int).mangleof == `_Z14func16479_13_5IiET_PS0_PS1_`); // Opaque types result in a slightly different AST vector!T* func16479_14 (T) (T v); static assert(func16479_14!(int).mangleof == `_Z12func16479_14IiEPSt6vectorIT_ES1_`); struct Foo16479_15 (T); struct Baguette16479_15 (T); struct Bar16479_15 (T); struct FooBar16479_15 (A, B); void inst16479_15_2 (A, B) (); void inst16479_15_3 (A, B, C) (); static assert(inst16479_15_2!(Bar16479_15!int, int).mangleof == `_Z14inst16479_15_2I11Bar16479_15IiEiEvv`); static assert(inst16479_15_2!(int, Bar16479_15!int).mangleof == `_Z14inst16479_15_2Ii11Bar16479_15IiEEvv`); static assert(inst16479_15_2!(Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof == `_Z14inst16479_15_2I11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`); static assert(inst16479_15_3!(int, Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof == `_Z14inst16479_15_3Ii11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`); static import cppmangle2; cppmangle2.Struct18922* func16479_16_1 (T) (T*); static assert(func16479_16_1!int.mangleof == `_Z14func16479_16_1IiEPN14Namespace1892211Struct18922EPT_`); T* func16479_16_2 (T) (T*); static assert(func16479_16_2!int.mangleof == `_Z14func16479_16_2IiEPT_S1_`); static assert(func16479_16_2!(cppmangle2.vector!int).mangleof == `_Z14func16479_16_2ISt6vectorIiEEPT_S3_`); static assert(func16479_16_2!(cppmangle2.vector!int).mangleof == func16479_16_2!(cppmangle2.vector!int).mangleof); cppmangle2.vector!T* func16479_16_3 (T) (T*); static assert(func16479_16_3!int.mangleof == `_Z14func16479_16_3IiEPSt6vectorIiEPT_`); extern(C++, `fakestd`) { extern (C++, `__1`) { struct allocator16479 (T); struct vector16479(T, alloc = allocator16479!T); } } vector16479!(T, allocator16479!T)* func16479_17_1(T)(); vector16479!(T)* func16479_17_2(T)(); static assert(func16479_17_1!int.mangleof == `_Z14func16479_17_1IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`); static assert(func16479_17_2!int.mangleof == `_Z14func16479_17_2IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/cppmangle2.d ================================================ module cppmangle2; extern(C++, Namespace18922) { struct Struct18922 { int i; } } extern(C++, std) { struct vector (T); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/cppmangle3.d ================================================ extern(C++, "true") { } extern(C++, "__traits") { } extern(C++, "foo") { } int foo; // no name clashing with above namespace extern(C++, "std", "chrono") { void func(); } version(Windows) static assert(func.mangleof == "?func@chrono@std@@YAXXZ"); else static assert(func.mangleof == "_ZNSt6chrono4funcEv"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ctfe_math.d ================================================ // Test CTFE builtins for std.math functions. import std.math; void main() { static assert(approxEqual(sin(2.0L), 0.9092974L)); static assert(approxEqual(cos(2.0), -0.4161468)); static assert(approxEqual(tan(2.0f), -2.185040f)); static assert(approxEqual(sqrt(2.0L), 1.414214L)); static assert(fabs(-2.0) == 2.0); static assert(ldexp(2.5f, 3) == 20.0f); static assert(isNaN(real.init)); static assert(isNaN(double.nan)); static assert(!isNaN(float.infinity)); static assert(isInfinity(real.infinity)); static assert(isInfinity(-double.infinity)); static assert(!isInfinity(float.nan)); static assert(isFinite(1.0L)); static assert(!isFinite(double.infinity)); static assert(!isFinite(float.nan)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc1.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // REQUIRED_ARGS: -d /** This module is for ABC * Copyright: Copyright © */ module abc; string foos = "foo"; alias int myint; /// alias int mytypedefint; /** windy * city * * paragraph 2 about of F $$(NAME) * ----- * #include * void main() * { * printf("hello\n"); * } * ----- * Copyright: 1998 */ myint f; enum E { e } /// comment1 int g; /// comment2 private int h; /// comment for H static int i; int j; wchar LS = 0x2028; /// UTF line separator wchar PS = 0x2029; /// UTF paragraph separator wchar _XX; /// ditto wchar YY; /// ditto /** Function foo takes argument c and adds it to argulid. * * Then it munges argulid, u underline. * Params: * c = the character which adds c to argulid * argulid = the argument * u = the other argument */ int foo(char c, int argulid, char u); int barr() { return 3; } /// doc for barr() /++ The Class Bar +/ class Bar { int x; /// member X int y; /// member Y protected int z; /// member Z } /++ The Enum Easy +/ enum Easy : int { red, /// the Red blue, /// the Blue green, /// the Green } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // https://issues.dlang.org/show_bug.cgi?id=294 /// The foo struct Foo(T) { } /// ditto struct Foo(T,U) { } /** This basic case doesn't work very well. The template signature is * documented twice, but the function signature (argument names and return * type) is not documented at all. This comment is also repeated twice. */ int func1(T)(T x) {} /** This comment is also repeated twice, and the second function signature is * not very well documented. */ int func2(T,U)(T x, U y) {} /// ditto int func2(T)(T x) {} /// Separate overload item. int func2()() {} /// template func3(T,U) { /** This used to work adequately and documented both func3 templates * simultaneously. Now, it documents the first template twice and * no longer documents the function argument and return types.*/ int func3(T x, U y) {} } /// ditto deprecated template func3(T, U=int, V:long) { private int func3(T x) {} } /** * blah */ void map(char rs) { } /// Ditto void map(int rs) { } /** * blah */ void map2()(char rs) { } /// Ditto void map2()(int rs) { } /** * blah http://www.map3.com map3 */ void map3(char rs) { } /** * blah http://www.map.com map */ void map4(string s)(char rs) { } /** * blah http://www.map.com map */ template map5(string s) { } /** blah */ struct bar6 { int blah; } /** template bodies */ struct Foo7(T) { /**Attempt one: Doc outside static if.*/ static if(is(T == uint)) { /**Attempt two: Inside.*/ void bar() {} } else { /**Attempt two: else.*/ void bar() {} } /** the abc function should be static */ static void abc() { } } /** show abstract */ abstract class Foo8 { } /// a stray $(RPAREN) mustn't foul the macros void bug4878(string a = ")") {} /**** */ struct S { /**** */ this(long ticks) const pure nothrow { } /**** */ pure nothrow this(this) { } /**** */ const pure nothrow ~this() { } /**** */ void foo(long ticks) const pure nothrow { } } /** Produces something in (a;b] */ float f10(float a, float b) { return (a+b)/2.0; } /** Produces something in [a;b) */ float h10(float a, float b) { return (a+b)/2.0; } /// void bug6090(string f="$(B b)", char g=')')(string h="$(", string i="$)") {} /**** */ struct T { /**** */ this(A...)(A args) { } /// this(int){} } // https://issues.dlang.org/show_bug.cgi?id=14547 /// doc-comment int x14547 = 1; /// ditto enum int y14547 = 2; /// doc-comment enum isInt14547(T) = is(T == int); /// ditto enum bool isString14547(T) = is(T == string); /// ditto static immutable typeName14547(T) = T.stringof; /// ditto int storageFor14547(T) = 0; /// doc-comment template foo14547(T) { enum int foo14547 = T.stringof.length; } /// ditto template bar14547(T) if (is(T == int)) { enum int bar14547 = T.stringof.length; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10236.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- /* TEST_OUTPUT: --- compilable/ddoc10236.d(33): Warning: Ddoc: parameter count mismatch compilable/ddoc10236.d(45): Warning: Ddoc: function declaration has no parameter 'y' compilable/ddoc10236.d(57): Warning: Ddoc: function declaration has no parameter 'y' compilable/ddoc10236.d(57): Warning: Ddoc: parameter count mismatch --- */ /*********************************** * foo_good does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_good(int x, int y) { } /*********************************** * foo_count_mismatch does this. * Params: * x = is for this * and not for that */ void foo_count_mismatch(int x, int y) // Warning: Ddoc: parameter count mismatch { } /*********************************** * foo_no_param_y does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_no_param_y(int x, int z) // Warning: Ddoc: function declaration has no parameter 'y' { } /*********************************** * foo_count_mismatch_no_param_y does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_count_mismatch_no_param_y(int x) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10236b.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- /* TEST_OUTPUT: --- compilable/ddoc10236b.d(43): Warning: Ddoc: parameter count mismatch compilable/ddoc10236b.d(55): Warning: Ddoc: function declaration has no parameter 'y' compilable/ddoc10236b.d(67): Warning: Ddoc: function declaration has no parameter 'y' compilable/ddoc10236b.d(67): Warning: Ddoc: parameter count mismatch --- */ /*********************************** * foo_good does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_good(int x)(int y) { } /*********************************** * foo_good2 does this. * Params: * y = is for that */ void foo_good2(int x)(int y) { } /*********************************** * foo_count_mismatch does this. * Params: * x = is for this * and not for that */ void foo_count_mismatch(int x)(int y) // Warning: Ddoc: parameter count mismatch { } /*********************************** * foo_no_param_y does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_no_param_y(int x)(int z) // Warning: Ddoc: function declaration has no parameter 'y' { } /*********************************** * foo_count_mismatch_no_param_y does this. * Params: * x = is for this * and not for that * y = is for that */ void foo_count_mismatch_no_param_y(int x)() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10325.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc10325; /** */ template templ(T...) if (someConstraint!T) { } /** */ void foo(T)(T t) if (someConstraint!T) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10334.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc10334; template Foo10334(T) if (Bar10334!()) {} /// template Foo10334(T) if (Bar10334!100) {} /// template Foo10334(T) if (Bar10334!3.14) {} /// template Foo10334(T) if (Bar10334!"str") {} /// template Foo10334(T) if (Bar10334!1.4i) {} /// template Foo10334(T) if (Bar10334!null) {} /// template Foo10334(T) if (Bar10334!true) {} /// template Foo10334(T) if (Bar10334!false) {} /// template Foo10334(T) if (Bar10334!'A') {} /// template Foo10334(T) if (Bar10334!int) {} /// template Foo10334(T) if (Bar10334!string) {} /// template Foo10334(T) if (Bar10334!([1,2,3])) {} /// template Foo10334(T) if (Bar10334!(Baz10334!())) {} /// template Foo10334(T) if (Bar10334!(Baz10334!T)) {} /// template Foo10334(T) if (Bar10334!(Baz10334!100)) {} /// template Foo10334(T) if (Bar10334!(.foo)) {} /// template Foo10334(T) if (Bar10334!(const int)) {} /// template Foo10334(T) if (Bar10334!(shared T)) {} /// template Test10334(T...) {} /// mixin Test10334!int a; /// mixin Test10334!(int,long) b; /// mixin Test10334!"str" c; /// ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10366.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// struct S(T) { /// void method() {} public { /// struct Nested { /// void nestedMethod() {} } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10367.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // REQUIRED_ARGS: -m32 // EXTRA_SOURCES: extra-files/ddoc10367.ddoc module ddoc10367; /// A enum A { a = 1, /// a b = 2 /// b } /// B enum B : long { a = 1, /// a b = 2 /// b } /// C enum C : string { a = "a", /// a b = "b" /// b } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10869.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc10869; /// class C { const { /// void c1Foo() const { } /// void i1Foo() immutable { } } immutable { /// void c2Foo() const { } /// void i2Foo() immutable { } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc10870.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// interface I { /// void f(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc11.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// The various floating point exceptions enum { FE_INVALID = 1, /// FE_DENORMAL = 2, /// FE_DIVBYZERO = 4, /// FE_OVERFLOW = 8, /// FE_UNDERFLOW = 0x10, /// FE_INEXACT = 0x20, /// FE_ALL_EXCEPT = 0x3F, /// Mask of all the exceptions } alias int myint; /// myint bar; /// myint foo(myint x = myint.max) { return x; } /// class Foo { /// this(string s) { } } extern (C): /// struct div_t { int quot,rem; } /// struct ldiv_t { int quot,rem; } /// struct lldiv_t { long quot,rem; } div_t div(int,int); /// ldiv_t ldiv(int,int); /// lldiv_t lldiv(long, long); /// void *calloc(size_t, size_t); /// void *malloc(size_t); /// dittx /** Example: --- private: int i = 0; --- */ void test1() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc11479.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc11479; /// struct S1(T) { /// int a; /// private: int x; private: /// int y; /// public: int b; public: /// int c; } /// struct S2(T) { /// int a; /// private int x; /// int b; /// public int c; public /// int d; } /// struct S3(T) { /// int a; /// private { int x; } /// int b; /// private { int y; public { int c; } } private { int z; /// public { int d; } } private { int w; public { /// int e; } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc11511.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -w -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc11511; /** Params: abcd = none1 bcdef = none23 ... = doo */ void foo(int abcd, int bcdef, ...); /** Params: abcd = none1 bcdef = none23 arr = doo */ void foo(int abcd, int bcdef, int[] arr...); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc11823.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc11823; /// file function name is _file, arg defaults to __FILE__ but not __something__ void file(string arg) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc12.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh int ruhred; /// This documents correctly. int rühred; /// This should too /** * BUG: The parameters are not listed under Params in the generated output * * Params: * ü = first * ş = second * ğ = third * */ int foo(int ü, int ş, int ğ) { return ğ; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc12706.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// void test()(string[] args) if (args[$]) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc12745.d ================================================ // EXTRA_SOURCES: // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** i underlined $(BR) _i not underlined $(BR) __i force underscore $(BR) $(BR) _0 not underscored $(BR) __0 force underscored 1 underscore: $(BR) 1_1 $(BR) 1_a $(BR) a_1 $(BR) a_a $(BR) $(BR) 2 underscores: $(BR) 1__a $(BR) 2__b */ int i; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc13.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// struct doc struct Bug4107(T) { /// templated function doc void foo(U)(U u) { } } /// alpha struct Bug4107b(T) { /// beta struct B(U) { /// gamma struct C(V) { /// delta struct D(W) { /// epsilon B!W e(X)(C!V c, X[] x...) {} } } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc13270.d ================================================ // PERMUTE_ARGS: -w // REQUIRED_ARGS: -o- -D -Dd${RESULTS_DIR}/compilable // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc13270; /** * My overloaded function. * * Params: * task = String description of stuff to do. * tasks = Array of descriptions of stuff to do. * maxJobs = Max parallel jobs to run while doing stuff. */ void doStuff(string task) {} /// ditto void doStuff(string[] tasks, int maxJobs) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc13502.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- /* TEST_OUTPUT: --- compilable/ddoc13502.d(14): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. compilable/ddoc13502.d(17): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. compilable/ddoc13502.d(21): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. compilable/ddoc13502.d(24): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. --- */ /// ( enum isSomeString(T) = true; /// ( enum bool isArray(T) = true; /// ( extern(C) alias int T1; /// ( extern(C) alias T2 = int; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc13645.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** Documentation comment on module */ deprecated("msg") @(1) module ddoc13645; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc14.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh alias void V; alias double* P; /// -1 struct Structure { public P variable; /// 0 V mNone(lazy P p) {} /// 1 pure nothrow V mPrefix(lazy P p) {} /// 2 V mSuffix(lazy P p) pure nothrow {} /// 3 // pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 pure nothrow { V mScoped(lazy P p) {} /// 6 } pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 // pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 pure nothrow: V mColon(lazy P p) {} /// 10 } /// -1 class Class { public P variable; /// 0 V mNone(lazy P p) {} /// 1 pure nothrow V mPrefix(lazy P p) {} /// 2 V mSuffix(lazy P p) pure nothrow {} /// 3 // pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 pure nothrow { V mScoped(lazy P p) {} /// 6 } pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 // pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 pure nothrow: V mColon(lazy P p) {} /// 10 } /+ /// -1 struct StructTemplate() { public P variable; /// 0 V mNone(lazy P p) {} /// 1 pure nothrow V mPrefix(lazy P p) {} /// 2 V mSuffix(lazy P p) pure nothrow {} /// 3 // pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 pure nothrow { V mScoped(lazy P p) {} /// 6 } pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 // pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 pure nothrow: V mColon(lazy P p) {} /// 10 } /// -1 interface Interface { V mNone(lazy P p) ; /// 1 pure nothrow V mPrefix(lazy P p) ; /// 2 V mSuffix(lazy P p) pure nothrow ; /// 3 // pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) ; /// 4 V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow ; /// 5 pure nothrow { V mScoped(lazy P p) ; /// 6 } // pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 pure nothrow: V mColon(lazy P p) ; /// 10 } +/ public P variable; /// 0 V mNone(lazy P p) {} /// 1 pure nothrow V mPrefix(lazy P p) {} /// 2 V mSuffix(lazy P p) pure nothrow {} /// 3 // pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 pure nothrow { V mScoped(lazy P p) {} /// 6 } pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 // pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 pure nothrow: V mColon(lazy P p) {} /// 10 ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc14383.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** * Module docs. */ module ddoc14383; /// Ddoc'd unittest unittest { int iShouldAppearInTheDocs; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc14413.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc14413; /// This should /// be one /// paragraph. /// /// Paragraph 2 void foo(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc14633.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- /* TEST_OUTPUT: --- --- */ /** Blah Params: T = some type test = something overnext = for testing overloaded functions */ template case1(T) { void case1(R)(R test) { } void case1(R)(R test, string overnext) { } } ///ditto alias case2 = case1!int; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc14778.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc14778; /// docs for Z template Z14778(T) { /// docs for E enum E; /// docs for x enum x = 1.0; /// docs for mv auto mv = 1; /// docs for wv inout wv = 3; /// doc for cv const cv = "a"; /// docs for wcv inout const wcv = "ab"; /// doc for sv shared sv = 1.4142; /// doc for swv shared inout swv = 3.14; /// doc for scv shared const scv = new Object(); /// docs for swcv shared inout const swcv = undefined; /// doc for iv immutable iv = [1,2,3]; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc15475.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** My module ---- // Computes the interval [x,y) auto interval = computeInterval(x, y); ---- Backslash-escape parentheses with `\(` and `\)`. --- ( --- --- ) --- --- Here are some nested `backticks` // Another interval [x,y) --- --- This won't end the code block: --- ) // Yet another interval [x,y) --- */ module ddoc15475; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc17697.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /*** * See: * http://www.fooa.com/test1 * http://www.fooa.com/_test1 * https://www.foob.com/test1 * $(LINK http://www.fooc.com/test1) * $(LINK2 http://www.food.com/test1, test1) */ /** Also piggyback a few tests for https://github.com/dlang/dmd/pull/6989 not_a_tag_because_it_does_not_start_with_uppercase: not_a_tag_because_no_whitespace_after_colon:x TagGalore: yes this is a tag MoreTag: yes the above is also a tag */ module test1; int a; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc18361.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // REQUIRED_ARGS: -d // Test notes: 'main' is the symbol being documented (DDOC_AUTO_PSYMBOL), // 'arguments' is a parameter (DDOC_AUTO_PARAM), and 'false' is a keyword // (DDOC_AUTO_KEYWORD). /** * The main thing this program does is nothing, and I do _not want to hear any * false arguments about that! * * Macros: * DDOC_AUTO_PSYMBOL = $0 * DDOC_AUTO_KEYWORD = $0 * DDOC_AUTO_PARAM = $0 * DDOC_AUTO_PSYMBOL_SUPPRESS = HALPIMBEINGSUPPRESSED $0 * * DDOC = $(BODY) * DDOC_DECL = $0 * DDOC_MEMBER_HEADER = * DDOC_MODULE_MEMBERS = $0 * DDOC_MEMBER = $0 */ void main(string[] arguments) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc198.d ================================================ // EXTRA_SOURCES: extra-files/ddoc198.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc198; /// interface I1 { } /// class C1 { } /// class Foo : C1, I1 { } /// enum X { x = 1 } /// enum Y : X { y = X.x } /// struct S1 { } /// enum enS : S1 { a = S1() } // disabled until class enums are possible // enum enC : C1 { a = new C1() } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc2.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** * Summary * * Description1 * * Description2 * * Description3 * * Macros: * WIKI = StdStream * meemie * See_Also: * Things to see also. * * And more things. */ /* */ module std.test; /// A base class for stream exceptions. class StreamException: Exception { /** Construct a StreamException with given error message msg. * Params: * msg = the $(RED red) $(BLUE blue) $(GREEN green) $(YELLOW yellow). * foo = next parameter which is a much longer * message spanning multiple * lines. */ this(string msg, int foo) { super(msg); } /********** stars ***************/ int stars; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc2273.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // REQUIRED_ARGS: -m32 module ddoc2273; interface A { } interface C { } interface D { } /// interface B : C, D { } /// class Foo : A, B { } /// MinType!(T1, T2, T) min(T1, T2, T...)(T1 a, T2 b, T xs) { } /// Templ!([1, 2, 3]) max(T...)() { } /// template Base64Impl(char Map62th, char Map63th, char Padding) { } /// int sqlite3_config(int,...); template staticIndexOf(T, TList...) { alias int staticIndexOf; } /// alias staticIndexOf IndexOf; void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc3.d ================================================ // EXTRA_SOURCES: extra-files/ddoc3.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** * Summary * * Description1 * * Description2 * * Description3 * * Macros: * WIKI = StdStream * meemie * ARG0 = $0 * ARG1 = $1 * ARG2 = $2 * ARG3 = $3 * PLUS = $+ * TROW = $(TR $(TCOL $1,$+)) * TCOL = $(TD $1) $(TCOL $+) * LPAREN = ( * See_Also: * Things to see also. * * And more things $(BR) * 'arg1, arg2, arg3' : $(ARG0 arg1, arg2, arg3). $(BR) * 'arg2, arg3' : $(PLUS arg1, arg2, arg3). $(BR) * 'arg1' : $(ARG1 arg1, arg2, arg3). $(BR) * 'arg2' : $(ARG2 arg1, arg2, arg3). $(BR) * 'arg3' : $(ARG3 arg1, arg2, arg3). $(BR) */ /** * Things to see also $(HELLO). * * $(TABLE * $(TROW 1, 2, 3) * $(TROW 4, 5, 6) * ) * * $(D_CODE $(B pragma)( $(I name) ); $(B pragma)( $(I name) , $(I option) [ $(I option) ] ); $(U $(LPAREN)) ) */ /* */ module std.test; /// A base class for stream exceptions. class StreamException: Exception { /** Construct a StreamException with given error message msg. * Params: * msg = the $(RED red) $(BLUE blue) $(GREEN green) $(YELLOW yellow). * foo = next parameter which is a much longer * message spanning multiple * lines. */ this(string msg, int foo) { super(msg); } /********** stars ***************/ int stars; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc4.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** a */ enum { ONE } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc4162.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// interface A { /// static void staticHello() { } /// final void hello() { } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc4899.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- /* TEST_OUTPUT: --- compilable/ddoc4899.d(18): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. compilable/ddoc4899.d(19): Warning: Ddoc: Stray ')'. This may cause incorrect Ddoc output. Use $(RPAREN) instead for unpaired right parentheses. --- */ /++ (See accompanying file LICENSE_1_0.txt or copy at foo:) +/ module d; /** ( */ int a; /** ) */ int b; void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc5.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** Test module */ module test; /// class to test DDOC on members class TestMembers(TemplateArg) { public: /** a static method Params: idx = index */ static void PublicStaticMethod(int idx) { } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc5446.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc5446; import ddoc5446a; private import ddoc5446b; /** */ alias A_Foo This_Foo; /** */ alias A_Foo_Alias This_Foo_Alias; /** */ alias int This_Int; /** */ alias A_Enum This_Enum; /** */ deprecated alias ddoc5446b.A_Enum_New A_Enum_New; struct Nested { } /** */ struct Bar { /** */ alias A_Foo Bar_A_Foo; /** */ alias A_Foo_Alias Bar_A_Foo_Alias; /** */ alias A_Int Bar_A_Int; /** */ alias This_Foo Bar_This_Foo; /** */ alias This_Foo_Alias Bar_This_Foo_Alias; /** */ alias This_Int Bar_This_Int; /** */ alias Nested Nested_Alias; /** */ alias .Nested Fake_Nested; /** */ struct Nested { /** */ alias Bar Bar_Nested_Bar_Alias; /** */ alias .Bar Bar_Alias; /** */ struct Bar { } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc5446a.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- module ddoc5446a; /** */ struct A_Foo { } /** */ alias A_Foo A_Foo_Alias; /** */ alias int A_Int; /** */ enum A_Enum { x } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc5446b.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- module ddoc5446b; /** */ enum A_Enum_New { x } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc6.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** * */ struct MyStruct(T) { static if( true ) { void MyStruct() {} } } void main() { } /+ 23 C:\code\d\bugs>dmd -D -o- 148_1.d 148_1.d(6): Error: static if conditional cannot be at global scope +/ ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc648.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc648; /// Mixin declaration mixin template Mixin1() { /// struct S struct S { } } /// class A class A { /// field x int x; /// no docs for mixin statement (only for expanded members) mixin Mixin1!(); } /// class AB class AB { /// field x int x; // no docs for mixin or its contents, must be a ddoc comment mixin Mixin1!(); } /// Mixin declaration2 mixin template Mixin2() { /// struct S2 struct S2 { } } /// Mixin declaration3 mixin template Mixin3() { /// another field int f; /// no docs for mixin statement (only for expanded members) mixin Mixin2!(); } /// class B1 class B1 { /// no docs for mixin statement (only for expanded members) mixin Mixin3!(); } /// Mixin declaration3 mixin template Mixin4() { /// another field int f; // no docs at all for non-ddoc comment mixin Mixin2!(); } /// class B2 class B2 { /// no docs for mixin statement (only for expanded members) mixin Mixin4!(); } /// no docs for mixin statement (only for expanded members) mixin Mixin3!(); /// struct TS(T) { mixin template MT() { } mixin MT; /// avoid calling semantic /// int field; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc6491.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc6491; import core.cpuid; enum int c6491 = 4; /// test void bug6491a(int a = ddoc6491.c6491, string b = core.cpuid.vendor); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc7.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh //----------------------------------------------- /// my enum enum E1 { A, /// element a B /// element b } /// my enum enum E2 { /// element a A, /// element b B } /// my enum enum E3 { A /// element a , B /// element b } /// my enum enum E4 { A /// element a , B /// element b } /// my enum enum E5 { /// element a A , /// element b B } /// Some doc void foo() {} /// More doc alias foo bar; /// asdf class C { /// Some doc abstract void foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc7555.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc7555; /** Dummy doc. $(X0 DelimitedString TokenString) $(X1 DelimitedString TokenString) $(X2 x,HexString) $(X2 x, HexString) $(X3 x,x,HexString) $(X3 x,x, HexString) $(X4 x,x,x,HexString) $(X4 x,x,x, HexString) $(X5 x,x,x,x,HexString) $(X5 x,x,x,x, HexString) $(X6 x,x,x,x,x,HexString) $(X6 x,x,x,x,x, HexString) $(X7 x,x,x,x,x,x,HexString) $(X7 x,x,x,x,x,x, HexString) $(X8 x,x,x,x,x,x,x,HexString) $(X8 x,x,x,x,x,x,x, HexString) $(X9 x,x,x,x,x,x,x,x,HexString) $(X9 x,x,x,x,x,x,x,x, HexString) Macros: X0=$0 X1=$1 X2=$2 X3=$3 X4=$4 X5=$5 X6=$6 X7=$7 X8=$8 X9=$9 */ void dummy(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc7656.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc7656; /** -------- int x; // This is a $ comment (and here is some int y; // more information about that comment) -------- */ void main() { } /** (Regression check) Example: ---- assert(add(1, 1) == 2); ---- */ int add(int a, int b) { return a + b; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc7715.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc7656; /** $1 $2 --- string s = "$1$2 $ $4"; --- */ void foo(){} /// void test(string a = ")") {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc7795.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc7795; struct TimeValue { this(int hour, int minute, int second = 0, int ms = 0) {} } /// struct DateTime { /// this(int x, TimeValue t = TimeValue(0, 0)) {} } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc8.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** foo */ class Foo(T) : Bar { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc8271.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc8271; /** $(まくろ) Macros: まくろ = $(マクロ) マクロ = Macro */ void ddoc8271() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc8739.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc8739; /// void delegate(int a) dg; /// void delegate(int b) dg2; /// void delegate(int c)[] dg3; /// void delegate(int d)* dg4; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh // https://issues.dlang.org/show_bug.cgi?id=273 /// Template Documentation (OK) template Template(T) { } /// Function Documentation (Not included at all by DDoc) void Function(T)(T x) { } /// Class Documentation (OK) class Class(T) { } /// Struct Documentation struct Struct(T) { } /// Union Documentation union Union(T) { } /// Template documentation with anonymous enum template TemplateWithAnonEnum(T) { enum { TemplateWithAnonEnum = 1 } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9037.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9037; /** Example: ---- D d = d; ---- ---- D d = d; ---- */ void test9037() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9155.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9155; /++ + Note: + test document note + 2nd line + Example: + --- + import std.stdio; //& + writeln("Hello world!"); + if (test) { + writefln("D programming language"); + } + + algorithm; + + xxx; //comment + yyy; + /* test + * comment + */ + + // Create MIME Base64 with CRLF, per line 76. +File f = File("./text.txt", "r"); +uint line = 0; + // The ElementType of data is not aggregation type +foreach (encoded; Base64.encoder(data)) + --- +/ /** -------------------------------------------------------- wstring ws; transcode("hello world",ws); // transcode from UTF-8 to UTF-16 -------------------------------------------------------- */ /** * Example: * --- * import std.stdio; //& * writeln("Hello world!"); * if (test) { * writefln("D programming language"); * } * * algorithm; * * xxx; //comment * yyy; * /+ test * + comment * +/ * --- */ /** ---- #!/usr/bin/env rdmd // Computes average line length for standard input. import std.stdio; ---- */ /** --- writefln(q"EOS This is a multi-line heredoc string EOS" ); --- */ void foo(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9305.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9305; /** foo() */ void foo(alias p = (a => a))() {} /* ret / prm / body */ /* _ / _ / expr */ template X(alias pred = x => x) {} /// /* _ / _ / stmt */ template X(alias pred = (x){ int y; return y; }) {} /// ditto /* _ / x / expr */ template X(alias pred = (int x) => x) {} /// ditto /* _ / x / stmt */ template X(alias pred = (int x){ int y; return y; }) {} /// ditto /* x / _ / expr */ /* x / _ / stmt */ /* x / x / expr */ /* x / x / stmt */ /* _ / _ / expr */ template X(alias pred = function (x) => x) {} /// /* _ / _ / stmt */ template X(alias pred = function (x){ return x + 1; }) {} /// ditto /* _ / x / expr */ template X(alias pred = function (int x) => x) {} /// ditto /* _ / x / stmt */ template X(alias pred = function (int x){ return x + 1; }) {} /// ditto /* x / _ / expr */ template X(alias pred = function int(x) => x) {} /// ditto /* x / _ / stmt */ template X(alias pred = function int(x){ return x + 1; }) {} /// ditto /* x / x / expr */ template X(alias pred = function int(int x) => x) {} /// ditto /* x / x / stmt */ template X(alias pred = function int(int x){ return x + 1; }) {} /// ditto /* _ / _ / expr */ template X(alias pred = delegate (x) => x) {} /// /* _ / _ / stmt */ template X(alias pred = delegate (x){ return x + 1; }) {} /// ditto /* _ / x / expr */ template X(alias pred = delegate (int x) => x) {} /// ditto /* _ / x / stmt */ template X(alias pred = delegate (int x){ return x + 1; }) {} /// ditto /* x / _ / expr */ template X(alias pred = delegate int(x) => x) {} /// ditto /* x / _ / stmt */ template X(alias pred = delegate int(x){ return x + 1; }) {} /// ditto /* x / x / expr */ template X(alias pred = delegate int(int x) => x) {} /// ditto /* x / x / stmt */ template X(alias pred = delegate int(int x){ return x + 1; }) {} /// ditto ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9369.d ================================================ // PERMUTE_ARGS: // EXTRA_SOURCES: extra-files/ddoc9369.ddoc // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** Sample: --- a=1; writeln(&a); ! ? --- */ void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9475.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9475; /// foo void foo() { } /// unittest { // comment 1 foreach (i; 0 .. 10) { // comment 2 documentedFunction(); } } /// bar void bar() { } /// unittest { // bar comment } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9497a.d ================================================ // EXTRA_SOURCES: extra-files/ddoc9497a.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** foo function. Args: $(XYZ arg1, arg2) */ void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9497b.d ================================================ // EXTRA_SOURCES: extra-files/ddoc9497b.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** foo function. Args: $(XYZ arg1, arg2) */ void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9497c.d ================================================ // EXTRA_SOURCES: extra-files/ddoc9497c.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** foo function. Args: $(XYZ arg1, arg2) */ void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9497d.d ================================================ // EXTRA_SOURCES: extra-files/ddoc9497d.ddoc // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /** foo function. Args: $(XYZ arg1, arg2) */ void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9676a.d ================================================ // PERMUTE_ARGS: // EXTRA_SOURCES: /extra-files/ddoc9676a.ddoc // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9676a; /// deprecated void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9676b.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9676b; /// deprecated void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9727.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9727; /** The function foo. */ void foo(int x); /** */ unittest { foo(1); } /** foo can be used like this: */ unittest { foo(2); } /** foo can also be used like this: */ unittest { foo(3); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9789.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -w -o- -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddoc9789; /// struct S {} /// alias A = S; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddoc9903.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /// sss struct S9903X {} /// Ditto struct S9903Y {} /// ccc class C9903X {} /// Ditto class C9903Y {} /// uuu union U9903X {} /// Ditto union U9903Y {} /// iii interface I9903X {} /// Ditto interface I9903Y {} /// eee enum E9903X { a } /// Ditto enum E9903Y { a } /// enum { a9903, /// ea b9903, /// Ditto c9903, /// ec } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddocYear.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocYear-postscript.sh /// $(YEAR) int year; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddocbackticks.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh /++ Closely related to std.datetime is `core.time`, and some of the time types used in std.datetime come from there - such as $(CXREF time, Duration), $(CXREF time, TickDuration), and $(CXREF time, FracSec). core.time is publically imported into std.datetime, it isn't necessary to import it separately. +/ module ddocbackticks; /// This should produce `inline code`. void test() {} /// But `this should NOT be inline' /// /// However, restarting on a new line should be `inline again`. void test2() {} /// This `int foo;` should show highlight on foo, but not int. void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ddocunittest.d ================================================ // PERMUTE_ARGS: -unittest // REQUIRED_ARGS: -D -w -o- -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh module ddocunittest; /* Insert test-cases for documented unittests feature here. */ /// foo function - 1 example int foo(int a, int b) { return a + b; } /// unittest { assert(foo(1, 1) == 2); } /// bar function - 1 example bool bar() { return true; } /// unittest { // documented assert(bar()); } /// placeholder unittest { } /// doo function - no examples void doo() { } /// private unittest { // undocumented doo(); } unittest { // undocumented doo(); } /** add function - 3 examples Examples: ---- assert(add(1, 1) == 2); ---- */ int add(int a, int b) { return a + b; } /// unittest { // documented assert(add(3, 3) == 6); assert(add(4, 4) == 8); } unittest { // undocumented assert(add(2, 2) + add(2, 2) == 8); } /// unittest { // documented assert(add(5, 5) == 10); assert(add(6, 6) == 12); } /// class Foo immutable pure nothrow class Foo { int x; /// unittest { // another foo example Foo foo = new Foo; } } /// unittest { Foo foo = new Foo; } pure { const { immutable { /// some class - 1 example class SomeClass {} } } } /// unittest { SomeClass sc = new SomeClass; } /// Outer - 1 example class Outer { /// Inner static class Inner { } /// unittest { Inner inner = new Inner; } } /// unittest { Outer outer = new Outer; } /** foobar - no examples */ void foobar() { } unittest { foobar(); } /** func - 4 examples Examples: --- foo(1); --- Examples: --- foo(2); --- */ void foo(int x) { } /// unittest { foo(2); } /// unittest { foo(4); } // ------------------------------------ // insert import declaration between documented function and unittests /// void fooImport() {} import core.stdc.stdio; /// test unittest { fooImport(); } /// void fooStaticImport() {} static import core.stdc.stdlib; /// test unittest { fooStaticImport(); } /// void fooPublicImport() {} public import core.stdc.string; /// test unittest { fooPublicImport(); } /// void fooSelectiveImport() {} import core.stdc.ctype : isalpha; /// test unittest { fooSelectiveImport(); } /// void fooRenamedImport() {} import io = core.stdc.stdio; /// test unittest { fooRenamedImport(); } // ------------------------------------ // documented unittest after conditional declarations static if (true) void fooConditionalDecl1a() {} /** */ unittest { int x1a; } /// static if (true) { void fooConditionalDecl1b() {} /** */ } unittest { int x1b; } /// static if (false) void fooConditionalDecl2a() {} /** */ unittest { int x2a; } /// static if (false) { void fooConditionalDecl2b() {} /** */ } unittest { int x2b; } /// static if (true) { void fooConditionalDecl3a() {} /** */ } else { void barConditionalDecl3a() {} /** */ } unittest { int x3a; } /// static if (true) { void fooConditionalDecl3b() {} /** */ } else { void barConditionalDecl3b() {} /** */ } unittest { int x3b; } /// static if (false) void fooConditionalDecl4a() {} /** */ else void barConditionalDecl4a() {} /** */ unittest { int x4a; } /// static if (false) { void fooConditionalDecl4b() {} /** */ } else { void barConditionalDecl4b() {} /** */ } unittest { int x4b; } /// static if (true) {} else void barConditionalDecl5a() {} /** */ unittest { int x5a; } /// static if (true) {} else { void barConditionalDecl5b() {} /** */ } unittest { int x5b; } /// static if (false) {} else void barConditionalDecl6a() {} /** */ /// unittest { int x6a; } static if (false) {} else { void barConditionalDecl6b() {} /** */ } /// unittest { int x6b; } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=9474 /// void foo9474() { } version(none) unittest { } /// Example unittest { foo9474(); } /// doc void bar9474() { } version(none) unittest { } /// Example unittest { bar9474(); } /// struct S9474 { } /// unittest { S9474 s; } /// auto autovar9474 = 1; /// unittest { int v = autovar9474; } /// auto autofun9474() { return 1; } /// unittest { int n = autofun9474(); } /// template Template9474() { /// Shouldn't link following unittest to here void foo() {} } /// unittest { alias Template9474!() T; } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=9713 /// void fooNoDescription() {} /// unittest { fooNoDescription(); } /// unittest { if (true) {fooNoDescription(); } /* comment */ } // ------------------------------------ /// test for https://issues.dlang.org/show_bug.cgi?id=9757 void foo9757() {} /// ditto void bar9757() {} /// ditto void baz9757() {} /// unittest { foo9757(); bar9757(); } /// unittest { bar9757(); foo9757(); } /// with template functions auto redBlackTree(E)(E[] elems...) { return 1; } /// ditto auto redBlackTree(bool allowDuplicates, E)(E[] elems...) { return 2; } /// ditto auto redBlackTree(alias less, E)(E[] elems...) { return 3; } /// unittest { auto rbt1 = redBlackTree(0, 1, 5, 7); auto rbt2 = redBlackTree!string("hello", "world"); auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=9758 /// test void foo(){} /// unittest { } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=10519 /// bool balancedParens10519(string, char, char) { return true; } /// unittest { auto s = "1 + (2 * (3 + 1 / 2)"; assert(!balancedParens10519(s, '(', ')')); } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=12097 /// declaration struct S12097 { /// method void foo() {} } /// ditto void f12097() {} /// ddoc code 1 unittest { int a = 1; } /// ditto struct T12097(T) {} /// ddoc code 2 unittest { int[] arr; } // ------------------------------------ // https://issues.dlang.org/show_bug.cgi?id=14594 /******************* * testA */ void fun14594a()() {} /// unittest { fun14594a(); } /******************* * testB */ void fun14594b()() {} /// ditto void fun14594b(T)(T) {} /// unittest { fun14594b(); fun14594b(1); } /******************* * testC */ void fun14594c()() {} /// unittest { fun14594c(); fun14594c(1); } /// ditto void fun14594c(T)(T) {} /******************* * testD */ void fun14594d()() {} /// unittest { fun14594d(); } /// ditto void fun14594d(T)(T) {} /// unittest { fun14594d(1); } /******************* * testE */ template fun14594e() { /// concatenated doc-comment fun14594e void fun14594e() {} /// ignored-unittest fun14594e unittest { fun14594e(); } } /// doc-unittest fun14594e unittest { fun14594e(); } /******************* * testF */ template fun14594f() { /// concatenated doc-comment fun14594f void fun14594f() {} /// ignored-unittest fun14594f unittest { fun14594f(); } } /// ditto template fun14594f(T) { /// ignored doc-comment fun14594f void fun14594f(T) {} /// ignored-unittest fun14594f unittest { fun14594f(1); } } /// doc-unittest fun14594f unittest { fun14594f(); } // ------------------------------------ void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/debuginfo.d ================================================ // REQUIRED_ARGS: -g struct Bug7127a { const(Bug7127a)* self; } struct Bug7127b { void function(const(Bug7127b) self) foo; } void main() { Bug7127a a; Bug7127b b; } // https://issues.dlang.org/show_bug.cgi?id=13975 static immutable int a = 8; enum Bar { aa = a } void foo(Bar bar) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/defa.d ================================================ // PERMUTE_ARGS: module defa; private import imports.defaa; public abstract class A { Display d; int style; this() {} public this(A parent, int style) { this.style = style; d = parent.d; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/depmsg.d ================================================ // REQUIRED_ARGS: -d // PERMUTE_ARGS: -dw void main() { class Inner { deprecated("With message!") { struct A { } class B { } interface C { } union D { } enum E { e }; //typedef int F; alias int G; static int H; template I() { class I {} } } } with(Inner) { A a; B b; C c; D d; E e; //F f; G g; auto h = H; I!() i; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/deprecate12979a.d ================================================ // REQUIRED_ARGS: -dw // PERMUTE_ARGS: /* TEST_OUTPUT: --- compilable/deprecate12979a.d(13): Deprecation: `asm` statement is assumed to throw - mark it with `nothrow` if it does not --- */ void foo() nothrow { version(GNU) { asm { ""; } } else { asm { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/deprecate14283.d ================================================ // REQUIRED_ARGS: -dw // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ class C { void bug() { autoref(this); // 'auto ref' becomes non-ref parameter autoref(super); // 'auto ref' becomes non-ref parameter } } void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/depsOutput9948.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -deps=${RESULTS_DIR}/compilable/depsOutput9948.deps // POST_SCRIPT: compilable/extra-files/depsOutput.sh // EXTRA_SOURCES: /extra-files/depsOutput9948a.d module depsOutput9948; import depsOutput9948a; void main() { templateFunc!("import std.string;")(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/derivedarray.d ================================================ // PERMUTE_ARGS: class C {} class D : C {} void dynamicarrays() { C[] a; D[] b; const(C)[] c; const(D)[] d; immutable(C)[] e; immutable(D)[] f; static assert( __traits(compiles, a = a)); static assert(!__traits(compiles, a = b)); static assert(!__traits(compiles, a = c)); static assert(!__traits(compiles, a = d)); static assert(!__traits(compiles, a = e)); static assert(!__traits(compiles, a = f)); static assert(!__traits(compiles, b = a)); static assert( __traits(compiles, b = b)); static assert(!__traits(compiles, b = c)); static assert(!__traits(compiles, b = d)); static assert(!__traits(compiles, b = e)); static assert(!__traits(compiles, b = f)); static assert( __traits(compiles, c = a)); static assert( __traits(compiles, c = b)); static assert( __traits(compiles, c = c)); static assert( __traits(compiles, c = d)); static assert( __traits(compiles, c = e)); static assert( __traits(compiles, c = f)); static assert(!__traits(compiles, d = a)); static assert( __traits(compiles, d = b)); static assert(!__traits(compiles, d = c)); static assert( __traits(compiles, d = d)); static assert(!__traits(compiles, d = e)); static assert( __traits(compiles, d = f)); static assert(!__traits(compiles, e = a)); static assert(!__traits(compiles, e = b)); static assert(!__traits(compiles, e = c)); static assert(!__traits(compiles, e = d)); static assert( __traits(compiles, e = e)); static assert( __traits(compiles, e = f)); static assert(!__traits(compiles, f = a)); static assert(!__traits(compiles, f = b)); static assert(!__traits(compiles, f = c)); static assert(!__traits(compiles, f = d)); static assert(!__traits(compiles, f = e)); static assert( __traits(compiles, f = f)); } void statictodynamicarrays() { C[] a; D[] b; const(C)[] c; const(D)[] d; immutable(C)[] e; immutable(D)[] f; C[1] sa; D[1] sb; const(C)[1] sc = void; const(D)[1] sd = void; immutable(C)[1] se = void; immutable(D)[1] sf = void; static assert( __traits(compiles, a = sa)); static assert(!__traits(compiles, a = sb)); static assert(!__traits(compiles, a = sc)); static assert(!__traits(compiles, a = sd)); static assert(!__traits(compiles, a = se)); static assert(!__traits(compiles, a = sf)); static assert(!__traits(compiles, b = sa)); static assert( __traits(compiles, b = sb)); static assert(!__traits(compiles, b = sc)); static assert(!__traits(compiles, b = sd)); static assert(!__traits(compiles, b = se)); static assert(!__traits(compiles, b = sf)); static assert( __traits(compiles, c = sa)); static assert( __traits(compiles, c = sb)); static assert( __traits(compiles, c = sc)); static assert( __traits(compiles, c = sd)); static assert( __traits(compiles, c = se)); static assert( __traits(compiles, c = sf)); static assert(!__traits(compiles, d = sa)); static assert( __traits(compiles, d = sb)); static assert(!__traits(compiles, d = sc)); static assert( __traits(compiles, d = sd)); static assert(!__traits(compiles, d = se)); static assert( __traits(compiles, d = sf)); static assert(!__traits(compiles, e = sa)); static assert(!__traits(compiles, e = sb)); static assert(!__traits(compiles, e = sc)); static assert(!__traits(compiles, e = sd)); static assert( __traits(compiles, e = se)); static assert( __traits(compiles, e = sf)); static assert(!__traits(compiles, f = sa)); static assert(!__traits(compiles, f = sb)); static assert(!__traits(compiles, f = sc)); static assert(!__traits(compiles, f = sd)); static assert(!__traits(compiles, f = se)); static assert( __traits(compiles, f = sf)); } void staticarrays() { C[1] sa; D[1] sb; const(C)[1] sc = sa; const(D)[1] sd = sb; sa = sb; static assert(!__traits(compiles, sb = sa)); } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/diag11066.d ================================================ // REQUIRED_ARGS: -w -profile /* TEST_OUTPUT: --- --- */ void main() { string s; foreach (dchar c; s) // affected by dchar return; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/diag3243.d ================================================ // REQUIRED_ARGS: -vtls // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ template T() { static this() {} } class C { alias ti = T!(); } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/dip22.d ================================================ // REQUIRED_ARGS: -de import imports.dip22; class Foo : Base1, Base2 { void test() { static assert(typeof(bar()).sizeof == 2); static assert(baz == 2); static assert(T.sizeof == 2); } } void test() { bar(12); baz(12); 12.bar(); 12.baz(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/disable_new.d ================================================ class C { // force user of a type to use an external allocation strategy @disable new(); } struct S { // force user of a type to use an external allocation strategy @disable new(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/empty_file.d ================================================ ================================================ FILE: gcc/testsuite/gdc.test/compilable/exception.d ================================================ class E2 : Exception { this() { super(null); } } class E3 : Exception { this() { super(null); } } void main() { try { } catch (E3) { } catch (E2) { } catch (Exception) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/c6395.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=6395 template map(alias fun) { auto map(Range)(Range r) { struct Result { @property auto ref front() { return fun("a"); } } return Result(); } } Range find(alias pred, Range)(Range haystack) { pred(haystack.front); return haystack; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc10367.ddoc ================================================ DDOC_ENUM_BASETYPE = $(RED $0) ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc198.ddoc ================================================ DDOC_PSYMBOL = $0 DDOC_PSUPER_SYMBOL = $0 ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc3.ddoc ================================================ HELLO = world UNUSED=unused ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9369.ddoc ================================================ ESCAPES = /&/AddressOf!/ /!/Exclamation/ /?/QuestionMark/ ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497a.ddoc ================================================ DDOC_UNDEFINED_MACRO= ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497b.ddoc ================================================ DDOC_UNDEFINED_MACRO=$(DOLLAR)($1 $+) ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497c.ddoc ================================================ DDOC_UNDEFINED_MACRO=$+ ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497d.ddoc ================================================ DDOC_UNDEFINED_MACRO=ERROR_UNDEFINED_MACRO: "$1" ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9676a.ddoc ================================================ DEPRECATED = $0 ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/ddoc9764.dd ================================================ Ddoc Check ddoc9764 document. ---- // Check ddoc9764 comment. ddoc9764(); ---- ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d ================================================ module depsOutput9948a; void templateFunc(string myImport)() { mixin(myImport); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/e6815.d ================================================ bool e(T)(T) { f(true); return true; } void f(lazy bool) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/emptymain.d ================================================ void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/example7190/controllers/HomeController.d ================================================ module example7190.controllers.HomeController; import serenity7190.core.Controller; class HomeController : Controller { mixin register!(HomeController); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/example7190/models/HomeModel.d ================================================ module example7190.models.HomeModel; import serenity7190.core.Model; struct Article { ulong id; } class HomeModel : Model { private SqlitePersister!Article mArticles; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/header1.d ================================================ // REQUIRED_ARGS: -ignore module foo.bar; import core.vararg; import std.stdio; pragma(lib, "test"); pragma(msg, "Hello World"); pragma(linkerDirective, "/DEFAULTLIB:test2"); static assert(true, "message"); alias double mydbl; alias fl1 = function () in {} in (true) out (; true) out (r; true) out { } out (r) { } do { return 2; }; alias fl2 = function () in (true) out(; true) out(r; true) { return 2; }; int testmain() in { assert(1+(2+3) == -(1 - 2*3)); } out (result) { assert(result == 0); } body { float f = float.infinity; int i = cast(int) f; writeln(i,1,2); writeln(cast(int)float.max); assert(i == cast(int)float.max); assert(i == 0x80000000); return 0; } struct S { int m, n; } template Foo(T, int V) { void foo(...) { static if (is(Object _ : X!TL, alias X, TL...)) {} // https://issues.dlang.org/show_bug.cgi?id=10044 auto x = __traits(hasMember, Object, "noMember"); auto y = is(Object : X!TL, alias X, TL...); assert(!x && !y, "message"); S s = { 1,2 }; auto a = [1, 2, 3]; auto aa = [1:1, 2:2, 3:3]; int n,m; } int bar(double d, int x) { if (d) { d++; } else d--; asm { naked ; mov EAX, 3; } for (;;) { d = d + 1; } for (int i = 0; i < 10; i++) { d = i ? d + 1 : 5; } char[] s; foreach (char c; s) { d *= 2; if (d) break; else continue; } switch (V) { case 1: case 2: break; case 3: goto case 1; case 4: goto default; default: d /= 8; break; } enum Label { A, B, C } void fswitch(Label l) { final switch (l) { case A: break; case B: break; case C: break; } } loop: while (x) { x--; if (x) break loop; else continue loop; } do { x++; } while (x < 10); try { bar(1, 2); } catch (Object o) { x++; } finally { x--; } try bar(1, 2); catch(Object o) x++; finally x--; Object o; synchronized (o) { x = ~x; } synchronized { x = x < 3; } with (o) { toString(); } } } static this() { } static ~this() { } pure nothrow @safe @nogc static this() {} pure nothrow @safe @nogc static ~this() {} static this() pure nothrow @safe @nogc {} static ~this() pure nothrow @safe @nogc {} pure nothrow @safe @nogc shared static this() {} pure nothrow @safe @nogc shared static ~this() {} shared static this() pure nothrow @safe @nogc {} shared static ~this() pure nothrow @safe @nogc {} interface iFoo{} class xFoo: iFoo{} interface iFoo2{} class xFoo2: iFoo, iFoo2{} class Foo3 { this(int a, ...){} this(int* a){} } alias int myint; static notquit = 1; class Test { void a() {} void b() {} void c() {} void d() {} void e() {} void f() {} void g() {} void h() {} void i() {} void j() {} void k() {} void l() {} void m() {} void n() {} void o() {} void p() {} void q() {} void r() {} void s() {} void t() {} void u() {} void v() {} void w() {} void x() {} void y() {} void z() {} void aa() {} void bb() {} void cc() {} void dd() {} void ee() {} // Try adding or removing some functions here to see the effect. template A(T) { } alias A!(uint) getHUint; alias A!(int) getHInt; alias A!(float) getHFloat; alias A!(ulong) getHUlong; alias A!(long) getHLong; alias A!(double) getHDouble; alias A!(byte) getHByte; alias A!(ubyte) getHUbyte; alias A!(short) getHShort; alias A!(ushort) getHUShort; alias A!(real) getHReal; alias void F(); pure nothrow @safe @nogc unittest {} pure nothrow @safe @nogc invariant {} pure nothrow @safe @nogc invariant (true); pure nothrow @safe @nogc new (size_t sz) { return null; } pure nothrow @safe @nogc delete (void* p) { } } template templ( T ) { void templ( T val ) { pragma( msg, "Invalid destination type." ); } } static char[] charArray = [ '\"', '\'' ]; class Point { auto x = 10; uint y = 20; } template Foo2(bool bar) { void test() { static if(bar) { int i; } else { } static if(!bar) { } else { } } } template Foo4() { void bar() { } } template Foo4x( T... ) {} class Baz4 { mixin Foo4 foo; mixin Foo4x!(int, "str") foox; alias foo.bar baz; } int test(T)(T t) { if (auto o = cast(Object)t) return 1; return 0; } enum x6 = 1; bool foo6(int a, int b, int c, int d) { return (a < b) != (c < d); } auto foo7(int x) { return 5; } class D8{} void func8() { scope a= new D8(); } T func9(T)() if (true) { T i; scope(exit) i= 1; scope(success) i = 2; scope(failure) i = 3; return i; } template V10(T) { void func() { for(int i,j=4; i<3;i++) { } } } int foo11(int function() fn) { return fn(); } int bar11(T)() { return foo11(function int (){ return 0; }); } struct S6360 { @property long weeks1() const pure nothrow { return 0; } @property const pure nothrow long weeks2() { return 0; } } struct S12 { /// postfix storage class and constructor this(int n) nothrow{} /// prefix storage class (==StorageClassDeclaration) and constructor nothrow this(string s){} } /// dummy struct T12 { /// postfix storage class and template constructor this()(int args) immutable { } /// prefix storage class (==StorageClassDeclaration) and template constructor immutable this(A...)(A args){ } } // https://issues.dlang.org/show_bug.cgi?id=6591 import std.stdio : writeln, F = File; void foo6591()() { import std.stdio : writeln, F = File; } // https://issues.dlang.org/show_bug.cgi?id=8081 version(unittest) { pure nothrow unittest {} pure nothrow unittest {} public unittest {} extern(C) unittest {} align unittest {} } // https://issues.dlang.org/show_bug.cgi?id=10334 template Foo10334(T) if (Bar10334!()) {} /// template Foo10334(T) if (Bar10334!100) {} /// template Foo10334(T) if (Bar10334!3.14) {} /// template Foo10334(T) if (Bar10334!"str") {} /// template Foo10334(T) if (Bar10334!1.4i) {} /// template Foo10334(T) if (Bar10334!null) {} /// template Foo10334(T) if (Bar10334!true) {} /// template Foo10334(T) if (Bar10334!false) {} /// template Foo10334(T) if (Bar10334!'A') {} /// template Foo10334(T) if (Bar10334!int) {} /// template Foo10334(T) if (Bar10334!string) {} /// template Foo10334(T) if (Bar10334!wstring) {} /// template Foo10334(T) if (Bar10334!dstring) {} /// template Foo10334(T) if (Bar10334!this) {} /// template Foo10334(T) if (Bar10334!([1,2,3])) {} /// template Foo10334(T) if (Bar10334!(Baz10334!())) {} /// template Foo10334(T) if (Bar10334!(Baz10334!T)) {} /// template Foo10334(T) if (Bar10334!(Baz10334!100)) {} /// template Foo10334(T) if (Bar10334!(.foo)) {} /// template Foo10334(T) if (Bar10334!(const int)) {} /// template Foo10334(T) if (Bar10334!(shared T)) {} /// template Test10334(T...) {} /// mixin Test10334!int a; /// mixin Test10334!(int,long) b; /// mixin Test10334!"str" c; /// // https://issues.dlang.org/show_bug.cgi?id=12266 auto clamp12266a(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) { return 0; } pure clamp12266b(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) { return 0; } @disable pure clamp12266c(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) { return 0; } // https://issues.dlang.org/show_bug.cgi?id=13832 alias Dg13832 = ref int delegate(); // https://issues.dlang.org/show_bug.cgi?id=16590 class TestClass { int aa; int b1, b2; this(int b1, int b2) { this.b1 = b1; this.b2 = b2; } ref foo() { return aa; } ref retFunc() return { return aa; } ~this() @trusted @disable @nogc { } } class FooA { protected void method42() { } ~this() @safe { } } class Bar : FooA { override void method42() { } } double foo() @trusted { int a = 5; return a; } struct Foo1(size_t Size = 42 / magic()) { } size_t magic() { return 42; } class Foo2A { immutable(FooA) Dummy = new immutable(FooA); private immutable pure nothrow @nogc @safe this() { } } // https://issues.dlang.org/show_bug.cgi?id=15676 struct Foo3A(T) { @disable this(this); @disable this(); } // return ref, return scope, return ref scope ref int foo(return ref int a) @safe { return a; } int* foo(return scope int* a) @safe { return a; } ref int* foo(scope return ref int* a) @safe { return a; } struct SafeS { @safe: ref SafeS foo() return { return this; } SafeS foo2() return scope { return this; } ref SafeS foo3() return scope { return this; } int* p; } void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {} enum Test14UDA1; struct Test14UDA2 { string str; } Test14UDA2 test14uda3(string name) { return Test14UDA2(name); } struct Test14UDA4(string v){} void test14x(@Test14UDA1 int, @Test14UDA2("1") int, @test14uda3("2") int, @Test14UDA4!"3" int) {} void test15x(@(20) void delegate(int) @safe dg){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/header18365.d ================================================ module foo.bar.ba; nothrow pure @nogc @safe package(foo) { void foo(); nothrow pure @nogc @safe package(foo.bar) void foo2(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/header2.d ================================================ // for D 2.0 only class C { } void foo(const C c, const(char)[] s, const int* q, const (int*) p) { } void bar(in void *p) { } void f(void function() f2); class C2; void foo2(const C2 c); struct Foo3 { int k; ~this() @trusted @disable @nogc { k = 1; } this(this) { k = 2; } } class C3 { @property int get() { return 0; } } T foo3(T)() {} struct S4A(T) { T x; ~this() @safe {} } struct S4B(T) if (1) { T x; } union U4A(T) { T x; } union U4B(T) if (2*4 == 8) { T x; } class C4A(T) { T x; } class C4B(T) if (true) { T x; } class C4C(T) : C4A!int if (!false) { T x; } class C4D(T) if (!false) : C4B!long, C4C!(int[]) { T x; } interface I4(T) if ((int[1]).length == 1) { T x; } // eponymous template case template MyClass4(T) if (is(typeof(T.subtype))) { alias HelperSymbol = T.subtype; class MyClass4 {} } enum isInt(T) = is(T == int); enum bool isString(T) = is(T == string); static immutable typeName(T) = T.stringof; int storageFor(T) = 0; template templateVariableFoo(T) { enum int templateVariableFoo = T.stringof.length; } template templateVariableBar(T) if (is(T == int)) { enum int templateVariableBar = T.stringof.length; } auto flit = 3 / 2.0; // https://issues.dlang.org/show_bug.cgi?id=11217 void foo11217()( const int[] arr) {} void foo11217()(immutable int[] arr) {} void foo11217()( ref int[] arr) {} void foo11217()( lazy int[] arr) {} void foo11217()( auto ref int[] arr) {} void foo11217()( scope int[] arr) {} void foo11217()( in int[] arr) {} void foo11217()( inout int[] arr) {} // https://issues.dlang.org/show_bug.cgi?id=13275 void test13275() { if ( auto n = 1) {} if ( const n = 1) {} if ( immutable n = 1) {} if (shared n = 1) {} if (shared const n = 1) {} if ( int n = 1) {} if ( const int n = 1) {} if ( immutable int n = 1) {} if (shared int n = 1) {} if (shared const int n = 1) {} if ( const(int) n = 1) {} if ( immutable(int) n = 1) {} if (shared (int) n = 1) {} if (shared const(int) n = 1) {} foreach ( e; [1,2]) {} foreach ( const e; [1,2]) {} foreach ( immutable e; [1,2]) {} foreach (shared e; [1,2]) {} foreach (shared const e; [1,2]) {} foreach ( int e; [1,2]) {} foreach ( const int e; [1,2]) {} foreach ( immutable int e; [1,2]) {} foreach (shared int e; [1,2]) {} foreach (shared const int e; [1,2]) {} foreach ( int e; [1,2]) {} foreach ( const(int) e; [1,2]) {} foreach ( immutable(int) e; [1,2]) {} foreach (shared (int) e; [1,2]) {} foreach (shared const(int) e; [1,2]) {} } // https://issues.dlang.org/show_bug.cgi?id=9766 align (1) struct S9766 { align (true ? 2 : 3): int var1; align: int var2; } // https://issues.dlang.org/show_bug.cgi?id=16649 void leFoo()() { sign = a == 2 ? false : (y < 0) ^ sign; sign = a == 2 ? false : sign ^ (y < 0); sign = 2 + 3 | 7 + 5; } // https://issues.dlang.org/show_bug.cgi?id=17371 interface LeInterface {} class LeClass { this() { auto foo = new class () LeInterface {}; } } const levar = new class LeClass, LeInterface {}; // https://issues.dlang.org/show_bug.cgi?id=17663 private: public struct Export {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/header3.d ================================================ auto elseifchain() { bool a,b,c; if (a) { } else if (b) { } else if (c) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/imp12624.d ================================================ // typecons.d template RebindableCommon(T, U, This) { union { U stripped; } void opAssign(T another) { stripped = cast() another; } this(T initializer) { opAssign(initializer); } } template Rebindable(T) { static if (is(T == immutable U, U)) struct Rebindable { mixin RebindableCommon!(T, U, Rebindable); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d ================================================ struct BugInt { uint[] data = ZEROX; } enum uint [] ZEROX = [0]; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/imp9057_2.d ================================================ struct BugInt { uint[] data = [0]; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/minimal/object.d ================================================ module object; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/common.d ================================================ module pkgDIP37.datetime.common; void def(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/package.d ================================================ module pkgDIP37.datetime; public import pkgDIP37.datetime.common; //alias std.datetime.common.def def; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/common.di ================================================ module pkgDIP37.test17629.common; void foo17629(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/package.di ================================================ module pkgDIP37.test17629; public import pkgDIP37.test17629.common; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/liba.d ================================================ module pkgDIP37_10302.liba; void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/libb.d ================================================ module pkgDIP37_10302.libb; import pkgDIP37_10302.liba; void bar() { foo(); // should be error, but unfortunately this works by bug 314 now. //lib.foo(); pkgDIP37_10302.liba.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/package.d ================================================ module pkgDIP37_10302; public import pkgDIP37_10302.liba; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mbar.d ================================================ module pkgDIP37_10354.mbar; void bar(T)() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mfoo.d ================================================ module pkgDIP37_10354.mfoo; void foo(T)() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/package.d ================================================ module pkgDIP37_10354; public import pkgDIP37_10354.mfoo; public import pkgDIP37_10354.mbar; ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/mod.d ================================================ module pkgDIP37_10421.algo.mod; import pkgDIP37_10421.algo; // foo import pkgDIP37_10421.except; // baz void test() { foo(); // should be accessible baz(); // should be accessible } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/package.d ================================================ module pkgDIP37_10421.algo; public import pkgDIP37_10421.algo.mod; package { void foo() {} void bar() { foo(); } // should be accessible } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/except.d ================================================ module pkgDIP37_10421.except; package void baz() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Controller.d ================================================ class Controller { mixin template register(T : Controller) { enum _s_pkg = __traits(parent, __traits(parent, __traits(parent, T))).stringof["package ".length .. $]; enum _s_model = T.stringof[0 .. $-`Controller`.length] ~ `Model`; mixin(q{enum _ = is(} ~ _s_pkg ~ q{.models.} ~ _s_model ~ q{.} ~ _s_model ~ q{ : serenity7190.core.Model.Model);}); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Model.d ================================================ class SqlitePersister(T) { static assert(T.tupleof.length > 0, T.stringof ~ `(` ~ (T.tupleof.length + '0') ~ `): ` ~ T.tupleof.stringof); } class Model {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test14894a.d ================================================ module imports.test14894a; mixin template Protocol() { void onReceive() {} } struct Foo { mixin Protocol!(); unittest { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test14894main.d ================================================ import test14894a; void main() { Foo foo; foo.onReceive(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test16080b.d ================================================ import imp16080; void test2() { A!() v = A!().a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test6461/a.d ================================================ module a; import tmpl; TypeInfo fun() { return typeid(Tmpl!int()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test6461/b.d ================================================ module b; import tmpl; TypeInfo fun() { return typeid(Tmpl!long()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test6461/main.d ================================================ import a, b; void main() { auto t1 = a.fun(); auto t2 = b.fun(); assert(t1 != t2); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test6461/tmpl.d ================================================ module tmpl; struct Tmpl(T) { T a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test9680dllmain.d ================================================ import core.sys.windows.windows; extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test9680main.d ================================================ void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/extra-files/test9680winmain.d ================================================ import core.sys.windows.windows; extern(Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/fail260.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -d struct Static(uint width2, uint height2) { immutable width = width2; immutable height = height2; static Static opCall() { Static ret; return ret; } alias float E; template MultReturn(alias M1, alias M2) { alias Static!(M2.width, M1.height) MultReturn; } void opMultVectors(M2)(M2 b) { alias MultReturn!(Static, M2) ret_matrix; } } void test() { alias Static!(4, 1) matrix_stat; static matrix_stat m4 = matrix_stat(); alias Static!(1, 4) matrix_stat2; static m6 = matrix_stat2(); m6.opMultVectors(m4); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/filefullpath_18911.d ================================================ // REQUIRED_ARGS: -Icompilable/imports -c -o- // EXTRA_FILES: imports/a18911.d import a18911; enum THIS_FILE = __FILE_FULL_PATH__; enum suffix_this = "filefullpath_18911.d"; static assert(THIS_FILE[0..$-suffix_this.length-1] == A_FILE[0..$-suffix_a.length-1]); ================================================ FILE: gcc/testsuite/gdc.test/compilable/fix17123.d ================================================ /* PERMUTE_ARGS: https://issues.dlang.org/show_bug.cgi?id=17123 */ void test() { char[256] buffer; char[] delegate() read = () { return buffer[]; }; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/fix17335.d ================================================ /* * PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=17335 bool alwaysFalse() { return false; } void main() { static if (false && a == 1) { } static if ("a" == "b" && b == 1) { } static if (alwaysFalse() && c == 1) { } static if (!alwaysFalse() || d == 1) { } static if (alwaysFalse() ? e == 1 : 1) { } static if (!alwaysFalse() ? 1 : f == 1) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/fix17349.d ================================================ /* REQUIRED_ARGS: -dw * PERMUTE_ARGS: * TEST_OUTPUT: --- compilable/fix17349.d(37): Deprecation: cannot implicitly override base class method `fix17349.E.foo` with `fix17349.F.foo`; add `override` attribute --- */ // https://issues.dlang.org/show_bug.cgi?id=17349 struct S { } class C { void bar(); void foo(void* p); void abc(Object); void def(S); } class D : C { override void bar() const; override void foo(const void*); override void abc(const Object); override void def(const S); } alias fp_t = void function(int*); @safe void abc(const int*); fp_t fp = &abc; class E { void foo(void*); } class F : E { void foo(const void*); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/fix17686.d ================================================ /* REQUIRED_ARGS: * PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=17686 interface INode { @property INode parentNode(); @property IDocument ownerDocument(); } interface IDocument: INode {} interface IEntityReference: INode {} class DOMImplementation(T) { abstract class Node: INode { override { @property Node parentNode() { return null; } @property Document ownerDocument() { return null; } } @property bool readonly() { return true; } } abstract class NodeWithChildren: Node {} class Document: NodeWithChildren, IDocument {} class EntityReference: NodeWithChildren, IEntityReference { override { @property bool readonly() { return true; } } } } void main() { alias aaa = DOMImplementation!string; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/forward1.d ================================================ // REQUIRED_ARGS: -g // https://issues.dlang.org/show_bug.cgi?id=104 // fails only with -g Foofunc f; alias int Foo; alias int function(Foo) Foofunc; ================================================ FILE: gcc/testsuite/gdc.test/compilable/future.d ================================================ /* PERMUTE_ARGS: * TEST_OUTPUT: --- compilable/future.d(15): Deprecation: `@__future` base class method `future.A.msg` is being overridden by `future.B.msg`; rename the latter --- */ class A { @__future char msg() { return 'a'; } } class B : A { char msg() { return 'b'; } } class C : B { override char msg() { return 'c'; } } class D : A { override char msg() { return 'd'; } } int main() { auto a = new A(); assert(a.msg() == 'a'); auto b = new B(); assert(b.msg() == 'b'); auto c = new C(); assert(c.msg() == 'c'); auto d = new D(); assert(d.msg() == 'd'); assert(b.A.msg() == 'a'); auto ba = cast(A)b; assert(ba.msg() == 'a'); auto da = cast(A)d; assert(da.msg() == 'd'); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/futurexf.d ================================================ /* PERMUTE_ARGS: REQUIRED_ARGS: -Xf${RESULTS_DIR}/compilable/futurexf.json */ class A { @__future char msg(); } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/header18364.d ================================================ // REQUIRED_ARGS: -o- -Hf${RESULTS_DIR}/compilable/header18364.di // POST_SCRIPT: compilable/extra-files/header-postscript.sh module foo.bar.ba; @safe pure nothrow @nogc package(foo): void foo(); @safe pure nothrow @nogc package(foo.bar): void foo2(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/header18365.d ================================================ // REQUIRED_ARGS: -c -o- -Hf${RESULTS_DIR}/compilable/header18365.di // POST_SCRIPT: compilable/extra-files/header-postscript.sh struct FullCaseEntry { dchar[3] seq; ubyte n, size; ubyte entry_len; @property auto value() const @trusted pure nothrow @nogc return { return seq[0 .. entry_len]; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/iasm_labeloperand.d ================================================ version (D_InlineAsm_X86) version = TestInlineAsm; else version (D_InlineAsm_X86_64) version = TestInlineAsm; else version (GNU) version = TestInlineAsm; else pragma(msg, "Inline asm not supported, not testing."); version (TestInlineAsm) { void testInlineAsm() { version (GNU) { L1: asm { "" : : : : L1; } // Check back references asm { "" : : : : L2; } // Check forward references L2: asm { ""; } } else { asm { L1: nop; nop; nop; nop; mov EAX, dword ptr L1; // Check back references mov EAX, dword ptr L2; // Check forward references mov EAX, dword ptr DS:L1; // Not really useful in standard use, but who knows. mov EAX, dword ptr FS:L2; // Once again, not really useful, but it is valid. mov EAX, dword ptr CS:L1; // This is what the first test case should implicitly be. L2: nop; nop; nop; nop; } } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice10040.d ================================================ struct MsgProc1 { mixin MsgMixin; } struct MsgProc2 { mixin MsgMixin; } struct MsgHeader {} template MsgMixin() { mixin(mixinMembers!(MsgHeader.init)); } string mixinMembers(T ...)() { struct Op {} return null; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice10431a.d ================================================ mixin ADT!(); struct Tuple(TL...) { TL expand; } template Seq(T...) { alias T Seq; } template ADT() { mixin(q{ struct ListI { private { size_t tag; union { Seq!(Tuple!()*, Tuple!(int,ListI,)*,) data; } } } }); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice10431b.d ================================================ struct X(alias Y) { } struct A { int[] data; } alias X!(A([])) X1; alias X!(A([])) X2; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice10486.d ================================================ void main() { typeof(null) null_; int[1] sarr = null_; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice10598.d ================================================ // EXTRA_SOURCES: imports/ice10598a.d imports/ice10598b.d void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11054.d ================================================ import imports.ice11054a; static assert(!__traits(compiles, tuple())); E[] appender(A : E, E)() { return E; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11300.d ================================================ // PERMUTE_ARGS: module ice11300; import imports.ice11300a; enum value = 42; ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11596.d ================================================ // PERMUTE_ARGS: -inline -release -g -O -version=X version(X) alias M = real; else alias M = int[2]; /* or other T[n] with n != 1 */ struct S { M m; } S f() { assert(false); } class C { S[1] ss; /* Here, size doesn't matter. */ this() { ss[] = f(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11610.d ================================================ struct Token { TokenType type; } enum TokenType : ushort { invalid } class Parser { bool peekIsOneOf(TokenType[] types...) { canFind(types, tokens[1].type); return true; } Token[] tokens; } /*************************************************/ // std.algorithm R find(alias pred = "a == b", R, E)(R haystack, E needle) { enum isIntegralNeedle = isSomeChar!E/* || isIntegral!E || isBoolean!E*/; return haystack; } bool canFind(alias pred = "a == b", R, E)(R haystack, E needle) if (is(typeof(find!pred(haystack, needle)))) // 1st instantiate of find template with error gagging { return find!pred(haystack, needle).length != 0; // 2nd instantiate of find template without gagging } /*************************************************/ // std.traits template CharTypeOf(T) { inout( char) idx( inout( char) ); inout(wchar) idx( inout(wchar) ); inout(dchar) idx( inout(dchar) ); shared(inout char) idx( shared(inout char) ); shared(inout wchar) idx( shared(inout wchar) ); shared(inout dchar) idx( shared(inout dchar) ); static if (is(T == enum)) { /* This line instantiates CharTypeOf!short and will make error. * But, when CharTypeOf!short is re-instantiated without gagging, * that's for correct error report, its 'members' does not re-created. * so, members' semantic will call FuncDeclaration::overloadInsert of * 'idx' functions, and will make circular linked list of * FuncDeclaration::overnext. Finally, iterating it will cause * infinite recursion and compiler segfault. */ alias .CharTypeOf!(OriginalType!T) CharTypeOf; } else static if (is(typeof(idx(T.init)) X)) { alias X CharTypeOf; } else static assert(0, T.stringof~" is not a character type"); } template isSomeChar(T) { enum isSomeChar = is(CharTypeOf!T); } template OriginalType(T) { alias OriginalType = ushort; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11777.d ================================================ void f(void delegate(int)) {} class C { int i; this() { f((a){}); /* (a){} is a template lambda, so FuncExp::semantic -> TemplateDeclaration::semantic * will save the scope in TemplateDeclaration::scope with fieldinit. Later push/pop * of the scope for template lambda body semantics will violate the assertion in Scope::pop(). */ } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11906.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: nothrow /*extern(Windows) */export int GetModuleHandleA(const char* lpModuleName); void main() { /*extern(Windows) */int function(const char*) f; assert(f != &GetModuleHandleA); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice11925.d ================================================ void test11925a() { try { try { L1: {} } finally { } } finally { } goto L1; } void test11925b() { switch (1) { case 1: goto L1; break; default: break; } try { L1: { } } finally { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice12002.d ================================================ // REQUIRED_ARGS: -inline // PERMUTE_ARGS: void doFormat(void delegate(dchar) putc, TypeInfo[] arguments) { void formatArg(char fc) { const(char)* prefix = ""; void putstr(const char[] s) { //if (flags & FL0pad) { while (*prefix) putc(*prefix++); } foreach (dchar c; s) putc(c); } putstr(null); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice12554.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: void main() pure { int[] foo; // if indirectly instantiated aggregate is struct (== MapResultS) foo.map!(MapResultS, x => foo.map!(MapResultS, y => x).array); // if indirectly instantiated aggregate is class (== MapResultC) foo.map!(MapResultC, x => foo.map!(MapResultC, y => x).array); } T array(T)(T a) { static int g; g = 1; // impure operation return a; } template map(alias MapResult, fun...) { auto map(Range)(Range r) { alias AppliedReturnType(alias f) = typeof(f(r[0])); static assert(!is(AppliedReturnType!fun == void)); return MapResult!(fun).init; } } struct MapResultS(alias fun) { @property front() { return fun(1); } } class MapResultC(alias fun) { @property front() { return fun(1); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice12956.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: template isCallable(T...) { static if (is(typeof(& T[0].opCall) == delegate)) { enum bool isCallable = true; } else static if (is(typeof(& T[0].opCall) V : V*) && is(V == function)) { enum bool isCallable = true; } else enum bool isCallable = false; } @property auto injectChain(Injectors...)() { return &ChainTemplates!(Injectors); } template ChainTemplates(Templates...) { alias Head = Templates[0]; alias Tail = Templates[1..$]; alias Head!(Tail) ChainTemplates; } static assert(!isCallable!(injectChain)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13071.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: T foo(T)() { __gshared int[] bar = []; return T.init; } void main() { foo!char(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13088.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct X { void mfoo(this T)() {} } void test() { shared const X scx; scx.mfoo(); } struct Vec { int x; void sc() shared const {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13245.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: template T(alias f) {} static assert(!is(T!( (int x){ return invalid; } ))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13323.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct UDA {} struct S { @UDA: import object; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13403.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -o- import imports.ice13403a; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13792.d ================================================ enum E; void main() { E* p; // ICE in glue layer } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13874.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: template FunctionTypeOf(func...) if (func.length == 1) { static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate)) { alias Fsym FunctionTypeOf; } else static if (is(typeof(& func[0].opCall) Fobj == delegate)) { alias Fobj FunctionTypeOf; } else static assert(0); } enum DummyEnum; static assert(!is(FunctionTypeOf!DummyEnum)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13886.d ================================================ // REQUIRED__ARGS: // PERMUTE_ARGS: struct Y() { this() {} ~this() { this = null; } ref opAssign(S)(S) { } } void main() { static if (is(typeof({ Y!(); }))) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13920.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: class Foo { void foo() { foreach (f; __traits(getOverloads, typeof(this), "bar")) { auto dg = &f; } foreach (f; __traits(getVirtualMethods, typeof(this), "bar")) { auto dg = &f; } foreach (f; __traits(getVirtualFunctions, typeof(this), "bar")) { auto dg = &f; } } uint bar() { return 0; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice13968.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: union U { bool a; long b; } U test1() { return U(); } U* test2() { return new U(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice14075.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct Foo { auto opAssign(this X)(ref typeof(this)); auto opAssign(this X, V)(ref V) if (!is(V == typeof(this))); } void test() { Foo src; const(Foo) target; static if (is(typeof(target = src))) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice14739.d ================================================ // REQUIRED_ARGS: -o- void main(string[] args) { immutable int a; immutable int b; S!a sa; S!b sb; C!a ca; C!b cb; } struct S(alias a) { } class C(alias a) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice1524.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=1524 // ICE(constfold.c) on using "is" with strings in CTFE /* 1524 PATCH Assertion failure: '0' on line 863 in file 'constfold.c' constfold.c @@ -845,9 +845,9 @@ Loc loc = e1->loc; int cmp; - if (e1->op == TOKnull && e2->op == TOKnull) + if (e1->op == TOKnull || e2->op == TOKnull) { - cmp = 1; + cmp = (e1->op == TOKnull && e2->op == TOKnull) ? 1 : 0; } else if (e1->op == TOKsymoff && e2->op == TOKsymoff) { */ bool isNull(string str) { return str is null; } const bool test = isNull("hello!"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice15333.d ================================================ // EXTRA_SOURCES: imports/a15333.d module ice15333; void map(alias fun)() {} struct IdentifierResolver(alias handler) { void resolve() { map!((a) {}); handler(true); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice15760.d ================================================ // PERMUTE_ARGS: // EXTRA_SOURCES: imports/a15760.d module ice15760; import imports.a15760 : Foo; struct Bar { __gshared Foo foo; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice15789.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct InputRange {} auto md5OfA(T...)(T ) {} auto md5OfB(T...)(T ) {} template fqnSymA(alias T : X!A, alias X, A...) { template fqnTuple(B) { enum fqnTuple = 1; } enum fqnSymA = fqnTuple!A; } template fqnSymB(alias T : X!A, alias X, A...) { template fqnTuple(B) { enum fqnTuple = 1; } enum fqnSymB = fqnTuple!A; } void test1() // OK <- NG { md5OfA(InputRange()); auto n = fqnSymA!(md5OfA!InputRange); } void test2() // OK { auto n = fqnSymB!(md5OfB!InputRange); md5OfB(InputRange()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice15992.d ================================================ // PERMUTE_ARGS: struct Appender() { bool canExtend = false; } struct CustomFloat() { union ToBinary { CustomFloat!() get; } void opAssign(F)(F input) if (__traits(compiles, cast(real)input)) { } real get()() { Appender!() app; assert(false); } T opCast(T)() { return get!(); } alias g = get!(); } void f() { alias FPTypes = CustomFloat!(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice6538.d ================================================ /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=6538 template allSatisfy(alias F, T...) { enum bool allSatisfy = true; } template isIntegral(T) { enum bool isIntegral = true; } void foo(I...)(I sizes) if (allSatisfy!(isIntegral, sizes)) {} void test6538a() { foo(42, 86); } void bar(T1, T2)(T1 t1, T2 t2) if (allSatisfy!(isIntegral, t1, t2)) {} void test6538b() { bar(42, 86); } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=9361 template Sym(alias A) { enum Sym = true; } struct S { void foo()() if (Sym!(this)) {} void bar()() { static assert(Sym!(this)); } // OK } void test9361a() { S s; s.foo(); // fail s.bar(); // OK } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice8392.d ================================================ // EXTRA_SOURCES: imports/a8392.d module ice8392; struct A { } auto fooa(alias handler)(A a) { return handler(null); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice854.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=854 // TypeTuple in anonymous delegate causes ice in glue.c /* 854 VOTE PATCH (=2863, =2251?) Assertion failure: '0' on line 935 in file 'glue.c' I haven't checked this patch myself. --- dmd/func.c 2009-03-05 01:56:46.000000000 +0100 +++ dmd-fixed/func.c 2009-03-30 00:39:41.000000000 +0200 @@ -756,6 +756,27 @@ } } + if (f->parameters) + { + for (size_t i = 0; i < Argument::dim(f->parameters); i++) + { + Argument *arg = (Argument *)Argument::getNth(f->parameters, i); + Type* nw = arg->type->semantic(0, sc); + if (arg->type != nw) { + arg->type = nw; + // Examine this index again. + // This is important if it turned into a tuple. + // In particular, the empty tuple should be handled or the + // next parameter will be skipped. + // FIXME: Maybe we only need to do this for tuples, + // and can add tuple.length after decrement? + i--; + } + } + // update nparams to include expanded tuples + nparams = Argument::dim(f->parameters); + } + // Propagate storage class from tuple parameters to their element-parameters. if (f->parameters) { */ template Foo(T...) { alias T Foo; } void main() { auto y = (Foo!(int) x){ return 0; }; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/ice9663.d ================================================ // REQUIRED_ARGS: -wi void main() { int[1] a; int[] b = [1]; a = 1; b[] = a; b = a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a12506.d ================================================ module imports.a12506; auto f12506(alias fun)() { return fun(1); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a12511.d ================================================ module a12511; public class A { private static void foo() {} public static void foo(int) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a12567.d ================================================ deprecated("This module will be removed in future release.") module imports.a12567; void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a13226.d ================================================ module imports.a13226; enum isFunction(alias f) = is(typeof(f) == function); enum isIntField(alias f) = is(typeof(f) == int); string t(alias cls, string method)() { static if (isFunction!(mixin("cls."~method))) {} return ""; } string u(alias cls, string member)() { static if (isIntField!(mixin("cls."~member))) {} return ""; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a14528.d ================================================ module imports.a14528; void foo(alias f)() { f(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a15333.d ================================================ module imports.a15333; import ice15333; struct StatementVisitor { void visit() { int location; alias IR = IdentifierResolver!((e){ location = 0; }); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a15760.d ================================================ module imports.a15760; import ice15760; struct Foo { Bar a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a15856.d ================================================ module imports.a15856; alias int c_long; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a18911.d ================================================ enum A_FILE = __FILE_FULL_PATH__; enum suffix_a = "imports/a18911.d"; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a313.d ================================================ module imports.a313; // adds private package imports private import imports.b313; // adds private package core private import core.stdc.stdio; // adds public alias cstdio public alias cstdio = core.stdc.stdio; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a313templatemixin1.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a313templatemixin2.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a314.d ================================================ module imports.pkg.a314; // sub package package(imports) static import imports.c314; package(imports) import renamed = imports.c314; package(imports) import imports.c314 : bug; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/a8392.d ================================================ module imports.a8392; import ice8392; class B { this(B); } void foob(A a, B b) { a.fooa!((arg){ return new B(b); }); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/art4769a.d ================================================ module imports.art4769a; import core.stdc.stdio; template DataStreamability(T) { const int isStreamable = true; alias T footype; void write() { printf("hallo\n"); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/art4769b.d ================================================ private import imports.art4769a; private import art4769; int main(char [][] args) { Vector!(wchar) str; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/b313.d ================================================ module imports.b313; void bug() { // scope has access to it's own module imports.b313.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/b33a.d ================================================ module imports.b33a; struct IsEqual( T ) { bool opCall( char p1, char p2 ) { return p1 == p2; } } template find_( Elem, Pred = IsEqual!(Elem) ) { size_t fn( char[] buf, Pred pred = Pred.init ) { return 3; } } template find() { size_t find( char[3] buf ) { return find_!(char).fn( buf ); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/b3682.d ================================================ module imports.b3682; import a3682; alias Tuple!(int) tint; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/bug8922.d ================================================ module imports.bug8922; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/c314.d ================================================ module imports.c314; void bug(string s) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/checkimports3a.d ================================================ void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/checkimports3b.d ================================================ private void foo(int) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/checkimports3c.d ================================================ void foo(string) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/defaa.d ================================================ module imports.defaa; class Display { private import imports.defab; B lastHittestB; this() { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/defab.d ================================================ module imports.defab; private import defa; public class B : A { private import imports.defad; D parent; this() {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/defac.d ================================================ module imports.defac; private import imports.defab; public abstract class C : B { private import imports.defad; this() {} this(D parent, int style) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/defad.d ================================================ module imports.defad; private import imports.defac; private import imports.defab; public class D : C { B [] tabList; this() {} this(D parent, int style){ } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/dip22.d ================================================ module imports.dip22; interface Base1 { private ubyte bar() { return 1; } private enum baz = 1; private alias T = byte; } interface Base2 { final short bar() { return 2; } enum baz = 2; alias T = short; } private void bar() {} void bar(int) {} void baz(int) {} private void baz() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/f313.d ================================================ // different module declaration not used for access check module foo.bar; void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/fwdref12201a.d ================================================ alias int FILE; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/fwdref2_test17548.d ================================================ module fwdref2_test17548; import test17548; struct S2 { void bar(int arg = .test17548.cnst) {} S1 s; import fwdref2_test17548; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/fwdref9514.d ================================================ bool find9514(alias pred, R)(R range) { return true; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/g313.d ================================================ module imports.g313; // adds public package imports (see https://issues.dlang.org/show_bug.cgi?id=15900) public import imports.g313public; // same w/ deferred semantics static if (true) public import imports.g313staticif; mixin("public import imports.g313stringmixin;"); template impD() { public import imports.g313templatemixin; } mixin impD!(); void test15900() { // publically imported modules should obviously be available in here as well imports.g313public.bug(); imports.g313staticif.bug(); imports.g313stringmixin.bug(); imports.g313templatemixin.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/g313public.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/g313staticif.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/g313stringmixin.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/g313templatemixin.d ================================================ void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/ice10598a.d ================================================ module imports.ice10598a; template TypeTuple(TL...) { alias TL TypeTuple; } alias TypeTuple!(__traits(getMember, imports.ice10598b, (__traits(allMembers, imports.ice10598b)[1])))[0] notImportedType; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/ice10598b.d ================================================ module imports.ice10598b; struct LocalType {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/ice11054a.d ================================================ template Tuple() { string injectNamedFields() { formatNthX(); return ""; } } Tuple!T tuple(T...)() { } void formatNthX(A...)(A) { static gencode(size_t count)() { result ~= ""; // comment out this line will remove the ICE return ""; } mixin(gencode!(A.length)()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/ice11300a.d ================================================ module imports.ice11300a; static import ice11300; enum value = ice11300.value; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/ice13403a.d ================================================ module imports.ice13403a; package(imports): template BacktrackingMatcher() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242a.d ================================================ module imports.imp12242a; public: import imports.imp12242a1; // std.string import imports.imp12242a2; // std.algorithm private mixin template MixTmp(T, int x) { template foo(U) if (is(U == T)) { enum foo = x; } } mixin MixTmp!(int, 1); mixin MixTmp!(long, 2); ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242a1.d ================================================ module imports.imp12242a1; // std.string.strip int stripA(C)(C[] str) @safe pure if (is(immutable C == immutable char)) { return 1; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242a2.d ================================================ module imports.imp12242a2; // std.algorithm.strip auto stripA(R, E)(R range, E element) { return 2; } auto stripA(alias pred, R)(R range) { return 3; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242b.d ================================================ module imports.imp12242b; public: import imports.imp12242b1; // std.string import imports.imp12242b2; // std.algorithm private mixin template MixTmp(T, int x) { template foo(U) if (is(U == T)) { enum foo = x; } } mixin MixTmp!(float, 3); mixin MixTmp!(real, 4); ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242b1.d ================================================ module imports.imp12242b1; // std.string.strip int stripB(C)(C[] str) @safe pure if (is(immutable C == immutable char)) { return 1; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp12242b2.d ================================================ module imports.imp12242b2; // std.algorithm.strip auto stripB(R, E)(R range, E element) { return 2; } auto stripB(alias pred, R)(R range) { return 3; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp15490a.d ================================================ module imports.imp15490a; import imports.imp15490b; void listenTCP() { enum r = regex(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp15490b.d ================================================ module imports.imp15490b; int regex() { return regexImpl(); } auto regexImpl() { int r = 0; return r; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp15907.d ================================================ module imports.imp15907; void process(T)(T t) { foreach (member; __traits(allMembers, T)) { static if (__traits(getProtection, __traits(getMember, t, member)) != "private") { } } } enum allMembers(T) = [__traits(allMembers, T)]; struct PublicStruct { private struct S {} } private: struct PrivateStruct {} int privateVar; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp15925.d ================================================ enum X = 1; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16080.d ================================================ struct A() { static immutable A a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16085.d ================================================ struct Pass { } struct S { import imports.imp16085b : functionAndFunction, staticFunctionAndFunction, functionAndTemplate, templateAndTemplate; //<- private // public Pass functionAndFunction() { return Pass(); } static Pass staticFunctionAndFunction() { return Pass(); } Pass functionAndTemplate() { return Pass(); } Pass templateAndTemplate()() { return Pass(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16085b.d ================================================ import imp16085 : S; struct Fail { } Fail functionAndFunction(ref S) { return Fail(); } Fail staticFunctionAndFunction(int) { return Fail(); } Fail functionAndTemplate(T)(T) { return Fail(); } Fail templateAndTemplate(T)(T) { return Fail(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16088.d ================================================ module imports.imp16088; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16460.d ================================================ module imports.imp16460; package enum val = 0; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/imp16798.d ================================================ module its.a.dessert.topping; pragma(msg, "it's a dessert topping"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/jsonimport1.d ================================================ module imports.jsonimport1; int target1, target2; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/jsonimport2.d ================================================ module imports.jsonimport2; int target1, target2; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/jsonimport3.d ================================================ module imports.jsonimport3; int target1, target2, target3; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/jsonimport4.d ================================================ module imports.jsonimport4; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/pkg313/c313.d ================================================ module imports.pkg313.c313; void bug() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/pkgmod313/mod.d ================================================ module imports.pkgmod313.mod; void bar() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/pkgmod313/package.d ================================================ module imports.pkgmod313; public import imports.pkgmod313.mod; void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/protectionimp.d ================================================ private { void privF() {} class privC {} struct privS {} union privU {} interface privI {} enum privE { foo } mixin template privMT() {} void privTF(T)() {} class privTC(T) {} struct privTS(T) {} union privTU(T) {} interface privTI(T) {} } void publF(T)() {} void publFA(alias A)() {} private alias privC privA; public mixin template publMT() {} /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14169 template GetName14169(TemplateParam) { enum GetName14169 = TemplateParam.Name; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/stdio4003.d ================================================ module imports.stdio4003; import imports.typecons4003; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test10375a.d ================================================ module imports.test10375a; private template Pack(T...) { alias T tuple; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test10752.d ================================================ module imports.test10752; private int priv; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11225b.d ================================================ module imports.test11225b; import test11225a; interface J : I {} // remove this line to make it work static assert(is(typeof({ import imports.test11225c; }))); // OK pragma(msg, B!().result); // just instantiates the template template B() { static assert(is(typeof({ import imports.test11225c; }))); // FAILS enum result = "WORKS"; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11225c.d ================================================ module imports.test11225c; // empty ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11563core_bitop.d ================================================ module test11563core_bitop; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11563std_array.d ================================================ module imports.test11563std_array; void popFront(S)(ref S str)// @trusted pure nothrow { import imports.test11563core_bitop; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11563std_range.d ================================================ module imports.test11563std_range; public import imports.test11563std_array; template isInputRange(R) { enum bool isInputRange = is(typeof( { R r = void; r.popFront(); })); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d ================================================ module imports.test11563std_traits; import imports.test11563std_range; bool startsWith(R1, R2)(R1 doesThisStart, R2 withThis) if (isInputRange!R1) { return true; } template moduleName(alias T) { static if (T.stringof.startsWith("module ")) { enum moduleName = "b"; } else { pragma(msg, "--error--"); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test1238a.d ================================================ module imports.test1238a; private int zuiop; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test1238b.d ================================================ module imports.test1238b; public int zuiop; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test13242a.d ================================================ module imports.test13242a; template expensiveArgs(alias v) { pragma(msg, "a.expensiveArgs: ", v); } template expensiveTemplate(Args...) { pragma(msg, "a.expensiveTemplate: ", Args[0]); } alias apiSym1 = expensiveTemplate!(1, expensiveArgs!(1)); alias apiSym2 = expensiveTemplate!(2, expensiveArgs!(2)); public import imports.test13242b : apiSym3; void cheapFunc() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test13242b.d ================================================ module imports.test13242b; template expensiveArgs(alias v) { pragma(msg, "b.expensiveArgs: ", v); } template expensiveTemplate(Args...) { pragma(msg, "b.expensiveTemplate: ", Args[0]); } alias apiSym3 = expensiveTemplate!(3, expensiveArgs!(3)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test14666a.d ================================================ module imports.test14666a; auto getNames() { import imports.test14666b; return ""; } enum Names = getNames; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test14666b.d ================================================ module imports.test14666b; import test14666; struct Token { Location location; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15117a.d ================================================ module imports.test15117a; struct AssertResult {} auto test_usr_1() { // 2. generate TyepInfoStructDeclaration auto x = typeid(AssertResult); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15150a.d ================================================ module imports.test15150a; enum { x } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15150b.d ================================================ module imports.test15150b; import imports.test15150a : x; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15785.d ================================================ module imports.test15785; interface IBase2 { final protected void faz() {} } class Base { protected void foo() {} protected void bar() {} protected alias T = int; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15857a.d ================================================ public import imports.test15857b; public import imports.test15857c; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15857b.d ================================================ void bar15857(int) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test15857c.d ================================================ void bar15857(string) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test16348.d ================================================ module mypackage.bar; package bool bar() { return false; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test17541_2.d ================================================ module two; import one; struct ET(bool a) { enum e = BB.MAX_NUM_FIBERS; } alias Event = ET!false; struct TWOR(size_t M) { Event e; void open() { bb.foo(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test17541_3.d ================================================ module three; void aaa() @nogc { } struct TT(T) { void insertabcdefg(T) // @nogc <-- deduction problem { pragma(msg, insertabcdefg.mangleof); aaa(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test1754a.d ================================================ module imports.test1754a; private void bar() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test1754b.d ================================================ module imports.test1754b; void bar() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test17991a/a.d ================================================ ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test17991a/package.d ================================================ ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test18771a.d ================================================ module imports.test18771a; void foo(int) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test18771b.d ================================================ module imports.test18771b; void foo(string) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test18771c.d ================================================ module imports.test18771c; import imports.test18771a, imports.test18771b; alias fooC = foo; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test18771d.d ================================================ module imports.test18771d; import imports.test18771b, imports.test18771a; alias fooD = foo; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test19107a.d ================================================ module imports.test19107a.d; alias I(alias A) = A; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test19107b.d ================================================ module imports.test19107b; import imports.test19107a : I; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test19187.d ================================================ module imports.test19187; void test()() { } alias foo = test; alias foo = test; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test1imp.d ================================================ alias uint DWORD; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test25a.d ================================================ module imports.test25a; import imports.test25b; import core.stdc.stdio; class Afoo { static this() { printf("Afoo()\n"); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test25b.d ================================================ module imports.test25b; import imports.test25a; import core.stdc.stdio; class Bfoo { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test2991.d ================================================ module imports.test2991; private void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test4003a.d ================================================ module imports.test4003a; import imports.typecons4003; Tuple!(string) t; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test50a.d ================================================ module imports.test50a; class Foo { protected int a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test55a.d ================================================ module imports.test55a; import test55; class Arm { alias int ListHead; MessageQueue.ListHead mqueue; } class Arm2 { alias int ListHead; Queue2.ListHead mqueue; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test59a.d ================================================ module imports.test59a; import test59; HRESULT h; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test59b.d ================================================ module imports.test59b; alias int HRESULT; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test6013.d ================================================ module imports.test6013; int value; int func() { return 0; }; public alias value public_alias_value; private alias value private_alias_value; public alias func public_alias_func; private alias func private_alias_func; public alias int public_alias_type; private alias int private_alias_type; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test61a.d ================================================ module imports.test61a; enum FooA { fooA }; void bar(FooA x) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test62a.d ================================================ module imports.test62a; import test62; struct T() { struct Nested { S member; } } alias T!() instance; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test63a.d ================================================ module imports.test63a; private import test63; struct s { char[SIZE] a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test66a.d ================================================ module imports.test66a; import test66; class A : Lexer { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test67a.d ================================================ module imports.test67a; import test67; class Base { I create() { return null; } } class Derived : Base { override SubI create() { return null; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test68a.d ================================================ module imports.test68a; class OtherModuleClass { protected void foo() { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test70.d ================================================ module imports.test70; void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test71.d ================================================ module imports_test71; import imports = object; void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test72a.d ================================================ module imports.test72a; public import imports.test72b; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test72b.d ================================================ module imports.test72b; private import imports.test72c : foo; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test72c.d ================================================ module imports.test72c; void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test7491a.d ================================================ module imports.test7491a; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test7491b.d ================================================ module imports.test7491b; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276decl.d ================================================ module imports.test9276decl; import imports.test9276sem, imports.test9276visitors, imports.test9276util; class Declaration { mixin DownCastMethods!TemplateDecl; } class TemplateDecl : OverloadableDecl { mixin Visitors; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276expr.d ================================================ module imports.test9276expr; import imports.test9276parser; import imports.test9276util; class Node { mixin DownCastMethods!Declaration; } class Expression : Node { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276hash.d ================================================ module imports.test9276hash; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276parser.d ================================================ module imports.test9276parser; public import imports.test9276expr, imports.test9276decl; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276sem.d ================================================ module imports.test9276sem; class Declaration { mixin Visitors; } template Semantic(T) { private: struct { import imports.test9276hash; } } import imports.test9276visitors; class OverloadableDecl : Declaration { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276type.d ================================================ module imports.test9276type; import imports.test9276parser; class Type : Expression // <- note to Walter. { } class BasicType : Type { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276util.d ================================================ module imports.test9276util; string _dgliteral(T...)() { foreach (t; T) return t.stringof; assert(0); } template DownCastMethods(T...) { enum x = _dgliteral!T; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d ================================================ module imports.test9276visitors; template Visitors() { mixin Semantic!(typeof(this)); mixin DeepDup!(typeof(this)); } import imports.test9276type; template DeepDup(T) if (is(T : BasicType)) {} template DeepDup(T) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9399a.d ================================================ module imports.test9399a; void call(alias n)() { n(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9436aggr.d ================================================ module imports.test9436aggr; import imports.test9436type; class Aggregate : Type { } class Class { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9436interp.d ================================================ module imports.test9436interp; import imports.test9436type; import imports.test9436aggr; class ReferenceValueT(T) { void doCast() { auto x = Type.ConversionFlags.kAllowBaseClass; } } class ClassValue : ReferenceValueT!Class { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9436node.d ================================================ module imports.test9436node; import imports.test9436aggr; template ForwardCtor() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9436type.d ================================================ module imports.test9436type; import imports.test9436node; class Type { mixin ForwardCtor!(); enum ConversionFlags { kAllowBaseClass = 0 } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9672a.d ================================================ module imports.test9672a; // interpret import test9672; // node class Type { mixin ForwardCtor!(); } //BasicType only created for standard types associated with tokens class BasicType : Type { static Type createType() { return null; } } class ValueT(T) { Type getType() { return BasicType.createType(); } } class CharValue : ValueT!char { string toStr() { return null; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9692b.d ================================================ module imports.test9692b; int j; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9919a.d ================================================ module imports.test9919a; import imports.test9919c; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9919b.d ================================================ module imports.test9919b; class Event { mixin genToString; // @BUG@ } class MouseEvent : Event { enum Action { A, B } } mixin template genToString() { override string toString() { return ""; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/test9919c.d ================================================ module imports.test9919c; import test9919; MouseEvent.Action action; ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/testcontracts.d ================================================ module imports.testcontracts; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3602 class Base3602 { void method(int x, int y) in { assert(x > 0); assert(y > 0); } body { } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5230 class Base5230 { int method() out (res) { } body { return 42; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/testlambda1.d ================================================ module imports.testlambda1; int bar() { return 7; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/testlambda2.d ================================================ module imports.testlambda2; int bar() { return 7; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/typecons4003.d ================================================ module imports.typecons4003; struct Tuple(T...) { alias T Types; Types field; ref Tuple!(Types[from .. to]) slice(uint from, uint to)() { return *cast(typeof(return) *) &(field[from]); } void test() //unittest { .Tuple!(int, string, float, double) a; a.field[1] = "abc"; a.field[2] = 4.5; auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); //assert(s.field[0] == "abc" && s.field[1] == 4.5); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/udamodule1.d ================================================ @(1) deprecated("This module will be removed.") @(2) module imports.udamodule1; void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/udamodule2.d ================================================ @UDA(1) @UDA(2) module imports.udamodule2; import imports.udamodule2a; void foo() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/udamodule2a.d ================================================ module imports.udamodule2a; struct UDA { int a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/imports/wax16798.d ================================================ module its.a.floorwax.wax16798; pragma(msg, "it's a floor wax"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/interpret3.d ================================================ // PERMUTE_ARGS: -inline template compiles(int T) { bool compiles = true; } alias TypeTuple(T...) = T; /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3901 // Arbitrary struct assignment, ref return struct ArrayRet { int x; } int arrayRetTest(int z) { ArrayRet[6] w; int q = (w[3].x = z); return q; } static assert(arrayRetTest(51) == 51); // https://issues.dlang.org/show_bug.cgi?id=3842 -- must not segfault int ice3842(int z) { ArrayRet w; return arrayRetTest((*(&w)).x); } static assert(true || is(typeof(compiles!(ice3842(51))))); int arrayret2() { int[5] a; int[3] b; b[] = a[1 .. $-1] = 5; return b[1]; } static assert(arrayret2() == 5); struct DotVarTest { ArrayRet z; } struct DotVarTest2 { ArrayRet z; DotVarTest p; } int dotvar1() { DotVarTest w; w.z.x = 3; return w.z.x; } static assert(dotvar1() == 3); int dotvar2() { DotVarTest2[4] m; m[2].z.x = 3; m[1].p.z.x = 5; return m[2].z.x + 7; } static assert(dotvar2() == 10); struct RetRefStruct { int x; char c; } // Return value reference tests, for D2 only. ref RetRefStruct reffunc1(ref RetRefStruct a) { int y = a.x; return a; } ref RetRefStruct reffunc2(ref RetRefStruct a) { RetRefStruct z = a; return reffunc1(a); } ref int reffunc7(ref RetRefStruct aa) { return reffunc1(aa).x; } ref int reffunc3(ref int a) { return a; } struct RefTestStruct { RetRefStruct r; ref RefTestStruct reffunc4(ref RetRefStruct[3] a) { return this; } ref int reffunc6() { return this.r.x; } } ref RetRefStruct reffunc5(ref RetRefStruct[3] a) { int t = 1; for (int i = 0; i < 10; ++i) { if (i == 7) ++t; } return a[reffunc3(t)]; } int retRefTest1() { RetRefStruct b = RetRefStruct(0, 'a'); reffunc1(b).x = 3; return b.x - 1; } int retRefTest2() { RetRefStruct b = RetRefStruct(0, 'a'); reffunc2(b).x = 3; RetRefStruct[3] z; RefTestStruct w; w.reffunc4(z).reffunc4(z).r.x = 4; assert(w.r.x == 4); w.reffunc6() = 218; assert(w.r.x == 218); z[2].x = 3; int q = 4; int u = reffunc5(z).x + reffunc3(q); assert(u == 7); reffunc5(z).x += 7; assert(z[2].x == 10); RetRefStruct m = RetRefStruct(7, 'c'); m.x = 6; reffunc7(m) += 3; assert(m.x == 9); return b.x - 1; } int retRefTest3() { RetRefStruct b = RetRefStruct(0, 'a'); auto deleg = function (RetRefStruct a){ return a; }; typeof(deleg)[3] z; z[] = deleg; auto y = deleg(b).x + 27; b.x = 5; assert(y == 27); y = z[1](b).x + 22; return y - 1; } int retRefTest4() { RetRefStruct b = RetRefStruct(0, 'a'); reffunc3(b.x) = 218; assert(b.x == 218); return b.x; } static assert(retRefTest1() == 2); static assert(retRefTest2() == 2); static assert(retRefTest3() == 26); static assert(retRefTest4() == 218); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7887 // assign to returned reference bool test7887() { ref int f(ref int x) { return x; } int a; f(a) = 42; return (a == 42); } static assert(test7887()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7473 // struct non-ref struct S7473 { int i; } static assert({ S7473 s = S7473(1); assert(s.i == 1); bug7473(s); assert(s.i == 1); return true; }()); void bug7473(S7473 s) { s.i = 2; } struct S7473b { S7473 m; } static assert({ S7473b s = S7473b(S7473(7)); assert(s.m.i == 7); bug7473b(s); assert(s.m.i == 7); return true; }()); void bug7473b(S7473b s) { s.m.i = 2; } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4389 int bug4389() { string s; dchar c = '\u2348'; s ~= c; assert(s.length == 3); dchar d = 'D'; s ~= d; assert(s.length == 4); s = ""; s ~= c; assert(s.length == 3); s ~= d; assert(s.length == 4); string z; wchar w = '\u0300'; z ~= w; assert(z.length == 2); z = ""; z ~= w; assert(z.length == 2); return 1; } static assert(bug4389()); // ICE(constfold.c) int ice4389() { string s; dchar c = '\u2348'; s ~= c; s = s ~ "xxx"; return 1; } static assert(ice4389()); // ICE(expression.c) string ice4390() { string s; dchar c = '`'; s ~= c; s ~= c; return s; } static assert(mixin(ice4390()) == ``); // https://issues.dlang.org/show_bug.cgi?id=5248 // (D1 + D2) struct Leaf5248 { string Compile_not_ovloaded() { return "expression"; } } struct Matrix5248 { Leaf5248 Right; string Compile() { return Right.Compile_not_ovloaded(); } }; static assert(Matrix5248().Compile()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4837 // >>>= bool bug4837() { ushort x = 0x89AB; x >>>= 4; assert(x == 0x89A); byte y = 0x7C; y >>>= 2; assert(y == 0x1F); return true; } static assert(bug4837()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10252 // shift out of range int lshr10252(int shift) { int a = 5; return a << shift; } int rshr10252(int shift) { int a = 5; return a >> shift; } int ushr10252(int shift) { int a = 5; return a >>> shift; } static assert( is(typeof(compiles!(lshr10252( 4))))); static assert(!is(typeof(compiles!(lshr10252(60))))); static assert( is(typeof(compiles!(rshr10252( 4))))); static assert(!is(typeof(compiles!(rshr10252(80))))); static assert( is(typeof(compiles!(ushr10252( 2))))); static assert(!is(typeof(compiles!(ushr10252(60))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=1982 // CTFE null problems enum a1982 = [1, 2, 3]; static assert(a1982 !is null); string foo1982() { return null; } static assert(foo1982() is null); static assert(!foo1982().length); static assert(null is null); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7988 // CTFE return values should be allowed in compile-time expressions class X7988 { int y; this() { y = 2; } } static assert((new X7988).y == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8253 // ICE: calling of member function of non-CTFE class variable class Bug8253 { bool j() { return true; } } Bug8253 m8253; static assert(!is(typeof(compiles!(m8253.j())))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8285 // Issue with slice returned from CTFE function string foo8285() { string s = "ab"; return s[0 .. $]; } template T8285b(string s) { } template T8285a() { enum s = foo8285(); alias T8285b!(s) t2; } int bar8285() { alias T8285a!() t1; return 0; } int baz8285(int x) { return 0; } static assert(baz8285(bar8285()) == 0); // test case 2 string xbar8285() { string s = "ab"; return s[0 .. $]; } template xT8285a() { enum xT8285a = xbar8285()[0 .. $]; } string xbaz8285() { return xT8285a!(); } string xfoo8285(string s) { return s; } static assert(xfoo8285(xbaz8285()) == "ab"); /************************************************** 'this' parameter bug revealed during refactoring **************************************************/ int thisbug1(int x) { return x; } struct ThisBug1 { int m = 1; int wut() { return thisbug1(m); } } int thisbug2() { ThisBug1 spec; return spec.wut(); } static assert(thisbug2()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6972 // ICE with cast()cast()assign int bug6972() { ubyte n = 6; n /= 2u; return n; } static assert(bug6972() == 3); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6164 size_t bug6164() { int[] ctfe2(int n) { int[] r = []; if (n != 0) r ~= [1] ~ ctfe2(n - 1); return r; } return ctfe2(2).length; } static assert(bug6164() == 2); /************************************************** Interpreter code coverage tests **************************************************/ int cov1(int a) { a %= 15382; a /= 5; a = ~ a; bool c = (a == 0); bool b = true && c; assert(b == 0); b = false && c; assert(b == 0); b = false || c; assert(b == 0); a ^= 0x45349; a = ~ a; a &= 0xFF3F; a >>>= 1; a = a ^ 0x7393; a = a >> 1; a = a >>> 1; a = a | 0x010101; return a; } static assert(cov1(534564) == 71589); int cov2() { int i = 0; do { goto DOLABEL; DOLABEL: if (i != 0) { goto IFLABEL; IFLABEL: switch(i) { case 3: break; case 6: goto SWITCHLABEL; SWITCHLABEL: i = 27; goto case 3; default: assert(0); } return i; } i = 6; } while(true); return 88; // unreachable } static assert(cov2() == 27); template CovTuple(T...) { alias T CovTuple; } alias CovTuple!(int, long) TCov3; int cov3(TCov3 t) { TCov3 s; s = t; assert(s[0] == 1); assert(s[1] == 2); return 7; } static assert(cov3(1, 2) == 7); int badassert1(int z) { assert(z == 5, "xyz"); return 1; } size_t badslice1(int[] z) { return z[0 .. 3].length; } size_t badslice2(int[] z) { return z[0 .. badassert1(1)].length; } size_t badslice3(int[] z) { return z[badassert1(1) .. 2].length; } static assert(!is(typeof(compiles!(badassert1(67))))); static assert( is(typeof(compiles!(badassert1(5))))); static assert(!is(typeof(compiles!(badslice1([1,2]))))); static assert(!is(typeof(compiles!(badslice2([1,2]))))); static assert(!is(typeof(compiles!(badslice3([1,2,3]))))); /*******************************************/ int bug7894() { for (int k = 0; k < 2; ++k) { goto Lagain; Lagain: ; } int m = 1; do { ++m; goto Ldo; Ldo: ; } while (m < 3); assert(m == 3); return 1; } static assert(bug7894()); /*******************************************/ size_t bug5524(int x, int[] more...) { int[0] zz; assert(zz.length == 0); return 7 + more.length + x; } static assert(bug5524(3) == 10); // https://issues.dlang.org/show_bug.cgi?id=5722 static assert(("" ~ "\©"[0]).length == 1); const char[] null5722 = null; static assert((null5722 ~ "\©"[0]).length == 1); static assert(("\©"[0] ~ null5722).length == 1); /******************************************* * Tests for CTFE Array support. * https://issues.dlang.org/show_bug.cgi?id=1330 * https://issues.dlang.org/show_bug.cgi?id=3801 * https://issues.dlang.org/show_bug.cgi?id=3835 * https://issues.dlang.org/show_bug.cgi?id=4050 * https://issues.dlang.org/show_bug.cgi?id=4051 * https://issues.dlang.org/show_bug.cgi?id=5147 * and major functionality *******************************************/ char[] bug1330StringIndex() { char[] blah = "foo".dup; assert(blah == "foo"); char[] s = blah[0 .. 2]; blah[0] = 'h'; assert(s == "ho"); s[0] = 'm'; return blah; } static assert(bug1330StringIndex() == "moo"); static assert(bug1330StringIndex() == "moo"); // check we haven't clobbered any string literals int[] bug1330ArrayIndex() { int[] blah = [1,2,3]; int[] s = blah; s = blah[0 .. 2]; int z = blah[0] = 6; assert(z == 6); assert(blah[0] == 6); assert(s[0] == 6); assert(s == [6, 2]); s[1] = 4; assert(z == 6); return blah; } static assert(bug1330ArrayIndex() == [6, 4, 3]); static assert(bug1330ArrayIndex() == [6, 4, 3]); // check we haven't clobbered any literals char[] bug1330StringSliceAssign() { char[] blah = "food".dup; assert(blah == "food"); char[] s = blah[1 .. 4]; blah[0 .. 2] = "hc"; assert(s == "cod"); s[0 .. 2] = ['a', 'b']; // Mix string + array literal assert(blah == "habd"); s[0 .. 2] = "mq"; return blah; } static assert(bug1330StringSliceAssign() == "hmqd"); static assert(bug1330StringSliceAssign() == "hmqd"); int[] bug1330ArraySliceAssign() { int[] blah = [1, 2, 3, 4]; int[] s = blah[1 .. 4]; blah[0 .. 2] = [7, 9]; assert(s == [9, 3, 4]); s[0 .. 2] = [8, 15]; return blah; } static assert(bug1330ArraySliceAssign() == [7, 8, 15, 4]); int[] bug1330ArrayBlockAssign() { int[] blah = [1, 2, 3, 4, 5]; int[] s = blah[1 .. 4]; blah[0 .. 2] = 17; assert(s == [17, 3, 4]); s[0 .. 2] = 9; return blah; } static assert(bug1330ArrayBlockAssign() == [17, 9, 9, 4, 5]); char[] bug1330StringBlockAssign() { char[] blah = "abcde".dup; char[] s = blah[1 .. 4]; blah[0 .. 2] = 'x'; assert(s == "xcd"); s[0 .. 2] = 'y'; return blah; } static assert(bug1330StringBlockAssign() == "xyyde"); int assignAA(int x) { int[int] aa; int[int] cc = aa; assert(cc.values.length == 0); assert(cc.keys.length == 0); aa[1] = 2; aa[x] = 6; int[int] bb = aa; assert(bb.keys.length == 2); assert(cc.keys.length == 0); // cc is not affected to aa, because it is null aa[500] = 65; assert(bb.keys.length == 3); // but bb is affected by changes to aa return aa[1] + aa[x]; } static assert(assignAA(12) == 8); template Compileable(int z) { bool OK; } int arraybounds(int j, int k) { int[] xxx = [1, 2, 3, 4, 5]; int[] s = xxx[1 .. $]; s = s[j .. k]; // slice of slice return s[$ - 1]; } static assert(!is(typeof(Compileable!(arraybounds(1, 14))))); static assert(!is(typeof(Compileable!(arraybounds(15, 3))))); static assert(arraybounds(2, 4) == 5); int arraybounds2(int j, int k) { int[] xxx = [1, 2, 3, 4, 5]; int[] s = xxx[j .. k]; // direct slice return 1; } static assert(!is(typeof(Compileable!(arraybounds2(1, 14))))); static assert(!is(typeof(Compileable!(arraybounds2(15, 3))))); static assert(arraybounds2(2, 4) == 1); int bug5147a() { int[1][2] a = 37; return a[0][0]; } static assert(bug5147a() == 37); int bug5147b() { int[4][2][3][17] a = 37; return a[0][0][0][0]; } static assert(bug5147b() == 37); int setlen() { int[][] zzz; zzz.length = 2; zzz[0].length = 10; assert(zzz.length == 2); assert(zzz[0].length == 10); assert(zzz[1].length == 0); return 2; } static assert(setlen() == 2); int[1][1] bug5147() { int[1][1] a = 1; return a; } static assert(bug5147() == [[1]]); enum int[1][1] enum5147 = bug5147(); static assert(enum5147 == [[1]]); immutable int[1][1] bug5147imm = bug5147(); // Index referencing int[2][2] indexref1() { int[2][2] a = 2; a[0] = 7; int[][] b = [null, null]; b[0 .. $] = a[0][0 .. 2]; assert(b[0][0] == 7); assert(b[0][1] == 7); int[] w; w = a[0]; assert(w[0] == 7); w[0 .. $] = 5; assert(a[0] != [7, 7]); assert(a[0] == [5, 5]); assert(b[0] == [5, 5]); return a; } int[2][2] indexref2() { int[2][2] a = 2; a[0] = 7; int[][2] b = null; b[0 .. $] = a[0]; assert(b[0][0] == 7); assert(b[0][1] == 7); assert(b == [[7, 7], [7, 7]]); int[] w; w = a[0]; assert(w[0] == 7); w[0 .. $] = 5; assert(a[0] != [7, 7]); assert(a[0] == [5, 5]); assert(b[0] == [5, 5]); return a; } int[2][2] indexref3() { int[2][2] a = 2; a[0]=7; int[][2] b = [null, null]; b[0 .. $] = a[0]; assert(b[0][0] == 7); assert(b[0][1] == 7); int[] w; w = a[0]; assert(w[0] == 7); w[0 .. $] = 5; assert(a[0] != [7, 7]); assert(a[0] == [5, 5]); assert(b[0] == [5, 5]); return a; } int[2][2] indexref4() { int[2][2] a = 2; a[0] = 7; int[][2] b =[[1, 2, 3], [1, 2, 3]]; // wrong code b[0] = a[0]; assert(b[0][0] == 7); assert(b[0][1] == 7); int[] w; w = a[0]; //[0 .. $]; assert(w[0] == 7); w[0 .. $] = 5; assert(a[0] != [7, 7]); assert(a[0] == [5, 5]); assert(b[0] == [5, 5]); return a; } static assert(indexref1() == [[5, 5], [2, 2]]); static assert(indexref2() == [[5, 5], [2, 2]]); static assert(indexref3() == [[5, 5], [2, 2]]); static assert(indexref4() == [[5, 5], [2, 2]]); int staticdynamic() { int[2][1] a = 2; assert(a == [[2, 2]]); int[][1] b = a[0][0 .. 1]; assert(b[0] == [2]); auto k = b[0]; auto m = a[0][0 .. 1]; assert(k == [2]); assert(m == k); return 0; } static assert(staticdynamic() == 0); int chainassign() { int[4] x = 6; int[] y = new int[4]; auto k = (y[] = (x[] = 2)); return k[0]; } static assert(chainassign() == 2); // index assignment struct S3801 { char c; int[3] arr; this(int x, int y) { c = 'x'; arr[0] = x; arr[1] = y; } } int bug3801() { S3801 xxx = S3801(17, 67); int[] w = xxx.arr; xxx.arr[1] = 89; assert(xxx.arr[0] == 17); assert(w[1] == 89); assert(w == [17, 89, 0]); return xxx.arr[1]; } enum : S3801 { bug3801e = S3801(17, 18) } static assert(bug3801e.arr == [17, 18, 0]); immutable S3801 bug3801u = S3801(17, 18); static assert(bug3801u.arr == [17, 18, 0]); static assert(bug3801() == 89); int bug3835() { int[4] arr; arr[] = 19; arr[0] = 4; int kk; foreach (ref el; arr) { el += 10; kk = el; } assert(arr[2] == 29); arr[0] += 3; return arr[0]; } static assert(bug3835() == 17); auto bug5852(const(string) s) { string[] r; r ~= s; assert(r.length == 1); return r[0].length; } static assert(bug5852("abc") == 3); // https://issues.dlang.org/show_bug.cgi?id=7217 struct S7217 { int[] arr; } bool f7217() { auto s = S7217(); auto t = s.arr; return true; } static assert(f7217()); /******************************************* Set array length *******************************************/ static assert( { struct W { int[] z; } W w; w.z.length = 2; assert(w.z.length == 2); w.z.length = 6; assert(w.z.length == 6); return true; }()); // https://issues.dlang.org/show_bug.cgi?id=7185 // char[].length = n bool bug7185() { auto arr = new char[2]; auto arr2 = new char[2]; arr2[] = "ab"; arr.length = 1; arr2.length = 7; assert(arr.length == 1); assert(arr2.length == 7); assert(arr2[0 .. 2] == "ab"); return true; } static assert(bug7185()); bool bug9908() { static const int[3] sa = 1; return sa == [1, 1, 1]; } static assert(bug9908()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6934 struct Struct6934 { int[] x = [1, 2]; } void bar6934(ref int[] p) { p[0] = 12; assert(p[0] == 12); p[0 .. 1] = 17; assert(p[0] == 17); p = p[1 .. $]; } int bug6934() { Struct6934 q; bar6934(q.x); int[][] y = [[2, 5], [3, 6, 8]]; bar6934(y[0]); return 1; } static assert(bug6934()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5671 static assert(['a', 'b'] ~ "c" == "abc"); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8624 int evil8624() { long m = 0x1_0000_0000L; assert(m != 0); long[] a = [0x1_0000_0000L]; long[] b = [0x4_0000_0000L]; assert(a[] != b[]); return 1; } static assert(evil8624()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8644 // array literal >,< int bug8644() { auto m = "a"; auto z = ['b']; auto c = "b7"; auto d = ['b', '6']; assert(m < z); assert(z > m); assert(z <= c); assert(c > z); assert(c > d); assert(d >= d); return true; } static assert(bug8644()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6159 struct A6159 {} static assert({ return A6159.init is A6159.init; }()); static assert({ return [1] is [1]; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5685 string bug5685() { return "xxx"; } struct Bug5865 { void test1() { enum file2 = (bug5685())[0 .. $]; } } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6235 // Regression ICE on $ in template struct Bug6235(R) { enum XXX = is(typeof(R.init[0 .. $]) : const ubyte[]); } Bug6235!(ubyte[]) bug6235; /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8673 // ICE enum dollar8673 = [0][(() => $ - 1)()]; /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5840 struct Bug5840 { string g; int w; } int bug5840(int u) { // check for clobbering Bug5840 x = void; x.w = 4; x.g = "3gs"; if (u == 1) bug5840(2); if (u == 2) { x.g = "abc"; x.w = 3465; } else { assert(x.g == "3gs"); assert(x.w == 4); } return 56; } static assert(bug5840(1) == 56); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7810 int bug7810() { int[1][3] x = void; x[0] = [2]; x[1] = [7]; assert(x[0][0] == 2); char[1][3] y = void; y[0] = "a"; y[1] = "b"; assert(y[0][0] == 'a'); return 1; } static assert(bug7810()); struct Bug7810 { int w; } int bug7810b(T)(T[] items...) { assert(items[0] == Bug7810(20)); return 42; } static assert(bug7810b(Bug7810(20), Bug7810(10)) == 42); /******************************************* std.datetime ICE (30 April 2011) *******************************************/ struct TimeOfDayZ { public: this(int hour) { } invariant() { } } const testTODsThrownZ = TimeOfDayZ(0); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5954 struct Bug5954 { int x; this(int xx) { this.x = xx; } } void bug5954() { enum f = Bug5954(10); static assert(f.x == 10); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5972 int bug5972() { char[] z = "abc".dup; char[][] a = [null, null]; a[0] = z[0 .. 2]; char[] b = a[0]; assert(b == "ab"); a[0][1] = 'q'; assert(a[0] == "aq"); assert(b == "aq"); assert(b[1] == 'q'); //a[0][0 .. $ - 1][0 .. $] = a[0][0 .. $ - 1][0 .. $]; // overlap return 56; } static assert(bug5972() == 56); /******************************************* 2.053beta [CTFE]ICE 'global errors' *******************************************/ int wconcat(wstring replace) { wstring value; value = "A"w; value = value ~ replace; return 1; } static assert(wconcat("X"w)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10397 // string concat static assert(!is(typeof(compiles!("abc" ~ undefined)))); static assert(!is(typeof(compiles!(otherundefined ~ "abc")))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9634 // struct concat struct Bug9634 { int raw; } bool bug9634() { Bug9634[] jr = [Bug9634(42)]; Bug9634[] ir = null ~ jr; Bug9634[] kr = jr ~ null; Bug9634[] mr = jr ~ jr; jr[0].raw = 6; assert(ir[0].raw == 42); assert(kr[0].raw == 42); assert(jr[0].raw == 6); assert(&mr[0] != &mr[1]); return true; } static assert(bug9634()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4001: A Space Oddity int space() { return 4001; } void oddity4001(int q) { const int bowie = space(); static assert(space() == 4001); static assert(bowie == 4001); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3779 static const bug3779 = ["123"][0][$ - 1]; /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8893 // ICE with bad struct literal struct Foo8893 { char[3] data; } int bar8893(Foo8893 f) { return f.data[0]; } static assert(!is(typeof(compiles!(bar8893(Foo8893(['a','b'])))))); /******************************************* non-Cow struct literals *******************************************/ struct Zadok { int[3] z; char[4] s = void; ref int[] fog(ref int[] q) { return q; } int bfg() { z[0] = 56; auto zs = z[]; fog(zs) = [56, 6, 8]; assert(z[0] == 56); assert(z[1] == 61); assert(z[2] == 61); assert(zs[0] == 56); assert(zs[1] == 6); return zs[2]; } } struct Vug { Zadok p; int[] other; } int quop() { int[] heap = new int[5]; heap[] = 738; Zadok pong; pong.z = 3; int[] w = pong.z; assert(w[0] == 3); Zadok phong; phong.z = 61; pong = phong; assert(w[0] == 61); Vug b = Vug(Zadok(17, "abcd")); b = Vug(Zadok(17, "abcd"), heap); b.other[2] = 78; assert(heap[2] == 78); char[] y = b.p.s; assert(y[2] == 'c'); phong.s = ['z','x','f', 'g']; w = b.p.z; assert(y[2] == 'c'); assert(w[0] == 17); b.p = phong; assert(y[2] == 'f'); Zadok wok = Zadok(6, "xyzw"); b.p = wok; assert(y[2] == 'z'); b.p = phong; assert(w[0] == 61); Vug q; q.p = pong; return pong.bfg(); } static assert(quop() == 8); static assert(quop() == 8); // check for clobbering /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5676 // tuple assign of struct that has void opAssign struct S5676 { int x; void opAssign(S5676 rhs) { x = rhs.x; } } struct Tup5676(E...) { E g; void foo(E values) { g = values; } } bool ice5676() { Tup5676!(S5676) q; q.foo(S5676(3)); assert(q.g[0].x == 3); return true; } static assert(ice5676()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5682 // Wrong CTFE with operator overloading struct A { int n; auto opBinary(string op : "*")(A rhs) { return A(n * rhs.n); } } A foo(A[] lhs, A[] rhs) { A current; for (size_t k = 0; k < rhs.length; ++k) { current = lhs[k] * rhs[k]; } return current; } auto test() { return foo([A(1), A(2)], [A(3), A(4)]); } static assert(test().n == 8); /************************************************** Attempt to modify a read-only string literal **************************************************/ struct Xarg { char[] s; } int zfs(int n) { char[] m = "exy".dup; if (n == 1) { // it's OK to cast to const, then cast back string ss = cast(string)m; m = cast(char[])ss; m[2]='q'; return 56; } auto q = Xarg(cast(char[])"abc"); assert(q.s[1] == 'b'); if (n == 2) q.s[1] = 'p'; else if (n == 3) q.s[0 .. $] = 'p'; char* w = &q.s[2]; if (n == 4) *w = 'z'; return 76; } static assert(!is(typeof(compiles!(zfs(2))))); static assert(!is(typeof(compiles!(zfs(3))))); static assert(!is(typeof(compiles!(zfs(4))))); static assert( is(typeof(compiles!(zfs(1))))); static assert( is(typeof(compiles!(zfs(5))))); /************************************************** .dup must protect string literals **************************************************/ string mutateTheImmutable(immutable string _s) { char[] s = _s.dup; foreach (ref c; s) c = 'x'; return s.idup; } string doharm(immutable string _name) { return mutateTheImmutable(_name[2 .. $].idup); } enum victimLiteral = "CL_INVALID_CONTEXT"; enum thug = doharm(victimLiteral); static assert(victimLiteral == "CL_INVALID_CONTEXT"); /************************************************** Use $ in a slice of a dotvar slice **************************************************/ int sliceDollar() { Xarg z; z.s = new char[20]; z.s[] = 'b'; z.s = z.s[2 .. $ - 2]; z.s[$ - 2] = 'c'; return z.s[$ - 2]; } static assert(sliceDollar() == 'c'); /************************************************** Variation of 5972 which caused segfault **************************************************/ int bug5972crash() { char[] z = "abc".dup; char[][] a = [null, null]; a[0] = z[0 .. 2]; a[0][1] = 'q'; return 56; } static assert(bug5972crash() == 56); /************************************************** String slice assignment through ref parameter **************************************************/ void popft(A)(ref A a) { a = a[1 .. $]; } int sdfgasf() { auto scp = "abc".dup; popft(scp); return 1; } static assert(sdfgasf() == 1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8830 // slice of slice.ptr string bug8830(string s) { auto ss = s[1 .. $]; return ss.ptr[0 .. 2]; } static assert(bug8830("hello") == "el"); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8608 // ICE void bug8608(ref int m) {} void test8608() { int z; int foo(bool b) { if (b) bug8608(z); return 1; } static assert( is(typeof(compiles!(foo(false))))); static assert(!is(typeof(compiles!(foo(true) )))); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7770 immutable char[] foo7770 = "abcde"; int bug7770a(string a) { return 1; } bool bug7770b(char c) { return true; } static assert(bug7770a(foo7770[0 .. $])); static assert(bug7770b(foo7770[$ - 2])); void baz7770() { static assert(bug7770a(foo7770[0 .. $])); static assert(bug7770b(foo7770[$ - 2])); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8601 // ICE dchar bug8601(dstring s) { dstring w = s[1 .. $]; return w[0]; } enum dstring e8601 = [cast(dchar)'o', 'n']; static assert(bug8601(e8601) == 'n'); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6015 struct Foo6015 { string field; } bool func6015(string input) { Foo6015 foo; foo.field = input[0 .. $]; assert(foo.field == "test"); foo.field = "test2"; assert(foo.field != "test"); assert(foo.field == "test2"); return true; } static assert(func6015("test")); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6001 void bug6001e(ref int[] s) { int[] r = s; s ~= 0; } bool bug6001f() { int[] s; bug6001e(s); return true; } static assert(bug6001f()); // Assignment to AAs void blah(int[char] as) { auto k = [6: as]; as = k[6]; } int blaz() { int[char] q; blah(q); return 67; } static assert(blaz() == 67); void bug6001g(ref int[] w) { w = [88]; bug6001e(w); w[0] = 23; } bool bug6001h() { int[] s; bug6001g(s); assert(s.length == 2); assert(s[1] == 0); assert(s[0] == 23); return true; } static assert(bug6001h()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10243 // wrong code *&arr as ref parameter // https://issues.dlang.org/show_bug.cgi?id=10551 // wrong code (&arr)[0] as ref parameter void bug10243(ref int n) { n = 3; } void bug10551(int* p) { bug10243(p[0]); } bool test10243() { int[1] arr; bug10243(*arr.ptr); assert(arr[0] == 3); int[1] arr2; bug10551(arr2.ptr); assert(arr2[0] == 3); int v; bug10551(&v); assert(v == 3); return true; } static assert(test10243()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4910 int bug4910(int a) { return a; } static int var4910; static assert(!is(typeof(Compiles!(bug4910(var4910))))); static assert(bug4910(123)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5845 // Regression(2.041) void test5845(ulong cols) {} uint solve(bool niv, ref ulong cols) { if (niv) solve(false, cols); else test5845(cols); return 65; } ulong nqueen(int n) { ulong cols = 0; return solve(true, cols); } static assert(nqueen(2) == 65); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5258 struct Foo5258 { int x; } void bar5258(int n, ref Foo5258 fong) { if (n) bar5258(n - 1, fong); else fong.x++; } int bug5258() { Foo5258 foo5258 = Foo5258(); bar5258(1, foo5258); return 45; } static assert(bug5258() == 45); struct Foo5258b { int[2] r; } void baqopY(int n, ref int[2] fongo) { if (n) baqopY(n - 1, fongo); else fongo[0]++; } int bug5258b() { Foo5258b qq; baqopY(1, qq.r); return 618; } static assert(bug5258b() == 618); // Notice that this case involving reassigning the dynamic array struct Foo5258c { int[] r; } void baqop(int n, ref int[] fongo) { if (n) baqop(n - 1, fongo); else { fongo = new int[20]; fongo[0]++; } } size_t bug5258c() { Foo5258c qq; qq.r = new int[30]; baqop(1, qq.r); return qq.r.length; } static assert(bug5258c() == 20); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6049 struct Bug6049 { int m; this(int x) { m = x; } invariant() { } } const Bug6049[] foo6049 = [Bug6049(6), Bug6049(17)]; static assert(foo6049[0].m == 6); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6052 struct Bug6052 { int a; } bool bug6052() { Bug6052[2] arr; for (int i = 0; i < 2; ++ i) { Bug6052 el = {i}; Bug6052 ek = el; arr[i] = el; el.a = i + 2; assert(ek.a == i); // ok assert(arr[i].a == i); // fail } assert(arr[1].a == 1); // ok assert(arr[0].a == 0); // fail return true; } static assert(bug6052()); bool bug6052b() { int[][1] arr; int[1] z = [7]; arr[0] = z; assert(arr[0][0] == 7); arr[0] = z; z[0] = 3; assert(arr[0][0] == 3); return true; } static assert(bug6052b()); struct Bug6052c { int x; this(int a) { x = a; } } int bug6052c() { Bug6052c[] pieces = []; for (int c = 0; c < 2; ++ c) pieces ~= Bug6052c(c); assert(pieces[1].x == 1); assert(pieces[0].x == 0); return 1; } static assert(bug6052c() == 1); static assert(bug6052c() == 1); static assert({ Bug6052c[] pieces = []; pieces.length = 2; int c = 0; pieces[0] = Bug6052c(c); ++c; pieces[1] = Bug6052c(c); assert(pieces[0].x == 0); return true; }()); static assert({ int[1][] pieces = []; pieces.length = 2; for (int c = 0; c < 2; ++ c) pieces[c][0] = c; assert(pieces[1][0] == 1); assert(pieces[0][0] == 0); return true; }()); static assert({ Bug6052c[] pieces = []; for (int c = 0; c < 2; ++ c) pieces ~= Bug6052c(c); assert(pieces[1].x == 1); assert(pieces[0].x == 0); return true; }()); static assert({ int[1] z = 7; int[1][] pieces = [z,z]; pieces[1][0]=3; assert(pieces[0][0] == 7); pieces = pieces ~ [z,z]; pieces[3][0] = 16; assert(pieces[2][0] == 7); pieces = [z,z] ~ pieces; pieces[5][0] = 16; assert(pieces[4][0] == 7); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6749 struct CtState { string code; } CtState bug6749() { CtState[] pieces; CtState r = CtState("correct"); pieces ~= r; r = CtState("clobbered"); return pieces[0]; } static assert(bug6749().code == "correct"); /************************************************** Index + slice assign to function returns **************************************************/ int[] funcRetArr(int[] a) { return a; } int testFuncRetAssign() { int[] x = new int[20]; funcRetArr(x)[2] = 4; assert(x[2] == 4); funcRetArr(x)[] = 27; assert(x[15] == 27); return 5; } static assert(testFuncRetAssign() == 5); int keyAssign() { int[int] pieces; pieces[3] = 1; pieces.keys[0] = 4; pieces.values[0] = 27; assert(pieces[3] == 1); return 5; } static assert(keyAssign() == 5); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6054 // AA literals enum x6054 = { auto p = { int[string] pieces; pieces[['a'].idup] = 1; return pieces; }(); return p; }(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6077 enum bug6077 = { string s; string t; return s ~ t; }(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6078 // Pass null array by ref struct Foo6078 { int[] bar; } static assert({ Foo6078 f; int i; foreach (ref e; f.bar) { i += e; } return i; }() == 0); int bug6078(ref int[] z) { int[] q = z; return 2; } static assert({ Foo6078 f; return bug6078(f.bar); }() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6079 // Array bounds checking static assert(!is(typeof(compiles!({ int[] x = [1, 2, 3, 4]; x[4] = 1; return true; }() )))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6100 struct S6100 { int a; } S6100 init6100(int x) { S6100 s = S6100(x); return s; } static const S6100[2] s6100a = [init6100(1), init6100(2)]; static assert(s6100a[0].a == 1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4825 // failed with -inline int a4825() { int r; return r; } int b4825() { return a4825(); } void c4825() { void d() { auto e = b4825(); } static const int f = b4825(); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5708 // failed with -inline string b5708(string s) { return s; } string a5708(string s) { return b5708(s); } void bug5708() { void m() { a5708("lit"); } static assert(a5708("foo") == "foo"); static assert(a5708("bar") == "bar"); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6120 // failed with -inline struct Bug6120(T) { this(int x) { } } static assert({ auto s = Bug6120!int(0); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6123 // failed with -inline struct Bug6123(T) { void f() {} // can also trigger if the struct is normal but f is template } static assert({ auto piece = Bug6123!int(); piece.f(); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6053 // ICE involving pointers static assert({ int* a = null; assert(a is null); assert(a == null); return true; }()); static assert({ int b; int* a = &b; assert(a !is null); *a = 7; assert(b == 7); assert(*a == 7); return true; }()); int dontbreak6053() { auto q = &dontbreak6053; void caz() {} auto tr = &caz; return 5; } static assert(dontbreak6053()); static assert({ int a; *(&a) = 15; assert(a == 15); assert(*(&a) == 15); return true; }()); static assert({ int a = 5, b = 6, c = 2; assert(*(c ? &a : &b) == 5); assert(*(!c ? &a : &b) == 6); return true; }()); static assert({ int a, b, c; (c ? a : b) = 1; return true; }()); static assert({ int a, b, c = 1; int* p = &a; (c ? *p : b) = 51; assert(a == 51); return true; }()); /************************************************** Pointer arithmetic, dereference, and comparison **************************************************/ // dereference null pointer static assert(!is(typeof(compiles!({ int a, b, c = 1; int* p; (c ? *p : b) = 51; return 6; }() )))); static assert(!is(typeof(compiles!({ int* a = null; assert(*a != 6); return 72; }() )))); // cannot <, > compare pointers to different arrays static assert(!is(typeof(compiles!({ int[5] a, b; bool c = (&a[0] > &b[0]); return 72; }() )))); // can ==, is, !is, != compare pointers for different arrays static assert({ int[5] a; int[5] b; assert(!(&a[0] == &b[0])); assert(&a[0] != &b[0]); assert(!(&a[0] is &b[0])); assert(&a[0] !is &b[0]); return 72; }()); static assert({ int[5] a; a[0] = 25; a[1] = 5; int* b = &a[1]; assert(*b == 5); *b = 34; int c = *b; *b += 6; assert(b == &a[1]); assert(b != &a[0]); assert(&a[0] < &a[1]); assert(&a[0] <= &a[1]); assert(!(&a[0] >= &a[1])); assert(&a[4] > &a[0]); assert(c == 34); assert(*b == 40); assert(a[1] == 40); return true; }()); static assert({ int[12] x; int* p = &x[10]; int* q = &x[4]; return p - q; }() == 6); static assert({ int[12] x; int* p = &x[10]; int* q = &x[4]; q = p; assert(p == q); q = &x[4]; assert(p != q); q = q + 6; assert(q is p); return 6; }() == 6); static assert({ int[12] x; int[] y = x[2 .. 8]; int* p = &y[4]; int* q = &x[6]; assert(p == q); p = &y[5]; assert(p > q); p = p + 5; // OK, as long as we don't dereference assert(p > q); return 6; }() == 6); static assert({ char[12] x; const(char)* p = "abcdef"; const (char)* q = p; q = q + 2; assert(*q == 'c'); assert(q > p); assert(q - p == 2); assert(p - q == -2); q = &x[7]; p = &x[1]; assert(q>p); return 6; }() == 6); // Relations involving null pointers bool nullptrcmp() { // null tests void* null1 = null, null2 = null; int x = 2; void* p = &x; assert(null1 == null2); assert(null1 is null2); assert(null1 <= null2); assert(null1 >= null2); assert(!(null1 > null2)); assert(!(null2 > null1)); assert(null1 != p); assert(null1 !is p); assert(p != null1); assert(p !is null1); assert(null1 <= p); assert(p >= null2); assert(p > null1); assert(!(null1 > p)); return true; } static assert(nullptrcmp()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10840 // null pointer in dotvar struct Data10840 { bool xxx; } struct Bug10840 { Data10840* _data; } bool bug10840(int n) { Bug10840 stack; if (n == 1) { // detect deref through null pointer return stack._data.xxx; } // Wrong-code for ?: return stack._data ? false : true; } static assert(bug10840(0)); static assert(!is(typeof(Compileable!(bug10840(1))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8216 // ptr inside a pointer range // Four-pointer relations. Return true if [p1 .. p2] points inside [q1 .. q2] // (where the end points don't coincide). bool ptr4cmp(void* p1, void* p2, void* q1, void* q2) { // Each compare can be written with <, <=, >, or >=. // Either && or || can be used, giving 32 permutations. // Additionally each compare can be negated with !, yielding 128 in total. bool b1 = (p1 > q1 && p2 <= q2); bool b2 = (p1 > q1 && p2 < q2); bool b3 = (p1 >= q1 && p2 <= q2); bool b4 = (p1 >= q1 && p2 < q2); bool b5 = (q1 <= p1 && q2 > p2); bool b6 = (q1 <= p1 && q2 >= p2); bool b7 = (p2 <= q2 && p1 > q1); bool b8 = (!(p1 <= q1) && p2 <= q2); bool b9 = (!(p1 <= q1) && !(p2 > q2)); bool b10 = (!!!(p1 <= q1) && !(p2 > q2)); assert(b1 == b2 && b1 == b3 && b1 == b4 && b1 == b5 && b1 == b6); assert(b1 == b7 && b1 == b8 && b1 == b9 && b1 == b10); bool c1 = (p1 <= q1 || p2 > q2); assert(c1 == !b1); bool c2 = (p1 < q1 || p2 >= q2); bool c3 = (!(q1 <= p1) || !(q2 >= p2)); assert(c1 == c2 && c1 == c3); return b1; } bool bug8216() { int[4] a; int[13] b; int v; int* p = &v; assert(!ptr4cmp(&a[0], &a[3], p, p)); assert(!ptr4cmp(&b[2], &b[9], &a[1], &a[2])); assert(!ptr4cmp(&b[1], &b[9], &b[2], &b[8])); assert( ptr4cmp(&b[2], &b[8], &b[1], &b[9])); return 1; } static assert(bug8216()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6517 // ptr++, ptr-- int bug6517() { int[] arr = [1, 2, 3]; auto startp = arr.ptr; auto endp = arr.ptr + arr.length; for (; startp < endp; startp++) {} startp = arr.ptr; assert(startp++ == arr.ptr); assert(startp != arr.ptr); assert(startp-- != arr.ptr); assert(startp == arr.ptr); return 84; } static assert(bug6517() == 84); /************************************************** Out-of-bounds pointer assignment and deference **************************************************/ int ptrDeref(int ofs, bool wantDeref) { int[5] a; int* b = &a[0]; b = b + ofs; // OK if (wantDeref) return *b; // out of bounds return 72; } static assert(!is(typeof(compiles!(ptrDeref(-1, true))))); static assert( is(typeof(compiles!(ptrDeref(4, true))))); static assert( is(typeof(compiles!(ptrDeref(5, false))))); static assert(!is(typeof(compiles!(ptrDeref(5, true))))); static assert(!is(typeof(compiles!(ptrDeref(6, false))))); static assert(!is(typeof(compiles!(ptrDeref(6, true))))); /************************************************** Pointer += **************************************************/ static assert({ int[12] x; int zzz; assert(&zzz); int* p = &x[10]; int* q = &x[4]; q = p; assert(p == q); q = &x[4]; assert(p != q); q += 4; assert(q == &x[8]); q = q - 2; q = q + 4; assert(q is p); return 6; }() == 6); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5615 const(char)[] passthrough(const(char)[] x) { return x; } sizediff_t checkPass(Char1)(const(Char1)[] s) { const(Char1)[] balance = s[1 .. $]; return passthrough(balance).ptr - s.ptr; } static assert(checkPass("foobar") == 1); /************************************************** Pointers must not escape from CTFE **************************************************/ struct Toq { const(char)* m; } Toq ptrRet(bool b) { string x = "abc"; return Toq(b ? x[0 .. 1].ptr : null); } static assert(is(typeof(compiles!({ enum Toq boz = ptrRet(false); // OK - ptr is null Toq z = ptrRet(true); // OK -- ptr doesn't escape return 4; }() )))); static assert(!is(typeof(compiles!({ enum Toq boz = ptrRet(true); // fail - ptr escapes return 4; }() )))); /************************************************** Pointers to struct members **************************************************/ struct Qoz { int w; int[3] yof; } static assert({ int[3] gaz; gaz[2] = 3156; Toq z = ptrRet(true); auto p = z.m; assert(*z.m == 'a'); assert(*p == 'a'); auto q = &z.m; assert(*q == p); assert(**q == 'a'); Qoz g = Qoz(2, [5, 6, 7]); auto r = &g.w; assert(*r == 2); r = &g.yof[1]; assert(*r == 6); g.yof[0] = 15; ++r; assert(*r == 7); r -= 2; assert(*r == 15); r = &gaz[0]; r += 2; assert(*r == 3156); return *p; }() == 'a'); struct AList { AList* next; int value; static AList* newList() { AList[] z = new AList[1]; return &z[0]; } static AList* make(int i, int j) { auto r = newList(); r.next = (new AList[1]).ptr; r.value = 1; AList* z = r.next; (*z).value = 2; r.next.value = j; assert(r.value == 1); assert(r.next.value == 2); r.next.next = &(new AList[1])[0]; assert(r.next.next != null); assert(r.next.next); r.next.next.value = 3; assert(r.next.next.value == 3); r.next.next = newList(); r.next.next.value = 9; return r; } static int checkList() { auto r = make(1,2); assert(r.value == 1); assert(r.next.value == 2); assert(r.next.next.value == 9); return 2; } } static assert(AList.checkList() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7194 // pointers as struct members struct S7194 { int* p, p2; } int f7194() { assert(S7194().p == null); assert(!S7194().p); assert(S7194().p == S7194().p2); S7194 s = S7194(); assert(!s.p); assert(s.p == null); assert(s.p == s.p2); int x; s.p = &x; s.p2 = s.p; assert(s.p == &x); return 0; } int g7194() { auto s = S7194(); assert(s.p); // should fail return 0; } static assert(f7194() == 0); static assert(!is(typeof(compiles!(g7194())))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7248 // recursive struct pointers in array struct S7248 { S7248* ptr; } bool bug7248() { S7248[2] sarr; sarr[0].ptr = &sarr[1]; sarr[0].ptr = null; S7248* t = sarr[0].ptr; return true; } static assert(bug7248()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7216 // calling a struct pointer member struct S7216 { S7216* p; int t; void f() { } void g() { ++t; } } bool bug7216() { S7216 s0, s1; s1.t = 6; s0.p = &s1; s0.p.f(); s0.p.g(); assert(s1.t == 7); return true; } static assert(bug7216()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10858 // Wrong code with array of pointers bool bug10858() { int*[4] x; x[0] = null; assert(x[0] == null); return true; } static assert(bug10858()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12528 // painting inout type for value type literals inout(T)[] dup12528(T)(inout(T)[] a) { inout(T)[] res; foreach (ref e; a) res ~= e; return res; } enum arr12528V1 = dup12528([0]); enum arr12528V2 = dup12528([0, 1]); static assert(arr12528V1 == [0]); static assert(arr12528V2 == [0, 1]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9745 // Allow pointers to static variables shared int x9745; shared int[5] y9745; shared(int)* bug9745(int m) { auto k = &x9745; auto j = &x9745; auto p = &y9745[0]; auto q = &y9745[3]; assert(j - k == 0); assert(j == k); assert(q - p == 3); --q; int a = 0; assert(p + 2 == q); if (m == 7) { auto z1 = y9745[0 .. 2]; // slice global pointer } if (m == 8) p[1] = 7; // modify through a pointer if (m == 9) a = p[1]; // read from a pointer if (m == 0) return &x9745; return &y9745[1]; } int test9745(int m) { bug9745(m); // type painting shared int* w = bug9745(0); return 1; } shared int* w9745a = bug9745(0); shared int* w9745b = bug9745(1); static assert( is(typeof(compiles!(test9745(6))))); static assert(!is(typeof(compiles!(test9745(7))))); static assert(!is(typeof(compiles!(test9745(8))))); static assert(!is(typeof(compiles!(test9745(9))))); // pointers cast from an absolute address // (mostly applies to fake pointers, eg Windows HANDLES) bool test9745b() { void* b6 = cast(void*)0xFEFEFEFE; void* b7 = cast(void*)0xFEFEFEFF; assert(b6 is b6); assert(b7 != b6); return true; } static assert(test9745b()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9364 // ICE with pointer to local struct struct S9364 { int i; } bool bug9364() { S9364 s; auto k = (&s).i; return 1; } static assert(bug9364()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10251 // Pointers to const globals static const int glob10251 = 7; const(int)* bug10251() { return &glob10251; } static a10251 = &glob10251; // OK static b10251 = bug10251(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4065 // [CTFE] AA "in" operator doesn't work bool bug4065(string s) { enum int[string] aa = ["aa":14, "bb":2]; int* p = s in aa; if (s == "aa") assert(*p == 14); else if (s == "bb") assert(*p == 2); else assert(!p); int[string] zz; assert(!("xx" in zz)); bool c = !p; return cast(bool)(s in aa); } static assert(!bug4065("xx")); static assert( bug4065("aa")); static assert( bug4065("bb")); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12689 // assigning via pointer from 'in' expression int g12689() { int[int] aa; aa[1] = 13; assert(*(1 in aa) == 13); *(1 in aa) = 42; return aa[1]; } static assert(g12689() == 42); /************************************************** Pointers in ? : **************************************************/ static assert({ int[2] x; int* p = &x[1]; return p ? true: false; }()); /************************************************** Pointer slicing **************************************************/ int ptrSlice() { auto arr = new int[5]; int* x = &arr[0]; int[] y = x[0 .. 5]; x[1 .. 3] = 6; ++x; x[1 .. 3] = 14; assert(arr[1] == 6); assert(arr[2] == 14); //x[-1 .. 4] = 5; // problematic because negative lower boundary will throw RangeError in runtime (x - 1)[0 .. 3] = 5; int[] z = arr[1 .. 2]; z.length = 4; z[$ - 1] = 17; assert(arr.length == 5); return 2; } static assert(ptrSlice() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6344 // create empty slice from null pointer static assert({ char* c = null; auto m = c[0 .. 0]; return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8365 // block assignment of enum arrays enum E8365 { first = 7, second, third, fourth } static assert({ E8365[2] x; return x[0]; }() == E8365.first); static assert({ E8365[2][2] x; return x[0][0]; }() == E8365.first); static assert({ E8365[2][2][2] x; return x[0][0][0]; }() == E8365.first); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4448 // labelled break + continue int bug4448() { int n = 2; L1: do { switch(n) { case 5: return 7; default: n = 5; break L1; } int w = 7; } while (0); return 3; } static assert(bug4448() == 3); int bug4448b() { int n = 2; L1: for (n = 2; n < 5; ++n) { for (int m = 1; m < 6; ++m) { if (n < 3) { assert(m == 1); continue L1; } } break; } return 3; } static assert(bug4448b() == 3); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6985 // non-constant case int bug6985(int z) { int q = z * 2 - 6; switch(z) { case q: q = 87; break; default: } return q; } static assert(bug6985(6) == 87); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6281 // [CTFE] A null pointer '!is null' returns 'true' static assert(!{ auto p = null; return p !is null; }()); static assert(!{ auto p = null; return p != null; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6331 // evaluate SliceExp on if condition bool bug6331(string s) { if (s[0 .. 1]) return true; return false; } static assert(bug6331("str")); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6283 // assign to AA with slice as index static assert({ immutable p = "pp"; int[string] pieces = [p: 0]; pieces["qq"] = 1; return true; }()); static assert({ immutable renames = [0: "pp"]; int[string] pieces; pieces[true ? renames[0] : "qq"] = 1; pieces["anything"] = 1; return true; }()); static assert({ immutable qq = "qq"; string q = qq; int[string] pieces = ["a":1]; pieces[q] = 0; string w = "ab"; int z = pieces[w[0 .. 1]]; assert(z == 1); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6282 // dereference 'in' of an AA static assert({ int[] w = new int[4]; w[2] = 6; auto c = [5: w]; auto kk = (*(5 in c))[2]; (*(5 in c))[2] = 8; (*(5 in c))[1 .. $ - 2] = 4; auto a = [4:"1"]; auto n = *(4 in a); return n; }() == "1"); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6337 // member function call on struct literal struct Bug6337 { int k; void six() { k = 6; } int ctfe() { six(); return k; } } static assert(Bug6337().ctfe() == 6); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6603 // call manifest function pointer int f6603(int a) { return a + 5; } enum bug6603 = &f6603; static assert(bug6603(6) == 11); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6375 struct D6375 { int[] arr; } A6375 a6375(int[] array) { return A6375(array); } struct A6375 { D6375* _data; this(int[] arr) { _data = new D6375; _data.arr = arr; } int[] data() { return _data.arr; } } static assert({ int[] a = [1, 2]; auto app2 = a6375(a); auto data = app2.data(); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6280 // Converting pointers to bool static assert({ if ((0 in [0:0])) {} if ((0 in [0:0]) && (0 in [0:0])) {} return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6276 // ~= struct Bug6276 { int[] i; } static assert({ Bug6276 foo; foo.i ~= 1; foo.i ~= 2; return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6374 // ptr[n] = x, x = ptr[n] static assert({ int[] arr = [1]; arr.ptr[0] = 2; auto k = arr.ptr[0]; assert(k == 2); return arr[0]; }() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6306 // recursion and local variables void recurse6306() { bug6306(false); } bool bug6306(bool b) { int x = 0; if (b) recurse6306(); assert(x == 0); x = 1; return true; } static assert(bug6306(true)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6386 // ICE on unsafe pointer cast static assert(!is(typeof(compiles!({ int x = 123; int* p = &x; float z; float* q = cast(float*)p; return true; }() )))); static assert({ int[] x = [123, 456]; int* p = &x[0]; auto m = cast(const(int)*)p; auto q = p; return *q; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6420 // ICE on dereference of invalid pointer static assert({ // Should compile, but pointer can't be dereferenced int x = 123; int* p = cast(int*)x; auto q = cast(char*)x; auto r = cast(char*)323; // Valid const-changing cast const float *m = cast(immutable float*)[1.2f,2.4f,3f]; return true; }() ); static assert(!is(typeof(compiles!({ int x = 123; int* p = cast(int*)x; int a = *p; return true; }() )))); static assert(!is(typeof(compiles!({ int* p = cast(int*)123; int a = *p; return true; }() )))); static assert(!is(typeof(compiles!({ auto k = cast(int*)45; *k = 1; return true; }() )))); static assert(!is(typeof(compiles!({ *cast(float*)"a" = 4.0; return true; }() )))); static assert(!is(typeof(compiles!({ float f = 2.8; long *p = &f; return true; }() )))); static assert(!is(typeof(compiles!({ long *p = cast(long*)[1.2f, 2.4f, 3f]; return true; }() )))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6250 // deref pointers to array int[]* simple6250(int[]* x) { return x; } void swap6250(int[]* lhs, int[]* rhs) { int[] kk = *lhs; assert(simple6250(lhs) == lhs); lhs = simple6250(lhs); assert(kk[0] == 18); assert((*lhs)[0] == 18); assert((*rhs)[0] == 19); *lhs = *rhs; assert((*lhs)[0] == 19); *rhs = kk; assert(*rhs == kk); assert(kk[0] == 18); assert((*rhs)[0] == 18); } int ctfeSort6250() { int[][2] x; int[3] a = [17, 18, 19]; x[0] = a[1 .. 2]; x[1] = a[2 .. $]; assert(x[0][0] == 18); assert(x[0][1] == 19); swap6250(&x[0], &x[1]); assert(x[0][0] == 19); assert(x[1][0] == 18); a[1] = 57; assert(x[0][0] == 19); return x[1][0]; } static assert(ctfeSort6250() == 57); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6672 // circular references in array void bug6672(ref string lhs, ref string rhs) { auto tmp = lhs; lhs = rhs; rhs = tmp; } static assert({ auto kw = ["a"]; bug6672(kw[0], kw[0]); return true; }()); void slice6672(ref string[2] agg, ref string lhs) { agg[0 .. $] = lhs; } static assert({ string[2] kw = ["a", "b"]; slice6672(kw, kw[0]); assert(kw[0] == "a"); assert(kw[1] == "a"); return true; }()); // an unrelated rejects-valid bug static assert({ string[2] kw = ["a", "b"]; kw[0 .. 2] = "x"; return true; }()); void bug6672b(ref string lhs, ref string rhs) { auto tmp = lhs; assert(tmp == "a"); lhs = rhs; assert(tmp == "a"); rhs = tmp; } static assert({ auto kw=["a", "b"]; bug6672b(kw[0], kw[1]); assert(kw[0] == "b"); assert(kw[1] == "a"); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6399 // (*p).length = n struct A6399 { int[] arr; int subLen() { arr = [1, 2, 3, 4, 5]; arr.length -= 1; return cast(int)arr.length; } } static assert({ A6399 a; return a.subLen(); }() == 4); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7789 // (*p).length++ where *p is null struct S7789 { size_t foo() { _ary.length += 1; return _ary.length; } int[] _ary; } static assert(S7789().foo()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6418 // member named 'length' struct Bug6418 { size_t length() { return 189; } } static assert(Bug6418.init.length == 189); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4021 // rehash bool bug4021() { int[int] aa = [1: 1]; aa.rehash; return true; } static assert(bug4021()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11629 // crash on AA.rehash struct Base11629 { alias T = ubyte, Char = char; alias String = immutable(Char)[]; const Char[T] toChar; this(int _dummy) { Char[T] toCharTmp = [0:'A']; toChar = toCharTmp.rehash; } } enum ct11629 = Base11629(4); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3512 // foreach (dchar; string) // https://issues.dlang.org/show_bug.cgi?id=6558 // foreach (int, dchar; string) bool test3512() { string s = "öhai"; int q = 0; foreach (wchar c; s) { if (q == 2) assert(c == 'a'); ++q; } assert(q == 4); // _aApplycd1 foreach (dchar c; s) { ++q; if (c == 'h') break; } assert(q == 6); // _aApplycw2 foreach (int i, wchar c; s) { assert(i >= 0 && i < s.length); } // _aApplycd2 foreach (int i, dchar c; s) { assert(i >= 0 && i < s.length); } wstring w = "xüm"; // _aApplywc1 foreach (char c; w) { ++q; } assert(q == 10); // _aApplywd1 foreach (dchar c; w) { ++q; } assert(q == 13); // _aApplywc2 foreach (int i, char c; w) { assert(i >= 0 && i < w.length); } // _aApplywd2 foreach (int i, dchar c; w) { assert(i >= 0 && i < w.length); } dstring d = "yäq"; // _aApplydc1 q = 0; foreach (char c; d) { ++q; } assert(q == 4); // _aApplydw1 q = 0; foreach (wchar c; d) { ++q; } assert(q == 3); // _aApplydc2 foreach (int i, char c; d) { assert(i >= 0 && i < d.length); } // _aApplydw2 foreach (int i, wchar c; d) { assert(i >= 0 && i < d.length); } dchar[] dr = "squop"d.dup; foreach (int n, char c; dr) { if (n == 2) break; assert(c != 'o'); } // _aApplyRdc1 foreach_reverse (char c; dr) {} // _aApplyRdw1 foreach_reverse (wchar c; dr) {} // _aApplyRdc2 foreach_reverse (int n, char c; dr) { if (n == 4) break; assert(c != 'o'); } // _aApplyRdw2 foreach_reverse (int i, wchar c; dr) { assert(i >= 0 && i < dr.length); } q = 0; wstring w2 = ['x', 'ü', 'm']; // foreach over array literals foreach_reverse (int n, char c; w2) { ++q; if (c == 'm') assert(n == 2 && q == 1); if (c == 'x') assert(n == 0 && q == 4); } return true; } static assert(test3512()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6510 // ICE only with -inline struct Stack6510 { struct Proxy { void shrink() {} } Proxy stack; void pop() { stack.shrink(); } } int bug6510() { static int used() { Stack6510 junk; junk.pop(); return 3; } return used(); } void test6510() { static assert(bug6510() == 3); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6511 // arr[] shouldn't make a copy T bug6511(T)() { T[1] a = [1]; a[] += a[]; return a[0]; } static assert(bug6511!ulong() == 2); static assert(bug6511!long() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6512 // new T[][] bool bug6512(int m) { auto x = new int[2][][](m, 5); assert(x.length == m); assert(x[0].length == 5); assert(x[0][0].length == 2); foreach (i; 0.. m) foreach (j; 0 .. 5) foreach (k; 0 .. 2) x[i][j][k] = k + j*10 + i*100; foreach (i; 0.. m) foreach (j; 0 .. 5) foreach (k; 0 .. 2) assert(x[i][j][k] == k + j*10 + i*100); return true; } static assert(bug6512(3)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6516 // ICE(constfold.c) dstring bug6516() { return cast(dstring)new dchar[](0); } static assert(bug6516() == ""d); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6727 // ICE(interpret.c) const(char)* ice6727(const(char)* z) { return z; } static assert({ auto q = ice6727("a".dup.ptr); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6721 // Cannot get pointer to start of char[] static assert({ char[] c1 = "".dup; auto p = c1.ptr; string c2 = ""; auto p2 = c2.ptr; return 6; }() == 6); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6693 // Assign to null AA struct S6693 { int[int] m; } static assert({ int[int][int] aaa; aaa[3][1] = 4; int[int][3] aab; aab[2][1] = 4; S6693 s; s.m[2] = 4; return 6693; }() == 6693); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7602 // Segfault AA.keys on null AA string[] test7602() { int[string] array; return array.keys; } enum bug7602 = test7602(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6739 // Nested AA assignment static assert({ int[int][int][int] aaa; aaa[3][1][6] = 14; return aaa[3][1][6]; }() == 14); static assert({ int[int][int] aaa; aaa[3][1] = 4; aaa[3][3] = 3; aaa[1][5] = 9; auto kk = aaa[1][5]; return kk; }() == 9); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6751 // ref AA assignment void bug6751(ref int[int] aa) { aa[1] = 2; } static assert({ int[int] aa; bug6751(aa); assert(aa[1] == 2); return true; }()); void bug6751b(ref int[int][int] aa) { aa[1][17] = 2; } struct S6751 { int[int][int] aa; int[int] bb; } static assert({ S6751 s; bug6751b(s.aa); assert(s.aa[1][17] == 2); return true; }()); static assert({ S6751 s; s.aa[7][56] = 57; bug6751b(s.aa); assert(s.aa[1][17] == 2); assert(s.aa[7][56] == 57); bug6751c(s.aa); assert(s.aa.keys.length == 1); assert(s.aa.values.length == 1); return true; }()); static assert({ S6751 s; s.bb[19] = 97; bug6751(s.bb); assert(s.bb[1] == 2); assert(s.bb[19] == 97); return true; }()); void bug6751c(ref int[int][int] aa) { aa = [38: [56 : 77]]; } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7790 // AA foreach ref struct S7790 { size_t id; } size_t bug7790(S7790[string] tree) { foreach (k, ref v; tree) v.id = 1; return tree["a"].id; } static assert(bug7790(["a":S7790(0)]) == 1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6765 // null AA.length static assert({ int[int] w; return w.length; }() == 0); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6769 // AA.keys, AA.values with -inline static assert({ double[char[3]] w = ["abc" : 2.3]; double[] z = w.values; return w.keys.length; }() == 1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=4022 // AA.get static assert({ int[int] aa = [58: 13]; int r = aa.get(58, 1000); assert(r == 13); r = aa.get(59, 1000); return r; }() == 1000); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6775 // AA.opApply static assert({ int[int] aa = [58: 17, 45:6]; int valsum = 0; int keysum = 0; foreach (m; aa) // aaApply { valsum += m; } assert(valsum == 17 + 6); valsum = 0; foreach (n, m; aa) // aaApply2 { valsum += m; keysum += n; } assert(valsum == 17 + 6); assert(keysum == 58 + 45); // Check empty AA valsum = 0; int[int] bb; foreach (m; bb) { ++valsum; } assert(valsum == 0); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7890 // segfault struct with AA field struct S7890 { int[int] tab; } S7890 bug7890() { S7890 foo; foo.tab[0] = 0; return foo; } enum e7890 = bug7890(); /************************************************** AA.remove **************************************************/ static assert({ int[int] aa = [58: 17, 45:6]; aa.remove(45); assert(aa.length == 1); aa.remove(7); assert(aa.length == 1); aa.remove(58); assert(aa.length == 0); return true; }()); /************************************************** try, finally **************************************************/ static assert({ int n = 0; try { n = 1; } catch (Exception e) {} assert(n == 1); try { n = 2; } catch (Exception e) {} finally { assert(n == 2); n = 3; } assert(n == 3); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6800 // bad pointer casts bool badpointer(int k) { int m = 6; int* w = &m; assert(*w == 6); int[3] a = [17, 2, 21]; int* w2 = &a[2]; assert(*w2 == 21); // cast int* to uint* is OK uint* u1 = cast(uint*)w; assert(*u1 == 6); uint* u2 = cast(uint*)w2; assert(*u2 == 21); uint* u3 = cast(uint*)&m; assert(*u3 == 6); // cast int* to void* is OK void* v1 = cast(void*)w; void* v3 = &m; void* v4 = &a[0]; // cast from void* back to int* is OK int* t3 = cast(int*)v3; assert(*t3 == 6); int* t4 = cast(int*)v4; assert(*t4 == 17); // cast from void* to uint* is OK uint* t1 = cast(uint*)v1; assert(*t1 == 6); // and check that they're real pointers m = 18; assert(*t1 == 18); assert(*u3 == 18); int** p = &w; if (k == 1) // bad reinterpret double *d1 = cast(double*)w; if (k == 3) // bad reinterpret char* d3 = cast(char*)w2; if (k == 4) { void* q1 = cast(void*)p; // OK-void is int* void* *q = cast(void**)p; // OK-void is int } if (k == 5) void*** q = cast(void***)p; // bad: too many * if (k == 6) // bad reinterpret through void* double* d1 = cast(double*)v1; if (k == 7) double* d7 = cast(double*)v4; if (k == 8) ++v4; // can't do pointer arithmetic on void* return true; } static assert(badpointer(4)); static assert(!is(typeof(compiles!(badpointer(1))))); static assert( is(typeof(compiles!(badpointer(2))))); static assert(!is(typeof(compiles!(badpointer(3))))); static assert( is(typeof(compiles!(badpointer(4))))); static assert(!is(typeof(compiles!(badpointer(5))))); static assert(!is(typeof(compiles!(badpointer(6))))); static assert(!is(typeof(compiles!(badpointer(7))))); static assert(!is(typeof(compiles!(badpointer(8))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10211 // Allow casts S**->D**, when S*->D* is OK int bug10211() { int m = 7; int* x = &m; int** y = &x; assert(**y == 7); uint* p = cast(uint*)x; uint** q = cast(uint**)y; return 1; } static assert(bug10211()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10568 // CTFE rejects function pointer safety casts @safe void safetyDance() {} int isItSafeToDance() { void function() @trusted yourfriends = &safetyDance; void function() @safe nofriendsOfMine = yourfriends; return 1; } static assert(isItSafeToDance()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12296 // CTFE rejects const compatible AA pointer cast int test12296() { immutable x = [5 : 4]; auto aa = &x; const(int[int])* y = aa; return 1; } static assert(test12296()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9170 // Allow reinterpret casts float<->int int f9170(float x) { return *(cast(int*)&x); } float i9170(int x) { return *(cast(float*)&x); } float u9170(uint x) { return *(cast(float*)&x); } int f9170arr(float[] x) { return *(cast(int*)&(x[1])); } long d9170(double x) { return *(cast(long*)&x); } int fref9170(ref float x) { return *(cast(int*)&x); } long dref9170(ref double x) { return *(cast(long*)&x); } bool bug9170() { float f = 1.25; double d = 1.25; assert(f9170(f) == 0x3FA0_0000); assert(fref9170(f) == 0x3FA0_0000); assert(d9170(d) == 0x3FF4_0000_0000_0000L); assert(dref9170(d) == 0x3FF4_0000_0000_0000L); float [3] farr = [0, 1.25, 0]; assert(f9170arr(farr) == 0x3FA0_0000); int i = 0x3FA0_0000; assert(i9170(i) == 1.25); uint u = 0x3FA0_0000; assert(u9170(u) == 1.25); return true; } static assert(bug9170()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6792 // ICE with pointer cast of indexed array struct S6792 { int i; } static assert({ { void* p; p = [S6792(1)].ptr; S6792 s = *(cast(S6792*)p); assert(s.i == 1); } { void*[] ary; ary ~= [S6792(2)].ptr; S6792 s = *(cast(S6792*)ary[0]); assert(s.i == 2); } { void*[7] ary; ary[6]= [S6792(2)].ptr; S6792 s = *(cast(S6792*)ary[6]); assert(s.i == 2); } { void* p; p = [S6792(1)].ptr; void*[7] ary; ary[5]= p; S6792 s = *(cast(S6792*)ary[5]); assert(s.i == 1); } { S6792*[string] aa; aa["key"] = [S6792(3)].ptr; const(S6792) s = *(cast(const(S6792)*)aa["key"]); assert(s.i == 3); } { S6792[string] blah; blah["abc"] = S6792(6); S6792*[string] aa; aa["kuy"] = &blah["abc"]; const(S6792) s = *(cast(const(S6792)*)aa["kuy"]); assert(s.i == 6); void*[7] ary; ary[5]= &blah["abc"]; S6792 t = *(cast(S6792*)ary[5]); assert(t.i == 6); int q = 6; ary[3]= &q; int gg = *(cast(int*)(ary[3])); } return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7780 // array cast int bug7780(int testnum) { int[] y = new int[2]; y[0] = 2000000; if (testnum == 1) { void[] x = y; return (cast(byte[])x)[1]; } if (testnum == 2) { int[] x = y[0 .. 1]; return (cast(byte[])x)[1]; } return 1; } static assert( is(typeof(compiles!(bug7780(0))))); static assert(!is(typeof(compiles!(bug7780(1))))); static assert(!is(typeof(compiles!(bug7780(2))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14028 // static array pointer that refers existing array elements. int test14028a(size_t ofs)(bool ct) { int[4] a; int[2]* p; int num = ofs; if (ct) p = cast(int[2]*)&a[ofs]; // SymOffExp else p = cast(int[2]*)&a[num]; // CastExp + AddrExp // pointers comparison assert(cast(void*)a.ptr <= cast(void*)p); assert(cast(void*)a.ptr <= cast(void*)&(*p)[0]); assert(cast(void*)&a[0] <= cast(void*)p); return 1; } static assert(test14028a!0(true)); static assert(test14028a!0(false)); static assert(test14028a!3(true)); static assert(test14028a!3(false)); static assert(!is(typeof(compiles!(test14028a!4(true))))); static assert(!is(typeof(compiles!(test14028a!4(false))))); int test14028b(int num) { int[4] a; int[2]* p; if (num == 1) { p = cast(int[2]*)&a[0]; // &a[0..2]; (*p)[0] = 1; // a[0] = 1 (*p)[1] = 2; // a[1] = 2 assert(a == [1,2,0,0]); p = p + 1; // &a[0] -> &a[2] (*p)[0] = 3; // a[2] = 3 (*p)[1] = 4; // a[3] = 4 assert(a == [1,2,3,4]); } if (num == 2) { p = cast(int[2]*)&a[1]; // &a[1..3]; (*p)[0] = 1; // a[1] = 1 p = p + 1; // &a[1..3] -> &a[3..5] (*p)[0] = 2; // a[3] = 2 assert(a == [0,1,0,2]); } if (num == 3) { p = cast(int[2]*)&a[1]; // &a[1..3]; (*p)[0] = 1; // a[1] = 1 p = p + 1; // &a[1..3] -> &a[3..5] (*p)[0] = 2; // a[3] = 2 (*p)[1] = 3; // a[4] = 3 (CTFE error) } if (num == 4) { p = cast(int[2]*)&a[0]; // &a[0..2]; p = p + 1; // &a[0..2] -> &a[2..4] p = p + 1; // &a[2..4] -> &a[4..6] (ok) } if (num == 5) { p = cast(int[2]*)&a[1]; // &a[1..3]; p = p + 2; // &a[1..3] -> &a[5..7] (CTFE error) } return 1; } static assert(test14028b(1)); static assert(test14028b(2)); static assert(!is(typeof(compiles!(test14028b(3))))); static assert(test14028b(4)); static assert(!is(typeof(compiles!(test14028b(5))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10275 // cast struct literals to immutable struct Bug10275 { uint[] ivals; } Bug10275 bug10275() { return Bug10275([1, 2, 3]); } int test10275() { immutable(Bug10275) xxx = cast(immutable(Bug10275))bug10275(); return 1; } static assert(test10275()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6851 // passing pointer by argument void set6851(int* pn) { *pn = 20; } void bug6851() { int n = 0; auto pn = &n; *pn = 10; assert(n == 10); set6851(&n); } static assert({ bug6851(); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7876 int* bug7876(int n) @system { int x; auto ptr = &x; if (n == 2) ptr = null; return ptr; } struct S7876 { int* p; } S7876 bug7876b(int n) @system { int x; S7876 s; s.p = &x; if (n == 11) s.p = null; return s; } int test7876(int n) { if (n >= 10) { S7876 m = bug7876b(n); return 1; } int* p = bug7876(n); return 1; } static assert( is(typeof(compiles!(test7876(2))))); static assert(!is(typeof(compiles!(test7876(0))))); static assert( is(typeof(compiles!(test7876(11))))); static assert(!is(typeof(compiles!(test7876(10))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11824 int f11824(T)() { T[] arr = new T[](1); T* getAddr(ref T a) { return &a; } getAddr(arr[0]); return 1; } static assert(f11824!int()); // OK static assert(f11824!(int[])()); // OK <- NG /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6817 // if converted to &&, only with -inline static assert({ void toggle() { bool b; if (b) b = false; } toggle(); return true; }()); /************************************************** cast to void **************************************************/ static assert({ cast(void)(71); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6816 // nested function can't access this struct S6816 { size_t foo() { return (){ return value +1 ; }(); } size_t value; } enum s6816 = S6816().foo(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7277 // ICE nestedstruct.init.tupleof struct Foo7277 { int a; int func() { int b; void nested() { b = 7; a = 10; } nested(); return a+b; } } static assert(Foo7277().func() == 17); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10217 // ICE. CTFE version of 9315 bool bug10217() { struct S { int i; void bar() {} } auto yyy = S.init.tupleof[$ - 1]; assert(!yyy); return 1; } static assert(bug10217()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8276 // ICE void bug8676(int n) { const int X1 = 4 + n; const int X2 = 4; int X3 = 4; int bar1() { return X1; } int bar2() { return X2; } int bar3() { return X3; } static assert(!is(typeof(compiles!(bar1())))); static assert( is(typeof(compiles!(bar2())))); static assert(!is(typeof(compiles!(bar3())))); } /************************************************** classes and interfaces **************************************************/ interface SomeInterface { int daz(); float bar(char); int baz(); } interface SomeOtherInterface { int xxx(); } class TheBase : SomeInterface, SomeOtherInterface { int q = 88; int rad = 61; int a = 14; int somebaseclassfunc() { return 28; } int daz() { return 0; } int baz() { return 0; } int xxx() { return 762; } int foo() { return q; } float bar(char c) { return 3.6; } } class SomeClass : TheBase, SomeInterface { int gab = 9; int fab; int a = 17; int b = 23; override int foo() { return gab + a; } override float bar(char c) { return 2.6; } int something() { return 0; } override int daz() { return 0; } override int baz() { return 0; } } class Unrelated : TheBase { this(int x) { a = x; } } auto classtest1(int n) { SomeClass c = new SomeClass; assert(c.a == 17); assert(c.q == 88); TheBase d = c; assert(d.a == 14); assert(d.q == 88); if (n == 7) { // bad cast -- should fail Unrelated u = cast(Unrelated)d; assert(u is null); } SomeClass e = cast(SomeClass)d; d.q = 35; assert(c.q == 35); assert(c.foo() == 9 + 17); ++c.a; assert(c.foo() == 9 + 18); assert(d.foo() == 9 + 18); d = new TheBase; SomeInterface fc = c; SomeOtherInterface ot = c; assert(fc.bar('x') == 2.6); assert(ot.xxx() == 762); fc = d; ot = d; assert(fc.bar('x') == 3.6); assert(ot.xxx() == 762); Unrelated u2 = new Unrelated(7); assert(u2.a == 7); return 6; } static assert(classtest1(1)); static assert(classtest1(2)); static assert(classtest1(7)); // https://issues.dlang.org/show_bug.cgi?id=7154 // can't initialize enum with not null class SomeClass classtest2(int n) { return n == 5 ? (new SomeClass) : null; } static assert( is(typeof((){ enum const(SomeClass) xx = classtest2(2);}()))); static assert(!is(typeof((){ enum const(SomeClass) xx = classtest2(5);}()))); class RecursiveClass { int x; this(int n) { x = n; } RecursiveClass b; void doit() { b = new RecursiveClass(7); b.x = 2;} } int classtest3() { RecursiveClass x = new RecursiveClass(17); x.doit(); RecursiveClass y = x.b; assert(y.x == 2); assert(x.x == 17); return 1; } static assert(classtest3()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12016 // class cast and qualifier reinterpret class B12016 { } class C12016 : B12016 { } bool f12016(immutable B12016 b) { assert(b); return true; } static assert(f12016(new immutable C12016)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10610 // ice immutable implicit conversion class Bug10610(T) { int baz() immutable { return 1; } static immutable(Bug10610!T) min = new Bug10610!T(); } void ice10610() { alias T10610 = Bug10610!(int); static assert (T10610.min.baz()); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13141 // regression fix caused by 10610 struct MapResult13141(alias pred) { int[] range; @property empty() { return range.length == 0; } @property front() { return pred(range[0]); } void popFront() { range = range[1 .. $]; } } string[] array13141(R)(R r) { typeof(return) result; foreach (e; r) result ~= e; return result; } //immutable string[] splitterNames = [4].map!(e => "4").array(); immutable string[] splitterNames13141 = MapResult13141!(e => "4")([4]).array13141(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11587 // AA compare static assert([1:2, 3:4] == [3:4, 1:2]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14325 // more AA comparisons static assert([1:1] != [1:2, 2:1]); // OK static assert([1:1] != [1:2]); // OK static assert([1:1] != [2:1]); // OK <- Error static assert([1:1, 2:2] != [3:3, 4:4]); // OK <- Error /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7147 // typeid() static assert({ TypeInfo xxx = typeid(Object); TypeInfo yyy = typeid(new Error("xxx")); return true; }()); int bug7147(int n) { Error err = n ? new Error("xxx") : null; TypeInfo qqq = typeid(err); return 1; } // Must not segfault if class is null static assert(!is(typeof(compiles!(bug7147(0))))); static assert( is(typeof(compiles!(bug7147(1))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14123 // identity TypeInfo objects static assert({ bool eq(TypeInfo t1, TypeInfo t2) { return t1 is t2; } class C {} struct S {} assert( eq(typeid(C), typeid(C))); assert(!eq(typeid(C), typeid(Object))); assert( eq(typeid(S), typeid(S))); assert(!eq(typeid(S), typeid(int))); assert( eq(typeid(int), typeid(int))); assert(!eq(typeid(int), typeid(long))); Object o = new Object; Object c = new C; assert( eq(typeid(o), typeid(o))); assert(!eq(typeid(c), typeid(o))); assert(!eq(typeid(o), typeid(S))); return 1; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6885 // wrong code with new array struct S6885 { int p; } int bug6885() { auto array = new double[1][2]; array[1][0] = 6; array[0][0] = 1; assert(array[1][0] == 6); auto barray = new S6885[2]; barray[1].p = 5; barray[0].p = 2; assert(barray[1].p == 5); return 1; } static assert(bug6885()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6886 // ICE with new array of dynamic arrays int bug6886() { auto carray = new int[][2]; carray[1] = [6]; carray[0] = [4]; assert(carray[1][0] == 6); return 1; } static assert(bug6886()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10198 // Multidimensional struct block initializer struct Block10198 { int[4][3] val; } int bug10198() { Block10198 pp = Block10198(67); assert(pp.val[2][3] == 67); assert(pp.val[1][3] == 67); return 1; } static assert(bug10198()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14440 // Multidimensional block initialization should create distinct arrays for each elements struct Matrix14440(E, size_t row, size_t col) { E[col][row] array2D; @safe pure nothrow this(E[row * col] numbers...) { foreach (r; 0 .. row) { foreach (c; 0 .. col) { array2D[r][c] = numbers[r * col + c]; } } } } void test14440() { // Replace 'enum' with 'auto' here and it will work fine. enum matrix = Matrix14440!(int, 3, 3)( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); static assert(matrix.array2D[0][0] == 1); static assert(matrix.array2D[0][1] == 2); static assert(matrix.array2D[0][2] == 3); static assert(matrix.array2D[1][0] == 4); static assert(matrix.array2D[1][1] == 5); static assert(matrix.array2D[1][2] == 6); static assert(matrix.array2D[2][0] == 7); static assert(matrix.array2D[2][1] == 8); static assert(matrix.array2D[2][2] == 9); } /**************************************************** * Exception chaining tests from xtest46.d ****************************************************/ class A75 { pure static void raise(string s) { throw new Exception(s); } } int test75() { int x = 0; try { A75.raise("a"); } catch (Exception e) { x = 1; } assert(x == 1); return 1; } static assert(test75()); /**************************************************** * Exception chaining tests from test4.d ****************************************************/ int test4_test54() { int status = 0; try { try { status++; assert(status == 1); throw new Exception("first"); } finally { status++; assert(status == 2); status++; throw new Exception("second"); } } catch (Exception e) { assert(e.msg == "first"); assert(e.next.msg == "second"); } return true; } static assert(test4_test54()); void foo55() { try { Exception x = new Exception("second"); throw x; } catch (Exception e) { assert(e.msg == "second"); } } int test4_test55() { int status = 0; try { try { status++; assert(status == 1); Exception x = new Exception("first"); throw x; } finally { status++; assert(status == 2); status++; foo55(); } } catch (Exception e) { assert(e.msg == "first"); assert(status == 3); } return 1; } static assert(test4_test55()); /**************************************************** * Exception chaining tests from eh.d ****************************************************/ void bug1513outer() { int result1513; void bug1513a() { throw new Exception("d"); } void bug1513b() { try { try { bug1513a(); } finally { result1513 |= 4; throw new Exception("f"); } } catch (Exception e) { assert(e.msg == "d"); assert(e.next.msg == "f"); assert(!e.next.next); } } void bug1513c() { try { try { throw new Exception("a"); } finally { result1513 |= 1; throw new Exception("b"); } } finally { bug1513b(); result1513 |= 2; throw new Exception("c"); } } void bug1513() { result1513 = 0; try { bug1513c(); } catch (Exception e) { assert(result1513 == 7); assert(e.msg == "a"); assert(e.next.msg == "b"); assert(e.next.next.msg == "c"); } } bug1513(); } void collideone() { try { throw new Exception("x"); } finally { throw new Exception("y"); } } void doublecollide() { try { try { try { throw new Exception("p"); } finally { throw new Exception("q"); } } finally { collideone(); } } catch (Exception e) { assert(e.msg == "p"); assert(e.next.msg == "q"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } void collidetwo() { try { try { throw new Exception("p2"); } finally { throw new Exception("q2"); } } finally { collideone(); } } void collideMixed() { int works = 6; try { try { try { throw new Exception("e"); } finally { throw new Error("t"); } } catch (Exception f) { // Doesn't catch, because Error is chained to it. works += 2; } } catch (Error z) { works += 4; assert(z.msg == "t"); // Error comes first assert(z.next is null); assert(z.bypassedException.msg == "e"); } assert(works == 10); } class AnotherException : Exception { this(string s) { super(s); } } void multicollide() { try { try { try { try { throw new Exception("m2"); } finally { throw new AnotherException("n2"); } } catch (AnotherException s) { // Not caught -- we needed to catch the root cause "m2", not // just the collateral "n2" (which would leave m2 uncaught). assert(0); } } finally { collidetwo(); } } catch (Exception f) { assert(f.msg == "m2"); assert(f.next.msg == "n2"); Throwable e = f.next.next; assert(e.msg == "p2"); assert(e.next.msg == "q2"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } int testsFromEH() { bug1513outer(); doublecollide(); collideMixed(); multicollide(); return 1; } static assert(testsFromEH()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6901 // With + synchronized statements struct With1 { int a; int b; } class Foo6 { } class Foo32 { struct Bar { int x; } } class Base56 { private string myfoo; private string mybar; // Get/set properties that will be overridden. void foo(string s) { myfoo = s; } string foo() { return myfoo; } // Get/set properties that will not be overridden. void bar(string s) { mybar = s; } string bar() { return mybar; } } class Derived56 : Base56 { alias Base56.foo foo; // Bring in Base56's foo getter. override void foo(string s) { super.foo = s; } // Override foo setter. } int testwith() { With1 x = With1(7); with (x) { a = 2; } assert(x.a == 2); // from test11.d Foo6 foo6 = new Foo6(); with (foo6) { int xx; xx = 4; } with (new Foo32) { Bar z; z.x = 5; } Derived56 d = new Derived56; with (d) { foo = "hi"; d.foo = "hi"; bar = "hi"; assert(foo == "hi"); assert(d.foo == "hi"); assert(bar == "hi"); } int w = 7; synchronized { ++w; } assert(w == 8); return 1; } static assert(testwith()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9236 // ICE switch with(EnumType) enum Command9236 { Char, Any, }; bool bug9236(Command9236 cmd) { int n = 0; with (Command9236) switch (cmd) { case Any: n = 1; break; default: n = 2; } assert(n == 1); switch (cmd) with (Command9236) { case Any: return true; default: return false; } } static assert(bug9236(Command9236.Any)); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6416 // static struct declaration static assert({ static struct S { int y = 7; } S a; a.y += 6; assert(a.y == 13); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10499 // static template struct declaration static assert({ static struct Result() {} return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13757 // extern(C) alias declaration static assert({ alias FP1 = extern(C) int function(); alias extern(C) int function() FP2; return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6522 // opAssign + foreach ref struct Foo6522 { bool b = false; void opAssign(int x) { this.b = true; } } bool foo6522() { Foo6522[1] array; foreach (ref item; array) item = 1; return true; } static assert(foo6522()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7245 // pointers + foreach ref int bug7245(int testnum) { int[3] arr; arr[0] = 4; arr[1] = 6; arr[2] = 8; int* ptr; foreach (i, ref p; arr) { if (i == 1) ptr = &p; if (testnum == 1) p = 5; } return *ptr; } static assert(bug7245(0) == 6); static assert(bug7245(1) == 5); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8498 // modifying foreach // https://issues.dlang.org/show_bug.cgi?id=7658 // foreach ref // https://issues.dlang.org/show_bug.cgi?id=8539 // nested funcs, ref param, -inline int bug8498() { foreach (ref i; 0 .. 5) { assert(i == 0); i = 100; } return 1; } static assert(bug8498()); string bug7658() { string[] children = ["0"]; foreach (ref child; children) child = "1"; return children[0]; } static assert(bug7658() == "1"); int bug8539() { static void one(ref int x) { x = 1; } static void go() { int y; one(y); assert(y == 1); // fails with -inline } go(); return 1; } static assert(bug8539()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7874 // https://issues.dlang.org/show_bug.cgi?id=13297 // https://issues.dlang.org/show_bug.cgi?id=13740 // better lvalue handling int bug7874(int x){ return ++x = 1; } static assert(bug7874(0) == 1); // ---- struct S13297 { int* p; } void f13297(ref int* p) { p = cast(int*) 1; assert(p); // passes } static assert( { S13297 s; f13297(s.p); return s.p != null; // false }()); // ---- class R13740 { int e; bool empty = false; @property ref front() { return e; } void popFront() { empty = true; } } static assert({ auto r = new R13740(); foreach (ref e; r) e = 42; assert(r.e == 42); /* fails in CTFE */ return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6919 void bug6919(int* val) { *val = 1; } void test6919() { int n; bug6919(&n); assert(n == 1); } static assert({ test6919(); return true; }()); void bug6919b(string* val) { *val = "1"; } void test6919b() { string val; bug6919b(&val); assert(val == "1"); } static assert({ test6919b(); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6995 struct Foo6995 { static size_t index(size_t v)() { return v; } } static assert(Foo6995.index!(27)() == 27); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7043 // ref with -inline int bug7043(S)(ref int x) { return x; } static assert({ int i = 416; return bug7043!(char)(i); }() == 416); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6037 // recursive ref void bug6037(ref int x, bool b) { int w = 3; if (b) { bug6037(w, false); assert(w == 6); } else { x = 6; assert(w == 3); // fails } } int bug6037outer() { int q; bug6037(q, true); return 401; } static assert(bug6037outer() == 401); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14299 // [REG2.067a], more than one depth of recursive call with ref string gen14299(int max, int idx, ref string name) { string ret; name = [cast(char)(idx + '0')]; ret ~= name; if (idx < max) { string subname; ret ~= gen14299(max, idx + 1, subname); } ret ~= name; return ret; } string test14299(int max) { string n; return gen14299(max, 0, n); } static assert(test14299(1) == "0110"); // OK <- fail static assert(test14299(2) == "012210"); // OK <- ICE static assert(test14299(3) == "01233210"); static assert(test14299(4) == "0123443210"); static assert(test14299(5) == "012345543210"); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7940 // wrong code for complicated assign struct Bug7940 { int m; } struct App7940 { Bug7940[] x; } int bug7940() { Bug7940[2] y; App7940 app; app.x = y[0 .. 1]; app.x[0].m = 12; assert(y[0].m == 12); assert(app.x[0].m == 12); return 1; } static assert(bug7940()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10298 // wrong code for struct array literal init struct Bug10298 { int m; } int bug10298() { Bug10298[1] y = [Bug10298(78)]; y[0].m = 6; assert(y[0].m == 6); // Root cause Bug10298[1] x; x[] = [cast(const Bug10298)(Bug10298(78))]; assert(x[0].m == 78); return 1; } static assert(bug10298()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7266 // dotvar ref parameters struct S7266 { int a; } bool bug7266() { S7266 s; s.a = 4; bar7266(s.a); assert(s.a == 5); out7266(s.a); assert(s.a == 7); return true; } void bar7266(ref int b) { b = 5; assert(b == 5); } void out7266(out int b) { b = 7; assert(b == 7); } static assert(bug7266()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9982 // dotvar assign through pointer struct Bug9982 { int a; } int test9982() { Bug9982 x; int*q = &x.a; *q = 99; assert(x.a == 99); return 1; } static assert(test9982()); // https://issues.dlang.org/show_bug.cgi?id=9982 // rejects-valid case struct SS9982 { Bug9982 s2; this(Bug9982 s1) { s2.a = 6; emplace9982(&s2, s1); assert(s2.a == 3); } } void emplace9982(Bug9982* chunk, Bug9982 arg) { *chunk = arg; } enum s9982 = Bug9982(3); enum p9982 = SS9982(s9982); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11618 // dotvar assign through casted pointer struct Tuple11618(T...) { T field; alias field this; } static assert({ Tuple11618!(immutable dchar) result = void; auto addr = cast(dchar*)&result[0]; *addr = dchar.init; return (result[0] == dchar.init); }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7143 // 'is' for classes class C7143 { int x; } int bug7143(int test) { C7143 c = new C7143; C7143 d = new C7143; if (test == 1) { if (c) return c.x + 8; return -1; } if (test == 2) { if (c is null) return -1; return c.x + 45; } if (test == 3) { if (c is c) return 58; } if (test == 4) { if (c !is c) return -1; else return 48; } if (test == 6) d = c; if (test == 5 || test == 6) { if (c is d) return 188; else return 48; } return -1; } static assert(bug7143(1) == 8); static assert(bug7143(2) == 45); static assert(bug7143(3) == 58); static assert(bug7143(4) == 48); static assert(bug7143(5) == 48); static assert(bug7143(6) == 188); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7147 // virtual function calls from base class class A7147 { int foo() { return 0; } int callfoo() { return foo(); } } class B7147 : A7147 { override int foo() { return 1; } } int test7147() { A7147 a = new B7147; return a.callfoo(); } static assert(test7147() == 1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7158 class C7158 { bool b() { return true; } } struct S7158 { C7158 c; } bool test7158() { S7158 s = S7158(new C7158); return s.c.b; } static assert(test7158()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8484 class C8484 { int n; int b() { return n + 3; } } struct S { C8484 c; } int t8484(ref C8484 c) { return c.b(); } int test8484() { auto s = S(new C8484); s.c.n = 4; return t8484(s.c); } static assert(test8484() == 7); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7419 struct X7419 { double x; this(double x) { this.x = x; } } void bug7419() { enum x = { auto p = X7419(3); return p.x; }(); static assert(x == 3); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9445 // ice template c9445(T...) { } void ice9445(void delegate() expr, void function() f2) { static assert(!is(typeof(c9445!(f2())))); static assert(!is(typeof(c9445!(expr())))); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10452 // delegate == struct S10452 { bool func() { return true; } } struct Outer10452 { S10452 inner; } class C10452 { bool func() { return true; } } bool delegate() ref10452(ref S10452 s) { return &s.func; } bool test10452() { bool delegate() bar = () { return true; }; assert(bar !is null); assert(bar is bar); S10452 bag; S10452[6] bad; Outer10452 outer; C10452 tag = new C10452; auto rat = &outer.inner.func; assert(rat == rat); auto tat = &tag.func; assert(tat == tat); auto bat = &outer.inner.func; auto mat = &bad[2].func; assert(mat is mat); assert(rat == bat); auto zat = &bag.func; auto cat = &bag.func; assert(zat == zat); assert(zat == cat); auto drat = ref10452(bag); assert(cat == drat); assert(drat == drat); drat = ref10452(bad[2]); assert( drat == mat); assert(tat != rat); assert(zat != rat); assert(rat != cat); assert(zat != bar); assert(tat != cat); cat = bar; assert(cat == bar); return true; } static assert(test10452()); /**************************************************/ //https://issues.dlang.org/show_bug.cgi?id=7162 // https://issues.dlang.org/show_bug.cgi?id=4711 void f7162() { } bool ice7162() { false && f7162(); false || f7162(); false && f7162(); // https://issues.dlang.org/show_bug.cgi?id=4711 true && f7162(); return true; } static assert(ice7162()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8857 // only with -inline (creates an &&) struct Result8857 { char[] next; } void bug8857()() { Result8857 r; r.next = null; if (true) { auto next = r.next; } } static assert({ bug8857(); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7527 struct Bug7527 { char[] data; } int bug7527() { auto app = Bug7527(); app.data.ptr[0 .. 1] = "x"; return 1; } static assert(!is(typeof(compiles!(bug7527())))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7527 int bug7380; static assert(!is(typeof( compiles!( (){ return &bug7380; }() )))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7165 struct S7165 { int* ptr; bool f() const { return !!ptr; } } static assert(!S7165().f()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7187 int[] f7187() { return [0]; } int[] f7187b(int n) { return [0]; } int g7187(int[] r) { auto t = r[0 .. 0]; return 1; } static assert(g7187(f7187())); static assert(g7187(f7187b(7))); struct S7187 { const(int)[] field; } const(int)[] f7187c() { auto s = S7187([0]); return s.field; } bool g7187c(const(int)[] r) { auto t = r[0 .. 0]; return true; } static assert(g7187c(f7187c())); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6933 // struct destructors struct Bug6933 { int x = 3; ~this() { } } int test6933() { Bug6933 q; assert(q.x == 3); return 3; } static assert(test6933()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7197 int foo7197(int[] x...) { return 1; } template bar7197(y...) { enum int bar7197 = foo7197(y); } enum int bug7197 = 7; static assert(bar7197!(bug7197)); /************************************************** Enum string compare **************************************************/ enum EScmp : string { a = "aaa" } bool testEScmp() { EScmp x = EScmp.a; assert(x < "abc"); return true; } static assert(testEScmp()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7667 bool baz7667(int[] vars...) { return true; } struct S7667 { static void his(int n) { static assert(baz7667(2)); } } bool bug7667() { S7667 unused; unused.his(7); return true; } enum e7667 = bug7667(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7536 bool bug7536(string expr) { return true; } void vop() { const string x7536 = "x"; static assert(bug7536(x7536)); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6681 // unions struct S6681 { this(int a, int b) { this.a = b; this.b = a; } union { ulong g; struct { int a, b; }; } } static immutable S6681 s6681 = S6681(0, 1); bool bug6681(int test) { S6681 x = S6681(0, 1); x.g = 5; auto u = &x.g; auto v = &x.a; long w = *u; int z; assert(w == 5); if (test == 4) z = *v; // error x.a = 2; // invalidate g, and hence u. if (test == 1) w = *u; // error z = *v; assert(z == 2); x.g = 6; w = *u; assert(w == 6); if (test == 3) z = *v; return true; } static assert(bug6681(2)); static assert(!is(typeof(compiles!(bug6681(1))))); static assert(!is(typeof(compiles!(bug6681(3))))); static assert(!is(typeof(compiles!(bug6681(4))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9113 // ICE with struct in union union U9113 { struct M { int y; } int xx; } int bug9113(T)() { U9113 x; x.M.y = 10; // error, need 'this' return 1; } static assert(!is(typeof(compiles!(bug9113!(int)())))); /************************************************** Creation of unions **************************************************/ union UnionTest1 { int x; float y; } int uniontest1() { UnionTest1 u = UnionTest1(1); return 1; } static assert(uniontest1()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6438 // void struct S6438 { int a; int b = void; } void fill6438(int[] arr, int testnum) { if (testnum == 2) { auto u = arr[0]; } foreach (ref x; arr) x = 7; auto r = arr[0]; S6438[2] s; auto p = &s[0].b; if (testnum == 3) { auto v = *p; } } bool bug6438(int testnum) { int[4] stackSpace = void; fill6438(stackSpace[], testnum); assert(stackSpace == [7, 7, 7, 7]); return true; } static assert( is(typeof(compiles!(bug6438(1))))); static assert(!is(typeof(compiles!(bug6438(2))))); static assert(!is(typeof(compiles!(bug6438(3))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10994 // void static array members struct Bug10994 { ubyte[2] buf = void; } static bug10994 = Bug10994.init; /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10937 // struct inside union struct S10937 { union { ubyte[1] a; struct { ubyte b; } } this(ubyte B) { if (B > 6) this.b = B; else this.a[0] = B; } } enum test10937 = S10937(7); enum west10937 = S10937(2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13831 struct Vector13831() { } struct Coord13831 { union { struct { short x; } Vector13831!() vector; } } struct Chunk13831 { this(Coord13831) { coord = coord; } Coord13831 coord; static const Chunk13831* unknownChunk = new Chunk13831(Coord13831()); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7732 struct AssociativeArray { int* impl; int f() { if (impl !is null) auto x = *impl; return 1; } } int test7732() { AssociativeArray aa; return aa.f; } static assert(test7732()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7784 struct Foo7784 { void bug() { tab["A"] = Bar7784(&this); auto pbar = "A" in tab; auto bar = *pbar; } Bar7784[string] tab; } struct Bar7784 { Foo7784* foo; int val; } bool ctfe7784() { auto foo = Foo7784(); foo.bug(); return true; } static assert(ctfe7784()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7781 static assert(({ return true; }())); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7785 bool bug7785(int n) { int val = 7; auto p = &val; if (n == 2) { auto ary = p[0 .. 1]; } auto x = p[0]; val = 6; assert(x == 7); if (n == 3) p[0 .. 1] = 1; return true; } static assert(bug7785(1)); static assert(!is(typeof(compiles!(bug7785(2))))); static assert(!is(typeof(compiles!(bug7785(3))))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7987 class C7987 { int m; } struct S7987 { int* p; C7987 c; } bool bug7987() { int[7] q; int[][2] b = q[0 .. 5]; assert(b == b); assert(b is b); C7987 c1 = new C7987; C7987 c2 = new C7987; S7987 s, t; s.p = &q[0]; t.p = &q[1]; assert(s != t); s.p = &q[1]; /*assert(s == t);*/ assert(s.p == t.p); s.c = c1; t.c = c2; /*assert(s != t);*/ assert(s.c !is t.c); assert(s !is t); s.c = c2; /*assert(s == t);*/ assert(s.p == t.p && s.c is t.c); assert(s is t); return true; } static assert(bug7987()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10579 // typeinfo.func() must not segfault static assert(!is(typeof(compiles!(typeid(int).toString.length)))); class Bug10579 { int foo() { return 1; } } Bug10579 uninitialized10579; static assert(!is(typeof(compiles!(uninitialized10579.foo())))); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10804 // mixin ArrayLiteralExp typed string void test10804() { String identity(String)(String a) { return a; } string cfun() { char[] s; s.length = 8 + 2 + (2) + 1 + 2; s[] = "identity(`Ω`c)"c[]; return cast(string)s; // Return ArrayLiteralExp as the CTFE result } { enum a1 = "identity(`Ω`c)"c; enum a2 = cfun(); static assert(cast(ubyte[])mixin(a1) == [0xCE, 0xA9]); static assert(cast(ubyte[])mixin(a2) == [0xCE, 0xA9]); // should pass } wstring wfun() { wchar[] s; s.length = 8 + 2 + (2) + 1 + 2; s[] = "identity(`\U0002083A`w)"w[]; return cast(wstring)s; // Return ArrayLiteralExp as the CTFE result } { enum a1 = "identity(`\U0002083A`w)"w; enum a2 = wfun(); static assert(cast(ushort[])mixin(a1) == [0xD842, 0xDC3A]); static assert(cast(ushort[])mixin(a2) == [0xD842, 0xDC3A]); } dstring dfun() { dchar[] s; s.length = 8 + 2 + (1) + 1 + 2; s[] = "identity(`\U00101000`d)"d[]; return cast(dstring)s; // Return ArrayLiteralExp as the CTFE result } { enum a1 = "identity(`\U00101000`d)"d; enum a2 = dfun(); static assert(cast(uint[])mixin(a1) == [0x00101000]); static assert(cast(uint[])mixin(a2) == [0x00101000]); } } /******************************************************/ struct B73 {} struct C73 { B73 b; } C73 func73() { C73 b = void; b.b = B73(); return b; } C73 test73 = func73(); /******************************************************/ struct S74 { int[1] n; static S74 test(){ S74 ret = void; ret.n[0] = 0; return ret; } } enum Test74 = S74.test(); /******************************************************/ static bool bug8865() in { int x = 0; label: foreach (i; (++x) .. 3) { if (i == 1) continue label; // doesn't work. else break label; // doesn't work. } } out { int x = 0; label: foreach (i; (++x) .. 3) { if (i == 1) continue label; // doesn't work. else break label; // doesn't work. } } body { int x = 0; label: foreach (i; (++x) .. 3) { if (i == 1) continue label; // works. else break label; // works. } return true; } static assert(bug8865()); /******************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15450 // labeled foreach + continue/break static assert({ L1: foreach (l; [0]) continue L1; L2: foreach (l; [0]) break L2; return true; }()); struct Test75 { this(int) pure {} } /******************************************************/ static assert( __traits(compiles, { static shared(Test75*) t75 = new shared(Test75)(0); return t75; })); static assert( __traits(compiles, { static shared(Test75)* t75 = new shared(Test75)(0); return t75; })); static assert( __traits(compiles, { static __gshared Test75* t75 = new Test75(0); return t75; })); static assert( __traits(compiles, { static const(Test75*) t75 = new const(Test75)(0); return t75; })); static assert( __traits(compiles, { static immutable Test75* t75 = new immutable(Test75)(0); return t75; })); static assert(!__traits(compiles, { static Test75* t75 = new Test75(0); return t75; })); /+ static assert(!__traits(compiles, { enum t75 = new shared(Test75)(0); return t75; })); static assert(!__traits(compiles, { enum t75 = new Test75(0); return t75; })); static assert(!__traits(compiles, { enum shared(Test75)* t75 = new shared(Test75)(0); return t75; })); static assert(!__traits(compiles, { enum Test75* t75 = new Test75(0); return t75; })); static assert( __traits(compiles, { enum t75 = new const(Test75)(0); return t75;})); static assert( __traits(compiles, { enum t75 = new immutable(Test75)(0); return t75;})); static assert( __traits(compiles, { enum const(Test75)* t75 = new const(Test75)(0); return t75;})); static assert( __traits(compiles, { enum immutable(Test75)* t75 = new immutable(Test75)(0); return t75;})); +/ /******************************************************/ class Test76 { this(int) pure {} } /+ static assert(!__traits(compiles, { enum t76 = new shared(Test76)(0); return t76;})); static assert(!__traits(compiles, { enum t76 = new Test76(0); return t76;})); static assert(!__traits(compiles, { enum shared(Test76) t76 = new shared(Test76)(0); return t76;})); static assert(!__traits(compiles, { enum Test76 t76 = new Test76(0); return t76;})); static assert( __traits(compiles, { enum t76 = new const(Test76)(0); return t76;})); static assert( __traits(compiles, { enum t76 = new immutable(Test76)(0); return t76;})); static assert( __traits(compiles, { enum const(Test76) t76 = new const(Test76)(0); return t76;})); static assert( __traits(compiles, { enum immutable(Test76) t76 = new immutable(Test76)(0); return t76;})); +/ /******************************************************/ static assert( __traits(compiles, { static shared Test76 t76 = new shared(Test76)(0); return t76; })); static assert( __traits(compiles, { static shared(Test76) t76 = new shared(Test76)(0); return t76; })); static assert( __traits(compiles, { static __gshared Test76 t76 = new Test76(0); return t76; })); static assert( __traits(compiles, { static const Test76 t76 = new const(Test76)(0); return t76; })); static assert( __traits(compiles, { static immutable Test76 t76 = new immutable Test76(0); return t76; })); static assert(!__traits(compiles, { static Test76 t76 = new Test76(0); return t76; })); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5678 struct Bug5678 { this(int) {} } static assert(!__traits(compiles, { enum const(Bug5678)* b5678 = new const(Bug5678)(0); return b5678; })); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10782 // run semantic2 for class field enum e10782 = 0; class C10782 { int x = e10782; } string f10782() { auto c = new C10782(); return ""; } mixin(f10782()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10929 // NRVO support in CTFE struct S10929 { this(this) { postblitCount++; } ~this() { dtorCount++; } int payload; int dtorCount; int postblitCount; } auto makeS10929() { auto s = S10929(42, 0, 0); return s; } bool test10929() { auto s = makeS10929(); assert(s.postblitCount == 0); assert(s.dtorCount == 0); return true; }; static assert(test10929()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9245 // support postblit call on array assignments bool test9245() { int postblits = 0; struct S { this(this) { ++postblits; } } S s; S[2] a; assert(postblits == 0); { S[2] arr = s; assert(postblits == 2); arr[] = s; assert(postblits == 4); postblits = 0; S[2] arr2 = arr; assert(postblits == 2); arr2 = arr; assert(postblits == 4); postblits = 0; const S[2] constArr = s; assert(postblits == 2); postblits = 0; const S[2] constArr2 = arr; assert(postblits == 2); postblits = 0; } { S[2][2] arr = s; assert(postblits == 4); arr[] = a; assert(postblits == 8); postblits = 0; S[2][2] arr2 = arr; assert(postblits == 4); arr2 = arr; assert(postblits == 8); postblits = 0; const S[2][2] constArr = s; assert(postblits == 4); postblits = 0; const S[2][2] constArr2 = arr; assert(postblits == 4); postblits = 0; } return true; } static assert(test9245()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12906 // don't call postblit on blit initializing struct S12906 { this(this) { assert(0); } } static assert({ S12906[1] arr; return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11510 // support overlapped field access in CTFE struct S11510 { union { size_t x; int* y; // pointer field } } bool test11510() { S11510 s; s.y = [1,2,3].ptr; // writing overlapped pointer field is OK assert(s.y[0 .. 3] == [1,2,3]); // reading valid field is OK s.x = 10; assert(s.x == 10); // There's no reinterpretation between S.x and S.y return true; } static assert(test11510()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11534 // subtitude inout struct MultiArray11534 { void set(size_t[] sizes...) { storage = new size_t[5]; } @property auto raw_ptr() inout { return storage.ptr + 1; } size_t[] storage; } enum test11534 = () { auto m = MultiArray11534(); m.set(3,2,1); auto start = m.raw_ptr; //this trigger the bug //auto start = m.storage.ptr + 1; //this obviously works return 0; }(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11941 // Regression of 11534 fix void takeConst11941(const string[]) {} string[] identity11941(string[] x) { return x; } bool test11941a() { struct S { string[] a; } S s; takeConst11941(identity11941(s.a)); s.a ~= []; return true; } static assert(test11941a()); bool test11941b() { struct S { string[] a; } S s; takeConst11941(identity11941(s.a)); s.a ~= "foo"; /* Error refers to this line (15), */ string[] b = s.a[]; /* but only when this is here. */ return true; } static assert(test11941b()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11535 // element-wise assignment from string to ubyte array literal struct Hash11535 { ubyte[6] _buffer; void put(scope const(ubyte)[] data...) { uint i = 0, index = 0; auto inputLen = data.length; (&_buffer[index])[0 .. inputLen - i] = (&data[i])[0 .. inputLen - i]; } } auto md5_digest11535(T...)(scope const T data) { Hash11535 hash; hash.put(cast(const(ubyte[]))data[0]); return hash._buffer; } static assert(md5_digest11535(`TEST`) == [84, 69, 83, 84, 0, 0]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11540 // goto label + try-catch-finally / with statement static assert(() { // enter to TryCatchStatement.body { bool c = false; try { if (c) // need to bypass front-end optimization throw new Exception(""); else { goto Lx; L1: c = true; } } catch (Exception e) {} Lx: if (!c) goto L1; } // jump inside TryCatchStatement.body { bool c = false; try { if (c) // need to bypass front-end optimization throw new Exception(""); else goto L2; L2: ; } catch (Exception e) {} } // exit from TryCatchStatement.body { bool c = false; try { if (c) // need to bypass front-end optimization throw new Exception(""); else goto L3; } catch (Exception e) {} c = true; L3: assert(!c); } return 1; }()); static assert(() { // enter to TryCatchStatement.catches which has no exception variable { bool c = false; goto L1; try { c = true; } catch (Exception/* e*/) { L1: ; } assert(c == false); } // jump inside TryCatchStatement.catches { bool c = false; try { throw new Exception(""); } catch (Exception e) { goto L2; c = true; L2: ; } assert(c == false); } // exit from TryCatchStatement.catches { bool c = false; try { throw new Exception(""); } catch (Exception e) { goto L3; c = true; } L3: assert(c == false); } return 1; }()); static assert(() { // enter forward to TryFinallyStatement.body { bool c = false; goto L0; c = true; try { L0: ; } finally {} assert(!c); } // enter back to TryFinallyStatement.body { bool c = false; try { goto Lx; L1: c = true; } finally { } Lx: if (!c) goto L1; } // jump inside TryFinallyStatement.body { try { goto L2; L2: ; } finally {} } // exit from TryFinallyStatement.body { bool c = false; try { goto L3; } finally {} c = true; L3: assert(!c); } // enter in / exit out from finally block is rejected in semantic analysis // jump inside TryFinallyStatement.finalbody { bool c = false; try { } finally { goto L4; c = true; L4: assert(c == false); } } return 1; }()); static assert(() { { bool c = false; with (Object.init) { goto L2; c = true; L2: ; } assert(c == false); } { bool c = false; with (Object.init) { goto L3; c = true; } L3: assert(c == false); } return 1; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11627 //cast dchar to char at compile time on AA assignment bool test11627() { char[ubyte] toCharTmp; dchar letter = 'A'; //char c = cast(char)letter; // OK toCharTmp[0] = cast(char)letter; // NG return true; } static assert(test11627()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11664 // ignore function local static variables bool test11664() { static int x; static int y = 1; return true; } static assert(test11664()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12110 // operand of dereferencing does not need to be an lvalue struct SliceOverIndexed12110 { Uint24Array12110* arr; @property front(uint val) { arr.dupThisReference(); } } struct Uint24Array12110 { ubyte[] data; this(ubyte[] range) { data = range; SliceOverIndexed12110(&this).front = 0; assert(data.length == range.length * 2); } void dupThisReference() { auto new_data = new ubyte[data.length * 2]; data = new_data; } } static m12110 = Uint24Array12110([0x80]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12310 // heap allocation for built-in sclar types bool test12310() { auto p1 = new int, p2 = p1; assert(*p1 == 0); assert(*p2 == 0); *p1 = 10; assert(*p1 == 10); assert(*p2 == 10); auto q1 = new int(3), q2 = q1; assert(*q1 == 3); assert(*q2 == 3); *q1 = 20; assert(*q1 == 20); assert(*q2 == 20); return true; } static assert(test12310()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12499 // initialize TupleDeclaraion in CTFE auto f12499() { //Initialize 3 ints to 5. TypeTuple!(int, int, int) a = 5; return a[0]; //Error: variable _a_field_0 cannot be read at compile time } static assert(f12499() == 5); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12602 // slice in struct literal members struct Result12602 { uint[] source; } auto wrap12602a(uint[] r) { return Result12602(r); } auto wrap12602b(uint[] r) { Result12602 x; x.source = r; return x; } auto testWrap12602a() { uint[] dest = [1, 2, 3, 4]; auto ra = wrap12602a(dest[0 .. 2]); auto rb = wrap12602a(dest[2 .. 4]); foreach (i; 0 .. 2) rb.source[i] = ra.source[i]; assert(ra.source == [1,2]); assert(rb.source == [1,2]); assert(&ra.source[0] == &dest[0]); assert(&rb.source[0] == &dest[2]); assert(dest == [1,2,1,2]); return dest; } auto testWrap12602b() { uint[] dest = [1, 2, 3, 4]; auto ra = wrap12602b(dest[0 .. 2]); auto rb = wrap12602b(dest[2 .. 4]); foreach (i; 0 .. 2) rb.source[i] = ra.source[i]; assert(ra.source == [1,2]); assert(rb.source == [1,2]); assert(&ra.source[0] == &dest[0]); assert(&rb.source[0] == &dest[2]); assert(dest == [1,2,1,2]); return dest; } auto testWrap12602c() { uint[] dest = [1, 2, 3, 4]; auto ra = Result12602(dest[0 .. 2]); auto rb = Result12602(dest[2 .. 4]); foreach (i; 0 .. 2) rb.source[i] = ra.source[i]; assert(ra.source == [1,2]); assert(rb.source == [1,2]); assert(&ra.source[0] == &dest[0]); assert(&rb.source[0] == &dest[2]); assert(dest == [1,2,1,2]); return dest; } auto testWrap12602d() { uint[] dest = [1, 2, 3, 4]; Result12602 ra; ra.source = dest[0 .. 2]; Result12602 rb; rb.source = dest[2 .. 4]; foreach (i; 0 .. 2) rb.source[i] = ra.source[i]; assert(ra.source == [1,2]); assert(rb.source == [1,2]); assert(&ra.source[0] == &dest[0]); assert(&rb.source[0] == &dest[2]); assert(dest == [1,2,1,2]); return dest; } static assert(testWrap12602a() == [1,2,1,2]); static assert(testWrap12602b() == [1,2,1,2]); static assert(testWrap12602c() == [1,2,1,2]); static assert(testWrap12602d() == [1,2,1,2]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12677 // class type initializing from DotVarExp final class C12677 { TypeTuple!(Object, int[]) _test; this() { auto t0 = _test[0]; // auto t1 = _test[1]; // assert(t0 is null); assert(t1 is null); } } struct S12677 { auto f = new C12677(); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12851 // interpret function local const static array void test12851() { const int[5] arr; alias staticZip = TypeTuple!(arr[0]); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13630 // indexing and setting array element via pointer struct S13630(T) { T[3] arr; this(A...)(auto ref in A args) { auto p = arr.ptr; foreach (ref v; args) { *p = 0; } } } enum s13630 = S13630!float(1); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13827 struct Matrix13827(T, uint N) { private static defaultMatrix() { T[N] arr; return arr; } union { T[N] A = defaultMatrix; T[N] flat; } this(A...)(auto ref in A args) { uint k; foreach (ref v; args) flat[k++] = cast(T)v; } } enum m13827 = Matrix13827!(int, 3)(1, 2, 3); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13847 // support DotTypeExp class B13847 { int foo() { return 1; } } class C13847 : B13847 { override int foo() { return 2; } final void test(int n) { assert(foo() == n); assert(B13847.foo() == 1); assert(C13847.foo() == 2); assert(this.B13847.foo() == 1); assert(this.C13847.foo() == 2); } } class D13847 : C13847 { override int foo() { return 3; } } static assert({ C13847 c = new C13847(); c.test(2); assert(c.B13847.foo() == 1); assert(c.C13847.foo() == 2); D13847 d = new D13847(); d.test(3); assert(d.B13847.foo() == 1); assert(d.C13847.foo() == 2); assert(d.D13847.foo() == 3); c = d; c.test(3); assert(c.B13847.foo() == 1); assert(c.C13847.foo() == 2); return true; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12495 // cast from string to immutable(ubyte)[] string getStr12495() { char[1] buf = void; // dummy starting point. string s = cast(string)buf[0..0]; // empty slice, .ptr points mutable. assert(buf.ptr == s.ptr); s ~= 'a'; // this should allocate. assert(buf.ptr != s.ptr); return s.idup; // this should allocate again, and // definitely point immutable memory. } auto indexOf12495(string s) { auto p1 = s.ptr; auto p2 = (cast(immutable(ubyte)[])s).ptr; assert(cast(void*)p1 == cast(void*)p2); // OK <- fails return cast(void*)p2 - cast(void*)p1; // OK <- "cannot subtract pointers ..." } static assert(indexOf12495(getStr12495()) == 0); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13992 // Repainting pointer arithmetic result enum hash13992 = hashOf13992("abcd".ptr); @trusted hashOf13992(const void* buf) { auto data = cast(const(ubyte)*) buf; size_t hash; data += 2; // problematic pointer arithmetic hash += *data; // CTFE internal issue was shown by the dereference return hash; } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13739 // Precise copy for ArrayLiteralExp elements static assert( { int[] a1 = [13]; int[][] a2 = [a1]; assert(a2[0] is a1); // OK assert(a2[0].ptr is a1.ptr); // OK <- NG a1[0] = 1; assert(a2[0][0] == 1); // OK <- NG a2[0][0] = 2; assert(a1[0] == 2); // OK <- NG return 1; }()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14463 // ICE on slice assignment without postblit struct Boo14463 { private int[1] c; this(int[] x) { c = x; } } immutable Boo14463 a14463 = Boo14463([1]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13295 // Don't copy struct literal in VarExp::interpret() struct S13295 { int n; } void f13295(ref const S13295 s) { *cast(int*) &s.n = 1; assert(s.n == 1); // OK <- fail } static assert( { S13295 s; f13295(s); return s.n == 1; // true <- false }()); int foo14061(int[] a) { foreach (immutable x; a) { auto b = a ~ x; return b == [1, 1]; } return 0; } static assert(foo14061([1])); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14024 // CTFE version bool test14024() { string op; struct S { char x = 'x'; this(this) { op ~= x-0x20; } // upper case ~this() { op ~= x; } // lower case } S[4] mem; ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; } op = null; mem[0].x = 'a'; mem[1].x = 'b'; mem[2].x = 'x'; mem[3].x = 'y'; slice(0, 2) = slice(2, 4); // [ab] = [xy] assert(op == "XaYb", op); op = null; mem[0].x = 'x'; mem[1].x = 'y'; mem[2].x = 'a'; mem[3].x = 'b'; slice(2, 4) = slice(0, 2); // [ab] = [xy] assert(op == "XaYb", op); op = null; mem[0].x = 'a'; mem[1].x = 'b'; mem[2].x = 'c'; slice(0, 2) = slice(1, 3); // [ab] = [bc] assert(op == "BaCb", op); op = null; mem[0].x = 'x'; mem[1].x = 'y'; mem[2].x = 'z'; slice(1, 3) = slice(0, 2); // [yz] = [xy] assert(op == "YzXy", op); return true; } static assert(test14024()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14304 // cache of static immutable value immutable struct Bug14304 { string s_name; alias s_name this; string fun()() { return "fun"; } } class Buggy14304 { static string fun(string str)() { return str; } static immutable val = immutable Bug14304("val"); } void test14304() { enum kt = Buggy14304.fun!(Buggy14304.val); static assert(kt == "val"); enum bt = Buggy14304.val.fun(); static assert(bt == "fun"); } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14371 // evaluate BinAssignExp as lvalue int test14371() { int x; ++(x += 1); return x; } static assert(test14371() == 2); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7151 // [CTFE] cannot compare classes with == bool test7151() { auto a = new Object; return a == a && a != new Object; } static assert(test7151()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12603 // [CTFE] goto does not correctly call dtors struct S12603 { this(uint* dtorCalled) { *dtorCalled = 0; this.dtorCalled = dtorCalled; } @disable this(); ~this() { ++*dtorCalled; } uint* dtorCalled; } auto numDtorCallsByGotoWithinScope() { uint dtorCalled; { S12603 s = S12603(&dtorCalled); assert(dtorCalled == 0); goto L_abc; L_abc: assert(dtorCalled == 0); } assert(dtorCalled == 1); return dtorCalled; } static assert(numDtorCallsByGotoWithinScope() == 1); auto numDtorCallsByGotoOutOfScope() { uint dtorCalled; { S12603 s = S12603(&dtorCalled); assert(dtorCalled == 0); goto L_abc; } L_abc: assert(dtorCalled == 1); return dtorCalled; } static assert(numDtorCallsByGotoOutOfScope() == 1); uint numDtorCallsByGotoDifferentScopeAfter() { uint dtorCalled; { S12603 s = S12603(&dtorCalled); assert(dtorCalled == 0); } assert(dtorCalled == 1); goto L_abc; L_abc: assert(dtorCalled == 1); return dtorCalled; } static assert(numDtorCallsByGotoDifferentScopeAfter() == 1); auto numDtorCallsByGotoDifferentScopeBefore() { uint dtorCalled; assert(dtorCalled == 0); goto L_abc; L_abc: assert(dtorCalled == 0); { S12603 s = S12603(&dtorCalled); assert(dtorCalled == 0); } assert(dtorCalled == 1); return dtorCalled; } static assert(numDtorCallsByGotoDifferentScopeBefore() == 1); struct S12603_2 { ~this() { dtorCalled = true; } bool dtorCalled = false; } auto structInCaseScope() { auto charsets = S12603_2(); switch(1) { case 0: auto set = charsets; break; default: break; } return charsets.dtorCalled; } static assert(!structInCaseScope()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15233 // ICE in TupleExp, Copy On Write bug alias TT15233(stuff ...) = stuff; struct Tok15233 {} enum tup15233 = TT15233!(Tok15233(), "foo"); static assert(tup15233[0] == Tok15233()); static assert(tup15233[1] == "foo"); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15251 // void cast in ForStatement.increment int test15251() { for (ubyte lwr = 19; lwr != 20; cast(void)++lwr) // have to to be evaluated with ctfeNeedNothing {} return 1; } static assert(test15251()); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15998 // Sagfault caused by memory corruption immutable string[2] foo15998 = ["",""]; immutable string[2][] bar15998a = foo15998 ~ baz15998; immutable string[2][] bar15998b = baz15998 ~ foo15998; auto baz15998() { immutable(string[2])[] r; return r; } static assert(bar15998a == [["", ""]]); static assert(bar15998b == [["", ""]]); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=16094 // Non-overlapped slice assignment on an aggregate char[] f16094a() { char[] x = new char[](6); x[3..6] = x[0..3]; return x; } int[] f16094b() { int[] x = new int[](6); x[3..6] = x[0..3]; return x; } enum copy16094a = f16094a(); enum copy16094b = f16094b(); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=17407 bool foo17407() { void delegate ( ) longest_convert; return __traits(compiles, longest_convert = &doesNotExists); } static assert(!foo17407); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=18057 // Recursive field initializer causes segfault. struct RBNode(T) { RBNode!T *copy = new RBNode!T; } static assert(!__traits(compiles, { alias bug18057 = RBNode!int; })); /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=19140 void test19140() { real f19140(); static if (__traits(compiles, (){ enum real r = f19140(); })) {} } /**************************************************/ // https://issues.dlang.org/show_bug.cgi?id=19074 struct S19074a { } struct S19074b { S19074a field; this(S19074a) { } static const S19074b* data = new S19074b(S19074a()); } void test19074() { auto var = S19074b.data; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/isZeroInit.d ================================================ alias AliasSeq(T...) = T; struct Holder(T, ubyte val) { T x = val; } struct SArrayHolder(T, ubyte val) { T[2] x = val; } static foreach (T; AliasSeq!(bool, byte, short, int, long, ubyte, ushort, uint, ulong, char, wchar, dchar, float, double, real)) { static assert(__traits(isZeroInit, T) == (T.init is T(0))); static assert(__traits(isZeroInit, T[2]) == (T.init is T(0))); static assert(!__traits(isZeroInit, Holder!(T, 1))); static assert(__traits(isZeroInit, Holder!(T, 0))); static assert(__traits(isZeroInit, SArrayHolder!(T, 0))); static assert(!__traits(isZeroInit, SArrayHolder!(T, 1))); } static assert(__traits(isZeroInit, void)); // For initializing arrays of element type `void`. static assert(__traits(isZeroInit, void*)); static assert(__traits(isZeroInit, void[])); static assert(__traits(isZeroInit, float[])); static assert(__traits(isZeroInit, Object)); class C1 : Object { int x = 1; } static assert(__traits(isZeroInit, C1)); // An Object's fields are irrelevant. struct S1 { int[] a; int b; } static assert(__traits(isZeroInit, S1)); struct S2 { alias H = Holder!(int, 1); H h; int a; } static assert(!__traits(isZeroInit, S2)); struct S3 { S1 h; float f = 0; } static assert(__traits(isZeroInit, S3)); struct S4 { S2 h = S2(S2.H(0), 0); int a; } static assert(__traits(isZeroInit, S4)); struct S5 { Object o = null; } static assert(__traits(isZeroInit, S5)); version(D_SIMD): import core.simd : int4; static assert(__traits(isZeroInit, Holder!(int4, 0))); static assert(!__traits(isZeroInit, Holder!(int4, 1))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/issue18097.d ================================================ // REQUIRED_ARGS: -unittest module issue18097; unittest // this first unittest is needed to trigger the bug { } unittest // second unittest { auto a = &mixin(__traits(identifier, __traits(parent, { }))); auto b = &__traits(parent, { }); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/json.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -dip1000 -o- -X -Xf${RESULTS_DIR}/compilable/json.out // POST_SCRIPT: compilable/extra-files/json-postscript.sh // EXTRA_FILES: imports/jsonimport1.d imports/jsonimport2.d imports/jsonimport3.d imports/jsonimport4.d module json; static this() {} static ~this() {} alias int myInt; myInt x; // https://issues.dlang.org/show_bug.cgi?id=3404 struct Foo(T) { T t; } class Bar(int T) { int t = T; } interface Baz(T...) { T[0] t() const; } // https://issues.dlang.org/show_bug.cgi?id=3466 template P(alias T) {} class Bar2 : Bar!1, Baz!(int, 2, null) { this() {} ~this() {} // https://issues.dlang.org/show_bug.cgi?id=4178 static foo() {} protected abstract Foo!int baz(); override int t() const { return 0; } } class Bar3 : Bar2 { private int val; this(int i) { val = i; } protected override Foo!int baz() { return Foo!int(val); } } struct Foo2 { Bar2 bar2; union U { struct { short s; int i; } Object o; } } struct Foo3(bool b) { version(D_Ddoc) { /// Doc 1 void method1(); } static if (b) { /// Doc 2 void method2(); } else { /// Doc 3 void method3(); } /// Doc 4 void method4(); } /++ + Documentation test +/ @trusted myInt bar(ref uint blah, Bar2 foo = new Bar3(7)) // https://issues.dlang.org/show_bug.cgi?id=4477 { return -1; } @property int outer() nothrow in { assert(true); } out(result) { assert(result == 18); } body { int x = 8; int inner(void* v) nothrow { int y = 2; assert(true); return x + y; } int z = inner(null); return x + z; } /** Issue 9484 - selective and renamed imports */ import imports.jsonimport1 : target1, target2; import imports.jsonimport2 : alias1 = target1, alias2 = target2; import imports.jsonimport3 : alias3 = target1, alias4 = target2, target3; import imports.jsonimport4; struct S { /** Issue 9480 - Template name should be stripped of parameters */ this(T)(T t) { } } /** Issue 9755 - Protection not emitted properly for Templates. */ private struct S1_9755(T) { } package struct S2_9755(T) { } class C_9755 { protected static class CI_9755(T) { } } /** Issue 10011 - init property is wrong for object initializer. */ const Object c_10011 = new Object(); /// enum Numbers { unspecified1, one = 2, two = 3, FILE_NOT_FOUND = 101, unspecified3, unspecified4, four = 4, } template IncludeConstraint(T) if (T == string) {} static foreach(enum i; 0..3) { mixin("int a" ~ i.stringof ~ " = 1;"); } alias Seq(T...) = T; static foreach(int i, alias a; Seq!(a0, a1, a2)) { mixin("alias b" ~ i.stringof ~ " = a;"); } // return ref, return scope, return ref scope ref int foo(return ref int a) @safe { return a; } int* foo(return scope int* a) @safe { return a; } ref int* foo(scope return ref int* a) @safe { return a; } struct SafeS { @safe: ref SafeS foo() return { return this; } SafeS foo2() return scope { return this; } ref SafeS foo3() return scope { return this; } int* p; } extern int vlinkageDefault; extern(D) int vlinkageD; extern(C) int vlinakgeC; extern(C++) __gshared int vlinkageCpp; extern(Windows) int vlinkageWindows; extern(Pascal) int vlinkagePascal; extern(Objective-C) int vlinkageObjc; extern int flinkageDefault(); extern(D) int flinkageD(); extern(C) int linakgeC(); extern(C++) int flinkageCpp(); extern(Windows) int flinkageWindows(); extern(Pascal) int flinkagePascal(); extern(Objective-C) int flinkageObjc(); mixin template test18211(int n) { static foreach (i; 0 .. n>10 ? 10 : n) { mixin("enum x" ~ cast(char)('0' + i)); } static if (true) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/line.d ================================================ module line; static assert(__LINE__ == 3); int #line 10 x; static assert(__LINE__ == 12); version(Windows) { static assert(__FILE__ == "compilable\\line.d"); static assert(__FILE_FULL_PATH__[1..3] == ":\\"); } else { static assert(__FILE__ == "compilable/line.d"); static assert(__FILE_FULL_PATH__[0] == '/'); } static assert(__FILE_FULL_PATH__[$-__FILE__.length..$] == __FILE__); #line 100 "newfile.d" static assert(__LINE__ == 101); static assert(__FILE__ == "newfile.d"); static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d"); # line 200 static assert(__LINE__ == 201); static assert(__FILE__ == "newfile.d"); static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/minimal.d ================================================ // DFLAGS: // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/minimal/verify_symbols.sh // REQUIRED_ARGS: -defaultlib= // EXTRA_SOURCES: extra-files/minimal/object.d // This test ensures an empty main with a struct and enum, built with a minimal // runtime, does not generate ModuleInfo or exception handling code, and does not // require TypeInfo struct S { } enum E { e0 = 0, e1 = 1 } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/minimal2.d ================================================ // DFLAGS: // REQUIRED_ARGS: -defaultlib= // EXTRA_SOURCES: extra-files/minimal/object.d // This test ensures that interfaces and classes can be used in a minimal // runtime as long as they only contain static members. // This should compile, but will not link and run properly without // a thread-local storage (TLS) implementation. interface I { static int i; } class A : I { static int a; } class B : A { static int b; } void main() { B.i = 32; B.a = 42; B.b = 52; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/mixintempl.d ================================================ struct TypeObj { alias This = typeof(this); mixin template MixinTempl() { int value; } } ref TypeObj Obj() { static TypeObj a; return a; } void func() { mixin Obj.This.MixinTempl; // ok mixin Obj.MixinTempl; // fixed: "MixinTempl!()" is not defined } ================================================ FILE: gcc/testsuite/gdc.test/compilable/noderef.d ================================================ // PERMUTE_ARGS: // https://github.com/dlang/dmd/pull/5860 int[] bar() @safe; void foo(int[] a) @safe { static int[] as; bool b; b = a.ptr == null; b = null == (*&as).ptr; b = bar().ptr == null; b = a.ptr != null; b = null != (*&as).ptr; b = bar().ptr != null; b = a.ptr is null; b = null is (*&as).ptr; b = bar().ptr is null; b = a.ptr !is null; b = null !is (*&as).ptr; b = bar().ptr !is null; b = !a.ptr; b = !(*&as).ptr; b = !bar().ptr; b = cast(bool)a.ptr; b = cast(bool)(*&as).ptr; b = cast(bool)bar().ptr; b = a.ptr ? false : true; b = a.ptr < null; b = null < a.ptr; b = a.ptr && null || a.ptr; if (a.ptr) b = true; while (a.ptr) b = true; for (; a.ptr;) b = true; // ptrdiff_t d = a.ptr - a.ptr; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/nogc.d ================================================ // REQUIRED_ARGS: -o- /***************** Covariance ******************/ class C1 { void foo() @nogc; void bar(); } class D1 : C1 { override void foo(); // no error override void bar() @nogc; // no error } /******************************************/ // __traits(compiles) static assert(__traits(compiles, new Object())); void foo_compiles() {} @nogc void test_compiles() { auto fp = &foo_compiles; static assert(!__traits(compiles, foo_compiles())); static assert(!__traits(compiles, fp())); static assert(!__traits(compiles, (*fp)())); static assert(!__traits(compiles, [1,2,3])); static assert(!__traits(compiles, [1:1, 2:2])); struct Struct {} static assert(!__traits(compiles, new int)); static assert(!__traits(compiles, new Struct())); static assert(!__traits(compiles, new Object())); int* p; static assert(!__traits(compiles, delete p)); int[int] aa; static assert(!__traits(compiles, aa[0])); int[] a; static assert(!__traits(compiles, a.length = 1)); static assert(!__traits(compiles, a.length += 1)); static assert(!__traits(compiles, a.length -= 1)); static assert(!__traits(compiles, a ~= 1)); static assert(!__traits(compiles, a ~ a)); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12630 void test12630() @nogc { // All of these declarations should cause no errors. static const ex1 = new Exception("invalid"); //enum ex2 = new Exception("invalid"); static const arr1 = [[1,2], [3, 4]]; enum arr2 = [[1,2], [3, 4]]; //static const aa1 = [1:1, 2:2]; enum aa2 = [1:1, 2:2]; //static const v1 = aa1[1]; enum v2 = aa2[1]; Object o; //static const del1 = (delete o).sizeof; //enum del2 = (delete o).sizeof; int[] a; static const len1 = (a.length = 1).sizeof; enum len2 = (a.length = 1).sizeof; static const cata1 = (a ~= 1).sizeof; enum cata2 = (a ~= 1).sizeof; static const cat1 = (a ~ a).sizeof; enum cat2 = (a ~ a).sizeof; } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12642 static if (is(__vector(ulong[2]))) { import core.simd; ulong2 test12642() @nogc { return [0, 0]; } } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=13550 auto foo13550() @nogc { static int[] bar() { return new int[2]; } return &bar; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/protattr.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: import protection.basic.tests; import protection.subpkg.tests; import protection.subpkg2.tests; ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/aggregate/mod14275.d ================================================ module protection.aggregate.mod14275; public struct Foo { package(protection) void foo() {} package void foo2() {} } package(protection) void bar() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/basic/mod1.d ================================================ module protection.basic.mod1; public void publicFoo() {} package void packageFoo() {} private void privateFoo() {} class Test { public void publicFoo(); protected void protectedFoo(); package void packageFoo(); private void privateFoo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/basic/tests.d ================================================ module protection.basic.tests; import protection.basic.mod1; static assert ( is(typeof(publicFoo()))); static assert ( is(typeof(packageFoo()))); static assert (!is(typeof(privateFoo()))); static assert ( is(typeof(Test.init.publicFoo()))); static assert (!is(typeof(Test.init.protectedFoo()))); static assert ( is(typeof(Test.init.packageFoo()))); static assert (!is(typeof(Test.init.privateFoo()))); class Deriv : Test { void stub() { static assert ( is(typeof(this.publicFoo()))); static assert ( is(typeof(this.protectedFoo()))); static assert ( is(typeof(this.packageFoo()))); static assert (!is(typeof(this.privateFoo()))); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/bug/bug14275.d ================================================ module protection.bug.bug14275; import protection.aggregate.mod14275; // https://issues.dlang.org/show_bug.cgi?id=14275 void main() { Foo f; f.foo(); static assert (!is(typeof(f.foo2()))); bar(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/subpkg/explicit.d ================================================ module protection.subpkg.explicit; package(protection) void commonAncestorFoo(); package(protection.subpkg) void samePkgFoo(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/subpkg/tests.d ================================================ module protection.subpkg.tests; import crosspkg = protection.basic.mod1; static assert ( is(typeof(crosspkg.publicFoo()))); static assert (!is(typeof(crosspkg.packageFoo()))); static assert (!is(typeof(crosspkg.privateFoo()))); import samepkg = protection.subpkg.explicit; static assert ( is(typeof(samepkg.commonAncestorFoo()))); static assert ( is(typeof(samepkg.samePkgFoo()))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection/subpkg2/tests.d ================================================ module protection.subpkg2.tests; import pkg = protection.subpkg.explicit; static assert (is(typeof(pkg.commonAncestorFoo()))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/protection.d ================================================ // REQUIRED_ARGS: -de import imports.protectionimp; alias TypeTuple(T...) = T; private { void localF() {} class localC {} struct localS {} union localU {} interface localI {} enum localE { foo } mixin template localMT() {} class localTC(T) {} struct localTS(T) {} union localTU(T) {} interface localTI(T) {} void localTF(T)() {} } void main() { // Private non-template declarations static assert(!__traits(compiles, privF())); static assert(!__traits(compiles, privC)); static assert(!__traits(compiles, privS)); static assert(!__traits(compiles, privU)); static assert(!__traits(compiles, privI)); static assert(!__traits(compiles, privE)); static assert(!__traits(compiles, privMT)); // Private local non-template declarations. static assert( __traits(compiles, localF())); static assert( __traits(compiles, localC)); static assert( __traits(compiles, localS)); static assert( __traits(compiles, localU)); static assert( __traits(compiles, localI)); static assert( __traits(compiles, localE)); static assert( __traits(compiles, localMT)); // Private template declarations. static assert(!__traits(compiles, privTF!int())); static assert(!__traits(compiles, privTC!int)); static assert(!__traits(compiles, privTS!int)); static assert(!__traits(compiles, privTU!int)); static assert(!__traits(compiles, privTI!int)); // Private local template declarations. static assert( __traits(compiles, localTF!int())); static assert( __traits(compiles, localTC!int)); static assert( __traits(compiles, localTS!int)); static assert( __traits(compiles, localTU!int)); static assert( __traits(compiles, localTI!int)); // Public template function with private type parameters. static assert(!__traits(compiles, publF!privC())); static assert(!__traits(compiles, publF!privS())); static assert(!__traits(compiles, publF!privU())); static assert(!__traits(compiles, publF!privI())); static assert(!__traits(compiles, publF!privE())); // Public template function with private alias parameters. static assert(!__traits(compiles, publFA!privC())); static assert(!__traits(compiles, publFA!privS())); static assert(!__traits(compiles, publFA!privU())); static assert(!__traits(compiles, publFA!privI())); static assert(!__traits(compiles, publFA!privE())); // Private alias. static assert(!__traits(compiles, privA)); // Public template mixin. static assert( __traits(compiles, publMT)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14169 template staticMap14169(alias fun, T...) { static if (T.length > 0) alias staticMap14169 = TypeTuple!(fun!(T[0]), staticMap14169!(fun, T[1..$])); else alias staticMap14169 = TypeTuple!(); } class C14169 { private struct InnerStruct(string NameS) { alias Name = NameS; } alias DimensionNames = staticMap14169!(GetName14169, InnerStruct!"A"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/pull6815.d ================================================ /* REQUIRED_ARGS: -inline -Icompilable/extra-files EXTRA_FILES: extra-files/e6815.d */ void b() { import e6815 : e; e(""); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/riia_ctor.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17494 struct S { ~this() {} } class C { S s; this() nothrow {} } // https://issues.dlang.org/show_bug.cgi?id=17505 struct Array { int[] _payload; ~this() { import core.stdc.stdlib : free; free(_payload.ptr); } } class Scanner { Array arr; this() @safe {} } // https://issues.dlang.org/show_bug.cgi?id=17506 struct TreeMap { this() @disable; this(TTree tree) { this.tree = tree; } TTree tree; } struct TTree { this() @disable; this(int foo) {} ~this() {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/scope.d ================================================ /* currently fails with extra safety checks PERMUTE_FIXME_ARGS: -dip1000 */ struct Cache { ubyte[1] v; ubyte[] set(ubyte[1] v) { return this.v[] = v[]; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/shared_destructor.d ================================================ struct MaybeShared { this(this T)() { } ~this() { } } void main() { { auto aboutToDie = MaybeShared(); } { auto aboutToDie = shared MaybeShared(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/staticforeach.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct Tuple(T...){ T expand; alias expand this; } auto tuple(T...)(T t){ return Tuple!T(t); } /+struct TupleStaticForeach{ // should work, but is not the fault of the static foreach implementation. //pragma(msg, [tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x)); static foreach(a,b,c;[tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x)){ pragma(msg,a," ",b," ",c); } }+/ void main(){ static foreach(a,b,c;[tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x)){ pragma(msg, a," ",b," ",c); } static struct S{ // (aggregate scope, forward referencing possible) static assert(stripA("123")==1); static assert(stripA([1],2)==2); static foreach(i;0..2){ mixin(`import imports.imp12242a`~text(i+1)~`;`); static assert(stripA("123")==1); static assert(stripA([1],2)==2); } static assert(stripA("123")==1); static assert(stripA([1],2)==2); } static foreach(i;0..2){ // (function scope, no forward referencing) mixin(`import imports.imp12242a`~text(i+1)~`;`); static assert(stripA("123")==1); static if(i) static assert(stripA([1],2)==2); } static assert(stripA("123")==1); static assert(stripA([1],2)==2); } auto front(T)(T[] a){ return a[0]; } auto popFront(T)(ref T[] a){ a=a[1..$]; } auto empty(T)(T[] a){ return !a.length; } auto back(T)(T[] a){ return a[$-1]; } auto popBack(T)(ref T[] a){ a=a[0..$-1]; } struct Iota(T){ T s,e; @property bool empty(){ return s>=e; } @property T front(){ return s; } @property T back(){ return cast(T)(e-1); } void popFront(){ s++; } void popBack(){ e--; } } auto iota(T)(T s, T e){ return Iota!T(s,e); } template map(alias a){ struct Map(R){ R r; @property front(){ return a(r.front); } @property back(){ return a(r.back); } @property bool empty(){ return r.empty; } void popFront(){ r.popFront(); } void popBack(){ r.popBack(); } } auto map(R)(R r){ return Map!R(r); } } template to(T:string){ string to(S)(S x)if(is(S:int)||is(S:size_t)||is(S:char)){ static if(is(S==char)) return cast(string)[x]; if(x<0) return "-"~to(-x); if(x==0) return "0"; return (x>=10?to(x/10):"")~cast(char)(x%10+'0'); } } auto text(T)(T arg){ return to!string(arg); }; template all(alias a){ bool all(R)(R r){ foreach(x;r) if(!a(x)) return false; return true; } } template any(alias a){ bool any(R)(R r){ foreach(x;r) if(a(x)) return true; return false; } } auto join(R)(R r,string sep=""){ string a; int first=0; foreach(x;r){ if(first++) a~=sep; a~=x; } return a; } static foreach_reverse(x;iota(0,10).map!(to!string)){ pragma(msg, x); } // create struct members iteratively struct S{ static foreach(i;a){ mixin("int x"~to!string(i)~";"); } immutable int[] a = [0,1,2]; } enum s=S(1,2,3); pragma(msg, s); // loop over struct members static foreach(member;__traits(allMembers,S)){ pragma(msg, member,": ",mixin("s."~member)); } // print prime numbers using overload sets as state variables. /+ static assert(is(typeof(bad57))); static assert(!is(typeof(bad53))); static foreach(x;iota(2,100)){ static foreach(y;iota(2,x)){ static if(!(x%y)){ mixin("void bad"~to!string(x)~"();"); } } static if(!is(typeof(mixin("bad"~to!string(x))))){ static assert(iota(2,x).all!(y=>!!(x%y))); pragma(msg, x); }else{ static assert(iota(2,x).any!(y=>!(x%y))); } } +/ alias Seq(T...)=T; alias Overloads(alias a) = Seq!(__traits(getOverloads, __traits(parent, a), __traits(identifier, a))); template Parameters(alias f){ static if(is(typeof(f) P == function)) alias Parameters=P; } template forward(alias a){ enum x=2; static foreach(f;Overloads!a){ auto ref forward(Parameters!f args){ return f(args); } } enum y=3; } int foo(int x){ return x; } string foo(string x){ return x; } static assert(forward!foo(2)==2 && forward!foo("hi") == "hi"); // simple boilerplate-free visitor pattern static foreach(char T;'A'..'F'){ mixin("class "~T~q{{ void accept(Visitor v){ return v.visit(this); } }}); } alias Types = Seq!(mixin("Seq!("~iota('A','F').map!(to!string).join(", ")~")")); abstract class Visitor{ static foreach(T;Types){ abstract void visit(T); } } string testVisitor(){ string r; void writeln(T...)(T args){ static foreach(x;args) r~=x; r~='\n'; } class Visitor: .Visitor{ static foreach(T;Types){ override void visit(T){ writeln("visited: ",T.stringof); } } } void main(){ auto v=new Visitor; static foreach(T;Types){ v.visit(new T); } } main(); return r; } static assert(testVisitor()=="visited: A visited: B visited: C visited: D visited: E "); // iterative computation over AliasSeq: template staticMap(alias F,T...){ alias state0=Seq!(); static foreach(i,A;T){ mixin("alias state"~to!string(i+1)~" = Seq!(state"~to!string(i)~",F!A);"); } alias staticMap = Seq!(mixin("state"~to!string(T.length))); } alias arrayOf(T)=T[]; static assert(is(staticMap!(arrayOf,int,char,bool,Object)==Seq!(int[], char[], bool[], Object[]))); pragma(msg, staticMap!(arrayOf,int,char,bool,Object)); struct StaticForeachLoopVariable{ int x; static foreach(i;0..1){ mixin("enum x"~text(i)~" = i;"); } int y; static assert(__traits(allMembers, StaticForeachLoopVariable).length==3); static assert(!is(typeof(StaticForeachLoopVariable.i))); static assert(!is(typeof(__traits(getMember, StaticForeachLoopVariable, "i")))); } struct StaticForeachScopeExit{ static: int[] test(){ int[] r; scope(exit) r ~= 1234; { static foreach(i;0..5){ scope(exit) r ~= i; } r ~= 5; } return r; } static assert(test()==[5,4,3,2,1,0]); } struct StaticForeachReverseHiding{ static foreach(i;[0]){ enum i = 1; // TODO: disallow? static assert(i==0); } } struct UnrolledForeachReverse{ static: alias Seq(T...)=T; int[] test(){ int[] r; foreach_reverse(i;Seq!(0,1,2,3)){ r~=i; } return r; } static assert(test()==[3,2,1,0]); } struct StaticForeachReverse{ static: alias Seq(T...)=T; int[] test(){ int[] r; static foreach_reverse(i;0..4){ r~=i; } return r; } static assert(test()==[3,2,1,0]); int[] test2(){ int[] r; static foreach_reverse(i;[0,1,2,3]){ r~=i; } return r; } static assert(test2()==[3,2,1,0]); int[] test3(){ static struct S{ int opApplyReverse(scope int delegate(int) dg){ foreach_reverse(i;0..4) if(auto r=dg(i)) return r; return 0; } } int[] r; static foreach_reverse(i;S()){ r~=i; } return r; } static assert(test3()==[3,2,1,0]); int[] test4(){ int[] r; static foreach_reverse(i;Seq!(0,1,2,3)){ r~=i; } return r; } static assert(test()==[3,2,1,0]); } struct StaticForeachByAliasDefault{ static: alias Seq(T...)=T; int[] test(){ int a,b,c; static foreach(i,x;Seq!(a,b,c)) x=i; return [a,b,c]; } static assert(test()==[0,1,2]); int[] test2(){ int x=0; int foo(){ return ++x; } static foreach(y;Seq!foo) return [y,y,y]; } static assert(test2()==[1,2,3]); void test3(){ int x=0; int foo(){ return ++x; } static assert(!is(typeof({ static foreach(enum y;Seq!foo) return [y,y,y]; }))); } } struct NestedStaticForeach{ static: static foreach(i,name;["a"]){ static foreach(j,name2;["d"]){ mixin("enum "~name~name2~"=[i,j];"); } } pragma(msg, ad); } struct TestAliasOutsideFunctionScope{ static: alias Seq(T...)=T; int a; static foreach(alias x;Seq!(a)){ } } struct OpApplyMultipleStaticForeach{ static: struct OpApply{ int opApply(scope int delegate(int,int) dg){ foreach(i;0..10) if(auto r=dg(i,i*i)) return r; return 0; } } static foreach(a,b;OpApply()){ mixin(`enum x`~cast(char)('0'+a)~"=b;"); } static foreach(i;0..10){ static assert(mixin(`x`~cast(char)('0'+i))==i*i); } } struct OpApplyMultipleStaticForeachLowered{ static: struct OpApply{ int opApply(scope int delegate(int,int) dg){ foreach(i;0..10) if(auto r=dg(i,i*i)) return r; return 0; } } static foreach(x;{ static struct S(T...){ this(T k){ this.x=k; } T x; } static s(T...)(T a){ return S!T(a); } typeof({ foreach(a,b;OpApply()){ return s(a,b); } assert(0);}())[] r; foreach(a,b;OpApply()) r~=s(a,b); return r; }()){ mixin(`enum x`~cast(char)('0'+x.x[0])~"=x.x[1];"); } static foreach(i;0..10){ static assert(mixin(`x`~cast(char)('0'+i))==i*i); } } struct RangeStaticForeach{ static: struct Range{ int x=0; this(int x){ this.x=x; } @property int front(){ return x; } void popFront(){ x += 2; } @property bool empty(){ return x>=10; } } static foreach(i;Range()){ mixin(`enum x`~cast(char)('0'+i)~"=i;"); } static foreach(i;0..5){ static assert(mixin(`x`~cast(char)('0'+2*i))==2*i); } static assert(!is(typeof({ struct S{ static foreach(i,k;Range()){} } }))); static foreach(k;Range()){} // ok } struct OpApplySingleStaticForeach{ static: struct OpApply{ int opApply(scope int delegate(int) dg){ foreach(i;0..10) if(auto r=dg(i)) return r; return 0; } } static foreach(b;OpApply()){ mixin(`enum x`~cast(char)('0'+b)~"=b;"); } static foreach(i;0..10){ static assert(mixin(`x`~cast(char)('0'+i))==i); } } struct TypeStaticForeach{ static: alias Seq(T...)=T; static foreach(i,alias T;Seq!(int,double,char)){ mixin(`T x`~cast(char)('0'+i)~";"); } pragma(msg, "x0: ",typeof(x0)); pragma(msg, "x1: ",typeof(x1)); pragma(msg, "x2: ",typeof(x2)); static assert(is(typeof(x0)==int)); static assert(is(typeof(x1)==double)); static assert(is(typeof(x2)==char)); } struct AliasForeach{ static: alias Seq(T...)=T; int[] test(){ int a,b,c; static foreach(x;Seq!(a,b,c,2)){ static if(is(typeof({x=2;}))) x=2; } int x,y,z; static foreach(alias k;Seq!(x,y,z,2)){ static if(is(typeof({k=2;}))) k=2; } int j,k,l; static assert(!is(typeof({ static foreach(ref x;Seq!(j,k,l,2)){ static if(is(typeof({x=2;}))) x=2; } }))); return [x,y,z]; } static assert(test()==[2,2,2]); } struct EnumForeach{ static: alias Seq(T...)=T; int a=1; int fun(){ return 1; } int gun(){ return 2; } int hun(){ return 3;} auto test(){ static foreach(i,enum x;Seq!(fun,gun,hun)){ static assert(i+1==x); } foreach(i,enum x;Seq!(fun,gun,hun)){ static assert(i+1==x); } } } struct TestUninterpretable{ static: alias Seq(T...)=T; auto test(){ int k; static assert(!is(typeof({ static foreach(x;[k]){} }))); static assert(!is(typeof({ foreach(enum x;[1,2,3]){} }))); static assert(!is(typeof({ foreach(alias x;[1,2,3]){} }))); foreach(enum x;Seq!(1,2,3)){} // ok foreach(alias x;Seq!(1,2,3)){} // ok static foreach(enum x;[1,2,3]){} // ok static foreach(alias x;[1,2,3]){} // ok static assert(!is(typeof({ static foreach(enum alias x;[1,2,3]){} }))); int x; static foreach(i;Seq!x){ } // ok static foreach(i,j;Seq!(1,2,x)){ } // ok static assert(!is(typeof({ static foreach(ref x;[1,2,3]){} }))); } } struct SeqForeachConstant{ static: alias Seq(T...)=T; static assert(!is(typeof({ foreach(x;Seq!1) x=2; }))); int test2(){ int r=0; foreach(x;Seq!(1,2,3)){ enum k=x; r+=k; } return r; } static assert(test2()==6); } struct SeqForeachBreakContinue{ static: alias Seq(T...)=T; int[] test(){ int[] r; foreach(i;Seq!(0,1,2,3,4,5)){ if(i==2) continue; if(i==4) break; r~=i; } return r; } static assert(test()==[0,1,3]); } struct TestStaticForeach{ static: int test(int x){ int r=0; label: switch(x){ static foreach(i;0..10){ case i: r=i; break label; // TODO: remove label when restriction is lifted } default: r=-1; break label; } return r; } static foreach(i;0..15){ pragma(msg, "test(",i,")→ ",test(i)); static assert(test(i)==(i<10?i:-1)); } enum x=[1,2,3]; static foreach(i;x){ mixin("enum x"~cast(char)('0'+i)~"="~cast(char)('0'+i)~";"); } static foreach(i;x){ pragma(msg, mixin("x"~cast(char)('0'+i))); pragma(msg,x); } int[] noBreakNoContinue(){ int[] r; static foreach(i;0..1){ // if(i==3) continue; // TODO: error? // if(i==7) break; // TODO: error? r~=i; } return r; } mixin("enum k=3;"); } static foreach(i,j;[1,2,3]){ pragma(msg, i," ",j); } void testtest(){ static foreach(i,v;[1,2,3]){ pragma(msg, i," ",v); static assert(i+1 == v); } } static foreach(i;Seq!(1,2,3,4,int)){ static if(!is(i) && i!=2){ pragma(msg, i); } } int fun(int x){ int r=0; label: switch(x){ static foreach(i;Seq!(0,1,2,3,4,5,6)){ static if (i < 5) case i: r=i; break label; // TODO: remove label when restriction is lifted } default: r=-1; break label; } return r; } static foreach(i;0..10) static assert(fun(i)==(i<5?i:-1)); static foreach(i;0..0) { } void testEmpty(){ static foreach(i;0..0) { } } auto bug17660(){ int x; static foreach (i; 0 .. 1) { return 3; } return x; } static assert(bug17660()==3); int breakContinueBan(){ static assert(!is(typeof({ for(;;){ static foreach(i;0..1){ break; } } }))); static assert(!is(typeof({ for(;;){ static foreach(i;0..1){ continue; } } }))); Louter1: for(;;){ static foreach(i;0..1){ break Louter1; } } Louter2: foreach(i;0..10){ static foreach(j;0..1){ continue Louter2; } return 0; } static foreach(i;0..1){ for(;;){ break; } // ok } return 1; } static assert(breakContinueBan()==1); mixin template MixinTemplate(){ static foreach(i;0..2){ mixin(`enum x`~cast(char)('0'+i)~"=i;"); } static foreach(i;[0,1]){ mixin(`enum y`~cast(char)('0'+i)~"=i;"); } } void testToStatement(){ mixin MixinTemplate; static assert(x0==0 && x1==1); static assert(y0==0 && y1==1); } void bug17688(){ final switch(1) static foreach(x;0..1){ int y=3; case 1: return; } static assert(!is(typeof(y))); } struct T{ enum n = 1; } T foo(T v)@nogc{ static foreach(x;0..v.n){ } return T.init; } T foo2(T v)@nogc{ static foreach(_;0..typeof(return).n){ } return T.init; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/sw_transition_complex.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -transition=complex /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(15): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(17): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead compilable/sw_transition_complex.d(19): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead compilable/sw_transition_complex.d(20): Deprecation: use of imaginary type `idouble` is deprecated, use `double` instead compilable/sw_transition_complex.d(21): Deprecation: use of imaginary type `ifloat` is deprecated, use `float` instead --- */ creal c80value; cdouble c64value; cfloat c32value; ireal i80value; idouble i64value; ifloat i32value; /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(34): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(35): Deprecation: use of complex type `cdouble*` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(36): Deprecation: use of complex type `cfloat*` is deprecated, use `std.complex.Complex!(float)` instead compilable/sw_transition_complex.d(38): Deprecation: use of imaginary type `ireal*` is deprecated, use `real` instead compilable/sw_transition_complex.d(39): Deprecation: use of imaginary type `idouble*` is deprecated, use `double` instead compilable/sw_transition_complex.d(40): Deprecation: use of imaginary type `ifloat*` is deprecated, use `float` instead --- */ creal* c80pointer; cdouble* c64pointer; cfloat* c32pointer; ireal* i80pointer; idouble* i64pointer; ifloat* i32pointer; /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(53): Deprecation: use of complex type `creal[]*` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(54): Deprecation: use of complex type `cdouble[]*` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(55): Deprecation: use of complex type `cfloat[]*` is deprecated, use `std.complex.Complex!(float)` instead compilable/sw_transition_complex.d(57): Deprecation: use of imaginary type `ireal[]*` is deprecated, use `real` instead compilable/sw_transition_complex.d(58): Deprecation: use of imaginary type `idouble[]*` is deprecated, use `double` instead compilable/sw_transition_complex.d(59): Deprecation: use of imaginary type `ifloat[]*` is deprecated, use `float` instead --- */ creal[]* c80arrayp; cdouble[]* d64arrayp; cfloat[]* c32arrayp; ireal[]* i80arrayp; idouble[]* i64arrayp; ifloat[]* i32arrayp; /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(72): Deprecation: use of complex type `creal[4][]*` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(73): Deprecation: use of complex type `cdouble[4][]*` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(74): Deprecation: use of complex type `cfloat[4][]*` is deprecated, use `std.complex.Complex!(float)` instead compilable/sw_transition_complex.d(76): Deprecation: use of imaginary type `ireal[4][]*` is deprecated, use `real` instead compilable/sw_transition_complex.d(77): Deprecation: use of imaginary type `idouble[4][]*` is deprecated, use `double` instead compilable/sw_transition_complex.d(78): Deprecation: use of imaginary type `ifloat[4][]*` is deprecated, use `float` instead --- */ creal[4][]* c80sarrayp; cdouble[4][]* c64sarrayp; cfloat[4][]* c32sarrayp; ireal[4][]* i80sarrayp; idouble[4][]* i64sarrayp; ifloat[4][]* i32sarrayp; /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(96): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(97): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(98): Deprecation: use of complex type `creal[]` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(99): Deprecation: use of complex type `creal[4]` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(101): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead compilable/sw_transition_complex.d(102): Deprecation: use of imaginary type `ireal*` is deprecated, use `real` instead compilable/sw_transition_complex.d(103): Deprecation: use of imaginary type `ireal[]` is deprecated, use `real` instead compilable/sw_transition_complex.d(104): Deprecation: use of imaginary type `ireal[4]` is deprecated, use `real` instead --- */ alias C14488 = creal; alias I14488 = ireal; C14488 calias1; C14488* calias2; C14488[] calias3; C14488[4] calias4; I14488 ialias1; I14488* ialias2; I14488[] ialias3; I14488[4] ialias4; /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(115): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(116): Deprecation: use of imaginary type `idouble` is deprecated, use `double` instead compilable/sw_transition_complex.d(117): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead compilable/sw_transition_complex.d(118): Deprecation: use of complex type `cdouble[]` is deprecated, use `std.complex.Complex!(double)` instead --- */ auto cauto = 1 + 0i; auto iauto = 1i; size_t c64sizeof = (cdouble).sizeof; TypeInfo c64ti = typeid(cdouble[]); /* TEST_OUTPUT: --- compilable/sw_transition_complex.d(128): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead compilable/sw_transition_complex.d(128): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead compilable/sw_transition_complex.d(132): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead --- */ void test14488a(creal *p, real r, ireal i) { } creal test14488b() { return 1 + 0i; } // Forward referenced types shouldn't cause errors during test for complex or imaginary. enum E; struct S; void test14488c(E *e, S *s) { } // https://issues.dlang.org/show_bug.cgi?id=18212 // Usage of cfloat,cdouble,cfloat,ifloat,idouble,ireal shouldn't trigger an error in deprecated code deprecated void test18212(creal c){} deprecated unittest { ireal = 2i; creal = 2 + 3i; } deprecated struct Foo { ifloat a = 2i; cfloat b = 2f + 2i; } // https://issues.dlang.org/show_bug.cgi?id=18218 static assert(__traits(isDeprecated, cfloat)); static assert(__traits(isDeprecated, cdouble)); static assert(__traits(isDeprecated, creal)); static assert(__traits(isDeprecated, ifloat)); static assert(__traits(isDeprecated, idouble)); static assert(__traits(isDeprecated, ireal)); static assert(!__traits(isDeprecated, float)); static assert(!__traits(isDeprecated, double)); static assert(!__traits(isDeprecated, real)); static assert(!__traits(isDeprecated, int)); static assert(!__traits(isDeprecated, long)); static assert(!__traits(isDeprecated, ubyte)); static assert(!__traits(isDeprecated, char)); static assert(!__traits(isDeprecated, bool)); static assert(!__traits(isDeprecated, S)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/sw_transition_field.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -transition=field /* TEST_OUTPUT: --- compilable/sw_transition_field.d(15): `sw_transition_field.S1.ix` is `immutable` field compilable/sw_transition_field.d(16): `sw_transition_field.S1.cx` is `const` field compilable/sw_transition_field.d(21): `sw_transition_field.S2!(immutable(int)).S2.f` is `immutable` field compilable/sw_transition_field.d(21): `sw_transition_field.S2!(const(int)).S2.f` is `const` field --- */ struct S1 { immutable int ix = 1; const int cx = 2; } struct S2(F) { F f = F.init; } alias S2!(immutable int) S2I; alias S2!( const int) S2C; ================================================ FILE: gcc/testsuite/gdc.test/compilable/sw_transition_tls.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -transition=tls /* TEST_OUTPUT: --- compilable/sw_transition_tls.d(11): `x` is thread local compilable/sw_transition_tls.d(15): `y` is thread local --- */ int x; struct S { static int y; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1.d ================================================ // PERMUTE_ARGS: class File { import imports.test1imp; static char[] read(char[] name) { DWORD size; // DWORD is defined in test1imp return null; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10056.d ================================================ void main() { alias Zoo = Foo10056!(false, false, 1); } struct Foo10056(bool S, bool L, size_t N) { string bar() { Appender10056!(string) w; char[] buf; put10056(w, buf); return ""; } public bool opEquals(T)(T other) //const //If you add const, also fails to compile with 2.062. { alias Foo10056!(typeof(this), T, "CMP") P; return false; } } template Foo10056(T, U, string OP) { static if (T.ISEMPTY && U.ISEMPTY) enum bool S = false; else enum bool S = false; alias Foo10056 = Foo10056!(false, false, 0); } /**********************************************/ void put10056(R, E)(ref R r, E e) { static if (is(typeof(r.put(e)))) { r.put(e); } else { static assert(false, "Cannot put a "~E.stringof~" into a "~R.stringof); } } struct Appender10056(A : T[], T) { private template canPutItem(U) { enum bool canPutItem = is(U : T); } private template canPutRange(R) { enum bool canPutRange = is(typeof(Appender10056.init.put(R.init[0]))); } void put(U)(U item) if (canPutItem!U) { char[T.sizeof == 1 ? 4 : 2] encoded; put(encoded[]); } void put(R)(R items) if (canPutRange!R) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10066.d ================================================ void main() { alias Zoo = Foo!(1); } struct Foo(size_t N) { string bar() { Appender!(string) w; char[] buf; put(w, buf); return ""; } public bool opEquals(T)(T other) const // Add const, different from bug 10056 { alias Foo!(typeof(this), T, "CMP") P; return false; } } template Foo(T, U, string OP) { static if (T.ISEMPTY && U.ISEMPTY) enum bool S = false; else enum bool S = false; alias Foo = Foo!(0); } /**********************************************/ void put(R, E)(ref R r, E e) { static if (is(typeof(r.put(e)))) { r.put(e); } else { static assert(false, "Cannot put a "~E.stringof~" into a "~R.stringof); } } struct Appender(A : T[], T) { private template canPutItem(U) { enum bool canPutItem = is(U : T); } private template canPutRange(R) { enum bool canPutRange = is(typeof(Appender.init.put(R.init[0]))); } void put(U)(U item) if (canPutItem!U) { char[T.sizeof == 1 ? 4 : 2] encoded; put(encoded[]); } void put(R)(R items) if (canPutRange!R) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10073.d ================================================ struct Arr(T) { T[] dArr; alias dArr this; bool opEquals(Arr!T d) { foreach (idx, it; d) { if (this[idx] != it) { return false; } } return true; } } class Bar { Arr!Foo fooQ; } class Foo {} // NG ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10186.d ================================================ struct S { @disable this(); this(int i) { } } class C { this() { s = S(1); } S s; } class CR { S s; this() { s = S(1); } } void main() { auto c = new C; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10312.d ================================================ version(D_SIMD) { const __vector(float[4]) si = [1f, 1f, 1f, 1f]; void main() { auto arr = si; return; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10375.d ================================================ // REQUIRED_ARGS: -o- import imports.test10375a; void packIt(Pack)(Pack p){ } //3 void main() { alias p = packIt!(int); p(2); // OK <- NG packIt(2); // OK <- NG packIt!(int)(2); // OK <- NG } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10520.d ================================================ // REQUIRED_ARGS: -debug -profile // https://issues.dlang.org/show_bug.cgi?id=10520 // [profile+nothrow] Building with profiler results in "is not nothrow" error on some contracts void f() { } void g()() in { f(); } // OK <- Error: 'main.f' is not nothrow body { } alias gi = g!(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10695.d ================================================ // PERMUTE_ARGS: module a; void main() { mixin("string mod1 = __MODULE__;"); mixin("enum mod2 = __MODULE__;"); static assert(mod2 == "a"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10726.d ================================================ // PERMUTE_ARGS: public struct CirBuff(T) { private T[] data; private size_t head = 0; private size_t size = 0; public size_t length() const { return size; } public bool opEquals(CirBuff!T d) @trusted { if (length != d.length) return false; for (size_t i=0; i!=size; ++i) { if (this.data[(this.head+i) % this.data.length] != d.data[(d.head + i) % d.data.length]) { return false; } } return true; } } class Once { Foo!Bar _bar; } class Bar { static Once _once; mixin(sync!(Once, "_once")); } class Foo(T = int) { CirBuff!T _buff; } template sync(T, string U = "this", size_t ITER = 0) { static if (ITER == __traits(derivedMembers, T).length) enum sync = ""; else { enum string mem = __traits(derivedMembers, T)[ITER]; enum string sync = "static if(! __traits(isVirtualMethod, " ~ U ~ "." ~ mem ~ ")) { }" ~ sync!(T, U, ITER+1); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10752.d ================================================ import imports.test10752; void main() { static assert(!__traits(compiles, priv)); static assert(!__traits(compiles, priv)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10981.d ================================================ void foo(int i) in { class X1 { void in_nested() pure in { assert(i); } // OK <- NG out { assert(i); } // OK <- NG body {} } } out { class X2 { void out_nested() pure in { assert(i); } // OK <- NG out { assert(i); } // OK <- NG body {} } } body { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10992.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -unittest unittest { } unittest { } unittest { } void main() { static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 3); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10992b.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -unittest version(none) {} else { unittest { } unittest { } unittest { } } void main() { static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 3); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test10993.d ================================================ module test10993; import core.demangle : demangleType; auto foo(T)(T a) { static immutable typeof(a) q; // pragma(msg, "foo: " ~ typeof(q).mangleof); return q; } struct test(alias fn) { bool ini = true; void* p; } auto fun() { auto x = foo!()(test!(a=>a)()); // pragma(msg, "fun: " ~ typeof(x).mangleof); return x; } void main() { const x = fun(); enum mangle_x = typeof(x).mangleof; // pragma(msg, "x : " ~ mangle_x); auto y = cast()x; enum mangle_y = typeof(y).mangleof; // pragma(msg, "y : " ~ mangle_y); enum demangle_x = demangleType(mangle_x); enum demangle_y = demangleType(mangle_y); static assert ("immutable(" ~ demangle_y ~ ")" == demangle_x); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11169.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- 1: false 2: true 3: true --- */ class A { abstract void foo(); } template MixinAbstractBar() { abstract void bar(); } class B1 : A { // Use pragma instead of static assert, in order to evaluate // __traits during ClassDeclaration.semantic(). pragma(msg, "1: ", __traits(isAbstractClass, typeof(this))); override void foo() {} } class B2 : A { pragma(msg, "2: ", __traits(isAbstractClass, typeof(this))); override void foo() {} abstract void bar(); } class B3 : A { pragma(msg, "3: ", __traits(isAbstractClass, typeof(this))); override void foo() {} mixin MixinAbstractBar!(); } void main() { static assert( __traits(compiles, { auto b = new B1(); })); static assert(!__traits(compiles, { auto b = new B2(); })); static assert(!__traits(compiles, { auto b = new B3(); })); } class B : A { // __traits(isAbstractClass) is not usable in static if condition. static assert (!__traits(isAbstractClass, typeof(this))); override void foo() { } } void main2() { B b = new B(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11225a.d ================================================ /* TEST_OUTPUT: --- WORKS --- */ import imports.test11225b; interface I {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11237.d ================================================ // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/test11237.sh struct Buffer { ubyte[64 * 1024] buffer; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11259.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=11259 version (Posix) { // smallest druntime module without imports on posix import core.sys.posix.libgen; static assert(__traits(isSame, __traits(parent, core.sys.posix.libgen), core.sys.posix)); static assert(__traits(isSame, core.sys.posix, __traits(parent, core.sys.posix.libgen))); static assert(__traits(isSame, __traits(parent, core.sys.posix), core.sys)); static assert(__traits(isSame, core.sys, __traits(parent, core.sys.posix))); } else { // smallest module without imports for windows import core.sys.windows.lmuseflg; static assert(__traits(isSame, __traits(parent, core.sys.windows.lmuseflg), core.sys.windows)); static assert(__traits(isSame, core.sys.windows, __traits(parent, core.sys.windows.lmuseflg))); static assert(__traits(isSame, __traits(parent, core.sys.windows), core.sys)); static assert(__traits(isSame, core.sys, __traits(parent, core.sys.windows))); } static assert(__traits(isSame, __traits(parent, core.sys), core)); static assert(__traits(isSame, core, __traits(parent, core.sys))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11371.d ================================================ version(D_SIMD) { __vector(long[2]) f() { __vector(long[2]) q; return q; } enum __vector(long[2]) v = f(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11471.d ================================================ // REQUIRED_ARGS: -profile void main() nothrow { // Error: asm statements are assumed to throw version(GNU) asm { ""; } else asm { nop; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11559upgradeoptlink.d ================================================ // REQUIRED_ARGS: -g // If this is failing, you need optlink 8.00.14 or higher string gen() { string m; foreach(i; 0..4096) m ~= "mixin(\"assert(0);\n\n\n\n\");\n"; return m; } void main() { mixin(gen()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11563.d ================================================ import imports.test11563std_traits; interface J : I {} // comment out to let compilation succeed struct A { } pragma(msg, moduleName!A); interface I {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11656.d ================================================ version(D_SIMD) { struct Foo { __vector(float[4]) x; } static assert(Foo.x.offsetof == 0); static assert(Foo.x.stringof == "x"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11824.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct Take(R) { public R source; private size_t _maxAvailable; alias R Source; @property bool empty() { return _maxAvailable == 0 || source.empty; } @property auto ref front() { return source.front; } void popFront() { source.popFront(); --_maxAvailable; } @property size_t length() const { return _maxAvailable; } } struct Repeat(T) { private T _value; enum bool empty = false; @property inout(T) front() inout { return _value; } void popFront() {} } Take!(Repeat!T) repeat(T)(T value, size_t n) { return typeof(return)(Repeat!T(value), n); } auto array(Range)(Range r) { alias E = typeof(r.front); //static if (hasLength!Range) { if (r.length == 0) return null; auto result = new E[](r.length); size_t i; static auto trustedGetAddr(T)(ref T t) @trusted nothrow pure { return &t; } foreach (e; r) { *trustedGetAddr(result[i]) = e; ++i; } return cast(E[])result; } } enum r = [1].repeat(1).array; static assert(r == [[1]]); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11914.d ================================================ // std.array @property bool empty(T)(in T[] a) { return !a.length; } @property ref T front(T)(T[] a) { return a[0]; } void popFront(T)(ref T[] a) { a = a[1 .. $]; } // std.typecons struct Tuple(T...) { T field; alias field this; } Tuple!T tuple(T...)(T args) { return typeof(return)(args); } // std.range template ElementType(R) { static if (is(typeof(R.init.front.init) T)) alias T ElementType; else alias void ElementType; } struct Repeat(T) { private T _value; enum bool empty = false; @property inout(T) front() inout { return _value; } void popFront() {} } Repeat!T repeat(T)(T value) { return Repeat!T(value); } struct Zip(R...) { //alias Tuple!(staticMap!(.ElementType, R)) ElementType; static if (R.length == 3) alias Tuple!(int, int, int) ElementType; static if (R.length == 2) alias Tuple!(int, int) ElementType; R ranges; this(R rs) { foreach (i, Unused; R) { ranges[i] = rs[i]; } } @property bool empty() { foreach (i, Unused; R) { if (ranges[i].empty) return true; } return false; } @property ElementType front() { ElementType result; return result; } void popFront() { foreach (i, Unused; R) { ranges[i].popFront(); } } ElementType opIndex(size_t n) { ElementType result; return result; } } auto zip(Rs...)(Rs ranges) { return Zip!Rs(ranges); } // std.algorithm template map(fun...) { auto map(Range)(Range r) { return MapResult!(fun, Range)(r); } } private struct MapResult(alias fun, R) { R _input; this(R input) { _input = input; } @property bool empty() { return _input.empty; } @property auto ref front() { return fun(_input.front); } void popFront() { _input.popFront(); } } auto cartesianProduct(R1, R2)(R1 range1, R2 range2) { return range2.map!((ElementType!R2 a) => zip(range1, repeat(a))); } auto cartesianProduct(R1, R2, RR...)(R1 range1, R2 range2, RR otherRanges) { return map!(a => tuple(a[0], a[1][0], a[1][1]))( cartesianProduct(range1, cartesianProduct(range2, otherRanges)) ); } // test void main() { foreach (i, j, k; cartesianProduct([1], [1], [1])) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test11980.d ================================================ void start() {} pragma(startaddress, start); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12009.d ================================================ struct RefCounted(T) { struct RefCountedStore { private struct Impl { T _payload; } private Impl* _store; } RefCountedStore _refCounted; ~this() { import core.stdc.stdlib : free; } } struct GroupBy(R) { struct SharedInput { Group unused; } struct Group { private RefCounted!SharedInput _allGroups; } } void main() { GroupBy!(int[]) g1; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1238.d ================================================ module test1238; import imports.test1238a; import imports.test1238b; void foo() { int qwert = zuiop; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12496.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=12496 final abstract class T1 { final abstract class C(uint value) { } alias Child = C!2; } void main() { static assert(__traits(isSame, __traits(parent, T1.Child), T1)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12511.d ================================================ module test12511; import imports.a12511; public class B { static void bar() { A.foo(0); } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12523.d ================================================ void test12523(inout(int)) { void check(T)() { T[] a; foreach (ref e; a) static assert(is(typeof(e) == T)); } check!(int)(); check!(inout(int))(); check!(inout(const(int)))(); check!(const(int))(); check!(immutable(int))(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12527.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=12527 @system: alias Fun = void function() @safe; pragma (msg, Fun.stringof); static assert(Fun.stringof == "void function() @safe"); alias Del = void delegate() @safe; pragma (msg, Del.stringof); static assert(Del.stringof == "void delegate() @safe"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12567a.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ deprecated module test12567a; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12567b.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ deprecated("message") module test12567b; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12567c.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: /* TEST_OUTPUT: --- compilable/test12567c.d(9): Deprecation: module `imports.a12567` is deprecated - This module will be removed in future release. --- */ import imports.a12567; void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12567d.d ================================================ // REQUIRED_ARGS: -d // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ import imports.a12567; void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12593.d ================================================ int[R] aa; // Place before the declaration of key struct struct R { int opCmp(ref const R) const { return 0; } //bool opEquals(ref const R) const { return true; } //size_t toHash() const nothrow @safe { return 0; } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12624.d ================================================ // REQUIRED_ARGS: -lib -Icompilable/extra-files // EXTRA_FILES: extra-files/imp12624.d // https://issues.dlang.org/show_bug.cgi?id=12624 struct SysTime { import imp12624; Rebindable!(immutable TimeZone) _timezone = UTC(); } class TimeZone { this(string , string , string ) immutable {} } class UTC : TimeZone { static immutable(UTC) opCall() { return _utc; } this() immutable { super("UTC", "UTC", "UTC"); } static _utc = new immutable(UTC); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12807.d ================================================ void foo(T)(ref T t) { } struct S { int impure() {assert(0);} alias impure this; } void main() pure { S s; foo(s); s.foo(); // triggering alias this violates purity, but ufcs matches } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12967.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: void foo() {} alias F = typeof(foo); const { void block_c() {} } immutable { void block_i() {} } inout { void block_w() {} } shared { void block_s() {} } shared const { void block_sc() {} } shared inout { void block_sw() {} } static assert(is(typeof(block_c) == F)); static assert(is(typeof(block_i) == F)); static assert(is(typeof(block_w) == F)); static assert(is(typeof(block_s) == F)); static assert(is(typeof(block_sc) == F)); static assert(is(typeof(block_sw) == F)); version (all) { const: void label_c() {} } version (all) { immutable: void label_i() {} } version (all) { inout: void label_w() {} } version (all) { shared: void label_s() {} } version (all) { shared const: void label_sc() {} } version (all) { shared inout: void label_sw() {} } static assert(is(typeof(label_c) == F)); static assert(is(typeof(label_i) == F)); static assert(is(typeof(label_w) == F)); static assert(is(typeof(label_s) == F)); static assert(is(typeof(label_sc) == F)); static assert(is(typeof(label_sw) == F)); class C { const { static void block_c() {} } immutable { static void block_i() {} } inout { static void block_w() {} } shared { static void block_s() {} } shared const { static void block_sc() {} } shared inout { static void block_sw() {} } static assert(is(typeof(block_c) == F)); static assert(is(typeof(block_i) == F)); static assert(is(typeof(block_w) == F)); static assert(is(typeof(block_s) == F)); static assert(is(typeof(block_sc) == F)); static assert(is(typeof(block_sw) == F)); version (all) { const: static void label_c() {} } version (all) { immutable: static void label_i() {} } version (all) { inout: static void label_w() {} } version (all) { shared: static void label_s() {} } version (all) { shared const: static void label_sc() {} } version (all) { shared inout: static void label_sw() {} } static assert(is(typeof(label_c) == F)); static assert(is(typeof(label_i) == F)); static assert(is(typeof(label_w) == F)); static assert(is(typeof(label_s) == F)); static assert(is(typeof(label_sc) == F)); static assert(is(typeof(label_sw) == F)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12979a.d ================================================ void parse() { asm pure nothrow @nogc @trusted {} asm @safe {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test12979b.d ================================================ // REQUIRED_ARGS: -w -de void foo() pure nothrow @nogc @safe { version(GNU) { asm pure nothrow @nogc @trusted { ""; } } else { asm pure nothrow @nogc @trusted { ret; } } } void bar()() { version(GNU) { asm pure nothrow @nogc @trusted { ""; } } else { asm pure nothrow @nogc @trusted { ret; } } } static assert(__traits(compiles, () pure nothrow @nogc @safe => bar())); void baz()() { version(GNU) { asm { ""; } } else { asm { ret; } } } // wait for deprecation of asm pure inference // static assert(!__traits(compiles, () pure => baz())); static assert(!__traits(compiles, () nothrow => baz())); // wait for deprecation of asm @nogc inference // static assert(!__traits(compiles, () @nogc => baz())); static assert(!__traits(compiles, () @safe => baz())); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13008.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: -d -de -dw /* TEST_OUTPUT* --- --- */ deprecated class Dep { } deprecated Dep depFunc1(); // error deprecated void depFunc2(Dep); // error ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13053.d ================================================ // PERMUTE_ARGS: -w -wi /* TEST_OUTPUT: --- --- */ @system: struct S { int[] a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13193.d ================================================ // REQUIRED_ARGS: -O -inline -c final class SharedLib { void getSymbol() {return getSymbolImpl();} void getSymbolImpl() {return getSymbol_();} /* add more intermediate functions to go slower */ void getSymbol_() {} } void test13193() { SharedLib ssllib; void bindFunc() {ssllib.getSymbol();} bindFunc(); /* add more of these to go slower */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 10 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 20 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 30 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 40 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 50 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 60 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 70 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 80 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 90 */ bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); bindFunc(); /* 100 */ } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13194.d ================================================ module test13194; class C13194 { static Object o = void; } struct S13194 { static Object o = void; } union U13194 { static Object o = void; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13226.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: -version=bug import imports.a13226; class C { // class C member m is not accessible version(bug) mixin(t!(typeof(this), "f")); else {} version(bug) mixin(u!(typeof(this), "v")); else {} void f() {} int v; // here is ok version(bug) {} else mixin(t!(typeof(this), "f")); version(bug) {} else mixin(u!(typeof(this), "v")); } struct S { // struct S member m is not accessible version(bug) mixin(t!(typeof(this), "f")); else {} version(bug) mixin(u!(typeof(this), "v")); else {} void f() {} int v; // here is ok version(bug) {} else mixin(t!(typeof(this), "f")); version(bug) {} else mixin(u!(typeof(this), "v")); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13242.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- main +alias apiSym1 a.expensiveArgs: 1 a.expensiveTemplate: 1 -alias apiSym1 +alias apiSym3 b.expensiveArgs: 3 b.expensiveTemplate: 3 -alias apiSym3 --- */ import imports.test13242a; void main() { pragma(msg, "main"); cheapFunc(); pragma(msg, "+alias apiSym1"); alias apiSym1 = .apiSym1; pragma(msg, "-alias apiSym1"); // imports.test13242a.apiSym2 is not analyzed. pragma(msg, "+alias apiSym3"); alias apiSym3 = .apiSym3; pragma(msg, "-alias apiSym3"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13281.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /* TEST_OUTPUT: --- 123 123u 123L 123LU 123.5 123.5F 123.5L 123.5i 123.5Fi 123.5Li (123.5+5.5i) (123.5F+5.5Fi) (123.5L+5.5Li) --- */ pragma(msg, 123); pragma(msg, 123u); pragma(msg, 123L); pragma(msg, 123uL); pragma(msg, 123.5); pragma(msg, 123.5f); pragma(msg, 123.5L); pragma(msg, 123.5i); pragma(msg, 123.5fi); pragma(msg, 123.5Li); pragma(msg, 123.5 +5.5i); pragma(msg, 123.5f+5.5fi); pragma(msg, 123.5L+5.5Li); static assert((123 ).stringof == "123"); static assert((123u ).stringof == "123u"); static assert((123L ).stringof == "123L"); static assert((123uL).stringof == "123LU"); static assert((123.5 ).stringof == "1.235e+2"); static assert((123.5f ).stringof == "1.235e+2F"); static assert((123.5L ).stringof == "1.235e+2L"); static assert((123.5i ).stringof == "1.235e+2i"); static assert((123.5fi).stringof == "1.235e+2Fi"); static assert((123.5Li).stringof == "1.235e+2Li"); static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13512.d ================================================ #!/opt/dmd//rdmd import std.stdio; void main () { writeln("we are here!"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1353.d ================================================ class A {} interface B {} interface C {} interface D(X) {} void fun() { class T : typeof(new A), .B, const(C), D!int {} version(none) { class U : int, float, __vector(int[3]) {} } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13600.d ================================================ // REQUIRED_ARGS: -g class Retry { alias bool delegate ( lazy void ) SuccessDecider; SuccessDecider success_decide; void on_retry ( ) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13668.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /* TEST_OUTPUT: --- tuple("id", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory") genProps --- */ class User : Entity!User { int id; } class Entity(T) { pragma(msg, generateProperties!T); /* Compiler runs pragma(msg) in semantic() phase, but it does not insert any members * in this class. Therefore getting __traits(allMembers, User) while evaluating * generateProperties!User should work. */ } template generateProperties(alias To) { string getProperties(alias Ta)() { string toRet = "genProps"; // This line is bad pragma(msg, __traits(allMembers, Ta)); return toRet; } enum generateProperties = getProperties!(To); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13858.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=13858 void foo() { assert(0); } void main() { int x = 0; LSwitch: switch (x) { case 0: break LSwitch; default: return; } foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test13902.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: void foo() { int a; int* bar() { return &a; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14275.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: import protection.bug.bug14275; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14317.d ================================================ // REQUIRED_ARGS: -O -profile -inline struct Range { private string s; char charAt(int unused1) { return s[0]; } } bool count(Range* r, int* unused2) { *unused2 = 0; int unused3; char c = r.charAt(0); return true; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14375.d ================================================ /* TEST_OUTPUT: --- --- */ interface IKeysAPI(string greetings) { static assert(greetings == "Hello world", greetings); } void main() { foreach (method; __traits(allMembers, IKeysAPI!("Hello world"))) { static assert (method.length, "Empty string from the compiler ??"); pragma(msg, method); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14528.d ================================================ // REQUIRED_ARGS: -o- // PERMTE_ARGS: import imports.a14528; class C { protected static void func() {} void test() { foo!func(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14666.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: module test14666; struct Location { import imports.test14666a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14747.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: -w int foo(Args...)() { int x; foreach (arg; Args) { static if(is(arg == int)) { return 0; } static if(is(arg == long)) { // fallthrough ++x; // this statement might be unreachable, but // UnrollStatement does not warn that. } } // no return } void main() { auto r1 = foo!(int)(); // return auto r2 = foo!(int, long)(); // return -> fallthrough (it's unreachable) auto r3 = foo!(long, int)(); // fallthough -> return static assert(!__traits(compiles, foo!(long)())); // fallthough static assert(!__traits(compiles, foo!(long, long)())); // fallthough -> fallthough } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14781.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: void impure() {} // impure auto fb1(T)() pure { int x; struct A(S) { void fc(T2)() { x = 1; // accessing pure function context is just ok impure(); // impure function call makes fc as impure } this(S a) {} } return A!int(); } auto fb2(T)() pure { int x; struct A(S) { void fc(T2)() { impure(); // impure function call makes fc as impure x = 1; // accessing pure function context is just ok } this(S a) {} } return A!int(); } void test1() { fb1!int().fc!int(); fb2!int().fc!int(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14838.d ================================================ // PERMUTE_ARGS: struct A(T) { ~this() {} } class C { A!int[1] array; } void test14838() pure nothrow @nogc @safe { C c; c.__xdtor(); // C.~this() will also be inferred to // pure nothrow @nogc @safe A!int[1] array; // scope destructor call does not cause attribute violation. } // ---- /* * This is a reduced test case comes from std.container.Array template, * to fix the semantic analysis order issue for correct destructor attribute inference. * * Before the bugfix: * 1. StructDeclaration('Array!int').semantic() instantiates * RangeT!(Array!int) at the `alias Range = ...;`, but * StructDeclaration('RangeT!(Array!int)').semantic() exits * with sizeok == SIZEOKfwd, because the size of _outer_ field is not yet determined. * 2. StructDeclaration('Array!int').semantic() succeeds to determine the size * (sizeok = SIZEOKdone). * 3. StructDeclaration('Array!int').buildOpAssign() will generate opAssign because * Array!int._data field has identity opAssign member function. * 4. The semantic3 will get called for the generated opAssign, then * 6-1. Array!int.~this() semantic3, and * 6-2. RefCounted!(Array!int.Payload).~this() semantic3 * will also get called to infer their attributes. * 5. In RefCounted!(Array!int.Payload).~this(), destroy(t) will be instantiated. * At that, TemplateInstance.expandMembers() will invoke runDeferredSemantic() * and it will re-run StructDeclaration('RangeT!(Array!int)').semantic(). * 6. StructDeclaration('RangeT!(Array!int)').semantic() determines the size * (sizeok = SIZEOKdone). Then, it will generate identity opAssign and run its semantic3. * It will need to infer RangeT!(Array!int).~this() attribute, then it requires the * correct attribute of Array!int.~this(). * * However, the Array!int.~this() attribute is not yet determined! [bug] * -> it's wongly handled as impure/system/throwable/gc-able. * * -> then, the attribute inference results for * RangeT!(Array!int).~this() and Array!int.~this() will be incorrect. * * After the bugfix: * In 6, StructDeclaration('RangeT!(Array!int)').semantic() will check that: * all base struct types of the instance fields have completed addition of * special functions (dtor, opAssign, etc). * If not, it will defer the completion of its semantic pass. */ void destroy14838(S)(ref S s) if (is(S == struct)) { s.__xdtor(); } struct RefCounted14838(T) { ~this() { T t; .destroy14838(t); } void opAssign(typeof(this) rhs) {} } struct RangeT14838(A) { A[1] _outer_; } struct Array14838(T) { struct Payload { ~this() {} } RefCounted14838!Payload _data; alias Range = RangeT14838!Array14838; } class Test14838 { Array14838!int[1] field; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14962.d ================================================ template map(fun...) { auto map(R)(R r) { return MapResult!(fun, R)(r); } } struct MapResult(alias fun, R) { R _input; @property bool empty() { return _input.length == 0; } @property auto front() { return fun(_input[0]); } void popFront() { _input = _input[1..$]; } } struct Foo { int baz(int v) { static int id; return v + id++; } void bar() { auto arr1 = [1, 2, 3]; auto arr2 = [4, 5, 6]; arr1.map!( // lambda1 i => arr2.map!( // lambda2 j => baz(i + j) ) ); } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test14973.d ================================================ template map(fun...) { auto map(R)(R r) { return MapResult!(fun, R)(r); } } struct MapResult(alias fun, R) { R _input; @property bool empty() { return _input.length == 0; } @property auto front() { return fun(_input[0]); } void popFront() { _input = _input[1..$]; } } class Foo { int baz() { return 1; } void bar() { auto s = [1].map!(i => baz()); // compiles auto r = [1].map!( // returns MapResult-1 // lambda1 i => [1].map!( // returns MapResult-2 // lambda2 j => baz() ) ); // compiles <- error // When lambda1 is called in MapResult-1.front(), it was changed to // TOKfunction in functionResolve. But in that time, MapResult-2 semantic3 // was not yet finished, then the lambda2 call in MapResult-2.front() // could not access to enclosing scope frame to call baz(). // To fix the issue, MapResult-2 semantic3 should be finished during the // lambda1 body analysis. } } class Bar { int baz; void bar() { auto s = [1].map!(i => baz); // compiles auto r = [1].map!( // lambda1 i => [1].map!( // lambda2 j => baz ) ); // compiles <- error } } /*******************************************/ struct ChunkByImpl(alias eq) { struct Group { int[] start; int[] current; void popFront() { // In here: // SortedRange.pred == (a, b) => a @ test14978b() // ChunkByImpl.eq == (a, b) => pred(a, b) @ SortedRange.groupBy() // // The context deduction should be: // First pred is deduced to function pointer, // and then, eq is also deduced to function pointer because pred is function pointer. // // Therefore, when ChunkByImpl is instantiated in groupBy(), its semantic3 // needs to be invoked to analyze ??? eq(start, current); } } } struct SortedRange(alias pred) { int[] input; auto groupBy() { ChunkByImpl!( (a, b) => pred(a, b) ) r; } } void test14973b() { SortedRange!( (a, b) => a ) r; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15019.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=15019 // dmd -m32 -c all.d import std.string; struct Color() { static fromHex(char[] s) { import std.conv; s.to!ubyte; } } Color!() RGB ; struct Matrix(T, int R, int C) { Vector!(T, C) row_t; T[C] v; // all elements /// Covnerts to pretty string. string toString() const { try return format("%s", v); catch assert(false); // should not happen since format is right } } // GLSL is a big inspiration here // we defines types with more or less the same names template mat2x2(T) { Matrix!(T, 2, 2) mat2x2; } template mat3x3(T) { Matrix!(T, 3, 3) mat3x3; } template mat4x4(T) { Matrix!(T, 4, 4) mat4x4; } alias mat2x2 mat2; alias mat3x3 mat3; // shorter names for most common matrices alias mat4x4 mat4; string definePostfixAliases(string type) { return "alias " ~ type ~ "!byte " ~ type ~ "b;\n" ~ "alias " ~ type ~ "!ubyte " ~ type ~ "ub;\n" ~ "alias " ~ type ~ "!short " ~ type ~ "s;\n" ~ "alias " ~ type ~ "!ushort " ~ type ~ "us;\n" ~ "alias " ~ type ~ "!int " ~ type ~ "i;\n" ~ "alias " ~ type ~ "!uint " ~ type ~ "ui;\n" ~ "alias " ~ type ~ "!long " ~ type ~ "l;\n" ~ "alias " ~ type ~ "!ulong " ~ type ~ "ul;\n" ~ "alias " ~ type ~ "!float " ~ type ~ "f;\n" ~ "alias " ~ type ~ "!double " ~ type ~ "d;\n"; } // define a lot of type names mixin(definePostfixAliases("mat2")); mixin(definePostfixAliases("mat3")); mixin(definePostfixAliases("mat4")); import std.string; struct Vector(T, int N) { T[N] v; string toString() { try return format("%s", v); catch assert(false); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15056.d ================================================ nothrow: version (Windows) { version (LP_64) import core.stdc.stdlib; else // doesn't currently work b/c SEH remains present even in nothrow code void* alloca(size_t) { return null; } } else import core.stdc.stdlib; struct S { ~this() nothrow {} } S foo(void* p = alloca(1234)) { return S(); } int main() { foo(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15150.d ================================================ // PERMUTE_ARGS: module test15150; import imports.test15150a; import imports.test15150b; enum y = x; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15177.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: // COMPILED_IMPORTS: imports/test15117a.d import users = imports.test15117a; void RunApiTest(T...)() { foreach (name; __traits(allMembers, users)) { // 3. list the name of TyepInfoStructDeclaration, // but it's just internal symbol and invisible. mixin("alias func = users . " ~ name ~ ";"); } } void main() { // 1. run semantic3 of users.test_usr_1 users.test_usr_1(); RunApiTest!(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15326.d ================================================ // REQUIRED_ARGS: -w -c -unittest version (unittest) private struct _NestedSym_ { static if ((void*).sizeof == 8) { pragma(msg, "64"); } else { pragma(msg, "32"); } version (X86_64) { pragma(msg, "X86_64"); } else { pragma(msg, "Not 64"); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1537.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=1537 void foo(char[] s) { int x = -1; while (s.length) { char c = s[0]; if (c == '}') break; assert (c >= '0' && c <= '9', s[0..$]); if (x == -1) x = 0; } } /**************************************/ enum bug4732 = 42; static assert( __traits(identifier, bug4732) == "bug4732"); /**************************************/ template Compileable(int z) { bool OK=true;} int bug5245a(U)() { { enum T { a = 5 } T v; } { enum T { a = 6 } T w; } return 91; } int bug5245b(U)() { { struct T { int a = 2; } T v; } { union T { int a = 3; } T w; } return 91; } int bug5245c(U)() { { struct T { int a = 2; } T v; } { class T { int a = 3; } T w; } return 91; } int bug5245d(U)() { { enum T { a = 3 } T w; } { struct T { int a = 2; } T v; } return 91; } static assert(!is(typeof(Compileable!(bug5245a!(int)()).OK))); static assert(!is(typeof(Compileable!(bug5245b!(int)()).OK))); static assert(!is(typeof(Compileable!(bug5245c!(int)()).OK))); static assert(!is(typeof(Compileable!(bug5245d!(int)()).OK))); /**************************************/ class Bug5349(T) // segfault D2.051 { int x; static int g() { class B { int inner() { return x; // should not compile } } return (new B).inner(); } int y = g(); } static assert(!is(typeof(Bug5349!(int)))); /**************************************/ class Bug4033 {} class Template4033(T) { static assert(is(T : Bug4033)); } alias Template4033!(Z4033) Bla; class Z4033 : Bug4033 { } /**************************************/ struct Bug4322 { int[1] a = void; } void bug4322() { Bug4322 f = Bug4322(); Bug4322 g = Bug4322.init; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15389_x.d ================================================ import test15389_y; //struct ns extern (C++, ns) { class X { test15389_y.ns.Y a; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15389_y.d ================================================ import test15389_x; //struct ns extern (C++, ns) { class Y { test15389_x.ns.X b; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15402.d ================================================ // REQUIRED_ARGS: -de struct S { package int field; } void test() { S s; s.field = 1; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15464.d ================================================ class C15464 { static immutable field = 0; } struct S15464 { this(int i) { } } void issue15464(T)() @S15464(T.field) { } void main() { issue15464!C15464(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15490.d ================================================ // REQUIRED_ARGS: -o- -inline // PERMUTE_ARGS: module test15490; import imports.imp15490a; import imports.imp15490b; void main() { regex(); listenTCP(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15519_x.d ================================================ import test15519_y; extern(C++, ns) { class X { test15519_y.ns.Y v; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15519_y.d ================================================ import test15519_x: NS = ns; // fails //import test15519_x; alias test15519_x.ns NS; // works extern(C++, ns) { class Y { NS.X v; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15550.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: struct Vector(T, int N) { void opDispatch(string, U)(U) { } void baz(string, U)(U) { } } static assert(!is(typeof(Vector!(int, 2)._isMatrix))); static assert(!is(typeof(Vector!(int, 2).baz!"_isMatrix"))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15565.d ================================================ alias X2 = X; extern (C++, ns) struct X {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15578.d ================================================ __gshared private: int j; extern(C++, ns) int k; void f() { j = 0; // works as expected k = 0; // Error: variable foo.ns.k is private } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15618.d ================================================ class Base { ~this() {} size_t x = 4; } interface Interface { int Method(); } class Derived : Base, Interface { size_t y = 5; int Method() { return 3; } } static assert(Derived.x.offsetof == (void*).sizeof * 2); static assert(Derived.y.offsetof == (void*).sizeof * 4); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15668.d ================================================ void foo ( int line = __LINE__ ) ( string msg = "" ) { static assert (line == 8); } void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15762.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=15762 enum Windows1252Char : ubyte { init } void main() @safe { ubyte[] a = [1, 2, 3, 4]; auto aw = cast(Windows1252Char[]) a; auto caw = cast(const(Windows1252Char)[]) a; const(ubyte)[] c = [1, 2, 3, 4]; auto d = cast(const(ubyte)[]) c; auto e = cast(const(Windows1252Char)[]) c; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15780.d ================================================ // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=15780 import std.typecons; //import std.stdio; void foo(alias fields)() { foreach(i, field; fields) { enum string a = fields[i]; // OK enum string b = field; // not OK with 2.069.2 ??? //writeln(field); } } void main() { foo!(tuple("H", "I"))(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15784.d ================================================ // PERMUTE_ARGS: template AddField(T) { T b; this(Args...)(T b, auto ref Args args) { this.b = b; this(args); } } template construcotrs() { int a; this(int a) { this.a = a; } } class B { mixin construcotrs; mixin AddField!(string); } class C : B { this(A...)(A args) { // The called super ctor is an overload set. super(args); } } struct S { mixin construcotrs; mixin AddField!(string); } void main() { auto s = S("bar", 15); auto c = new C("bar", 15); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15785.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- --- */ import imports.test15785; class Derived : Base, IBase2 { override void foo() { super.foo(); bar(); // Base.bar(); // doesn't work yet due to a bug in checkAccess faz(); // IBase2.faz(); // doesn't work yet due to a bug in checkAccess } typeof(super).T t; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15802.d ================================================ extern(C++) { template Foo(T) { static int boo(); } } void main() { string s = Foo!(int).boo.mangleof; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15856.d ================================================ // REQUIRED_ARGS: -transition=checkimports -de // PERMUTE_ARGS: /* TEST_PUTPUT: --- --- */ class Foo { import imports.a15856; struct Bar { c_long a; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15898.d ================================================ // REQUIRED_ARGS: -O // https://issues.dlang.org/show_bug.cgi?id=15898 int addAssignSimple(int[] , const(int)[] ) { uint c; return c; } void mulKaratsuba(int[] result, const(int)[] x, const(int)[] y, int[] ) { const(int)[] y1 = y; int[] newscratchbuff; int[] resultHigh = result; bool ysmaller2 = x.length >= y1.length; newscratchbuff[0..y1.length] = resultHigh; mulKaratsuba( resultHigh[1..$], ysmaller2 ? x[1..$] : y1, ysmaller2 ? y1 : x, newscratchbuff[y1.length..$] ); addAssignSimple(resultHigh[1..$], newscratchbuff[0..y1.length]); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15907.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: import imports.imp15907; struct S { private int a; } void test() { process(S()); } static assert(allMembers!S == ["a"]); enum sz = __traits(getMember, imports.imp15907, "PrivateStruct").sizeof; static assert(__traits(hasMember, imports.imp15907, "privateVar")); typeof(__traits(getMember, PublicStruct, "S").init) s; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test15925.d ================================================ /* REQUIRED_ARGS: -transition=import -transition=checkimports PERMUTE_ARGS: TEST_OUTPUT: --- compilable/test15925.d(17): Deprecation: local import search method found variable `imp15925.X` instead of nothing --- */ mixin template Import() { import imports.imp15925; } class Foo { mixin Import!(); static assert(X == 1); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16013a.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16013 struct Impl { S _payload; } /* Only this line has changed from above. */ struct RefCounted { void opAssign(RefCounted rhs) {} void opAssign(S rhs) {} S refCountedPayload() { return S.init; } alias refCountedPayload this; } struct S { RefCounted s; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16013b.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16013 S s; /* Only this line has changed from above. */ struct RefCounted { void opAssign(RefCounted rhs) {} void opAssign(S rhs) {} S refCountedPayload() { return S.init; } alias refCountedPayload this; } struct S { RefCounted s; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16031.d ================================================ // REQUIRED_ARGS: -fPIC -lib // PERMUTE_ARGS: // DISABLED: win32 win64 extern void throwing(); void foo() { // create plenty of symbols, so that the catch references get a high symbol index static int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; try { throwing(); } catch (Exception) { } } void bar() { try { throwing(); } // symbol index for DW.ref._D9Exception7__ClassZ // gets reused for another object and is out of bounds catch (Exception) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16037.d ================================================ /* REQUIRED_ARGS: -dip1000 */ // https://issues.dlang.org/show_bug.cgi?id=16037 @safe: void testXXX () @nogc { Object o; scope bool delegate (Object) alwaysFalse = (Object y) { return false; }; scope c1 = o !is null ? (Object y) { return o is y; } : alwaysFalse; } auto f() @nogc { int a; void g(){ a=1; } scope h=&g; h(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16080.d ================================================ // REQUIRED_ARGS: -lib -Icompilable/imports // COMPILED_IMPORTS: extra-files/test16080b.d // EXTRA_FILES: imports/imp16080.d // https://issues.dlang.org/show_bug.cgi?id=16080 import imp16080; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16083.d ================================================ template Alias(Stuff...) { alias Alias = Stuff; } enum A { a = 0 } enum B { b = 0 } enum C { c = "abc" } enum D { d = "abc" } static assert(is(typeof(Alias!(A.a)[0]) == A)); static assert(is(typeof(Alias!(B.b)[0]) == B)); static assert(is(typeof(Alias!(C.c)[0]) == C)); static assert(is(typeof(Alias!(D.d)[0]) == D)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16085.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: import imports.imp16085; void test() { S s; assert(s.functionAndFunction() == Pass()); assert(s.staticFunctionAndFunction() == Pass()); // assert(S.staticFunctionAndFunction() == Pass()); // erroneous not accessible error assert(s.functionAndTemplate() == Pass()); assert(s.templateAndTemplate() == Pass()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16088.d ================================================ // REQUIRED_ARGS: -Jcompilable/imports/ // EXTRA_FILES: imports/imp16088.d // https://issues.dlang.org/show_bug.cgi?id=16088 void bar(string x) {} auto foo() { import("imp16088.d").bar; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16107.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16107 bool check() { bool result = false; result |= false; if (result) goto ret; result |= false; if (result) {} ret: return true; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16183.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16183 void main() { const string g(const string s) { return s; } enum string y = ['f'] ~ g("g"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16225.d ================================================ // REQUIRED_ARGS: -O -m64 // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=16225 struct C { hash_t foo( ) { int y; return ((cast(ubyte*)&y)[1]); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16273.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16273 class A() { alias MyD = D!(); } class B { void f() {} alias MyA = A!(); } class C : B { override void f() {} } class D() : A!() { void g() { new C; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16292.d ================================================ /* PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=16292 void main() { goto label; if (makeS()[0]) { label: } } S makeS() { return S(); } struct S { int opIndex(size_t i) { return 0; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16303.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16303 void yayf(void function(int*) fp); void yayd(void delegate(int*) dg); void bar() { void function(const(int)* p) fp; yayf(fp); // should be good but produces error void delegate(const(int)* p) dg; yayd(dg); // should be good but produces error } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16340.d ================================================ // REQUIRED_ARGS: -w version(unittest) template symsToStrs(fields...) { static if (fields.length == 0) enum symsToStrs = ["hello"]; else enum symsToStrs = ["world"]; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16348.d ================================================ // EXTRA_SOURCES: imports/test16348.d module mypackage.foo; void bug() { // removing the if-else also removes the segfault if (true) {} else { import mypackage.bar; auto b = bar(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16460.d ================================================ module imports.test16460; void bug() { auto d1 = (){ import imports.imp16460; return val; }; enum d2 = (){ import imports.imp16460; return val; }; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16492.d ================================================ // ARG_SETS: -debug; -o-; -debug -dip1000 // https://issues.dlang.org/show_bug.cgi?id=16492 void mayCallGC(); void test() @nogc pure { debug new int(1); debug { mayCallGC(); auto b = [1, 2, 3]; b ~= 4; } } void debugSafe() @safe { debug unsafeSystem(); debug unsafeTemplated(); } void unsafeSystem() @system {} void unsafeTemplated()() { int[] arr; auto b = arr.ptr; } void debugSafe2() @safe { char[] arr1, arr2; debug unsafeDIP1000Lifetime(arr1, arr2); char* ptr; char[] arr; debug ptr = arr.ptr; } void unsafeDIP1000Lifetime()(ref char[] p, scope char[] s) { p = s; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16525.d ================================================ static immutable templ(alias var) = 1234; struct D { int memvar; } extern(C++) struct CPP { int memvar; } void test() { pragma(msg, templ!(D.memvar)); pragma(msg, templ!(CPP.memvar)); // root cause, C++ member variables have no mangling pragma(msg, CPP.memvar.mangleof); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16540.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=16540 @safe: void foo(scope lazy int* f) @nogc { } void bar1() @nogc { foo(new int(5)); // It does not understand that the new here is wrapped in an invisible delegate } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16563.d ================================================ void test16563() { align(1) struct S { uint i; ubyte b; static assert(S.sizeof == 5); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16570.d ================================================ static immutable int _a = 0; enum Regression { a = _a, } static assert(is(typeof(Regression.a) == immutable(Regression))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16572.d ================================================ class K { inout(int) f() inout { return var; } void bug() { auto d = &f; d(); } int var; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16574.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16574 template Recursive(T) if (is(T == class)) { // fails because T is still forward referenced // speculative determineSize must not set type to error static assert (!__traits(compiles, { new T; })); // known size of class static assert (is(typeof(T.init) == T)); alias Recursive = T; } // must be resolvable class C { Recursive!C r; } template Recursive(T) if (is(T == struct)) { // fails because T is still forward referenced // speculative determineSize must not set type to error static assert (!__traits(compiles, { T t; })); // no size yet for struct static assert (!is(typeof(T.init))); alias Recursive = T*; } // must be resolvable struct S { Recursive!S r; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16578a.d ================================================ // REQUIRED_ARGS: -debug // https://issues.dlang.org/show_bug.cgi?id=16578 string[string] opts; void main() { string arg; switch (arg) { case "-f": opts["fore"] = ""; break; debug { case "-throw": opts["throw"] = ""; break; } default: } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16578b.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16578 void main() { string[string] opts; switch (2) { case 0: opts["a"] = ""; { case 1: break; } default: } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16607.d ================================================ struct A(T) { T t; // causes A to be SIZEOKfwd b/c B (passed as T) isn't yet done // On the 2nd semantic pass through A, _scope of C got set again, // even though the struct was already done. struct C { } } struct B { A!B* a; // causes instantiation of A!B, but can finish semantic with A!B still being fwdref } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16621.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16621 template xxx() { Vector2f xxx() { return this; } } struct Vector2f { mixin xxx!(); alias xxx this; } void foo(ref Vector2f pos); void test() { Vector2f v; foo(v); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16627.d ================================================ void test() { int a; struct Field { this(this) { ++a; } ~this() { --a; } } struct S { Field field; // generates __fieldPostblit, __fieldDtor, and opAssign } static assert(__traits(isNested, Field)); static assert(!__traits(isNested, S)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16685.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=16685 struct Id { ushort value; } enum Id x = Id(5); struct S(ushort A) {} alias CannotCreateFromValue = S!(x.value); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1673.d ================================================ module test1673; template Foo(T...) { } template Bar(T...) { template Doo(T...) { } } template Tuple(T...) { alias Tuple = T; } void main() { static assert( __traits(isTemplate, Foo)); static assert(!__traits(isTemplate, Foo!int)); static assert(!__traits(isTemplate, main)); static assert( __traits(isTemplate, Bar)); static assert(!__traits(isTemplate, Bar!int)); static assert( __traits(isTemplate, Bar!(int).Doo)); static assert(!__traits(isTemplate, Bar!(int).Doo!int)); alias Tup = Tuple!(Foo, Foo!int, Bar, Bar!int, Bar!(int).Doo, Bar!(int).Doo!int); static assert( __traits(isTemplate, Tup[0])); static assert(!__traits(isTemplate, Tup[1])); static assert( __traits(isTemplate, Tup[2])); static assert(!__traits(isTemplate, Tup[3])); static assert( __traits(isTemplate, Tup[4])); static assert(!__traits(isTemplate, Tup[5])); } /// test overloads void foo_over() { } void foo_over(T : int)(T) { } void foo_over(T : float)(T) { } static assert(__traits(isTemplate, foo_over)); /// ditto void bar_over() { } void bar_over(int) { } static assert(!__traits(isTemplate, bar_over)); /// alias to overloads alias a_foo_over = foo_over; static assert(__traits(isTemplate, a_foo_over)); /// ditto alias a_bar_over = bar_over; static assert(!__traits(isTemplate, a_bar_over)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16747.d ================================================ /* PERMUTE_ARGS: */ class C { @safe ~this() { } } class D : C { } void fwd() @safe { scope o = new Object(); scope c = new C(); scope d = new D(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test16798.d ================================================ /* REQUIRED_ARGS: -mv=its.a.dessert.topping=imports/imp16798.d -mv=its.a.floorwax=imports/ PERMUTE_ARGS: TEST_OUTPUT: --- it's a floor wax it's a dessert topping --- */ import its.a.floorwax.wax16798; import its.a.dessert.topping; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17057.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: class LeClass { import std.stdio; } void main() { static assert([__traits(allMembers, LeClass)] == ["toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17059.d ================================================ mixin template impl() { alias T = typeof(this); enum doImplement = is(T : I); static if (doImplement) {} } interface I {} class A : I {mixin impl;} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17130.d ================================================ class Base { this() shared {} this() {} } class Derived1 : Base { this() { // implicit super(); } } class Derived2 : Base { // implicit this() } class Base2 { this() shared {} } class Derived3 : Base2 { // implicit this() shared } void test() { auto d2 = new Derived2; auto d3 = new shared(Derived3); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17143.d ================================================ import std.typecons : tuple; enum foo = tuple(1, 2).expand; pragma(msg, typeof(foo).stringof); pragma(msg, foo.stringof); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17168.d ================================================ // REQUIRED_ARGS: -O // PERMUTE_ARGS: void fn(uint x){uint a = 0 << x;} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17215.d ================================================ // REQUIRED_ARGS: -O version (X86_64): alias vec = __vector(int[4]); vec binop(vec a) { vec b = a; return b; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17339.d ================================================ void foo(alias param)() { } const CONST1 = 1; const CONST2 = 1; static assert(&foo!CONST1 !is &foo!CONST2); static assert(foo!CONST1.mangleof != foo!CONST2.mangleof); immutable IMM1 = 1; immutable IMM2 = 1; static assert(&foo!IMM1 !is &foo!IMM2); static assert(foo!IMM1.mangleof != foo!IMM2.mangleof); // Behaves different for manifest constants! enum ENUM1 = 1; enum ENUM2 = 1; static assert(&foo!ENUM1 is &foo!ENUM2); static assert(foo!ENUM1.mangleof == foo!ENUM2.mangleof); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17349.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=16538 const(int) retConst1(); int retConst2(); auto retConst = [&retConst1, &retConst2]; const(int*) retConstPtr1(); const(int)* retConstPtr2(); auto retConstPtr = [&retConstPtr1, &retConstPtr2]; void constArray1(const(int)[1]); void constArray2(const(int[1])); auto constArray = [&constArray1, &constArray2]; const(int)[] retConstSlice1(); const(int[]) retConstSlice2(); auto retConstSlice = [&retConstSlice1, &retConstSlice2]; void constSlice1(const(int)[]); void constSlice2(const(int[])); auto constSlice = [&constSlice1, &constSlice2]; void ptrToConst1(const(int)*); void ptrToConst2(const(int*)); auto ptrToConst = [&ptrToConst1, &ptrToConst2]; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17352.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17352 void bug(Args...)() { } void test(bool coin) { if (coin) { string foobar; bug!foobar(); } else { string foobar; bug!foobar(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17373.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17373 interface Foo { void visit (int); } interface Bar { void visit(double); } interface FooBar : Foo, Bar {} static assert(__traits(getOverloads, FooBar, "visit").length == 2); interface Fbar { void visit(char); void visit(double); } interface Triple : Foo, Bar, Fbar {} static assert(__traits(getOverloads, Triple, "visit").length == 3); interface InheritanceMadness : FooBar, Triple {} static assert(__traits(getOverloads, Triple, "visit").length == 3); interface Simple { int square(int); real square(real); } static assert(__traits(getOverloads, Simple, "square").length == 2); // https://issues.dlang.org/show_bug.cgi?id=19064 interface InputStream {} interface OutputStream{} interface Stream : InputStream, OutputStream{} interface ConnectionStream : Stream { @property bool connected() const; void close(); } static assert(__traits(getOverloads, ConnectionStream, "connected").stringof == "tuple(connected)"); static assert(__traits(getOverloads, ConnectionStream, "close").stringof == "tuple(close)"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17399.d ================================================ /* REQUIRED_ARGS: -inline */ // https://issues.dlang.org/show_bug.cgi?id=17399 pragma(inline, true) uint addu(uint x, uint y, ref bool overflow) { uint r = x + y; if (r < x || r < y) overflow = true; return r; } void foo() { uint a, b; bool over; addu(a, b, over); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17419.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17419 extern (C) int fooc(); alias aliasc = fooc; static assert(__traits(getLinkage, fooc) == "C"); static assert(__traits(getLinkage, aliasc) == "C"); extern (D) int food(); extern (C++) int foocpp(); extern (Windows) int foow(); extern (Pascal) int foop(); extern (Objective-C) int fooobjc(); extern (System) int foos(); static assert(__traits(getLinkage, food) == "D"); static assert(__traits(getLinkage, foocpp) == "C++"); static assert(__traits(getLinkage, foow) == "Windows"); static assert(__traits(getLinkage, foop) == "Pascal"); static assert(__traits(getLinkage, fooobjc) == "Objective-C"); version (Windows) static assert(__traits(getLinkage, foos) == "Windows"); else static assert(__traits(getLinkage, foos) == "C"); extern (C) int global; static assert(__traits(getLinkage, global) == "C"); static assert(__traits(getLinkage, typeof(fooc)) == "C"); static assert(__traits(getLinkage, typeof(&fooc)) == "C"); void bar() { void nested() { } static assert(__traits(getLinkage, typeof(&nested)) == "D"); } class FooD {} interface FooDInterface {} extern (C++) class FooCpp {} extern (C++) struct FooCppStruct {} extern (C++) interface FooCppInterface {} static assert(__traits(getLinkage, FooD) == "D"); static assert(__traits(getLinkage, FooDInterface) == "D"); static assert(__traits(getLinkage, FooCpp) == "C++"); static assert(__traits(getLinkage, FooCppStruct) == "C++"); static assert(__traits(getLinkage, FooCppInterface) == "C++"); version (D_ObjectiveC) { extern (Objective-C) interface FooObjC {} static assert(__traits(getLinkage, FooObjC) == "Objective-C"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17421.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17421 import core.stdc.stdarg; void novar() {} extern(C) void cstyle(int, ...) {} extern(C++) void cppstyle(int, ...) {} void dstyle(...) {} void typesafe(int[]...) {} static assert(__traits(getFunctionVariadicStyle, novar) == "none"); static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17468.d ================================================ // PERMUTE_ARGS: struct S { const char* path; @disable this(); this(const(char)* path) { this.path = path; } } const S CONST_S = S("/tmp".ptr); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17512.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17512 struct A { int _value; bool _hasValue; auto ref getOr(int alternativeValue) { return _hasValue ? _value : alternativeValue; } } A a; // https://issues.dlang.org/show_bug.cgi?id=18661 struct S0(T) { int a; auto ref immutable(int) getA() { return a; } } alias B = S0!int; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1754.d ================================================ module test1754; import imports.test1754a; import imports.test1754b; void foo() { bar(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17541.d ================================================ /* EXTRA_SOURCES: imports/test17541_2.d imports/test17541_3.d */ // https://issues.dlang.org/show_bug.cgi?id=17541 module one; import two; import three; struct BB { enum MAX_NUM_FIBERS = 4096; TWOR!1 t; TT!(int) tt; auto foo() { tt.insertabcdefg(1); } } BB bb; @nogc bar() { bb.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17545.d ================================================ /* TEST_OUTPUT: --- tuple((Attrib)) --- */ // https://issues.dlang.org/show_bug.cgi?id=17545 module example; struct Attrib {} @Attrib enum TEST = 123; pragma(msg, __traits(getAttributes, __traits(getMember, example, "TEST"))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17548.d ================================================ // REQUIRED_ARGS: -c module test17548; struct S1 { void foo(scope S2 arg) {} int myField; } enum cnst = 4321; import imports.fwdref2_test17548; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17590.d ================================================ // REQUIRED_ARGS: -o- void lazyfun(scope lazy int a) @nogc; // Test that returning a local _static_ struct does not lead to allocation of a closure. auto foo_static(int a, bool b) @nogc { static struct SInside {} SInside res; lazyfun(a); return res; } // Test that returning a local _non-static_ struct that does not reference any local variable does not lead to allocation of a closure. auto foo_nonstatic(int a, bool b) @nogc { struct SInside {} SInside res; lazyfun(a); return res; } // Test that returning a local non-static struct that references a local variable does lead to allocation of a closure. static assert(!__traits(compiles, () @nogc => goo(1))); static assert(__traits(compiles, () => goo(1))); auto goo(T)(T a) { struct SInside { T foo() { return a; } } SInside res; lazyfun(a); return res; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17752.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17752 // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- --- */ void main (string[] args) { switch (args.length) { // initialization not done on purpose is allowed int x = void; default: break; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17782.d ================================================ void main() { string str = q"_DLANG 123 _DLANG"; assert( str == "123\n" ); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17791.d ================================================ deprecated("A deprecated class") { class DepClass { } } class NewClass { } void main() { // test that a symbol (which is not likely to be deprecated) // is not depercated static assert(!__traits(isDeprecated, int)); // check that a class marked deprecated "isDeprecated" static assert(__traits(isDeprecated, DepClass)); // check that a class not marked deprecated is not deprecated static assert(!__traits(isDeprecated, NewClass)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17807.d ================================================ // REQUIRED_ARGS: -o- -w int bug17807(){ int y=0; Lswitch: switch(2){ { case 0: break; } enum x=0; struct S{ enum x=0; } int foo(){ return 0; } default: y=x+S.x+foo(); static foreach(i;1..5) case i: break Lswitch; } return y; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17819.d ================================================ static if (__traits(allMembers, __traits(parent,{}))[0]=="object") { pragma(msg, "compiled in!"); enum test = 0; } static foreach (m; __traits(allMembers, __traits(parent,{}))) { pragma(msg, m.stringof); mixin("enum new"~m~"=`"~m~"`;"); } static assert([__traits(allMembers, __traits(parent,{}))] == ["object", "test", "newobject", "newWorld", "newBuildStuff", "World", "BuildStuff"]); struct World { mixin BuildStuff; } template BuildStuff() { static foreach(elem; __traits(allMembers, typeof(this))) {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17853.d ================================================ // Switch with no braces & empty case should compile int main() { int ob = 1; final switch (ob) case 0: case 1: break; return ob; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17906.d ================================================ // REQUIRED_ARGS: -de // https://issues.dlang.org/show_bug.cgi?id=18647 deprecated void main () { Object o = new Object; delete o; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17908.d ================================================ // PERMUTE ARGS: @disable void foo() {} void foo(int) {} alias g = foo; // make sure the order of declaration // doesn't change anything void bar(int) {} @disable void bar() {} alias h = bar; void main() { g(10); h(10); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17942.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17942 alias AliasSeq(TList...) = TList; void test() { enum A = AliasSeq!(1); static assert(A[0] == 1); static assert(B[0] == 2); } enum B = AliasSeq!(2); enum C = AliasSeq!(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17970.d ================================================ shared struct Shared { static Shared make() { return Shared(); } ~this() { } } shared struct Foo { ~this() { } } struct Inner { ~this() {} } struct Outer { shared(Inner) inner; } void main() { Foo x = Foo(); auto s = Shared.make(); Outer _; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test17991.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17991 import imports.test17991a, imports.test17991a.a; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18000.d ================================================ // REQUIRED_ARGS: -dip1000 // https://issues.dlang.org/show_bug.cgi?id=18000 struct File { @safe @nogc: ~this() scope { } void* f; } void test() @safe @nogc { scope File x; x = File(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18020.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18020 void bug(T)(T t) { t.opCmp(t); } alias bugi = bug!(typeof(new class{})); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18030.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18030 struct S(T) { T var; pragma( msg, "Inside S: func() is ", __traits(getProtection, __traits(getMember, T, "func")) ); } class C { alias Al = S!C; static void func(U)(U var) { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18099.d ================================================ /* REQUIRED_ARGS: -betterC */ // https://issues.dlang.org/show_bug.cgi?id=18099 struct D { static struct V { ~this() { } } V get() { V v; return v; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18115.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18115 int test() { if (test.stringof.length > 6 && test.stringof[$-7..$] == "1234567") {} return 0; } enum a = test(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18199.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18199 // // struct initializer cases // // original error report struct Bla { int delegate(int, int) fun; } Bla bla1 = Bla((int a, int b) { return a + b; }); Bla bla2 = {(int a, int b) { return a + b; }}; // yielded error // additional error report with memberName:expression syntax struct Foo { int function(int) bar; int function(int) bar2; } Foo foo = { bar : function(x) { return 2 * x; }, // yielded error bar2 : (x) => 2 * x, }; struct MyStruct { int function() f; int delegate() d; } // confirm that ambiguous cases assume struct initializer MyStruct ambiguous_1 = {}; MyStruct ambiguous_2 = { { return 1 + 1; } }; // statement-holding function literal variants not covered above static MyStruct function_and_delegate_keywords = { function () { return 1 + 1; }, delegate () { return 1 + 1; } }; // // function literal initializer cases // alias IntFun = int function(); alias VoidFun = void function(); IntFun colon_at_top_level = { return 1 + 1; }; IntFun block_statement_only_with_nested_statement = { if (true) { return 1 + 1; } }; struct SomeStruct {} // previously these cases were incorrectly parsed as struct initializer VoidFun[] no_semicolon_statements = [ { asm {} }, { class Foo {} }, { debug(foo) {} }, { enum Foo { A } }, { final switch(5) {} }, { if (true) {} }, { interface Foo {} }, { pragma(inline) {} }, { scope(exit) {} }, { struct Foo {} }, { synchronized {} }, { try {} finally {} }, { union Foo {} }, { version(foo) {} }, { while (false) {} }, { with (SomeStruct) {} }, ]; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18430.d ================================================ template Alias(alias a) { alias Alias = a; } void main() { auto scale = 4; alias edentity = a => a * scale; static assert(__traits(isSame, Alias!edentity, edentity)); // fails in dmd-nightly } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18468.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18468 @safe void main() { synchronized {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18474.d ================================================ shared struct A { this(this); } struct B { A a; } void main() { shared B b1; auto b2 = b1; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18578.d ================================================ enum Foo { foo1 } enum Bar : Foo { bar } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18584.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18584 struct S { int n; auto fun() { return tmp!(a => n)(); } } struct tmp(alias fns) { alias fun = fns!int; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18645.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18645 immutable INIT = 42; enum A { x = INIT, y } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18670.d ================================================ // REQUIRED_ARGS: -dip1000 // https://issues.dlang.org/show_bug.cgi?id=18670 void foo() { new OVERLAPPED; } union OVERLAPPED { uint OffsetHigh; uint Pointer; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18694.d ================================================ struct S { enum int x = 42; } static S dummy; pure int fun(int x) { return dummy.x + x; } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18737.d ================================================ /* REQUIRED_ARGS: * PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=18737 struct S { this(char); this(int j) { this('a'); assert(0); this('b'); } this(long j) { if (j) { this('c'); assert(0); } else if (j + 1) { this('d'); return; } this('e'); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18771.d ================================================ // REQUIRED_ARGS : -c // https://issues.dlang.org/show_bug.cgi?id=18771 import imports.test18771c, imports.test18771d; static assert(__traits(isSame, fooC, fooD)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18775.d ================================================ // REQUIRED_ARGS: -de struct Foo { } struct Bar { deprecated @property Foo foo() { return Foo.init; } alias foo this; } void test(Bar bar) { } void main() { Bar bar; // test lookup will be satisfied via ufcs, not alias, so it must not deprecation warn foo! bar.test; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test1878a.d ================================================ void main() { ubyte from, to; foreach(i; from..to) { static assert(is(typeof(i) == ubyte)); } foreach(i; 'a'..'l') { static assert(is(typeof(i) == char)); } foreach(i; 'א' .. 'ת') { static assert(is(typeof(i) == wchar)); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18821.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18821 align(1) struct epoll_event { void* ptr; } template isAllZeroBits(epoll_event value) {} alias isInitAllZeroBits = isAllZeroBits!(epoll_event.init); epoll_event e = { null }; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18871.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18871 // and https://issues.dlang.org/show_bug.cgi?id=18819 struct Problem { ~this() {} } struct S { Problem[1] payload; } enum theTemplateB = { static foreach (e; S.init.tupleof) {} return true; }(); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18905.d ================================================ /* REQUIRED_ARGS: -betterC */ // https://issues.dlang.org/show_bug.cgi?id=18905 extern (C++) class C { } // Error: TypeInfo cannot be used with -betterC ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18936.d ================================================ // REQUIRED_ARGS: -fPIC -O -release -inline -m64 -betterC // DISABLED: win32 win64 // https://issues.dlang.org/show_bug.cgi?id=18936 // produces assert failure cgxmm.c line 684 import core.stdc.math; struct S { double re, im; static S sqrtcx(S* z) { S c; real x,y,w,r; { x = fabs(z.re); y = fabs(z.im); if (z.re >= 0) { c.im = (z.im >= 0) ? w : -w; c.re = z.im / (c.im + c.im); } } return c; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18951a.d ================================================ module compilable.test18951a; public class A { package static void foo(Object) {} public static void foo() {} } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18951b.d ================================================ module compilable.test18951b; import test18951a; void test() { A.foo(new Object); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test18976.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18976 class Expression : Statement {} class Statement {} class AssertSemanticVisitor { void visit (const Statement node) { } } class ExpressionVisitor : AssertSemanticVisitor { public void visit (Expression) { } alias visit = typeof(super).visit; } class ExpressionVisitor2 : AssertSemanticVisitor { public void visit (Expression) { } alias visit = AssertSemanticVisitor.visit; } void main () { scope x1 = new ExpressionVisitor; scope x2 = new ExpressionVisitor; scope y = new Statement; x1.visit(y); x2.visit(y); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19066.d ================================================ class C {} int Object; struct S { int object; C Object; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19081.d ================================================ void main() { @(1) enum { A } /// comment @(1) enum X { A } @(2) enum Y; @(1) @(2) enum Z { A } struct Test { int test; } @Test(1) enum W { A } @(1) enum V: int { A } X a; static assert(__traits(getAttributes, X).length == 1); static assert(__traits(getAttributes, X)[0] == 1); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19107.d ================================================ // REQUIRED_ARGS: -dw // EXTRA_FILES: imports/test19107a.d imports/test19107b.d /* TEST_OUTPUT: --- compilable/test19107.d(14): Deprecation: `imports.test19107b.I` is not visible from module `test19107` --- */ // https://issues.dlang.org/show_bug.cgi?id=19107 import imports.test19107b; void all(alias pred, T)(T t) if (is(typeof(I!pred(t)))) { } void main(string[] args) { args.all!(c => c); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19108.d ================================================ // REQUIRED_ARGS: -ignore // https://issues.dlang.org/show_bug.cgi?id=19108 pragma(unknown_global); void main() { pragma(unknown_local); // Error: unrecognized pragma } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19187.d ================================================ // EXTRA_FILES: imports/test19187.d import imports.test19187; void main() { enum test = __traits(compiles, imports.test19187.foo); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19201.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=19201 enum __c_long : int; enum __c_ulong : uint; enum __c_longlong : long; enum __c_ulonglong : ulong; void test19201a(uint r); void test19201a(int r); void test19201b(ulong r); void test19201b(long r); void test19201c(__c_long r); void test19201c(__c_ulong r); void test19201d(__c_longlong r); void test19201d(__c_ulonglong r); void test19201() { test19201a(0); test19201a(0u); test19201b(0L); test19201b(0UL); test19201c(0); test19201c(0u); test19201d(0L); test19201d(0UL); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19203.d ================================================ //https://issues.dlang.org/show_bug.cgi?id=19203 struct BoolWithErr { bool b; string error; alias b this; } struct Foo { int popBack() { return 0; } } struct Bar {} template hasPopBack(T) { static if (!is(typeof(T.init.popBack))) enum hasPopBack = BoolWithErr(false, T.stringof~" does not have popBack"); else enum hasPopBack = BoolWithErr(true,""); } void test() { static assert( hasPopBack!Foo); static assert(!hasPopBack!Bar); static assert( hasPopBack!Foo && !hasPopBack!Bar); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test19292.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=19292 mixin("enum a = ", 87, ";"); static assert(a == 87); int test() { mixin("enum x = ", 7, ";"); return mixin("1", x, 2U); } void testit() { static assert(test() == 172); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test25.d ================================================ // PERMUTE_ARGS: import imports.test25a, imports.test25b; import std.stdio; void main() { std.stdio.writefln("hello"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test2991.d ================================================ module test2991; void foo() { } class C { import imports.test2991; void bar() { foo(); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313a.d ================================================ /* REQUIRED_ARGS: -de */ module test313; import imports.a313; void test1() { import imports.b313; imports.b313.bug(); } void test2() { cstdio.printf(""); } import imports.pkg313.c313; void test3() { imports.pkg313.c313.bug(); } template imp() { static import imports.a313templatemixin1; import imports.a313templatemixin2; } mixin imp!(); void test4() { imports.a313templatemixin1.bug(); imports.a313templatemixin2.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313b.d ================================================ // REQUIRED_ARGS: -de void test1() { import core.stdc.stdio; core.stdc.stdio.printf(""); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313c.d ================================================ // REQUIRED_ARGS: -de import imports.pkgmod313; void test() { imports.pkgmod313.foo(); imports.pkgmod313.bar(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313d.d ================================================ // first imported as package // COMPILED_IMPORTS: imports/pkgmod313/mod.d // REQUIRED_ARGS: -de import imports.pkgmod313; // then as package module void test() { imports.pkgmod313.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313e.d ================================================ // first resolved as package, then created as module (with name package) // COMPILED_IMPORTS: imports/pkgmod313/mod.d imports/pkgmod313/package.d // REQUIRED_ARGS: -de import imports.pkgmod313; // then imported as package module void test() { imports.pkgmod313.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313f.d ================================================ // REQUIRED_ARGS: -de import imports.f313; void test() { imports.f313.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test313g.d ================================================ // REQUIRED_ARGS: -de // COMPILED_IMPORTS: imports/g313.d import imports.g313; void test15900() { // publically imported modules from g313 should be available here imports.g313public.bug(); imports.g313staticif.bug(); imports.g313stringmixin.bug(); imports.g313templatemixin.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test314.d ================================================ // REQUIRED_ARGS: -de module imports.test314; // package imports import imports.a314; void main() { imports.a314.bug("This should work.\n"); renamed.bug("This should work.\n"); bug("This should work.\n"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test3673.d ================================================ class Base {} class Foo(T) if (is(T == int)) : Base { } class Bar(T) : Base if (is(T == bool)) { } interface OutputRange(T...) if (T.length == 1) { void put(T[0] value); } interface OutputRange(T...) : OutputRange!(T[0]), OutputRange!(T[1 .. $]) if (T.length > 1) { } alias OutputRange!(int, float) OR; class COR : OR { void put(int) { } void put(float) { } } class A {}; class B(T) : A if (true) {} class C(T) if (false) : A {} alias Foo!int FooInt; alias Bar!bool BarBool; static assert(!__traits(compiles, Foo!bool)); static assert(!__traits(compiles, Bar!int)); void main() { auto fi = new FooInt; auto bb = new BarBool; auto cor = new COR; auto a = new A(); auto b = new B!int(); static assert(!__traits(compiles, new C!int())); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test3775.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=3775 struct Bug3775 { static int byLine()() { return 1; } } static assert(cast(int)Bug3775.byLine == 1); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test4003.d ================================================ // COMPILED_IMPORTS: imports/test4003a.d // PERMUTE_ARGS: import imports.stdio4003; void main(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test4090.d ================================================ void test4090a() { // for the mutable elements { int[] arr = [1,2,3]; // inference + qualifier foreach ( x; arr) static assert(is(typeof(x) == int)); foreach ( const x; arr) static assert(is(typeof(x) == const int)); foreach (immutable x; arr) static assert(is(typeof(x) == immutable int)); // inference + qualifier + ref foreach ( ref x; arr) static assert(is(typeof(x) == int)); foreach ( const ref x; arr) static assert(is(typeof(x) == const int)); static assert(!__traits(compiles, { foreach (immutable ref x; arr) {} })); // with exact type + qualifier foreach ( int x; arr) static assert(is(typeof(x) == int)); foreach ( const int x; arr) static assert(is(typeof(x) == const int)); foreach (immutable int x; arr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier + ref foreach ( ref int x; arr) static assert(is(typeof(x) == int)); foreach ( const ref int x; arr) static assert(is(typeof(x) == const int)); static assert(!__traits(compiles, { foreach (immutable ref int x; arr) {} })); // convertible type + qualifier foreach ( double x; arr) static assert(is(typeof(x) == double)); foreach ( const double x; arr) static assert(is(typeof(x) == const double)); foreach (immutable double x; arr) static assert(is(typeof(x) == immutable double)); // convertible type + qualifier + ref static assert(!__traits(compiles, { foreach ( ref double x; arr) {} })); static assert(!__traits(compiles, { foreach ( const ref double x; arr) {} })); static assert(!__traits(compiles, { foreach (immutable ref double x; arr) {} })); } // for the immutable elements { immutable(int)[] iarr = [1,2,3]; // inference + qualifier foreach ( x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach ( const x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (immutable x; iarr) static assert(is(typeof(x) == immutable int)); // inference + qualifier + ref foreach ( ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach ( const ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (immutable ref x; iarr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier foreach ( int x; iarr) static assert(is(typeof(x) == int)); foreach ( const int x; iarr) static assert(is(typeof(x) == const int)); foreach (immutable int x; iarr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier + ref static assert(!__traits(compiles, { foreach ( ref int x; iarr) {} })); foreach ( const ref int x; iarr) static assert(is(typeof(x) == const int)); foreach (immutable ref int x; iarr) static assert(is(typeof(x) == immutable int)); // convertible type + qualifier foreach ( double x; iarr) static assert(is(typeof(x) == double)); foreach ( const double x; iarr) static assert(is(typeof(x) == const double)); foreach (immutable double x; iarr) static assert(is(typeof(x) == immutable double)); // convertible type + qualifier + ref static assert(!__traits(compiles, { foreach (ref double x; iarr) {} })); static assert(!__traits(compiles, { foreach (const ref double x; iarr) {} })); static assert(!__traits(compiles, { foreach (immutable ref double x; iarr) {} })); } } void test4090b() { // for the key { int[] arr = [1,2,3]; // inference + qualifier foreach ( i, x; arr) static assert(is(typeof(i) == size_t)); foreach ( const i, x; arr) static assert(is(typeof(i) == const size_t)); foreach (immutable i, x; arr) static assert(is(typeof(i) == immutable size_t)); // inference + qualifier + ref foreach ( ref i, x; arr) static assert(is(typeof(i) == size_t)); foreach ( const ref i, x; arr) static assert(is(typeof(i) == const size_t)); static assert(!__traits(compiles, { foreach (immutable ref i, x; arr) {} })); // with exact type + qualifier foreach ( size_t i, x; arr) static assert(is(typeof(i) == size_t)); foreach ( const size_t i, x; arr) static assert(is(typeof(i) == const size_t)); foreach (immutable size_t i, x; arr) static assert(is(typeof(i) == immutable size_t)); // with exact type + qualifier + ref foreach ( ref size_t i, x; arr) static assert(is(typeof(i) == size_t)); foreach ( const ref size_t i, x; arr) static assert(is(typeof(i) == const size_t)); static assert(!__traits(compiles, { foreach (immutable ref size_t i, x; arr) {} })); } // for the mutable elements { int[] arr = [1,2,3]; // inference + qualifier foreach (i, x; arr) static assert(is(typeof(x) == int)); foreach (i, const x; arr) static assert(is(typeof(x) == const int)); foreach (i, immutable x; arr) static assert(is(typeof(x) == immutable int)); // inference + qualifier + ref foreach (i, ref x; arr) static assert(is(typeof(x) == int)); foreach (i, const ref x; arr) static assert(is(typeof(x) == const int)); static assert(!__traits(compiles, { foreach (i, immutable ref x; arr) {} })); // with exact type + qualifier foreach (i, int x; arr) static assert(is(typeof(x) == int)); foreach (i, const int x; arr) static assert(is(typeof(x) == const int)); foreach (i, immutable int x; arr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier + ref foreach (i, ref int x; arr) static assert(is(typeof(x) == int)); foreach (i, const ref int x; arr) static assert(is(typeof(x) == const int)); static assert(!__traits(compiles, { foreach (i, immutable ref int x; arr) {} })); // convertible type + qualifier foreach (i, double x; arr) static assert(is(typeof(x) == double)); foreach (i, const double x; arr) static assert(is(typeof(x) == const double)); foreach (i, immutable double x; arr) static assert(is(typeof(x) == immutable double)); // convertible type + qualifier + ref static assert(!__traits(compiles, { foreach (i, ref double x; arr) {} })); static assert(!__traits(compiles, { foreach (i, const ref double x; arr) {} })); static assert(!__traits(compiles, { foreach (i, immutable ref double x; arr) {} })); } // for the immutable elements { immutable(int)[] iarr = [1,2,3]; // inference + qualifier foreach (i, x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (i, const x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (i, immutable x; iarr) static assert(is(typeof(x) == immutable int)); // inference + qualifier + ref foreach (i, ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (i, const ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration foreach (i, immutable ref x; iarr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier foreach (i, int x; iarr) static assert(is(typeof(x) == int)); foreach (i, const int x; iarr) static assert(is(typeof(x) == const int)); foreach (i, immutable int x; iarr) static assert(is(typeof(x) == immutable int)); // with exact type + qualifier + ref static assert(!__traits(compiles, { foreach (i, ref int x; iarr) {} })); foreach (i, const ref int x; iarr) static assert(is(typeof(x) == const int)); foreach (i, immutable ref int x; iarr) static assert(is(typeof(x) == immutable int)); // convertible type + qualifier foreach (i , double x; iarr) static assert(is(typeof(x) == double)); foreach (i, const double x; iarr) static assert(is(typeof(x) == const double)); foreach (i, immutable double x; iarr) static assert(is(typeof(x) == immutable double)); // convertible type + qualifier + ref static assert(!__traits(compiles, { foreach (i, ref double x; iarr) {} })); static assert(!__traits(compiles, { foreach (i, const ref double x; iarr) {} })); static assert(!__traits(compiles, { foreach (i, immutable ref double x; iarr) {} })); } } void test4090c() { foreach ( x; 1..11) static assert(is(typeof(x) == int)); foreach ( const x; 1..11) static assert(is(typeof(x) == const int)); foreach (immutable x; 1..11) static assert(is(typeof(x) == immutable int)); foreach ( int x; 1..11) static assert(is(typeof(x) == int)); foreach ( const int x; 1..11) static assert(is(typeof(x) == const int)); foreach (immutable int x; 1..11) static assert(is(typeof(x) == immutable int)); foreach ( ref x; 1..11) static assert(is(typeof(x) == int)); foreach ( const ref x; 1..11) static assert(is(typeof(x) == const int)); static assert(!__traits(compiles, { foreach (immutable ref x; 1..11) {} })); foreach ( double x; 1..11) static assert(is(typeof(x) == double)); foreach ( const double x; 1..11) static assert(is(typeof(x) == const double)); foreach (immutable double x; 1..11) static assert(is(typeof(x) == immutable double)); foreach ( ref double x; 1..11) static assert(is(typeof(x) == double)); foreach ( const ref double x; 1..11) static assert(is(typeof(x) == const double)); static assert(!__traits(compiles, { foreach (immutable ref double x; 1..11) {} })); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test4364.d ================================================ struct Object{} class Game {} void main() { static assert(is(Object == struct)); static assert(is(object.Object == class)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test4375.d ================================================ // REQUIRED_ARGS: -unittest // https://issues.dlang.org/show_bug.cgi?id=4375 // disallow dangling else void main() { if (true) { if (false) { assert(1); } else { assert(2); } } if (true) { if (false) assert(7); } else assert(8); if (true) { if (false) assert(9); else assert(10); } { if (true) assert(11); else assert(12); } { label1: if (true) assert(13); else assert(14); } if (true) foreach (i; 0 .. 5) { if (true) assert(17); else assert(18); } if (true) { foreach (i; 0 .. 5) if (true) assert(18.1); } else assert(18.2); if (true) assert(19); else assert(20); if (true) assert(21); else if (false) assert(22); else assert(23); version (A) { if (true) assert(26); } else assert(27); version (A) { if (true) assert(28); else assert(29); } version (A) assert(30); else version (B) assert(31); else assert(32); static if (true) { static if (true) assert(35); } else assert(36); static if (true) { static if (true) assert(37); else assert(38); } static if (true) assert(39); else static if (true) assert(40); else assert(41); switch (4) { case 0: if (true) assert(42); else assert(43); break; case 1: .. case 5: if (true) assert(44); else assert(45); break; default: if (true) assert(46); else assert(47); break; } // (o_O) switch (1) default: if (true) assert(113); else assert(114); // (o_O) final switch (1) case 1: if (true) assert(117); else assert(118); mixin(q{ if (true) assert(56); else assert(57); }); while (false) if (true) assert(66); else assert(67); if (true) while (false) assert(68); else assert(69); do if (true) assert(72); else assert(73); while (false); if (true) do if (true) assert(74); else assert(75); while (false); for ( if (true) // (o_O) assert(78); else assert(79); false; false ) if (true) assert(80); else assert(81); if (true) for (if (true) assert(84); else assert(85); false;) assert(86); if (true) if (true) if (true) if (true) if (true) assert(87); auto x = new C; if (true) while (false) for (;;) scope (exit) synchronized (x) assert(88); else assert(89); if (true) while (false) for (;;) { scope (exit) synchronized (x) if (true) assert(90); else assert(89); } if (true) while (false) for (;;) scope (exit) synchronized (x) if (true) assert(90); else assert(89); else assert(12); with (x) if (false) assert(92); else assert(93); try if (true) assert(94); else assert(95); catch (Exception e) if (true) assert(96); else assert(97); finally if (true) assert(98); else assert(99); if (true) try if (true) assert(100); else assert(101); finally assert(102); if (true) try assert(109); catch(Exception e) if (true) assert(110); else assert(112); finally assert(111); static struct F { static if (true) int x; else int y; static if (true) { static if (false) int z; } else int w; static if (true) int t; else static if (false) int u; else int v; } if (true) if (true) assert(113); else assert(114); else assert(115); static if (true) static if (true) assert(116); else assert(117); else assert(118); } unittest { if (true) assert(50); else assert(51); } class C { invariant() { if (true) assert(58); else assert(59); } int f() in { if (true) assert(60); else assert(61); } out(res) { if (true) assert(62); else assert(63); } body { if (true) assert(64); else assert(65); return 0; } } enum q = q{ if(true) if(true) assert(54.1); else assert(55.2); }; static if (true) struct F0 {} else static if (true) struct F1 {} else struct F2 {} static if (true) { static if (false) struct F3 {} } else struct F4 {} version(A) { version(B) struct F5 {} } else struct F6 {} version(A) { version(B) struct F5a {} else struct F5b {} } version (C) struct F5c {} else struct F5d {} struct F7 { static if (true) int x; else float x; private: static if (true) int y; else float y; } template F8() { static if (true) int x; else float x; } static if (true) align(1) static if (false) struct F9 {} static if (true) align(1) { extern(C) pure static if (false) void F10(){} else void F11(){} } void f() { int[] x; static if (5 > 0) version (Y) scope (failure) foreach (i, e; x) while (i > 20) with (e) if (e < 0) synchronized(e) assert(1); else assert(2); else x = null; else x = null; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test50.d ================================================ // COMPILED_IMPORTS: imports/test50a.d // PERMUTE_ARGS: import imports.test50a; class Bar : Foo { alias typeof(Foo.tupleof) Bleh; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test5227.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: TEST_OUTPUT: --- log() 1.70475L log2() 2.45943L log10() 0.740363L round() 6.00000L floor() 5.00000F 5.00000 5.00000L ceil() 6.00000F 6.00000 6.00000L trunc() 5.00000L exp() 244.692L expm1() 243.692L exp2() 45.2548L fmin() -3.2L fmax() 5.2L copysign() -2.5F -2.5 -2.5L pow() 9.88212F 9.88212 9.88212L 9.88212 fma() -12.84L --- */ // https://issues.dlang.org/show_bug.cgi?id=5227 import std.math; pragma(msg, "log()"); enum logf = log(5.5f); //pragma(msg, logf); enum logd = log(5.5 ); //pragma(msg, logd); enum logr = log(5.5L); pragma(msg, logr); pragma(msg, "log2()"); enum log2f = log2(5.5f); //pragma(msg, log2f); enum log2d = log2(5.5 ); //pragma(msg, log2d); enum log2r = log2(5.5L); pragma(msg, log2r); pragma(msg, "log10()"); enum log10f = log10(5.5f); //pragma(msg, log10f); enum log10d = log10(5.5 ); //pragma(msg, log10d); enum log10r = log10(5.5L); pragma(msg, log10r); pragma(msg, "round()"); enum roundf = round(5.5f); //pragma(msg, roundf); enum roundd = round(5.5 ); //pragma(msg, roundd); enum roundr = round(5.5L); pragma(msg, roundr); pragma(msg, "floor()"); enum floorf = floor(5.5f); pragma(msg, floorf); enum floord = floor(5.5 ); pragma(msg, floord); enum floorr = floor(5.5L); pragma(msg, floorr); pragma(msg, "ceil()"); enum ceilf = ceil(5.5f); pragma(msg, ceilf); enum ceild = ceil(5.5 ); pragma(msg, ceild); enum ceilr = ceil(5.5L); pragma(msg, ceilr); pragma(msg, "trunc()"); enum truncf = trunc(5.5f); //pragma(msg, truncf); enum truncd = trunc(5.5 ); //pragma(msg, truncd); enum truncr = trunc(5.5L); pragma(msg, truncr); pragma(msg, "exp()"); enum expf = exp(5.5f); //pragma(msg, expf); enum expd = exp(5.5 ); //pragma(msg, expd); enum expr = exp(5.5L); pragma(msg, expr); pragma(msg, "expm1()"); enum expm1f = expm1(5.5f); //pragma(msg, expm1f); enum expm1d = expm1(5.5 ); //pragma(msg, expm1d); enum expm1r = expm1(5.5L); pragma(msg, expm1r); pragma(msg, "exp2()"); enum exp2f = exp2(5.5f); //pragma(msg, exp2f); enum exp2d = exp2(5.5 ); //pragma(msg, exp2d); enum exp2r = exp2(5.5L); pragma(msg, exp2r); pragma(msg, "fmin()"); enum fminf = fmin(-3.2f, 5.2f); //pragma(msg, fminf); enum fmind = fmin(-3.2 , 5.2 ); //pragma(msg, fmind); enum fminr = fmin(-3.2L, 5.2L); pragma(msg, fminr); pragma(msg, "fmax()"); enum fmaxf = fmax(-3.2f, 5.2f); //pragma(msg, fmaxf); enum fmaxd = fmax(-3.2 , 5.2 ); //pragma(msg, fmaxd); enum fmaxr = fmax(-3.2L, 5.2L); pragma(msg, fmaxr); pragma(msg, "copysign()"); enum csf = copysign(2.5f, -3.0f); pragma(msg, csf); static assert(csf == -2.5); enum csd = copysign(2.5 , -3.0 ); pragma(msg, csd); static assert(csd == -2.5); enum csr = copysign(2.5L, -3.0L); pragma(msg, csr); static assert(csr == -2.5); pragma(msg, "pow()"); enum powf = pow(2.5f, 2.5f); pragma(msg, powf); enum powd = pow(2.5 , 2.5 ); pragma(msg, powd); enum powr = pow(2.5L, 2.5L); pragma(msg, powr); enum powctfe = 2.5 ^^ 2.5; pragma(msg, powctfe); pragma(msg, "fma()"); enum fmaf = fma(-3.2f, 5.2f, 3.8f); //pragma(msg, fmaf); enum fmad = fma(-3.2 , 5.2 , 3.8 ); //pragma(msg, fmad); enum fmar = fma(-3.2L, 5.2L, 3.8L); pragma(msg, fmar); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test55.d ================================================ // COMPILE_SEPARATELY // COMPILED_IMPORT: imports/test55a.d // PERMUTE_ARGS: -dw // REQUIRED_ARGS: -d public import imports.test55a; class Queue { alias int ListHead; Arm a; } class MessageQueue : Queue { } class Queue2 { alias int ListHead; Arm2 a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test59.d ================================================ // PERMUTE_ARGS: public import imports.test59a; public import imports.test59b; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test5973.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=5973 class A { int a = 1; } class B { int b = 2; } class C : A { B obj; alias obj this; this(){ obj = new B(); } } class X : C {} class D { int i; } class E { D x; alias x this; } class F : E { void test() { i = 5; } } void main() { auto c = new C(); assert(c.a == 1); // lookup C -> A, OK assert(c.b == 2); // lookup C => B, OK auto x = new X(); assert(x.a == 1); // lookup X -> C -> A, OK assert(x.b == 2); // lookup X -> C => B, NG (Line 17) } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6013.d ================================================ // REQUIRED_ARGS: -de import imports.test6013; static assert(__traits(compiles, public_alias_value)); static assert(!__traits(compiles, private_alias_value)); static assert(__traits(compiles, public_alias_func())); static assert(!__traits(compiles, private_alias_func())); static assert(__traits(compiles, () { public_alias_type val; })); static assert(!__traits(compiles, () { private_alias_type val; })); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test602.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: // Disallow skipping variable decl static assert(!__traits(compiles, (bool b) { if (b) goto label; int x; label: {} assert(!x); })); // Disallow skipping variable in block backwards static assert(!__traits(compiles, (bool b) { { int x; label: {} assert(!x); } if (b) goto label; })); // Disallow skipping backwards int block static assert(!__traits(compiles, (bool b) { { int x; label: {} assert(!x); } if (b) goto label; })); // Variable inside try block static assert(!__traits(compiles, (bool b) { if (b) goto label; try { int x; label: {} assert(!x); } catch(Throwable) { } })); // Variable inside catch block static assert(!__traits(compiles, (bool b) { if (b) goto label; try { } catch(Throwable) { int x; label: {} assert(!x); } })); // Goto into catch block with unnamed exception static assert(__traits(compiles, (bool b) { if (b) goto label; try { } catch(Exception) { label: {} } })); // Goto into catch block with named exception static assert(!__traits(compiles, (bool b) { if (b) goto label; try { } catch(Exception e) { label: {} assert(e); } })); // Goto into finally block static assert(!__traits(compiles, (bool b) { if (b) goto label; try { } finally { label: {} } })); // Goto into variable with block static assert(!__traits(compiles, (bool b) { if (b) goto label; struct S { int x; } with (S()) { label: {} assert(!x); } })); // Goto backwards into variable with block static assert(!__traits(compiles, (bool b) { struct S { int x; } with (S()) { label: {} assert(!x); } if (b) goto label; })); // Goto into symbolic with block static assert(__traits(compiles, (bool b) { if (b) goto label; struct S { int x; } with (S) { label: {} } })); // Goto backwards into symbolic with block static assert(__traits(compiles, (bool b) { struct S { int x; } with (S) { label: {} } if (b) goto label; })); // Goto into for loop static assert(!__traits(compiles, (bool b) { if (b) goto label; for (int i = 0; i < 8; ++i) { label: {} assert(i); } })); // Goto into for loop backwards static assert(!__traits(compiles, (bool b) { for (int i = 0; i < 8; ++i) { label: {} assert(i); } if (b) goto label; })); // Goto into foreach loop static assert(!__traits(compiles, (bool b) { if (b) goto label; foreach(i; 0..8) { label: {} assert(i); } })); // Goto into foreach loop backwards static assert(!__traits(compiles, (bool b) { foreach(i; 0..8) { label: {} assert(i); } if (b) goto label; })); // Goto into if block with variable static assert(!__traits(compiles, (bool b) { if (b) goto label; if (auto x = b) { label: {} assert(x); } })); // Goto backwards into if block with variable static assert(!__traits(compiles, (bool b) { if (auto x = b) { label: {} assert(x); } if (b) goto label; })); // Goto into if block without variable static assert(__traits(compiles, (bool b) { if (b) goto label; if (b) { label: {} } })); // Goto into else block static assert(__traits(compiles, (bool b) { if (b) goto label; if (auto x = b) { } else { label: {} } })); // Goto backwards into else with variable static assert(!__traits(compiles, (bool b) { if (auto x = b) { } else { int y; label: {} } if (b) goto label; })); // Goto into while block static assert(__traits(compiles, (bool b) { if (b) goto label; while (b) { label: {} } })); // Goto into while block with internal variable static assert(!__traits(compiles, (bool b) { if (b) goto label; while (b) { int x; label: {} assert(!x); } })); // Goto into do block static assert(__traits(compiles, (bool b) { if (b) goto label; do { label: {} } while (b); })); // Goto over switch variable static assert(!__traits(compiles, (bool b) { if (b) goto label; switch(0) { default: break; int x; label: {} } })); // Goto over switch variable static assert(!__traits(compiles, (bool b) { if (b) goto label; switch(0) { default: break; case 0: int x; label: {} } })); // Goto into synchronized statement static assert(!__traits(compiles, (bool b) { if (b) goto label; synchronized { label: {} } })); // Goto into scope(success) with variable static assert(!__traits(compiles, (bool b) { scope(success) { int x; label: {} assert(!x); } if (b) goto label; })); // Goto into scope(failure) static assert(!__traits(compiles, (bool b) { if (b) goto label; scope(failure) { label: {} } })); // Goto into scope(failure) with variable static assert(!__traits(compiles, (bool b) { scope(failure) { int x; label: {} assert(!x); } if (b) goto label; })); // Goto into scope(exit) static assert(!__traits(compiles, (bool b) { if (b) goto label; scope(exit) { label: {} } })); // Goto into scope(exit) static assert(!__traits(compiles, (bool b) { scope(exit) { label: {} } if (b) goto label; })); // Goto into scope(exit) with variable static assert(!__traits(compiles, (bool b) { scope(exit) { int x; label: {} assert(!x); } if (b) goto label; })); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11659 int test11659() { goto LABEL; enum expr = "0"; LABEL: return mixin(expr); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13321 void test13321(bool b) { static struct Foo { this(int) {} } Foo x; if (b) goto EXIT; x = Foo(1); EXIT: } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6056a.d ================================================ alias const(typeof('c')*) A; alias const(typeof(0)*) B; static assert(is(B == const(int*))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6056b.d ================================================ template X(T) { alias T X; } alias const(X!char*) A; alias const(X!int*) B; static assert(is(B == const(int*))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6056c.d ================================================ alias int T; static assert( is( T** : const(T**) )); static assert( is( T* : const(T* ) )); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6089.d ================================================ // PERMUTE_ARGS: void main() { extern int[1][1] foo; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test61.d ================================================ // PERMUTE_ARGS: import imports.test61a; alias imports.test61a.bar bar; mixin(` enum FooB { fooB }; void bar(FooB x) {} `); void test() { bar(FooA.fooA); bar(FooB.fooB); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test62.d ================================================ // PERMUTE_ARGS: import imports.test62a; struct S { } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test63.d ================================================ // COMPILED_IMPORTS: imports/test63a.d // PERMUTE_ARGS: private import imports.test63a; const int SIZE = 7; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6319.d ================================================ // REQUIRED_ARGS: -debug int x; void main() pure { debug { { x = 0; } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6395.d ================================================ // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_SOURCES: b6395.d // https://issues.dlang.org/show_bug.cgi?id=6395 import c6395; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6534.d ================================================ void main() { class MC{ int x; } const class CC{ int x; } static assert(is(typeof( CC.x) == const)); immutable class IC{ int x; } static assert(is(typeof( IC.x) == immutable)); shared class SC{ int x; } static assert(is(typeof( SC.x) == shared)); shared const class SCC{ int x; } static assert(is(typeof(SCC.x) == shared) && is(typeof(SCC.x) == const)); struct MS{ int x; } const struct CS{ int x; } static assert(is(typeof( CS.x) == const)); immutable struct IS{ int x; } static assert(is(typeof( IS.x) == immutable)); shared struct SS{ int x; } static assert(is(typeof( SS.x) == shared)); shared const struct SCS{ int x; } static assert(is(typeof(SCS.x) == shared) && is(typeof(SCS.x) == const)); union MU{ int x; } const union CU{ int x; } static assert(is(typeof( CU.x) == const)); immutable union IU{ int x; } static assert(is(typeof( IU.x) == immutable)); shared union SU{ int x; } static assert(is(typeof( SU.x) == shared)); shared const union SCU{ int x; } static assert(is(typeof(SCU.x) == shared) && is(typeof(SCU.x) == const)); static class S_MC{ int x; } const static class S_CC{ int x; } static assert(is(typeof( S_CC.x) == const)); immutable static class S_IC{ int x; } static assert(is(typeof( S_IC.x) == immutable)); shared static class S_SC{ int x; } static assert(is(typeof( S_SC.x) == shared)); shared const static class S_SCC{ int x; } static assert(is(typeof(S_SCC.x) == shared) && is(typeof(S_SCC.x) == const)); static struct S_MS{ int x; } const static struct S_CS{ int x; } static assert(is(typeof( S_CS.x) == const)); immutable static struct S_IS{ int x; } static assert(is(typeof( S_IS.x) == immutable)); shared static struct S_SS{ int x; } static assert(is(typeof( S_SS.x) == shared)); shared const static struct S_SCS{ int x; } static assert(is(typeof(S_SCS.x) == shared) && is(typeof(S_SCS.x) == const)); static union S_MU{ int x; } const static union S_CU{ int x; } static assert(is(typeof( S_CU.x) == const)); immutable static union S_IU{ int x; } static assert(is(typeof( S_IU.x) == immutable)); shared static union S_SU{ int x; } static assert(is(typeof( S_SU.x) == shared)); shared const static union S_SCU{ int x; } static assert(is(typeof(S_SCU.x) == shared) && is(typeof(S_SCU.x) == const)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6552.d ================================================ // REQUIRED_ARGS: -w void main() { int i; switch (i) { case 1, 2: case 3, 4: break; default: break; } char ch; switch (ch) { case 'U', 'u': case 'L', 'l': default: } switch (i) { default: case 1: case 3,4: } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test66.d ================================================ // PERMUTE_ARGS: import imports.test66a; alias int TOK; enum { TOKmax }; struct Token { static char[][TOKmax] tochars; } class Lexer { Token token; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test67.d ================================================ // PERMUTE_ARGS: import imports.test67a; interface I { } interface SubI : I { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test68.d ================================================ // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=4278 import imports.test68a; class Foo : OtherModuleClass { override void foo() { super.foo(); } } void main() { new Foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test69.d ================================================ // PERMUTE_ARGS: // ICE(expression.c) DMD 0.110 // http://www.digitalmars.com/d/archives/digitalmars/D/bugs/2966.html string str255() { return "\255"; } void fromFail49() { switch("abc") { case "": case str255(): break; default: break; } } // https://issues.dlang.org/show_bug.cgi?id=5735 struct A {} void b() {} void foo(bool cond) {} void main() { A a; int i; static assert(!__traits(compiles, assert(a))); static assert(!__traits(compiles, assert(i || a))); static assert(!__traits(compiles, assert(0 || a))); static assert(!__traits(compiles, assert(i && a))); static assert(!__traits(compiles, assert(1 && a))); static assert(!__traits(compiles, foo(a))); static assert(!__traits(compiles, foo(i || a))); static assert(!__traits(compiles, foo(0 || a))); static assert(!__traits(compiles, foo(i && a))); static assert(!__traits(compiles, foo(1 && a))); static assert(!__traits(compiles, assert(b))); static assert(!__traits(compiles, assert(i || b))); static assert(!__traits(compiles, assert(0 || b))); static assert(!__traits(compiles, assert(i && b))); static assert(!__traits(compiles, assert(1 && b))); static assert(!__traits(compiles, foo(b))); static assert(!__traits(compiles, foo(i || b))); static assert(!__traits(compiles, foo(0 || b))); static assert(!__traits(compiles, foo(i && b))); static assert(!__traits(compiles, foo(1 && b))); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test6999.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=6999: inout in front of return type struct A { inout: inout(int) foo() { return 0; } } struct B { inout { inout(int) foo() { return 0; } } } struct C { inout inout(int) foo() { return 0; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test70.d ================================================ import imports.test70 : foo; void foo(int) // overloads with selective import { } void bar() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7065.d ================================================ void main() { align(1) struct X1 { ubyte b; int n; } static assert(X1.sizeof == 8); static assert(X1.b.offsetof == 0); static assert(X1.n.offsetof == 4); //X1 x1; //assert(cast(void*)&x1.b == cast(void*)&x1 + 0); //assert(cast(void*)&x1.n == cast(void*)&x1 + 1); struct Y1 { ubyte b; int n; } static assert(Y1.sizeof == 8); static assert(Y1.b.offsetof == 0); static assert(Y1.n.offsetof == 4); //Y1 y1; //assert(cast(void*)&y1.b == cast(void*)&y1 + 0); //assert(cast(void*)&y1.n == cast(void*)&y1 + 4); int local; align(1) struct X2 { ubyte b; int n; int f(){ return local; } } static assert(X2.sizeof == 8 + (void*).sizeof); static assert(X2.b.offsetof == 0); static assert(X2.n.offsetof == 4); //X2 x2; //assert(cast(void*)&x2.b == cast(void*)&x2 + 0); //assert(cast(void*)&x2.n == cast(void*)&x2 + 1); struct Y2 { ubyte b; int n; int f(){ return local; } } static assert(Y2.sizeof == 8 + (void*).sizeof); static assert(Y2.b.offsetof == 0); static assert(Y2.n.offsetof == 4); //Y2 y2; //assert(cast(void*)&y2.b == cast(void*)&y2 + 0); //assert(cast(void*)&y2.n == cast(void*)&y2 + 4); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test71.d ================================================ import imports.test71; void bar() { imports.test71.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7172.d ================================================ void main() { abstract class AbstractC{} static assert(!__traits(compiles, { new AbstractC(); })); final class FinalC{} static assert(!__traits(compiles, { class D : FinalC{} })); scope class ScopeC{} static assert(!__traits(compiles, { auto sc = new ScopeC(); })); static assert( __traits(compiles, { scope sc = new ScopeC(); })); synchronized class SyncC{ void f(){} } static assert(SyncC.f.mangleof[$-13..$] == "5SyncC1fMOFZv"); @safe class SCx{ void f(){} } @trusted class SCy{ void f(){} } @system class SCz{ void f(){} } static assert(SCx.f.mangleof[$-12..$] == "3SCx1fMFNfZv"); // Nf: FuncAttrSafe static assert(SCy.f.mangleof[$-12..$] == "3SCy1fMFNeZv"); // Ne: FuncAttrTrusted static assert(SCz.f.mangleof[$-10..$] == "3SCz1fMFZv"); // (none) } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7190.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_FILES: extra-files/example7190/controllers/HomeController.d extra-files/example7190/models/HomeModel.d extra-files/serenity7190/core/Controller.d extra-files/serenity7190/core/Model.d import example7190.controllers.HomeController; import example7190.models.HomeModel; void main(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test72.d ================================================ module test72; import imports.test72a, imports.test72c; void bar() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7252.d ================================================ alias char* function() Func; alias const char* function() CFunc; void to(S)(S) { } void foo(CFunc cFunc) { to(cFunc()); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7399.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7399 static assert(!__traits(compiles, { import non.existing.file; })); // https://issues.dlang.org/show_bug.cgi?id=7400 static assert(!is(typeof({import non_existing_file;}))); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7491.d ================================================ struct Struct { import object; import imports.test7491a; import renamed=imports.test7491b; } struct AliasThis { Struct _struct; alias _struct this; } class Base { import object; import imports.test7491a; import renamed=imports.test7491b; } class Derived : Base { } interface Interface { import object; import imports.test7491a; import renamed=imports.test7491b; } class Impl : Interface { } static assert(__traits(compiles, Struct.object)); static assert(__traits(compiles, Struct.imports)); static assert(__traits(compiles, Struct.renamed)); static assert(__traits(compiles, AliasThis.object)); static assert(__traits(compiles, AliasThis.imports)); static assert(__traits(compiles, AliasThis.renamed)); static assert(__traits(compiles, Base.object)); static assert(__traits(compiles, Base.imports)); static assert(__traits(compiles, Base.renamed)); static assert(__traits(compiles, Derived.object)); static assert(__traits(compiles, Derived.imports)); static assert(__traits(compiles, Derived.renamed)); static assert(__traits(compiles, Interface.object)); static assert(__traits(compiles, Interface.imports)); static assert(__traits(compiles, Interface.renamed)); static assert(__traits(compiles, Impl.object)); static assert(__traits(compiles, Impl.imports)); static assert(__traits(compiles, Impl.renamed)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7524.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7524 #line __LINE__ "y.d" ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7569.d ================================================ template Tuple(T...) { alias T Tuple; } void main() { Tuple!(int, int) tup1 = void; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7754.d ================================================ // REQUIRED_ARGS: -H -Hd${RESULTS_DIR}/compilable // POST_SCRIPT: compilable/extra-files/test7754-postscript.sh // PERMUTE_ARGS: -d -dw struct Foo(T) { shared static this() { } static this() { } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7815.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- --- */ mixin template Helpers() { static if (is(Flags!Move)) { Flags!Move flags; } else { pragma(msg, "X: ", __traits(derivedMembers, Flags!Move)); } } template Flags(T) { mixin({ int defs = 1; foreach (name; __traits(derivedMembers, Move)) { defs++; } if (defs) { return "struct Flags { bool x; }"; } else { return ""; } }()); } struct Move { int a; mixin Helpers!(); } enum a7815 = Move.init.flags; /+ This originally was an invalid case: When the Move struct member is analyzed: 1. mixin Helpers!() is instantiated. 2. In Helpers!(), static if and its condition is(Flags!Move)) evaluated. 3. In Flags!Move, string mixin evaluates and CTFE lambda. 4. __traits(derivedMembers, Move) tries to see the member of Move. 4a. mixin Helpers!() member is analyzed. 4b. `static if (is(Flags!Move))` in Helpers!() is evaluated 4c. The Flags!Move instantiation is already in progress, so it cannot be resolved. 4d. `static if` fails because Flags!Move cannot be determined as a type. 5. __traits(derivedMembers, Move) returns a 1-length tuple("a"). 6. The lambda in Flags!Move returns a string "struct Flags {...}", then Flags!Move is instantiated to a new struct Flags. 7. Finally Move struct does not have flags member, then the `enum a7815` definition will fail in its initializer. Now, static if will behave like a string mixin: it is invisible during its own expansion. +/ ================================================ FILE: gcc/testsuite/gdc.test/compilable/test7886.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7886 struct A { static assert (__traits(derivedMembers, A).length == 0); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8038.d ================================================ template t(T){alias T t;} t!(#line 10 t!( int, ) ) i; t!( t!(#line 10 int, ) ) j; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8041.d ================================================ // PERMUTE_ARGS: struct Foo { } void main() { static Foo sf; // ok __gshared Foo gf; // was: Error: non-constant expression gf = 0 __gshared int[1][1] arr; // dup: Issue 6089 } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8296.d ================================================ struct bar2 { int i; @disable this(); this(int i) { this.i = i; } } class InnerBar { bar2 b; this() { b = bar2(0); } } struct bar1 { InnerBar b; } class Foo { bar1 m_bar1; } void main(string[] args) { auto foo = new Foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8509.d ================================================ module test8509; enum E : string { a = "hello", b = "world" } struct S { E opCat(S s) { return E.a; } E opCat(string s) { return E.a; } } void main() { E e3 = S() ~ S(); E e4 = S() ~ "a"; assert(e3 == E.a); assert(e4 == E.a); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8513.d ================================================ interface I_Foo { void i_outer(); } class C_Foo { void c_outer() { } } class Bar { interface I_Foo { void i_inner(); } class C_Foo { void c_inner() { } } class Impl1 : C_Foo, I_Foo { override void i_inner() { } override void c_inner() { } } class Impl2 : C_Foo, .I_Foo { override void i_outer() { } override void c_inner() { } } class Impl3 : .C_Foo, I_Foo { override void i_inner() { } override void c_outer() { } } class Impl4 : .C_Foo, .I_Foo { override void i_outer() { } override void c_outer() { } } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8543.d ================================================ version (D_SIMD) { struct vfloat { public: __vector(float[4]) f32; this(float X) nothrow { f32.ptr[0] = X; f32.ptr[1] = X; f32.ptr[2] = X; f32.ptr[3] = X; } this(float X, float Y, float Z, float W) nothrow { f32.array[0] = X; f32.array[1] = Y; f32.array[2] = Z; f32.array[3] = W; } this(float[4] values) nothrow { f32.array = values; } } immutable GvfGlobal_ThreeA = vfloat(3.0f); immutable GvfGlobal_ThreeB = vfloat(3.0f, 3.0f, 3.0f, 3.0f); immutable GvfGlobal_ThreeC = vfloat([3.0f, 3.0f, 3.0f, 3.0f]); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8631.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -de class B { int foo() immutable { return 2; } int foo() const { return 2; } } class D : B { override int foo() immutable { return 2; } int foo() const shared { return 2; } override int foo() const { return 2; } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8675.d ================================================ class MyError : Error { this(string msg) { super(msg); } } void foo() nothrow { throw new Error("Some error"); } void bar() nothrow { throw new MyError("Some error"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8696.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=8696 // incorrect dangling else with version(): version (all): version (linux) { } else version (OSX) { } else { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8717.d ================================================ module test8717; struct SPR { private: enum e = 1; immutable int ii = 1; immutable static int sii = 1; static int sf() { return 1; } int f() const { return 1; } } static assert(SPR.e == 1); //static assert(SPR.ii == 1); static assert(SPR.sii == 1); static assert(SPR.sf() == 1); static assert(SPR.init.e == 1); static assert(SPR.init.ii == 1); static assert(SPR.init.sii == 1); static assert(SPR.sf() == 1); static assert(SPR.init.f() == 1); static if(SPR.e != 1) { static assert(0); } //static if(SPR.ii != 1) { static assert(0); } static if(SPR.sii != 1) { static assert(0); } static if(SPR.sf() != 1) { static assert(0); } static if(SPR.init.e != 1) { static assert(0); } static if(SPR.init.ii != 1) { static assert(0); } static if(SPR.init.sii != 1) { static assert(0); } static if(SPR.sf() != 1) { static assert(0); } static if(SPR.init.f() != 1) { static assert(0); } struct SPT { protected: enum e = 1; immutable int ii = 1; immutable static int sii = 1; static int sf() { return 1; } int f() const { return 1; } } static assert(SPT.e == 1); //static assert(SPT.ii == 1); static assert(SPT.sii == 1); static assert(SPT.sf() == 1); static assert(SPT.init.e == 1); static assert(SPT.init.ii == 1); static assert(SPT.init.sii == 1); static assert(SPT.sf() == 1); static assert(SPT.init.f() == 1); static if(SPT.e != 1) { static assert(0); } //static if(SPT.ii != 1) { static assert(0); } static if(SPT.sii != 1) { static assert(0); } static if(SPT.sf() != 1) { static assert(0); } static if(SPT.init.e != 1) { static assert(0); } static if(SPT.init.ii != 1) { static assert(0); } static if(SPT.init.sii != 1) { static assert(0); } static if(SPT.sf() != 1) { static assert(0); } static if(SPT.init.f() != 1) { static assert(0); } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8802.d ================================================ // PERMUTE_ARGS: enum A : typeof(null)* { a = null } enum B : typeof(null)** { a = null } enum C : void* { a = null } enum D : void** { a = null } enum NullEn : void* { z = null } enum E : NullEn { a = null } void main() { auto a = A.a; auto b = B.a; auto c = C.a; auto d = D.a; auto e = E.a; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8898.d ================================================ // REQUIRED_ARGS: -w // PERMUTE_ARGS: static if (true): version (Foo) { } else { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922a.d ================================================ // PERMUTE_ARGS: import imports.bug8922; void test() { static assert(!__traits(compiles, __traits(parent, imports))); enum x = __traits(parent, imports.bug8922).stringof; static assert(x == "package imports"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922b.d ================================================ // PERMUTE_ARGS: void test() { import imports.bug8922; static assert(!__traits(compiles, __traits(parent, imports))); enum x = __traits(parent, imports.bug8922).stringof; static assert(x == "package imports"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922c.d ================================================ // PERMUTE_ARGS: static import imports.bug8922; void test() { static assert(!__traits(compiles, __traits(parent, imports))); static assert(!__traits(compiles, __traits(parent, bug8922))); enum x = __traits(parent, imports.bug8922).stringof; static assert(x == "package imports"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922d.d ================================================ // PERMUTE_ARGS: void test() { static import imports.bug8922; static assert(!__traits(compiles, __traits(parent, imports))); static assert(!__traits(compiles, __traits(parent, bug8922))); enum x = __traits(parent, imports.bug8922).stringof; static assert(x == "package imports"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922e.d ================================================ // PERMUTE_ARGS: import renamed = imports.bug8922; void test() { enum x = __traits(parent, renamed).stringof; static assert(x == "package imports"); static assert(!__traits(compiles, __traits(parent, imports))); static assert(!__traits(compiles, __traits(parent, bug8922))); static assert(!__traits(compiles, __traits(parent, imports.bug8922))); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8922f.d ================================================ // PERMUTE_ARGS: void test() { import renamed = imports.bug8922; enum x = __traits(parent, renamed).stringof; static assert(x == "package imports"); static assert(!__traits(compiles, __traits(parent, imports))); static assert(!__traits(compiles, __traits(parent, bug8922))); static assert(!__traits(compiles, __traits(parent, imports.bug8922))); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8937.d ================================================ mixin template X8937() { int value; } debug = test; void main() { // (static) import statement { static assert(!__traits(compiles, cos(0))); if (true) { static assert(!__traits(compiles, cos(0))); import core.stdc.math; static assert( __traits(compiles, cos(0))); } static assert(!__traits(compiles, cos(0))); if (true) import core.stdc.math; static assert(!__traits(compiles, cos(0))); // fails if (true) static import core.stdc.math; static assert(!__traits(compiles, core.stdc.math.cos(0))); // fails } static assert(!__traits(compiles, cos(0))); // mixin statement { if (true) mixin X8937!(); static assert(!__traits(compiles, value)); // fails } // enum declaration { if (true) enum E { x = 10 } static assert(!__traits(compiles, E)); // fails } // conditional declarations { if (true) static if (true) struct S1 {} static assert(!__traits(compiles, S1)); // fails if (true) version (all) struct S2 {} static assert(!__traits(compiles, S2)); // fails if (true) debug (test) struct S3 {} static assert(!__traits(compiles, S3)); // fails } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test8959.d ================================================ /* TEST_OUTPUT: --- U1 = int U2 = int V1 = long, K1 = string V2 = long, K2 = string TL1 = (int, string) TL2 = (int, string) U3 = int U4 = int V3 = long, K3 = string V4 = long, K4 = string TL3 = (int, string) TL4 = (int, string) --- */ static if (is(int* == U1*, U1)) { pragma(msg, "U1 = ", U1); } static if (is(int* : U2*, U2)) { pragma(msg, "U2 = ", U2); } static assert(is(int* == U*, U)); static assert(is(int* : U*, U)); alias AA = long[string]; static if (is(AA == V1[K1], V1, K1)) { pragma(msg, "V1 = ", V1, ", K1 = ", K1); } static if (is(AA : V2[K2], V2, K2)) { pragma(msg, "V2 = ", V2, ", K2 = ", K2); } static assert(is(AA == V[K], V, K)); static assert(is(AA : V[K], V, K)); class B(TL...) {} class C(TL...) : B!TL {} alias X = C!(int, string); static if (is(X == C!TL1, TL1...)) { pragma(msg, "TL1 = ", TL1); } static if (is(X : B!TL2, TL2...)) { pragma(msg, "TL2 = ", TL2); } static assert(is(X == C!TL, TL...)); static assert(is(X : B!TL, TL...)); void test8959() { static if (is(int* == U3*, U3)) { pragma(msg, "U3 = ", U3); } static if (is(int* : U4*, U4)) { pragma(msg, "U4 = ", U4); } static assert(is(int* == U*, U)); static assert(is(int* : U*, U)); static if (is(AA == V3[K3], V3, K3)) { pragma(msg, "V3 = ", V3, ", K3 = ", K3); } static if (is(AA : V4[K4], V4, K4)) { pragma(msg, "V4 = ", V4, ", K4 = ", K4); } static assert(is(AA == V[K], V, K)); static assert(is(AA : V[K], V, K)); static if (is(X == C!TL3, TL3...)) { pragma(msg, "TL3 = ", TL3); } static if (is(X : B!TL4, TL4...)) { pragma(msg, "TL4 = ", TL4); } static assert(is(X == C!TL, TL...)); static assert(is(X : B!TL, TL...)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9057.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_FILES: extra-files/imp9057.d extra-files/imp9057_2.d struct Bug9057(T) { T x; } void test9507() { import imp9057; Bug9057!(BugInt) xxx; } void test9507_2() { import imp9057_2; Bug9057!(BugInt) xxx; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9209.d ================================================ // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=9209 auto array(T)(T t){ return t; } auto bar()(in int* x) { if (true) return 0; return array(bar(x)); } void main () { bar(null); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9276.d ================================================ // EXTRA_SOURCES: imports/test9276parser.d // This is a dummy module for compilable test void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9278a.d ================================================ // PREMUTE_ARGS: // Works fine here struct datum { float num = 0.0; } datum emitOne() { datum t; return t; } const dataArr = [emitOne()]; // A very bad day //struct datum { float num = 0.0; } void main(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9278b.d ================================================ // PREMUTE_ARGS: // Works fine here //struct datum { float num = 0.0; } datum emitOne() { datum t; return t; } const dataArr = [emitOne()]; // A very bad day struct datum { float num = 0.0; } void main(){} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9399.d ================================================ // REQUIRED_ARGS: -inline -Icompilable/imports // EXTRA_SOURCES: imports/test9399a.d import imports.test9399a; void fun(int a) { void nested() { a = 42; } call!nested(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9434.d ================================================ import test9435;//semantic; template Visitors() { mixin Semantic!(typeof(this)); } class Node { mixin Visitors; } class Expression : Node { } class BinaryExp(TokenType op) : Expression { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9435.d ================================================ import test9434;//expression; enum TokenType { Dot } template Tok(string type) { enum Tok = TokenType.Dot; } template Semantic(T) { invariant(){} } template Semantic(T) if (is(T == BinaryExp!(Tok!"."))) { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9436.d ================================================ // EXTRA_SOURCES: imports/test9436interp.d // this is a dummy module for test 9436. ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9526.d ================================================ template forward(args...) { @property fwd()() { return args[0]; } static assert(__traits(compiles, { auto ex = fwd; })); alias fwd forward; } void initializeClassInstance(C, Args...)(C chunk, auto ref Args args) { chunk.__ctor(forward!args); } void main() { static int si = 0; static class C { this(int) { ++si; } } void[__traits(classInstanceSize, C)] buff = void; auto c = cast(C) buff.ptr; initializeClassInstance(c, 0); assert(si); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9554.d ================================================ // REQUIRED_ARGS: -o- module pkg.test9554; alias mod = pkg.test9554; template Test(alias name) { enum Test = name; } void fun() {} static assert(fun.stringof == Test!(fun.stringof)); static assert(fun.stringof == "fun()"); static assert(fun.mangleof == Test!(fun.mangleof)); static assert(fun.mangleof == "_D3pkg8test95543funFZv"); static assert(mod.stringof == Test!(mod.stringof)); static assert(mod.stringof == "module test9554"); static assert(mod.mangleof == Test!(mod.mangleof)); static assert(mod.mangleof == "3pkg8test9554"); static assert(pkg.stringof == Test!(pkg.stringof)); static assert(pkg.stringof == "package pkg"); static assert(pkg.mangleof == Test!(pkg.mangleof)); static assert(pkg.mangleof == "3pkg"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9565.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: template TypeTuple(T...) { alias TypeTuple = T; } bool startsWith(string s, string m) { return s[0 .. m.length] == m; } void main() { enum string castPrefix = "cast(" ~ size_t.stringof ~ ")"; // TypeSArray static assert((int[10]).stringof == "int[10]", T.stringof); int[] arr; // IndexExp { // index == IntegerExp static assert((arr[ 4 ]).stringof == "arr[4]"); static assert((arr[ 4U ]).stringof == "arr[4]"); static assert((arr[ 4L ]).stringof == "arr[4]"); static assert((arr[ 4LU]).stringof == "arr[4]"); // index == UAddExp static assert((arr[+4 ]).stringof == "arr[4]"); static assert((arr[+4U ]).stringof == "arr[4]"); static assert((arr[+4L ]).stringof == "arr[4]"); static assert((arr[+4LU]).stringof == "arr[4]"); // index == NegExp static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]"); static assert((arr[-4U ]).stringof == "arr[4294967292]"); static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]"); static if (is(size_t == ulong)) { static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]"); static assert((arr[-4LU]).stringof == "arr[-4LU]"); // IntegerLiteral needs suffix if the value is greater than long.max static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]"); static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]"); } foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong)) { enum Int p4 = +4; enum string result1 = (arr[p4]).stringof; static assert(result1 == "arr[4]"); enum string result2 = (arr[cast(Int)+4]).stringof; static assert(result2 == "arr[4]"); } foreach (Int; TypeTuple!(byte, short, int, long)) { // keep "cast(Type)" in the string representation enum Int m4 = -4; static if (is(typeof({ size_t x = m4; }))) { enum string result1 = (arr[m4]).stringof; static assert(result1.startsWith("arr[" ~ castPrefix)); } else static assert(!__traits(compiles, arr[m4])); enum string result2 = (arr[cast(Int)-4]).stringof; static assert(result2.startsWith("arr[" ~ castPrefix)); } } // SliceExp { // lwr,upr == IntegerExp static assert((arr[4 .. 8 ]).stringof == "arr[4..8]"); static assert((arr[4U .. 8U ]).stringof == "arr[4..8]"); static assert((arr[4L .. 8L ]).stringof == "arr[4..8]"); static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]"); // lwr,upr == UAddExp static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]"); static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]"); static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]"); static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]"); } } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9570.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: void main() { ubyte[256] data; foreach (immutable i; 0..256) data[i] = i; foreach ( const i; 0..256) data[i] = i; foreach ( i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable int i; 0..256) data[i] = i; foreach ( const int i; 0..256) data[i] = i; foreach ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable(int) i; 0..256) data[i] = i; foreach ( const(int) i; 0..256) data[i] = i; foreach ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable(ulong) i; 0..256) data[i] = i; foreach ( const(ulong) i; 0..256) data[i] = i; foreach ( ulong i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable i, x; data) data[i] = i; foreach ( const i, x; data) data[i] = i; foreach ( i, x; data) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable int i, x; data) data[i] = i; foreach ( const int i, x; data) data[i] = i; foreach ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable(int) i, x; data) data[i] = i; foreach ( const(int) i, x; data) data[i] = i; foreach ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); foreach (immutable(ulong) i, x; data) data[i] = i; foreach ( const(ulong) i, x; data) data[i] = i; foreach ( ulong i, x; data) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable i; 0..256) data[i] = i; foreach_reverse ( const i; 0..256) data[i] = i; foreach_reverse ( i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable int i; 0..256) data[i] = i; foreach_reverse ( const int i; 0..256) data[i] = i; foreach_reverse ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable(int) i; 0..256) data[i] = i; foreach_reverse ( const(int) i; 0..256) data[i] = i; foreach_reverse ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable(ulong) i; 0..256) data[i] = i; foreach_reverse ( const(ulong) i; 0..256) data[i] = i; foreach_reverse ( ulong i; 0..256) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable i, x; data) data[i] = i; foreach_reverse ( const i, x; data) data[i] = i; foreach_reverse ( i, x; data) static assert(!__traits(compiles, (data[i] = i))); //foreach_reverse (immutable int i, x; data) data[i] = i; //foreach_reverse ( const int i, x; data) data[i] = i; //foreach_reverse ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); //foreach_reverse (immutable(int) i, x; data) data[i] = i; //foreach_reverse ( const(int) i, x; data) data[i] = i; //foreach_reverse ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); foreach_reverse (immutable(ulong) i, x; data) data[i] = i; foreach_reverse ( const(ulong) i, x; data) data[i] = i; foreach_reverse ( ulong i, x; data) static assert(!__traits(compiles, (data[i] = i))); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9613.d ================================================ // PREMUTE_ARGS: struct S9613 { int f( const(byte) a = const(byte).init, immutable(byte) b = immutable(byte).init, shared(byte) c = shared(byte).init, inout(byte) d = inout(byte).init, ) inout { assert(a == byte.init); assert(b == byte.init); assert(c == byte.init); assert(d == byte.init); static assert(const(byte).init == byte.init); static assert(immutable(byte).init == byte.init); static assert(shared(byte).init == byte.init); static assert(inout(byte).init == byte.init); return 0; } } void main() { static assert(const(byte).init == byte.init); static assert(immutable(byte).init == byte.init); static assert(shared(byte).init == byte.init); static assert(const(byte).init.sizeof == byte.sizeof); static assert(const(byte[2]).init[0] == byte.init); enum s = S9613(); enum v = s.f(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9639.d ================================================ class A { this(A) {} } class B {} class C {} // two sibling nested functions in main typeof(null) foo(alias fn)(A a) { fn(a); return foo!fn(B.init); } typeof(null) foo(alias fn)(B b) { return foo!fn(A.init); } // three sibling nested functions in main typeof(null) bar(alias fn)(A a) { fn(a); return bar!fn(B.init); } typeof(null) bar(alias fn)(B b) { return bar!fn(C.init); } typeof(null) bar(alias fn)(C c) { return bar!fn(A.init); } void main() { A a; foo!((stuff){ new A(a); })(a); bar!((stuff){ new A(a); })(a); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9672.d ================================================ module test9672; // node import imports.test9672a; // interpret mixin template ForwardCtor() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9692.d ================================================ module test9692; import test9692a; import imports.test9692b; enum x = [__traits(allMembers, imports.test9692b)]; // ok enum y = [__traits(allMembers, test9692a)]; // ng: should work ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9692a.d ================================================ module test9692a; int j; ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9701.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=9701 template AliasSeq(TList...) { alias AliasSeq = TList; } enum { uda4, uda5, uda6, uda8, uda9 } enum Enum { value0, @("uda1") value1, @("uda2", "uda3", 42) value2, @uda4 value3, @uda5 @uda6 value4, @("uda7") @uda8 value5, @uda9 @("uda10") value6, deprecated value7, deprecated("message") value8, } @("uda0") enum { value0, @("uda1") value1, @("uda2") @("uda3") value2, @uda4 value3, @uda5 @uda6 value4, @("uda7") @uda8 value5, @uda9 @("uda10") value6 } static assert(__traits(getAttributes, Enum.value0).length == 0); static assert(__traits(getAttributes, Enum.value1) == AliasSeq!("uda1")); static assert(__traits(getAttributes, Enum.value2) == AliasSeq!("uda2", "uda3", 42)); static assert(__traits(getAttributes, Enum.value3) == AliasSeq!(uda4)); static assert(__traits(getAttributes, Enum.value4) == AliasSeq!(uda5, uda6)); static assert(__traits(getAttributes, Enum.value5) == AliasSeq!("uda7", uda8)); static assert(__traits(getAttributes, Enum.value6) == AliasSeq!(uda9, "uda10")); static assert(__traits(isDeprecated, Enum.value7)); static assert(__traits(isDeprecated, Enum.value8)); static assert(__traits(getAttributes, value0) == AliasSeq!("uda0")); static assert(__traits(getAttributes, value1) == AliasSeq!("uda0", "uda1")); static assert(__traits(getAttributes, value2) == AliasSeq!("uda0", "uda2", "uda3")); static assert(__traits(getAttributes, value3) == AliasSeq!("uda0", uda4)); static assert(__traits(getAttributes, value4) == AliasSeq!("uda0", uda5, uda6)); static assert(__traits(getAttributes, value5) == AliasSeq!("uda0", "uda7", uda8)); static assert(__traits(getAttributes, value6) == AliasSeq!("uda0", uda9, "uda10")); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9766.d ================================================ // PERMUTE_ARGS: size_t getAlign9766(size_t n) { return n; } struct S9766 { align(getAlign9766(1)): ubyte[5] pad1; ubyte var1; align(getAlign9766(2)): ubyte[5] pad2; ubyte var2; align(getAlign9766(4)): ubyte[5] pad3; ubyte var3; align(getAlign9766(8)): ubyte[5] pad4; ubyte var4; } static assert(S9766.pad1.offsetof == 0); static assert(S9766.var1.offsetof == 5); static assert(S9766.pad2.offsetof == 6); static assert(S9766.var2.offsetof == 12); static assert(S9766.pad3.offsetof == 16); static assert(S9766.var3.offsetof == 24); static assert(S9766.pad4.offsetof == 32); static assert(S9766.var4.offsetof == 40); union U9766 { struct { align(getAlign9766(1)): ubyte[5] pad1; ubyte var1; align(getAlign9766(2)): ubyte[5] pad2; ubyte var2; align(getAlign9766(4)): ubyte[5] pad3; ubyte var3; align(getAlign9766(8)): ubyte[5] pad4; ubyte var4; } } static assert(U9766.pad1.offsetof == 0); static assert(U9766.var1.offsetof == 5); static assert(U9766.pad2.offsetof == 6); static assert(U9766.var2.offsetof == 12); static assert(U9766.pad3.offsetof == 16); static assert(U9766.var3.offsetof == 24); static assert(U9766.pad4.offsetof == 32); static assert(U9766.var4.offsetof == 40); struct TestMaxAlign { align(1u << 31): ubyte a; ubyte b; } static assert(TestMaxAlign.b.offsetof == 2147483648u); ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9818.d ================================================ /************************************/ // https://issues.dlang.org/show_bug.cgi?id=9818 /* TEST_OUTPUT: --- sa1: [1, 1, 1] ea1: [1, 1, 1] sa2: [1, 1, 1] ea2: [1, 1, 1] eas: [1, 1, 1] eac: [1, 1, 1] sa3: [1, 1, 1] ea3: [1, 1, 1] sa4: [1, 1, 1] ea4: [1, 1, 1] --- */ static const int[3] sa1 = 1; pragma(msg, "sa1: ", sa1); // doesn't work static assert(sa1 == [1, 1, 1]); // doesn't work enum int[3] ea1 = 1; pragma(msg, "ea1: ", ea1); // prints "1" - bad static assert(ea1 == [1, 1, 1]); // doesn't work struct X { static const int[3] sa2 = 1; pragma(msg, "sa2: ", sa1); // doesn't work static assert(sa2 == [1, 1, 1]); // doesn't work enum int[3] ea2 = 1; pragma(msg, "ea2: ", ea2); // prints "1" - bad static assert(ea2 == [1, 1, 1]); // doesn't work } struct S { enum int[3] eas = 1; } pragma(msg, "eas: ", S.eas); static assert(S.eas == [1, 1, 1]); class C { enum int[3] eac = 1; } pragma(msg, "eac: ", C.eac); static assert(C.eac == [1, 1, 1]); void test() { static const int[3] sa3 = 1; pragma(msg, "sa3: ", sa3); // doesn't work static assert(sa3 == [1, 1, 1]); // doesn't work enum int[3] ea3 = 1; pragma(msg, "ea3: ", ea3); // prints "1" - bad static assert(ea3 == [1, 1, 1]); // doesn't work struct Y { static const int[3] sa4 = 1; pragma(msg, "sa4: ", sa4); // doesn't work static assert(sa4 == [1, 1, 1]); // doesn't work enum int[3] ea4 = 1; pragma(msg, "ea4: ", ea4); // prints "1" - bad static assert(ea4 == [1, 1, 1]); // doesn't work } } /************************************/ void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/test9919.d ================================================ // REQUIRED_ARGS: -o- module test9919; public { import imports.test9919a; import imports.test9919b; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP37.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_FILES: extra-files/pkgDIP37/datetime/package.d extra-files/pkgDIP37/datetime/common.d extra-files/pkgDIP37/test17629/package.di extra-files/pkgDIP37/test17629/common.di void test1() { import pkgDIP37.datetime; def(); pkgDIP37.datetime.def(); pkgDIP37.datetime.common.def(); } void test3() { import pkgDIP37.datetime.common; def(); pkgDIP37.datetime.def(); pkgDIP37.datetime.common.def(); } void test4() { import pkgDIP37.datetime : def; def(); static assert(!__traits(compiles, pkgDIP37.datetime.def())); static assert(!__traits(compiles, pkgDIP37.datetime.common.def())); } void test7() { static import pkgDIP37.datetime; static assert(!__traits(compiles, def())); pkgDIP37.datetime.def(); } // https://issues.dlang.org/show_bug.cgi?id=17629 void test17629() { import pkgDIP37.test17629; foo17629(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP37_10302.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // EXTRA_SOURCES: extra-files/pkgDIP37_10302/liba.d extra-files/pkgDIP37_10302/libb.d // EXTRA_FILES: extra-files/pkgDIP37_10302/package.d module test; import pkgDIP37_10302; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP37_10354.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -o- -Icompilable/extra-files // EXTRA_FILES: extra-files/pkgDIP37_10354/mbar.d extra-files/pkgDIP37_10354/mfoo.d extra-files/pkgDIP37_10354/package.d module testDIP37_10354; import pkgDIP37_10354.mfoo; void main() { import pkgDIP37_10354; foo!string(); // OK bar!string(); // OK <- ICE } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP37_10421.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // COMPILED_IMPORTS: extra-files/pkgDIP37_10421/algo/package.d extra-files/pkgDIP37_10421/algo/mod.d extra-files/pkgDIP37_10421/except.d module testDIP37_10421; import pkgDIP37_10421.algo; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP37a.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -Icompilable/extra-files // COMPILED_IMPORTS: extra-files/pkgDIP37/datetime/package.d // COMPILED_IMPORTS: extra-files/pkgDIP37/datetime/common.d void main() { } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testDIP42.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: // enum ident(tpl) = Initializer; enum isIntegral(T) = is(T == int) || is(T == long); static assert( isIntegral!int); static assert( isIntegral!long); static assert(!isIntegral!double); static assert(!isIntegral!(int[])); version(none) { enum allSatisfy(alias pred, TL...) = TL.length == 0 || (pred!(TL[0]) && allSatisfy!(pred, TL[1..$])), anySatisfy(alias pred, TL...) = TL.length != 0 && (pred!(TL[0]) || anySatisfy!(pred, TL[1..$])) || false; static assert( allSatisfy!(isIntegral, int, long)); static assert(!allSatisfy!(isIntegral, int, double)); static assert( anySatisfy!(isIntegral, int, double)); static assert(!anySatisfy!(isIntegral, int[], double)); } void test1() { // statement enum isIntegral2(T) = is(T == int) || is(T == long); static assert(isIntegral2!int); } /******************************************/ // alias ident(tpl) = Type; alias TypeTuple(TL...) = TL; static assert(is(TypeTuple!(int, long)[0] == int)); static assert(is(TypeTuple!(int, long)[1] == long)); alias Id(T) = T, Id(alias A) = A; static assert(is(Id!int == int)); static assert(__traits(isSame, Id!TypeTuple, TypeTuple)); void test2() { // statement alias TypeTuple2(TL...) = TL; static assert(is(TypeTuple2!(int, long)[0] == int)); static assert(is(TypeTuple2!(int, long)[1] == long)); alias IdT(T) = T, IdA(alias A) = A; static assert(is(IdT!int == int)); static assert(__traits(isSame, IdA!TypeTuple, TypeTuple)); } /******************************************/ // template auto declaration auto tynameLen(T) = T.stringof.length; void test3() { assert(tynameLen!int == 3); assert(tynameLen!long == 4); tynameLen!int = 4; tynameLen!long = 5; assert(tynameLen!int == 4); assert(tynameLen!long == 5); // statement auto tynameLen2(T) = T.stringof.length; assert(tynameLen2!int == 3); assert(tynameLen2!long == 4); tynameLen2!int = 4; tynameLen2!long = 5; assert(tynameLen2!int == 4); assert(tynameLen2!long == 5); } /******************************************/ // template variable declaration static T math_pi(T) = cast(T)3.1415; enum bool isFloatingPoint(T) = is(T == float) || is(T == double); static assert( isFloatingPoint!double); static assert(!isFloatingPoint!string); void main() { assert(math_pi!int == 3); assert(math_pi!double == 3.1415); enum bool isFloatingPoint2(T) = is(T == float) || is(T == double); static assert( isFloatingPoint2!double); static assert(!isFloatingPoint2!string); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testInference.d ================================================ /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6265 pure nothrow @safe int h6265() { return 1; } int f6265a(alias g)() { return g(); } pure nothrow @safe int i6265a() { return f6265a!h6265(); } int f6265b()() { return h6265(); } pure nothrow @safe int i6265b() { return f6265b(); } pure nothrow @safe int i6265c() { return { return h6265(); }(); } /***************************************************/ // Make sure a function is not infered as pure if it isn't. int fNPa() { return 1; } int gNPa()() { return fNPa(); } static assert( __traits(compiles, function int () { return gNPa(); })); static assert(!__traits(compiles, function int () pure { return gNPa(); })); static assert(!__traits(compiles, function int () nothrow { return gNPa(); })); static assert(!__traits(compiles, function int () @safe { return gNPa(); })); /***************************************************/ // Need to ensure the comment in Expression::checkPurity is not violated. void fECPa() { void g()() { void h() { } h(); } static assert( is(typeof(&g!()) == void delegate() pure nothrow @nogc @safe)); static assert(!is(typeof(&g!()) == void delegate())); } void fECPb() { void g()() { void h() { } fECPb(); } static assert(!is(typeof(&g!()) == void delegate() pure)); static assert( is(typeof(&g!()) == void delegate())); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5635 pure bool foo5635(R = int)(string x) { bool result = false; foreach (dchar d; x) result = true; return result; } void test5635() { foo5635("hi"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5936 auto bug5936c(R)(R i) @safe pure nothrow { return true; } static assert( bug5936c(0) ); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6351 void bug6351(alias dg)() { dg(); } void test6351() { void delegate(int[] a...) deleg6351 = (int[] a...){}; alias bug6351!(deleg6351) baz6531; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6359 void impure6359() nothrow @safe @nogc {} void throwable6359() pure @safe @nogc {} void system6359() pure nothrow @nogc {} void gcable6359() pure nothrow @safe {} int global6359; void f6359() pure nothrow @safe @nogc { static assert(!__traits(compiles, impure6359())); static assert(!__traits(compiles, throwable6359())); static assert(!__traits(compiles, system6359())); static assert(!__traits(compiles, gcable6359())); static assert(!__traits(compiles, global6359++)); static assert(!__traits(compiles, { impure6359(); }())); static assert(!__traits(compiles, { throwable6359(); }())); static assert(!__traits(compiles, { system6359(); }())); static assert(!__traits(compiles, { gcable6359(); }())); static assert(!__traits(compiles, { global6359++; }())); } void g6359()() pure nothrow @safe @nogc { static assert(!__traits(compiles, impure6359())); static assert(!__traits(compiles, throwable6359())); static assert(!__traits(compiles, system6359())); static assert(!__traits(compiles, gcable6359())); static assert(!__traits(compiles, global6359++)); static assert(!__traits(compiles, { impure6359(); }())); static assert(!__traits(compiles, { throwable6359(); }())); static assert(!__traits(compiles, { system6359(); }())); static assert(!__traits(compiles, { gcable6359(); }())); static assert(!__traits(compiles, { global6359++; }())); } // attribute inference is not affected by the expressions inside __traits(compiles) void h6359()() { static assert( __traits(compiles, impure6359())); static assert( __traits(compiles, throwable6359())); static assert( __traits(compiles, system6359())); static assert( __traits(compiles, gcable6359())); static assert( __traits(compiles, global6359++)); static assert( __traits(compiles, { impure6359(); }())); static assert( __traits(compiles, { throwable6359(); }())); static assert( __traits(compiles, { system6359(); }())); static assert( __traits(compiles, { gcable6359(); }())); static assert( __traits(compiles, { global6359++; }())); } void test6359() pure nothrow @safe @nogc { f6359(); g6359(); h6359(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7017 template map7017(fun...) if (fun.length >= 1) { auto map7017() { struct Result { this(int dummy){} // impure member function -> inferred to pure by fixing issue 10329 } return Result(0); // impure call -> inferred to pure by fixing issue 10329 } } int foo7017(immutable int x) pure nothrow { return 1; } void test7017a() pure { int bar7017(immutable int x) pure nothrow { return 1; } static assert(__traits(compiles, map7017!((){})())); static assert(__traits(compiles, map7017!q{ 1 }())); static assert(__traits(compiles, map7017!foo7017())); static assert(__traits(compiles, map7017!bar7017())); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7017 (little simpler cases) auto map7017a(alias fun)() { return fun(); } // depends on purity of fun auto map7017b(alias fun)() { return; } // always pure auto map7017c(alias fun)() { return yyy7017(); } // always impure int xxx7017() pure { return 1; } int yyy7017() { return 1; } void test7017b() pure { static assert( __traits(compiles, map7017a!xxx7017() )); static assert(!__traits(compiles, map7017a!yyy7017() )); static assert( __traits(compiles, map7017b!xxx7017() )); static assert( __traits(compiles, map7017b!yyy7017() )); static assert(!__traits(compiles, map7017c!xxx7017() )); static assert(!__traits(compiles, map7017c!yyy7017() )); } /***************************************************/ // Test case from std.process auto escapeArgumentImpl(alias allocator)() { return allocator(); } auto escapeShellArgument(alias allocator)() { return escapeArgumentImpl!allocator(); } pure string escapeShellArguments() { char[] allocator() { return new char[1]; } /* Both escape!allocator and escapeImpl!allocator are impure, * but they are nested template function that instantiated here. * Then calling them from here doesn't break purity. */ return escapeShellArgument!allocator(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8234 void test8234() { immutable int x = 0; alias FP = typeof({ enum e = x; return e; }); static assert(is(FP : int function())); auto fp = { enum e = x; return e; }; static assert(is(typeof(fp) : int function())); alias DG = typeof({ auto e = x; return e; }); static assert(is(DG : int delegate())); auto dg = { auto e = x; return e; }; static assert(is(typeof(dg) : int delegate())); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8504 import core.demangle : demangle; void foo8504()() { static assert(typeof(foo8504!()).stringof == "void()"); static assert(typeof(foo8504!()).mangleof == "FZv"); static assert(demangle(foo8504!().mangleof) == "void testInference.foo8504!().foo8504()"); } auto toDelegate8504a(F)(auto ref F fp) { return fp; } F toDelegate8504b(F)(auto ref F fp) { return fp; } extern(C) void testC8504() {} void test8504() { static assert(typeof(foo8504!()).stringof == "pure nothrow @nogc @safe void()"); static assert(typeof(foo8504!()).mangleof == "FNaNbNiNfZv"); static assert(demangle(foo8504!().mangleof) == "pure nothrow @nogc @safe void testInference.foo8504!().foo8504()"); auto fp1 = toDelegate8504a(&testC8504); auto fp2 = toDelegate8504b(&testC8504); static assert(is(typeof(fp1) == typeof(fp2))); static assert(typeof(fp1).stringof == "extern (C) void function()"); static assert(typeof(fp2).stringof == "extern (C) void function()"); static assert(typeof(fp1).mangleof == "PUZv"); static assert(typeof(fp2).mangleof == "PUZv"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8751 alias bool delegate(in int) pure Bar8751; Bar8751 foo8751a(immutable int x) pure { return y => x > y; // OK } Bar8751 foo8751b(const int x) pure { return y => x > y; // error -> OK } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8793 alias bool delegate(in int) pure Dg8793; alias bool function(in int) pure Fp8793; Dg8793 foo8793fp1(immutable Fp8793 f) pure { return x => (*f)(x); } // OK Dg8793 foo8793fp2( const Fp8793 f) pure { return x => (*f)(x); } // OK Dg8793 foo8793dg1(immutable Dg8793 f) pure { return x => f(x); } // OK Dg8793 foo8793dg2( const Dg8793 f) pure { return x => f(x); } // OK <- error Dg8793 foo8793pfp1(immutable Fp8793* f) pure { return x => (*f)(x); } // OK Dg8793 foo8793pdg1(immutable Dg8793* f) pure { return x => (*f)(x); } // OK Dg8793 foo8793pfp2(const Fp8793* f) pure { return x => (*f)(x); } // OK <- error Dg8793 foo8793pdg2(const Dg8793* f) pure { return x => (*f)(x); } // OK <- error // general case for the hasPointer type Dg8793 foo8793ptr1(immutable int* p) pure { return x => *p == x; } // OK Dg8793 foo8793ptr2(const int* p) pure { return x => *p == x; } // OK <- error /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9072 struct A9072(T) { this(U)(U x) {} ~this() {} } void test9072() { A9072!int a = A9072!short(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5933 // https://issues.dlang.org/show_bug.cgi?id=8504 // Template attribute inferrence doesn't work int foo5933()(int a) { return a*a; } struct S5933 { double foo()(double a) { return a * a; } } // outside function static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); void test5933() { // inside function static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9148 void test9148a() pure { static int g; int x; void foo1() /+pure+/ { static assert(!__traits(compiles, g++)); x++; } void foo2() pure { static assert(!__traits(compiles, g++)); x++; } foo1(); static assert(is(typeof(&foo1) == void delegate() pure nothrow @nogc @safe)); foo2(); static assert(is(typeof(&foo2) == void delegate() pure nothrow @nogc @safe)); void bar1() immutable /+pure+/ { static assert(!__traits(compiles, g++)); static assert(!__traits(compiles, x++)); } void bar2() immutable pure { static assert(!__traits(compiles, g++)); static assert(!__traits(compiles, x++)); } bar1(); static assert(is(typeof(&bar1) == void delegate() pure immutable nothrow @nogc @safe)); bar2(); static assert(is(typeof(&bar2) == void delegate() pure immutable nothrow @nogc @safe)); struct S { void foo1() /+pure+/ { static assert(!__traits(compiles, g++)); x++; } void foo2() pure { static assert(!__traits(compiles, g++)); x++; } void bar1() immutable /+pure+/ { static assert(!__traits(compiles, g++)); static assert(!__traits(compiles, x++)); } void bar2() immutable pure { static assert(!__traits(compiles, g++)); static assert(!__traits(compiles, x++)); } } S sm; sm.foo1(); static assert(is(typeof(&sm.foo1) == void delegate() pure)); sm.foo2(); static assert(is(typeof(&sm.foo2) == void delegate() pure)); immutable S si; si.bar1(); static assert(is(typeof(&si.bar1) == void delegate() pure immutable)); si.bar2(); static assert(is(typeof(&si.bar2) == void delegate() pure immutable)); } // ---- // inheritance of pure and @safe void test9148b() pure nothrow @nogc @safe { void nf() {} static assert(is(typeof(&nf) == void delegate() pure nothrow @nogc @safe)); struct NS { void mf() {} static void sf() {} } NS ns; static assert(is(typeof(&ns.mf) == void delegate() pure nothrow @nogc @safe)); static assert(is(typeof(&NS.sf) == void function() pure nothrow @nogc @safe)); static void sf() {} static assert(is(typeof(&sf) == void function() pure nothrow @nogc @safe)); static struct SS { void mf() {} static void sf() {} } SS ss; static assert(is(typeof(&ss.mf) == void delegate() pure nothrow @nogc @safe)); static assert(is(typeof(&SS.sf) == void function() pure nothrow @nogc @safe)); } void impureSystem9148b() {} void func9148b()() { void bar() // do not inherit PUREfwdref { static assert(is(typeof(&bar) == void delegate())); impureSystem9148b(); } static assert(is(typeof(&bar) == void delegate())); } static assert(is(typeof(&func9148b!()) == void function() pure nothrow @nogc @safe)); // ---- // from fail_compilation/fail283.d pure int double_sqr9148c(int x) { int y = x; void do_sqr() pure { y *= y; } do_sqr(); return y; } void test9148c() { assert(double_sqr9148c(10) == 100); } // ---- // from fail_compilation/fail348.d void test9148d() pure { void g() // implicitly marked as 'pure' { void h() pure { // i() and j() are implicitly marked as 'pure' void i() { } void j() { i(); g(); } // can call i() and g() } } } void test9148e() { int x; static assert(is(typeof((int a){ return a + x; }) == int delegate(int) pure nothrow @nogc @safe)); auto dg = (int a){ return a + x; }; static assert(is(typeof(dg) == int delegate(int) pure nothrow @nogc @safe)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12912 struct S12912(alias fun) { void f() { fun(); } } class C12912 { int n; void f() pure { S12912!(() => n) s; // Here lambda should be inferred to weak purity. s.f(); // And this call will be a pure member function call. } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10002 void impure10002() {} void remove10002(alias pred, bool impure = false, Range)(Range range) { pred(range[0]); static if (impure) impure10002(); } class Node10002 { Node10002 parent; Node10002[] children; void foo() pure { parent.children.remove10002!(n => n is parent)(); remove10002!(n => n is parent)(parent.children); static assert(!__traits(compiles, parent.children.remove10002x!(n => n is parent, true)())); static assert(!__traits(compiles, remove10002x!(n => n is parent, true)(parent.children))); Node10002 p; p.children.remove10002!(n => n is p)(); remove10002!(n => n is p)(p.children); static assert(!__traits(compiles, p.children.remove10002x!(n => n is p, true)())); static assert(!__traits(compiles, remove10002x!(n => n is p, true)(p.children))); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10148 void fa10148() {} // fa is @system auto fb10148(T)() { struct A(S) { // [4] Parent function fb is already inferred to @safe, then // fc is forcely marked @safe on default until 2.052. // But fc should keep attribute inference ability // by overriding the inherited @safe-ty from its parent. void fc(T2)() { // [5] During semantic3 process, fc is not @safe on default. static assert(is(typeof(&fc) == void delegate())); fa10148(); } // [1] this is now inferred to @safe by implementing issue 7511 this(S a) {} } // [2] A!int(0) is now calling @safe function, then fb!T also be inferred to @safe return A!int(0); } void test10148() { fb10148!int.fc!int; // [0] instantiate fb // [3] instantiate fc // [6] After semantic3 done, fc!int is deduced to @system. static assert(is(typeof(&fb10148!int.fc!int) == void delegate() @system)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10289 void test10289() { void foo(E)() { throw new E(""); } void bar(E1, E2)() { throw new E1(""); throw new E2(""); } void baz(E1, E2)(bool cond) { if (cond) throw new E1(""); else throw new E2(""); } import core.exception; static class MyException : Exception { this(string) @safe pure nothrow { super(""); } } static assert( __traits(compiles, () nothrow { foo!Error(); })); static assert( __traits(compiles, () nothrow { foo!AssertError(); })); static assert(!__traits(compiles, () nothrow { foo!Exception(); })); static assert(!__traits(compiles, () nothrow { foo!MyException(); })); static assert( __traits(compiles, () nothrow { bar!(Error, Exception)(); })); static assert(!__traits(compiles, () nothrow { bar!(Exception, Error)(); })); static assert(!__traits(compiles, () nothrow { baz!(Error, Exception)(); })); static assert(!__traits(compiles, () nothrow { baz!(Exception, Error)(); })); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10296 void foo10296()() { int[3] a; void bar()() { a[1] = 2; } bar(); pragma(msg, typeof(bar!())); // nothrow @safe void() } pure void test10296() { foo10296(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12025 struct Foo12025 { int[5] bar; } void test12025a() pure { enum n1 = typeof(Foo12025.bar).length; // OK enum n2 = Foo12025.bar .length; // OK <- error auto x1 = typeof(Foo12025.bar).length; // OK auto x2 = Foo12025.bar .length; // OK <- error } void test12025b() pure { static int[5] bar; enum n1 = typeof(bar).length; // OK enum n2 = bar .length; // OK <- error auto x1 = typeof(bar).length; // OK auto x2 = bar .length; // OK <- error } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12542 int logOf12542(T)(T n) { if (n) return 1 + logOf12542(n/2); return 0; } void test12542() @safe nothrow pure { int log = logOf12542(9); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12704 void foo12704() @system; alias FP12704 = typeof(function() { foo12704(); }); static assert(is(FP12704 == void function() @system)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12970 @system { @safe void f12970a() {} } @system { void f12970b() @safe {} } static assert(is(typeof(&f12970a) == void function() @safe)); static assert(is(typeof(&f12970b) == void function() @safe)); @system { @trusted void f12970c() {} } @system { void f12970d() @trusted {} } static assert(is(typeof(&f12970c) == void function() @trusted)); static assert(is(typeof(&f12970d) == void function() @trusted)); @safe { @system void f12970e() {} } @safe { void f12970f() @system {} } static assert(is(typeof(&f12970e) == void function() @system)); static assert(is(typeof(&f12970f) == void function() @system)); @safe { @trusted void f12970g() {} } @safe { void f12970h() @trusted {} } static assert(is(typeof(&f12970g) == void function() @trusted)); static assert(is(typeof(&f12970h) == void function() @trusted)); @trusted { @safe void f12970i() {} } @trusted { void f12970j() @safe {} } static assert(is(typeof(&f12970i) == void function() @safe)); static assert(is(typeof(&f12970j) == void function() @safe)); @trusted { @system void f12970k() {} } @trusted { void f12970l() @system {} } static assert(is(typeof(&f12970k) == void function() @system)); static assert(is(typeof(&f12970l) == void function() @system)); /***************************************************/ // Parsing prefix STC_FUNCATTR for variable declaration __gshared immutable pure nothrow @property @nogc @safe void function() prefix_qualified_fp1; __gshared{immutable{pure{nothrow{@property{@nogc{@safe{void function() prefix_qualified_fp2;}}}}}}} static assert(typeof(prefix_qualified_fp1).stringof == typeof(prefix_qualified_fp2).stringof); static assert(typeof(prefix_qualified_fp1).stringof == "immutable(void function() pure nothrow @nogc @property @safe)"); const pure nothrow @property @nogc @safe void function()[] prefix_qualified_fp_array1; const{pure{nothrow{@property{@nogc{@safe{void function()[] prefix_qualified_fp_array2;}}}}}} static assert(typeof(prefix_qualified_fp_array1).stringof == typeof(prefix_qualified_fp_array2).stringof); static assert(typeof(prefix_qualified_fp_array1).stringof == "const(void function() pure nothrow @nogc @property @safe[])"); /***************************************************/ // Parsing prefix, intermediate, or postfix @safe for alias declaration @safe alias void function() AliasDecl_FP1; alias @safe void function() AliasDecl_FP2; // is not @safe alias void function() @safe AliasDecl_FP3; static assert(AliasDecl_FP1.stringof == "void function() @safe"); static assert(AliasDecl_FP2.stringof == "void function()"); static assert(AliasDecl_FP3.stringof == "void function() @safe"); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13217 void writeln13217(string) {} nothrow void a13217(T)(T x) { try { () { writeln13217("a"); } (); } catch (Exception e) {} } void test13217() { a13217(1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13840 struct Foo13840 { int opApply(int delegate(int)) { return 0; } } void func13840() { } void test13840() nothrow { try { foreach (i; Foo13840()) // generated delegate is throwable { func13840(); // throwable function call } } catch(Throwable) {} } // Add more tests regarding inferences later. ================================================ FILE: gcc/testsuite/gdc.test/compilable/testVRP.d ================================================ // PERMUTE_ARGS: -O -inline // Test value-range propagation. // https://issues.dlang.org/show_bug.cgi?id=3147 // https://issues.dlang.org/show_bug.cgi?id=6000 // https://issues.dlang.org/show_bug.cgi?id=5225 void add() { byte x, y; short a = x + y; } void leftShift() { byte x, y; short z = x << 1; } void leftShiftFail() { ubyte x, y; ushort z; static assert(!__traits(compiles, z = x << y)); // 1 << 31 surely overflows the range of 'ushort'. } void rightShiftFail() { short x; byte y, z; static assert(!__traits(compiles, z = x >> y)); // [this passes in 2.053.] } void rightShift() { ushort x; ubyte y = x >> 16; } void unsignedRightShiftFail() { int x; ubyte y; static assert(!__traits(compiles, y = x >>> 2)); // [this passes in 2.053.] } void subtract() { ubyte x, y; short z = x - y; } void multiply() { byte x, y; short z = x * y; } void subMulFail() { ubyte x, y; ubyte z; static assert(!__traits(compiles, z = x - y)); static assert(!__traits(compiles, z = x * y)); // [these pass in 2.053.] } void multiplyNeg1() { byte b; b = -1 + (b * -1); static assert(!__traits(compiles, b = -1 + b * ulong.max)); } void divide() { short w; byte y = w / 300; } void divideFail() { short w; byte y; static assert(!__traits(compiles, y = w / -1)); } void plus1Fail() { byte u, v; static assert(!__traits(compiles, v = u + 1)); // [these pass in 2.053.] } void modulus() { int x; byte u = x % 128; } void modulus_bug6000a() { ulong t; uint u = t % 16; } void modulus_bug6000b() { long n = 10520; ubyte b; static assert(!__traits(compiles, b = n % 10)); } void modulus2() { short s; byte b = byte.max; byte c = s % b; } void modulus3() { int i; short s = short.max; short t = i % s; } void modulus4() { uint i; ushort s; short t; static assert(!__traits(compiles, t = i % s)); } void modulus5() { short a; byte foo = (a - short.max - 1) % 127; } void modulusFail() { int i; short s; byte b; static assert(!__traits(compiles, b = i % s)); static assert(!__traits(compiles, b = i % 257)); // [these pass in 2.053.] } void bitwise() { ubyte a, b, c; uint d; c = a & b; c = a | b; c = a ^ b; c = d & 0xff; // [these pass in 2.053.] } void bitAnd() { byte c; int d; c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c)); // the result of the above is always 0 :). } void bitAndTest() { ushort a, b; byte res = ((a % 7) - 6) & ((b % 7) - 6); } void bitOrFail() { ubyte c; static assert(!__traits(compiles, c = c | 0x100)); // [this passes in 2.053.] } void bitAndOr() { ubyte c; c = (c | 0x1000) & ~0x1000; } void bitOrTest() { // Tests condition for different signs between min & max // ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1 ushort a, b; byte res = ((a % 127) - 126) | ((b % 6) - 5); } void bitAndFail() { int d; short s; byte c; static assert(!__traits(compiles, c = d & s)); static assert(!__traits(compiles, c = d & 256)); // [these pass in 2.053.] } void bitXor() { ushort s; ubyte c; c = (0xffff << (s & 0)) ^ 0xff00; } void bitComplement() { int i; ubyte b = ~(i | ~0xff); } void bitComplementFail() { ubyte b; static assert(!__traits(compiles, b = ~(b | 1))); // [this passes in 2.053.] } void negation() { int x; byte b = -(x & 0x7); } void negationFail() { int x; byte b; static assert(!__traits(compiles, b = -(x & 255))); // [this passes in 2.053.] } short bug5225(short a) { return a>>1; } short bug1977_comment5(byte i) { byte t = 1; short o = t - i; return o; } void testDchar() { dchar d; uint i; /+ static assert(!__traits(compiles, d = i)); static assert(!__traits(compiles, d = i & 0x1fffff)); +/ d = i % 0x110000; } void bug1977_comment11() { uint a; byte b = a & 1; // [this passes in 2.053.] } void bug1977_comment20() { long a; int b = a % 1000; } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=9617 void test9617() { void f1(int) {} void f2(short) {} void f3(byte) {} // Why these calls are accepted? static assert(!__traits(compiles, f1(ulong.max))); static assert(!__traits(compiles, f2(ulong.max))); static assert(!__traits(compiles, f3(ulong.max))); // But, if argument is not constant value, compilation fails. ulong x; static assert(!__traits(compiles, f1(x))); // is not callable using argument types (ulong) static assert(!__traits(compiles, f2(x))); // is not callable using argument types (ulong) static assert(!__traits(compiles, f3(x))); // is not callable using argument types (ulong) void f4(uint) {} void f5(ushort) {} void f6(ubyte) {} // If parameter type is unsigned, it is collectly rejected static assert(!__traits(compiles, f4(ulong.max))); // is not callable using argument types (ulong) static assert(!__traits(compiles, f5(ulong.max))); // is not callable using argument types (ulong) static assert(!__traits(compiles, f6(ulong.max))); // is not callable using argument types (ulong) } //import std.typetuple; template TypeTuple(T...) { alias TypeTuple = T; } template staticIota(size_t end) { static if (0 < end) alias staticIota = TypeTuple!(staticIota!(end - 1), end - 1); else alias staticIota = TypeTuple!(); } void test9617a() { alias Repr = TypeTuple!( byte, "127", // T and literal representation of T.max ubyte, "255", short, "32767", ushort, "65535", int, "2147483647", uint, "4294967295", long, "9223372036854775807", ulong, "18446744073709551615" // "" or "L" -> "signed integral overflow" ); alias Indices = staticIota!(Repr.length / 2); foreach (t; Indices) { alias T = Repr[t * 2]; void func(T)(T) {} alias func!T f; foreach (r; Indices) { alias S = Repr[r * 2]; S src = S.max; enum x = Repr[r * 2 + 1]; foreach (repr; TypeTuple!(S.stringof~".max", x~"", x~"U", x~"L", x~"LU")) { static if (S.sizeof != T.sizeof) static if (is(typeof(mixin(repr)) R)) { // "Compilable" test should be equal, even if // the given argument is either constant or runtime variable. enum ct = __traits(compiles, f( mixin(repr) )); enum rt = __traits(compiles, f( src )); static assert(ct == rt); //import std.string; //enum msg = format("%6s.max to %-6s variable/constant = %d/%d, constant_repr = (%s) %s", // S.stringof, T.stringof, rt, ct, R.stringof, repr); //static if (ct != rt) pragma(msg, msg); } } } } } void test10018(ubyte value) { const int c = value; ubyte b = c; static assert(!__traits(compiles, b = c - 1)); static assert(!__traits(compiles, b = c + 1)); immutable int i = value; b = i; static assert(!__traits(compiles, b = i - 1)); static assert(!__traits(compiles, b = i + 1)); } void test13001(bool unknown) { foreach (const i; 0..unknown?2:3) { ubyte b = i; static assert(!__traits(compiles, b = i - 1)); b = i + 253; static assert(!__traits(compiles, b = i + 254)); } } void test10310() { int y; ubyte x = ((y & 252) ^ 2) + 1; } // https://issues.dlang.org/show_bug.cgi?id=15289 void test15289a() { int [] arr = [1, 2, 3, 4]; uint foo = 50 / arr.length; } void test15289b() { int [] arr = [1, 2, 3, 4]; uint foo = 50 % arr.length; } void testShiftRightOnNegative() { int neg = -1; uint[] arr = [1, 2, 3]; ubyte b; // Shift with negative value returns value in range [0, ulong.max] static assert(!__traits(compiles, b = arr.length >> neg)); static assert(!__traits(compiles, b = arr.length << neg)); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testcheckimports.d ================================================ // REQUIRED_ARGS: -transition=checkimports -de /* TEST_OUTPUT: --- --- */ // https://issues.dlang.org/show_bug.cgi?id=15825 template anySatisfy15825(T...) { alias anySatisfy15825 = T[$ - 1]; } alias T15825 = anySatisfy15825!(int); // https://issues.dlang.org/show_bug.cgi?id=15857 template Mix15857(T) { void foo15857(T) {} } mixin Mix15857!int; mixin Mix15857!string; // will find an overloadset on 2nd lookup w/ SearchImportsOnly set import imports.test15857a; void test15857() { foo15857(1); bar15857(1); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testcontracts.d ================================================ // EXTRA_SOURCES: imports/testcontracts.d import imports.testcontracts; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3602 class Derived3602 : Base3602 { override void method(int x, int y) in { assert(x > 0); assert(y > 0); } body { } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5230 class Derived5230 : Base5230 { override int method() { return 69; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=17502 class Foo17502 { auto foo() out {} body {} auto bar() out { assert (__result > 5); } body { return 6; } auto bar_2() out (res) { assert (res > 5); } body { return 6; } int concrete() out { assert(__result > 5); } body { return 6; } int concrete_2() out(res) { assert (res > 5); } body { return 6; } void void_foo() out {} body {} auto void_auto() out {} body {} } /***************************************************/ // Order of declaration: (A), (C : B), (B : A) class A17502 { int method(int p) in { assert(p > 5); } out(res) { assert(res > 5); } body { return p; } } class C17502 : B17502 { override int method(int p) in { assert(p > 3); } body { return p * 2; } } class B17502 : A17502 { override int method(int p) in { assert(p > 2); } body { return p * 3; } } /***************************************************/ // Order of declaration: (X : Y), (Y : Z), (Z) class X17502 : Y17502 { override int method(int p) in { assert(p > 3); } body { return p * 2; } } class Y17502 : Z17502 { override int method(int p) in { assert(p > 2); } body { return p * 3; } } class Z17502 { int method(int p) in { assert(p > 5); } out(res) { assert(res > 5); } body { return p; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=17893 final class Foo17893(T) { extern(C) void maythrow(); void bar() in { maythrow(); } body { } } Foo17893!int foo17893; ================================================ FILE: gcc/testsuite/gdc.test/compilable/testdip1008.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -dip1008 int bar() { try { throw new Exception("message"); } catch (Exception e) { return 7; } } void foo() { enum r = bar(); static assert(r == 7); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testexpression.d ================================================ template TT(T...) { alias T TT; } void TestOpAssign(Tx, Ux, ops)() { foreach(T; Tx.x) foreach(U; Ux.x) foreach(op; ops.x) { T a = cast(T)1; mixin("a " ~ op ~ " cast(U)1;"); } } void TestOpAssignAssign(Tx, Ux, ops)() { foreach(T; Tx.x) foreach(U; Ux.x) foreach(op; ops.x) { T a = cast(T)1; U b = cast(U)1; T r; mixin("r = a " ~ op ~ " cast(U)1;"); } } void TestOpAssignAuto(Tx, Ux, ops)() { foreach(T; Tx.x) foreach(U; Ux.x) static if (U.sizeof <= T.sizeof) foreach(op; ops.x) { T a = cast(T)1; U b = cast(U)1; mixin("auto r = a " ~ op ~ " cast(U)1;"); } } void TestOpAndAssign(Tx, Ux, ops)() { foreach(T; Tx.x) foreach(U; Ux.x) static if (U.sizeof <= T.sizeof && T.sizeof >= 4) foreach(op; ops.x) { T a = cast(T)1; U b = cast(U)1; mixin("a = a " ~ op[0..$-1] ~ " cast(U)1;"); } } struct boolean { alias TT!(bool) x; } struct integral { alias TT!(byte, ubyte, short, ushort, int, uint, long, ulong) x; } struct floating { alias TT!(float, double, real) x; } struct imaginary { alias TT!(ifloat, idouble, ireal) x; } struct complex { alias TT!(cfloat, cdouble, creal) x; } struct all { alias TT!("+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", ">>>=") x; } struct arith { alias TT!("+=", "-=", "*=", "/=", "%=") x; } struct bitwise { alias TT!("&=", "|=", "^=") x; } struct shift { alias TT!("<<=", ">>=", ">>>=") x; } struct addsub { alias TT!("+=", "-=") x; } struct muldivmod { alias TT!("*=", "/=", "%=") x; } struct nomod { alias TT!("+=", "-=", "*=", "/=") x; } void OpAssignCases(alias X)() { X!(boolean, boolean, bitwise)(); X!(integral, boolean, all)(); X!(integral, integral, all)(); X!(integral, floating, arith)(); X!(floating, boolean, arith)(); X!(floating, integral, arith)(); X!(floating, floating, arith)(); X!(imaginary, boolean, muldivmod)(); X!(imaginary, integral, muldivmod)(); X!(imaginary, floating, muldivmod)(); X!(imaginary, imaginary, addsub)(); X!(complex, boolean, arith)(); X!(complex, integral, arith)(); X!(complex, floating, arith)(); X!(complex, imaginary, arith)(); X!(complex, complex, nomod)(); } void OpReAssignCases(alias X)() { X!(boolean, boolean, bitwise)(); X!(integral, boolean, all)(); X!(integral, integral, all)(); X!(floating, boolean, arith)(); X!(floating, integral, arith)(); X!(floating, floating, arith)(); X!(imaginary, boolean, muldivmod)(); X!(imaginary, integral, muldivmod)(); X!(imaginary, floating, muldivmod)(); X!(imaginary, imaginary, addsub)(); X!(complex, boolean, arith)(); X!(complex, integral, arith)(); X!(complex, floating, arith)(); X!(complex, imaginary, arith)(); X!(complex, complex, nomod)(); } void main() { OpAssignCases!TestOpAssign(); OpAssignCases!TestOpAssignAssign(); // was once disabled due to bug 7436 OpAssignCases!TestOpAssignAuto(); // https://issues.dlang.org/show_bug.cgi?id=5181 OpReAssignCases!TestOpAndAssign(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testfptr.d ================================================ // PERMUTE_ARGS: ref int frvv(); class A {} class B : A {} B restrictedfunc(in const(int)) @safe pure nothrow; A relaxedfunc(in int); void bug3797() { // Cannot convert if the return type or parameters are different void function() vv; void function(int) vi; int function() iv; const(int) function() cv; immutable(int) function() xv; static assert( is(typeof( vv = vv ))); static assert(!is(typeof( vv = vi ))); static assert(!is(typeof( vv = iv ))); static assert(!is(typeof( vv = cv ))); static assert(!is(typeof( vv = xv ))); static assert(!is(typeof( vi = vv ))); static assert( is(typeof( vi = vi ))); static assert(!is(typeof( vi = iv ))); static assert(!is(typeof( vi = cv ))); static assert(!is(typeof( vi = cx ))); static assert(!is(typeof( iv = vv ))); static assert(!is(typeof( iv = vi ))); static assert( is(typeof( iv = iv ))); static assert( is(typeof( iv = cv ))); static assert( is(typeof( iv = xv ))); static assert(!is(typeof( cv = vv ))); static assert( is(typeof( cv = iv ))); static assert(!is(typeof( cv = vi ))); static assert( is(typeof( cv = cv ))); static assert( is(typeof( cv = xv ))); static assert(!is(typeof( xv = vv ))); static assert( is(typeof( xv = iv ))); static assert(!is(typeof( xv = vi ))); static assert( is(typeof( xv = cv ))); static assert( is(typeof( xv = xv ))); int* function() ipfunc; const(int*) function() cipfunc; static assert( is(typeof( cipfunc = ipfunc )) ); static assert(!is(typeof( ipfunc = cipfunc )) ); // functions with different linkages can't convert extern(C) void function() cfunc; extern(D) void function() dfunc; static assert(!is(typeof( cfunc = dfunc ))); static assert(!is(typeof( dfunc = cfunc ))); // ref return can't convert to non-ref return typeof(&frvv) rvv; static assert(!is(typeof( rvv = iv ))); static assert(!is(typeof( rvv = cv ))); static assert(!is(typeof( iv = rvv ))); static assert(!is(typeof( cv = rvv ))); // variadic functions don't mix void function(...) vf; static assert(!is(typeof( vf = vv ))); static assert(!is(typeof( vv = vf ))); // non-nothrow -> nothrow void function() nothrow ntf; static assert(!is(typeof( ntf = vv ))); static assert( is(typeof( vv = ntf ))); // @safe <-> @trusted -> @system void function() @system systemfunc; void function() @trusted trustedfunc; void function() @safe safefunc; static assert( is(typeof( trustedfunc = safefunc ))); static assert( is(typeof( systemfunc = trustedfunc ))); static assert( is(typeof( systemfunc = safefunc ))); static assert( is(typeof( safefunc = trustedfunc ))); static assert(!is(typeof( trustedfunc = systemfunc ))); static assert(!is(typeof( safefunc = systemfunc ))); // pure -> non-pure void function() nonpurefunc; void function() pure purefunc; static assert(!is(typeof( purefunc = nonpurefunc ))); static assert( is(typeof( nonpurefunc = purefunc ))); // Cannot convert parameter storage classes (except const to in and in to const) void function(const(int)) constfunc; void function(in int) infunc; void function(out int) outfunc; void function(ref int) reffunc; void function(lazy int) lazyfunc; static assert(is(typeof( infunc = constfunc ))); static assert(is(typeof( constfunc = infunc ))); static assert(!is(typeof( infunc = outfunc ))); static assert(!is(typeof( infunc = reffunc ))); static assert(!is(typeof( infunc = lazyfunc ))); static assert(!is(typeof( outfunc = infunc ))); static assert(!is(typeof( outfunc = reffunc ))); static assert(!is(typeof( outfunc = lazyfunc ))); static assert(!is(typeof( reffunc = infunc ))); static assert(!is(typeof( reffunc = outfunc ))); static assert(!is(typeof( reffunc = lazyfunc ))); static assert(!is(typeof( lazyfunc = infunc ))); static assert(!is(typeof( lazyfunc = outfunc ))); static assert(!is(typeof( lazyfunc = reffunc ))); // Test class covariance A function() afunc; B function() bfunc; static assert( is(typeof( afunc = bfunc ))); static assert(!is(typeof( bfunc = afunc ))); // Test all the conversions at once typeof(&restrictedfunc) prestrictedfunc; typeof(&relaxedfunc) prelaxedfunc = prestrictedfunc; } void bug3797dg() { ref int frvv() { return *(new int); } B restrictedfunc(in const(int)) @safe pure nothrow { return null; } A relaxedfunc(in int) { return null; } // Cannot convert if the return type or parameters are different void delegate() vv; void delegate(int) vi; int delegate() iv; const(int) delegate() cv; immutable(int) delegate() xv; static assert( is(typeof( vv = vv ))); static assert(!is(typeof( vv = vi ))); static assert(!is(typeof( vv = iv ))); static assert(!is(typeof( vv = cv ))); static assert(!is(typeof( vv = xv ))); static assert(!is(typeof( vi = vv ))); static assert( is(typeof( vi = vi ))); static assert(!is(typeof( vi = iv ))); static assert(!is(typeof( vi = cv ))); static assert(!is(typeof( vi = cx ))); static assert(!is(typeof( iv = vv ))); static assert(!is(typeof( iv = vi ))); static assert( is(typeof( iv = iv ))); static assert( is(typeof( iv = cv ))); static assert( is(typeof( iv = xv ))); static assert(!is(typeof( cv = vv ))); static assert( is(typeof( cv = iv ))); static assert(!is(typeof( cv = vi ))); static assert( is(typeof( cv = cv ))); static assert( is(typeof( cv = xv ))); static assert(!is(typeof( xv = vv ))); static assert( is(typeof( xv = iv ))); static assert(!is(typeof( xv = vi ))); static assert( is(typeof( xv = cv ))); static assert( is(typeof( xv = xv ))); int* delegate() ipfunc; const(int*) delegate() cipfunc; static assert( is(typeof( cipfunc = ipfunc )) ); static assert(!is(typeof( ipfunc = cipfunc )) ); // delegates with different linkages can't convert extern(C) void delegate() cfunc; extern(D) void delegate() dfunc; static assert(!is(typeof( cfunc = dfunc ))); static assert(!is(typeof( dfunc = cfunc ))); // ref return can't convert to non-ref return typeof(&frvv) rvv; static assert(!is(typeof( rvv = iv ))); static assert(!is(typeof( rvv = cv ))); static assert(!is(typeof( iv = rvv ))); static assert(!is(typeof( cv = rvv ))); // variadic delegates don't mix void delegate(...) vf; static assert(!is(typeof( vf = vv ))); static assert(!is(typeof( vv = vf ))); // non-nothrow -> nothrow void delegate() nothrow ntf; static assert(!is(typeof( ntf = vv ))); static assert( is(typeof( vv = ntf ))); // @safe <-> @trusted -> @system void delegate() @system systemfunc; void delegate() @trusted trustedfunc; void delegate() @safe safefunc; static assert( is(typeof( trustedfunc = safefunc ))); static assert( is(typeof( systemfunc = trustedfunc ))); static assert( is(typeof( systemfunc = safefunc ))); static assert( is(typeof( safefunc = trustedfunc ))); static assert(!is(typeof( trustedfunc = systemfunc ))); static assert(!is(typeof( safefunc = systemfunc ))); // pure -> non-pure void delegate() nonpurefunc; void delegate() pure purefunc; static assert(!is(typeof( purefunc = nonpurefunc ))); static assert( is(typeof( nonpurefunc = purefunc ))); // Cannot convert parameter storage classes (except const to in and in to const) void delegate(const(int)) constfunc; void delegate(in int) infunc; void delegate(out int) outfunc; void delegate(ref int) reffunc; void delegate(lazy int) lazyfunc; static assert(is(typeof( infunc = constfunc ))); static assert(is(typeof( constfunc = infunc ))); static assert(!is(typeof( infunc = outfunc ))); static assert(!is(typeof( infunc = reffunc ))); static assert(!is(typeof( infunc = lazyfunc ))); static assert(!is(typeof( outfunc = infunc ))); static assert(!is(typeof( outfunc = reffunc ))); static assert(!is(typeof( outfunc = lazyfunc ))); static assert(!is(typeof( reffunc = infunc ))); static assert(!is(typeof( reffunc = outfunc ))); static assert(!is(typeof( reffunc = lazyfunc ))); static assert(!is(typeof( lazyfunc = infunc ))); static assert(!is(typeof( lazyfunc = outfunc ))); static assert(!is(typeof( lazyfunc = reffunc ))); // Test class covariance A delegate() afunc; B delegate() bfunc; static assert( is(typeof( afunc = bfunc ))); static assert(!is(typeof( bfunc = afunc ))); // Test all the conversions at once typeof(&restrictedfunc) prestrictedfunc; typeof(&relaxedfunc) prelaxedfunc = prestrictedfunc; } void bug3268() { auto a = &bug3268; const b = a; assert(a == a); assert(a == b); assert(b == b); immutable c = cast(immutable)a; assert(a == c); assert(b == c); assert(c == c); static assert(is(typeof(*a) == typeof(*b))); static assert(is(typeof(*a) == typeof(*c))); } void bug3268dg() { void bug3268x() {} auto a = &bug3268x; const b = a; assert(a == a); assert(a == b); assert(b == b); immutable c = cast(immutable)a; assert(a == c); assert(b == c); assert(c == c); } void bug3833() { bool b; void function() func; void function() pure purefunc; void function() nothrow nothrowfunc; void function() @safe safefunc; void function() @trusted trustedfunc; static assert( is(typeof( b ? func : purefunc ) == typeof( func ))); static assert( is(typeof( b ? func : nothrowfunc ) == typeof( func ))); static assert( is(typeof( b ? func : safefunc ) == typeof( func ))); static assert( is(typeof( b ? func : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : nothrowfunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : safefunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? nothrowfunc : safefunc ) == typeof( func ))); static assert( is(typeof( b ? nothrowfunc : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? safefunc : trustedfunc ) == typeof( trustedfunc ))); auto arr = [func, purefunc, nothrowfunc, safefunc, trustedfunc]; static assert( is(typeof( arr ) == typeof(func)[]) ); } void bug3833dg() { bool b; void delegate() func; void delegate() pure purefunc; void delegate() nothrow nothrowfunc; void delegate() @safe safefunc; void delegate() @trusted trustedfunc; static assert( is(typeof( b ? func : purefunc ) == typeof( func ))); static assert( is(typeof( b ? func : nothrowfunc ) == typeof( func ))); static assert( is(typeof( b ? func : safefunc ) == typeof( func ))); static assert( is(typeof( b ? func : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : nothrowfunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : safefunc ) == typeof( func ))); static assert( is(typeof( b ? purefunc : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? nothrowfunc : safefunc ) == typeof( func ))); static assert( is(typeof( b ? nothrowfunc : trustedfunc ) == typeof( func ))); static assert( is(typeof( b ? safefunc : trustedfunc ) == typeof( trustedfunc ))); auto arr = [func, purefunc, nothrowfunc, safefunc, trustedfunc]; static assert( is(typeof( arr ) == typeof(func)[]) ); } void bug4838() { void delegate() const dgc; static assert(typeof(dgc).stringof == "void delegate() const"); void delegate() immutable dgi; static assert(typeof(dgi).stringof == "void delegate() immutable"); void delegate() shared dgs; static assert(typeof(dgs).stringof == "void delegate() shared"); void delegate() shared const dgsc; static assert(typeof(dgsc).stringof == "void delegate() shared const"); void delegate() inout dgw; static assert(typeof(dgw).stringof == "void delegate() inout"); void delegate() shared inout dgsw; static assert(typeof(dgsw).stringof == "void delegate() shared inout"); } void test8822() { struct S { void foo() const {} } S s; void delegate() const dg = &s.foo; // OK void foo(void delegate() const dg){} // OK struct Foo(T) {} alias Foo!(void delegate() const) X; // NG -> OK } void main() { static assert(is(typeof(&main) P : U*, U)); auto x = cast(void*)&main; const void * p = &main; __gshared void function() gp = null; __gshared void delegate() gp2 = null; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testfwdref.d ================================================ // PERMUTE_ARGS: /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6766 class Foo6766 { this(int x) { } void test(Foo6766 foo = new Foo6766(1)) { } } struct Bar6766 { this(int x) { } void test(Bar6766 bar = Bar6766(1)) { } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8609 struct Tuple8609(T) { T arg; } // ---- struct Foo8609a { Bar8609a b; } struct Bar8609a { int x; Tuple8609!(Foo8609a) spam() { return Tuple8609!(Foo8609a)(); } } // ---- struct Foo8609b { Bar8609b b; } struct Bar8609b { int x; Tuple8609!(Foo8609b[1]) spam() { return Tuple8609!(Foo8609b[1])(); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8698 interface IRoot8698a {} interface IClass8698a : IRoot8698a { } struct Struct8698a { } class Class8698a : IClass8698a { alias Struct8698a Value; } void test8698a(Class8698a.Value) { } //interface IRoot8698a {} // ---- //interface IRoot8698b {} interface IClass8698b : IRoot8698b { } struct Struct8698b { } class Class8698b : IClass8698b { alias Struct8698b Value; } void test8698b(Class8698b.Value) { } interface IRoot8698b {} /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9514 template TStructHelpers9514a() { void opEquals(Foo9514a) { auto n = FieldNames9514a!(); } } struct Foo9514a { mixin TStructHelpers9514a!(); } import imports.fwdref9514 : find9514; // selective import without aliasing template FieldNames9514a() { static if (find9514!`true`([1])) enum int FieldNames9514a = 1; } // ---- template TStructHelpers9514b() { void opEquals(Foo9514b) { auto n = FieldNames9514b!(); } } struct Foo9514b { mixin TStructHelpers9514b!(); } import imports.fwdref9514 : foo9514 = find9514; // selective import with aliasing template FieldNames9514b() { static if (foo9514!`true`([1])) enum int FieldNames9514b = 1; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10015 struct S10015(T) { alias X = int; } alias Y10015 = s10015.X; S10015!int s10015; /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10101 int front10101(int); mixin template reflectRange10101() { static if (is(typeof(this.front10101))) { int x; } } struct S10101(R) { R r_; typeof(r_.front10101) front10101() @property { return r_.front10101; } mixin reflectRange10101; } void test10101() { S10101!(int) s; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11019 class A11019 { A11019 View() { return null; } } class B11019 : A11019 { override D11019 View() { return null; } } class D11019 : B11019 {} /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11166 template Tup11166(T...) { alias Tup11166 = T; } struct S11166a { enum S11166a a = S11166a(0); enum S11166a b = S11166a(1); this(long value) { } long value; // only triggered when private and a template instance. private alias types = Tup11166!(a, b); } struct S11166b { enum S11166b a = S11166b(0); enum S11166b b = S11166b(1); // not at the last of members alias types = Tup11166!(a, b); this(long value) { } long value; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12152 class A12152 { alias Y = B12152.X; } class B12152 : A12152 { alias int X; } static assert(is(A12152.Y == int)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12201 template T12201() { alias imports.fwdref12201a.FILE* FP; } struct S12201a { mixin T12201; import imports.fwdref12201a; } union U12201 { mixin T12201; import imports.fwdref12201a; } class C12201 { mixin T12201; import imports.fwdref12201a; } interface I12201 { mixin T12201; import imports.fwdref12201a; } template TI12201() { mixin T12201; import imports.fwdref12201a; } mixin template TM12201() { mixin T12201; import imports.fwdref12201a; } struct S12201b { alias ti = TI12201!(); mixin TM12201; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12531 struct Node12531(T) { T _val; } void test12531() { static struct Foo { Node12531!Foo* node; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12543 class C12543; static assert(C12543.sizeof == (void*).sizeof); static assert(C12543.alignof == (void*).sizeof); static assert(C12543.mangleof == "C10testfwdref6C12543"); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14010 enum E14010; static assert(E14010.mangleof == "E10testfwdref6E14010"); struct S14010; static assert(S14010.mangleof == "S10testfwdref6S14010"); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12983 alias I12983 = int; class B12983(T) { alias MyC = C12983!string; } class C12983(T) : B12983!float { void m() { f12983(0); } } alias MyB12983 = B12983!float; void f12983(); void f12983(I12983); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12984 class B12984a { alias MyD = D12984a!int; } class C12984a : B12984a { } class D12984a(T) { alias MyE = E12984a!float; } class E12984a(T) : D12984a!int { void m() { auto c = new C12984a(); } } static assert(__traits(classInstanceSize, B12984a) == (void*).sizeof * 2); static assert(__traits(classInstanceSize, C12984a) == (void*).sizeof * 2); // ---- class B12984b { int b; alias MyD = D12984b!int; } class C12984b : B12984b { int c; } class D12984b(T) { int d; alias MyE = E12984b!float; } class E12984b(T) : D12984b!int { int e; void m() { auto c = new C12984b(); } } static assert(__traits(classInstanceSize, B12984b) == (void*).sizeof * 2 + int.sizeof); static assert(__traits(classInstanceSize, C12984b) == (void*).sizeof * 2 + int.sizeof * 2); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14390 class B14390a { alias MyD = D14390a!int; } class C14390a : B14390a { void f(int) {} } class D14390a(T) { alias MyE = E14390a!float; } class E14390a(T) : D14390a!int { void m() { auto c = new C14390a(); } } class B14390b { alias MyD = D14390b!int; } class C14390b : B14390b { static struct S {} } class D14390b(T) { alias MyE = E14390b!float; } class E14390b(T) : D14390b!int { void m() { auto c = new C14390b(); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13860 /* TEST_OUTPUT: --- pure nothrow @nogc @safe void() pure nothrow @nogc @safe void() --- */ struct Foo13860(Bar...) { Bar bars; auto baz(size_t d)() {} pragma(msg, typeof(baz!0)); } auto bar13860(S, R)(S s, R r) { pragma(msg, typeof(Foo13860!().baz!0)); } void test13860() { int[] x; int[] y; x.bar13860(y); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14083 class NBase14083 { int foo(NA14083 a) { return 1; } int foo(NB14083 a) { return 2; } } class NA14083 : NBase14083 { int v; this(int v) { this.v = v; } } class NB14083 : NBase14083 { override int foo(NA14083 a) { return a.v; } } class TBase14083(T) { int foo(TA14083!T a) { return 1; } int foo(TB14083!T a) { return 2; } } class TA14083(T) : TBase14083!T { T v; this(T v) { this.v = v; } } class TB14083(T) : TBase14083!T { override int foo(TA14083!T a) { return a.v; } } static assert( { NA14083 na = new NA14083(10); NB14083 nb = new NB14083(); assert(na.foo(na) == 1); assert(na.foo(nb) == 2); assert(nb.foo(na) == 10); TA14083!int ta = new TA14083!int(10); TB14083!int tb = new TB14083!int(); assert(ta.foo(ta) == 1); assert(ta.foo(tb) == 2); assert(tb.foo(ta) == 10); return true; }()); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14549 string foo14549(T)() { static if (T.tupleof.length >= 0) return ""; } class Frop14549 { mixin(foo14549!(typeof(this))); static if (__traits(compiles, undefined)) { } else { int bar = 0; } static if (!__traits(isVirtualMethod, this.bar)) {} } // ---- // regression case template Mix14549() { mixin(code14549!(typeof(this))); } template code14549(T) { enum string code14549 = q{ static if (!__traits(isVirtualMethod, "boo")) {} }; } class Bar14549 { mixin Mix14549; int boo; } // ---- // https://issues.dlang.org/show_bug.cgi?id=14609 // regression case interface Foo14609(T) { static if (is(T == int)) public int bar(); } class Frop14609 : Foo14609!int { public int bar() { return 0; } } /***************************************************/ // test case 1, comes from Phobos /* TEST_OUTPUT: --- +alias Alias12540 +anySatisfy, T.length == 1 +isStaticArray +T.stringof in StaticArrayTypeOf -T.stringof in StaticArrayTypeOf -isStaticArray +hasElaborateCpCtor S == struct or else -hasElaborateCpCtor S == struct or else -anySatisfy, T.length == 1 -alias Alias12540 --- */ template anySatisfy15726x(alias F, T...) { //static if (T.length == 1) //{ pragma(msg, "+anySatisfy, T.length == 1"); enum anySatisfy15726x = F!(T[0]); pragma(msg, "-anySatisfy, T.length == 1"); //} } template StaticArrayTypeOf15726x(T) { alias X = T; static if (is(X : E[n], E, size_t n)) { //alias StaticArrayTypeOf15726x = X; } else { pragma(msg, "+T.stringof in StaticArrayTypeOf"); // Fixed: T.stringof (T == Class12540) should not invoke // T.size() in ClassDeclaration.search(). static assert(0, T.stringof~" is not a static array type"); pragma(msg, "-T.stringof in StaticArrayTypeOf"); } } //enum bool isStaticArray(T) = is(StaticArrayTypeOf15726x!T); template isStaticArray15726x(T) { pragma(msg, "+isStaticArray"); enum bool isStaticArray15726x = is(StaticArrayTypeOf15726x!T); pragma(msg, "-isStaticArray"); } template hasElaborateCpCtor15726x(S) { static if (isStaticArray15726x!S && S.length) { //pragma(msg, "X+"); enum bool hasElaborateCpCtor15726x = hasElaborateCpCtor15726x!(typeof(S.init[0])); //pragma(msg, "X-"); } else { pragma(msg, "+hasElaborateCpCtor S == struct or else"); static if (is(S == struct)) { enum bool hasElaborateCpCtor15726x = true; //enum hasElaborateCpCtor15726x = hasMember!(S, "__postblit") // || anySatisfy15726x!(.hasElaborateCpCtor15726x, FieldTypeTuple!S); } else { enum bool hasElaborateCpCtor15726x = false; } pragma(msg, "-hasElaborateCpCtor S == struct or else"); } } struct VariantN15726x(AllowedTypesParam...) { alias AllowedTypes = AllowedTypesParam; static if (!AllowedTypes.length || anySatisfy15726x!(hasElaborateCpCtor15726x, AllowedTypes)) { } } template Algebraic15726x(T) { alias Algebraic15726x = VariantN15726x!(T); } void test15726x() { static struct DummyScope { pragma(msg, "+alias Alias12540"); alias Alias12540 = Algebraic15726x!Class12540; pragma(msg, "-alias Alias12540"); static class Class12540 { Alias12540 entity; } } } /***************************************************/ // test case 2, comes from Phobos struct RefCounted15726y(T) { struct RefCountedStore { struct Impl { T _payload; } Impl* _store; } RefCountedStore _refCounted; this(this) {} ~this() { _refCounted._store._payload.__xdtor(); } } struct RangeT15726y(A) { A[1] _outer_; alias RC = RangeT15726y!(const(A)); } struct Array15726y(T) { struct Payload { ~this(); } alias Data = RefCounted15726y!(Payload); Data _data; alias Range = RangeT15726y!Array15726y; } void test15726y() { alias Range = RangeT15726y!(Array15726y!int); Range r; r = r; // opAssign } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15726 struct RC15726(T) { struct Impl { T _payload; } Impl* _store; ~this() { destroy15726a(_store._payload); } } // ---- struct Con15726a(T) { alias Stmt15726a = .Stmt15726a!T; } struct Stmt15726a(T) { alias Con15726a = .Con15726a!T; RC15726!Payload data; struct Payload { Con15726a con; } } Con15726a!int x15726a; void destroy15726a(T)(ref T obj) @trusted { auto buf = (cast(ubyte*)&obj)[0 .. T.sizeof]; } // ---- struct Util15726b(C, S) {} struct Con15726b(T) { alias Util15726b = .Util15726b!(Con15726b!T, Stmt15726b!T); } struct Stmt15726b(T) { struct Payload { Con15726b!T con; } RC15726!Payload data; } Con15726b!int x15726b; ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader1.d ================================================ // EXTRA_SOURCES: extra-files/header1.d // REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader1.di -ignore // PERMUTE_ARGS: -d -dw // POST_SCRIPT: compilable/extra-files/header-postscript.sh void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader12567a.d ================================================ // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567a.di // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/header-postscript.sh deprecated module header12567a; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader12567b.d ================================================ // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567b.di // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/header-postscript.sh deprecated("message") module header12567b; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader1i.d ================================================ // EXTRA_SOURCES: extra-files/header1.d // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader1i.di -inline -ignore // PERMUTE_ARGS: -d -dw // POST_SCRIPT: compilable/extra-files/header-postscript.sh void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader2.d ================================================ // EXTRA_SOURCES: extra-files/header2.d // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2.di // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/header-postscript.sh void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader2i.d ================================================ // EXTRA_SOURCES: extra-files/header2.d // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2i.di -inline // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/header-postscript.sh void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheader3.d ================================================ // EXTRA_SOURCES: extra-files/header3.d // REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader3.di // PERMUTE_ARGS: -d -dw // POST_SCRIPT: compilable/extra-files/header-postscript.sh void main() {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testheaderudamodule.d ================================================ // REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/header-postscript.sh @(1, UDA(2)) module testheaderudamodule; struct UDA { int a; } void main() {} void foo(@(1) int bar, @UDA(2) string bebe) {} ================================================ FILE: gcc/testsuite/gdc.test/compilable/testimport12242.d ================================================ // PERMUTE_ARGS: module testimport12242; import imports.imp12242a; // test // stripA == OverloadSet import imports.imp12242a1; // std.string // stripA == template import imports.imp12242b1; // std.string // stripB == template import imports.imp12242b; // test // stripB == OverloadSet void main() { static assert(stripA(" af ") == 1); static assert(" af ".stripA() == 1); // UFCS (1) static assert(" af ".stripA == 1); // UFCS (2) static assert(stripB(" af ") == 1); static assert(" af ".stripB() == 1); // UFCS (1) static assert(" af ".stripB == 1); // UFCS (2) static assert(foo!int == 1); static assert(foo!long == 2); static assert(foo!float == 3); static assert(foo!real == 4); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testlambdacomp.d ================================================ module testlambdacomp; void test1() { static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d)); static assert(__traits(isSame, a => ++a, b => ++b)); static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b)); static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10)); } class Y { static int r = 5; int x; this(int x) { this.x = x; } } class A { Y a; this(Y a) { this.a = a; } } void foo3(alias pred)() { static assert(!__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x))); } void test2() { int b; static assert(!__traits(isSame, a => a + b, a => a + b)); int f() { return 3;} static assert(__traits(isSame, a => a + f(), a => a + f())); class A { Y a; this(Y a) { this.a = a; } } class B { int a; this(int a) { this.a = a; } } B q = new B(7); alias pred = (A a, A b) => ++a.a.x + (--b.a.x); foo3!pred(); static assert(!__traits(isSame, (A a) => ++a.a.x + 2, (A b) => ++b.a.x + 3)); static assert(__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x))); static assert(!__traits(isSame, (B a) => ++a.a + 2, (B b) => ++b.a + 3)); static assert(__traits(isSame, (B a) => ++a.a, (B a) => ++a.a)); B cl = new B(7); static assert(!__traits(isSame, a => a + q.a, c => c + cl.a)); class C(G) { G a; this(int a) { this.a = a; } } static assert(!__traits(isSame, (C!int a) => ++a.a, (C!int a) => ++a.a)); struct X { int a; } static assert(__traits(isSame, (X a) => a.a + 2, (X b) => b.a + 2)); struct T(G) { G a; } static assert(!__traits(isSame, (T!int a) => ++a.a, (T!int a) => ++a.a)); } void test3() { enum q = 10; static assert(__traits(isSame, (a, b) => a + b + q, (c, d) => c + d + 10)); struct Bar { int a; } enum r1 = Bar(1); enum r2 = Bar(1); static assert(__traits(isSame, a => a + r1.a, b => b + r2.a)); enum X { A, B, C} static assert(__traits(isSame, a => a + X.A, a => a + 0)); } void foo(alias pred)() { static assert(__traits(isSame, pred, (c, d) => c + d)); static assert(__traits(isSame, (c, d) => c + d, pred)); } void bar(alias pred)() { static assert(__traits(isSame, pred, (c, d) => c < d + 7)); enum q = 7; static assert(__traits(isSame, pred, (c, d) => c < d + q)); int r = 7; static assert(!__traits(isSame, pred, (c, d) => c < d + r)); } void test4() { foo!((a, b) => a + b)(); bar!((a, b) => a < b + 7); } int bar() { return 2; } void testImportedFunctions(alias pred)() { // imports.testalambda1.bar != imports.testlambda2.bar import imports.testlambda2 : bar; static assert(!__traits(isSame, pred, (int a) => a + bar())); } void testLocalGlobalFunctionScopes(alias pred)() { // testlambdacomp.bar != testlambdacomp.test5.bar static assert(!__traits(isSame, pred, (int a) => a + bar())); // imports.testlambda1.bar != testlambdacomp.test5.bar import imports.testlambda1 : bar; static assert(!__traits(isSame, pred, (int a) => a + bar())); // functions imported from different modules are not equal testImportedFunctions!((int a) => a + bar())(); } // lambda functions which contain function calls void test5() { int bar() { return 3; } // functions in the same scope alias pred = a => a + bar(); alias pred2 = b => b + bar(); static assert(__traits(isSame, pred, pred2)); // functions in different scopes testLocalGlobalFunctionScopes!((int a) => a + bar())(); int foo(int a, int b) { return 2 + a + b; } // functions with different kind of parameters alias preda23 = a => a + foo(2, 3); alias predb23 = b => b + foo(2, 3); alias predc24 = c => c + foo(2, 4); alias predd23 = (int d) => d + foo(2, 3); alias prede23 = (int e) => e + foo(2, 3); alias predf24 = (int f) => f + foo(2, 4); static assert(__traits(isSame, preda23, predb23)); static assert(!__traits(isSame, predc24, predd23)); static assert(__traits(isSame, predd23, prede23)); static assert(!__traits(isSame, prede23, predf24)); // functions with function calls as parameters static assert(!__traits(isSame, (int a, int b) => foo(foo(1, a), foo(1, b)), (int a, int b) => foo(foo(1, a), foo(2, b)))); static assert(!__traits(isSame, (a, b) => foo(foo(1, a), foo(1, b)), (int a, int b) => foo(foo(1, a), foo(2, b)))); float floatFunc(float a, float b) { return a + b; } static assert(__traits(isSame, a => floatFunc(a, 1.0), b => floatFunc(b, 1.0))); static assert(!__traits(isSame, a => floatFunc(a, 1.0), b => floatFunc(b, 2.0))); } void main() { test1(); test2(); test3(); test4(); test5(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testparse.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -o- /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6719 pragma(msg, __traits(compiles, mixin("(const(A))[0..0]"))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9232 struct Foo9232 { void bar(T)() {} void baz() {} } void test9232() { Foo9232 foo; (foo).bar!int(); // OK <- Error: found '!' when expecting ';' following statement ((foo)).bar!int(); // OK foo.bar!int(); // OK (foo).baz(); // OK } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9401 struct S9401a { ~this() nothrow pure @safe { } } struct S9401b { @safe ~this() pure nothrow { } } void test9401() nothrow pure @safe { S9401a s1; S9401b s2; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9649 class Outer9649 { class Inner { } } void test9649() { Outer9649 outer9649; (outer9649).new Inner(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9679 void test9679(inout int = 0) { if ( auto n = 1) { static assert(is(typeof(n) == int)); } if ( const n = 1) { static assert(is(typeof(n) == const int)); } if ( immutable n = 1) { static assert(is(typeof(n) == immutable int)); } if (shared n = 1) { static assert(is(typeof(n) == shared int)); } if (shared const n = 1) { static assert(is(typeof(n) == shared const int)); } if ( inout n = 1) { static assert(is(typeof(n) == inout int)); } if (shared inout n = 1) { static assert(is(typeof(n) == shared inout int)); } if ( const int n = 1) { static assert(is(typeof(n) == const int)); } if ( immutable int n = 1) { static assert(is(typeof(n) == immutable int)); } if (shared int n = 1) { static assert(is(typeof(n) == shared int)); } if (shared const int n = 1) { static assert(is(typeof(n) == shared const int)); } if ( inout int n = 1) { static assert(is(typeof(n) == inout int)); } if (shared inout int n = 1) { static assert(is(typeof(n) == shared inout int)); } if ( const(int) n = 1) { static assert(is(typeof(n) == const int)); } if ( immutable(int) n = 1) { static assert(is(typeof(n) == immutable int)); } if (shared (int) n = 1) { static assert(is(typeof(n) == shared int)); } if (shared const(int) n = 1) { static assert(is(typeof(n) == shared const int)); } if ( inout(int) n = 1) { static assert(is(typeof(n) == inout int)); } if (shared inout(int) n = 1) { static assert(is(typeof(n) == shared inout int)); } if (immutable(int)[] n = [1]) { static assert(is(typeof(n) == immutable(int)[])); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9901 template isGood9901(T) { enum isGood9901 = true; } void test9901() { string foo(R)(R data) if (isGood9901!R) { return ""; } foo(1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10199 void test10199() { goto label; label: } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12460 void f12460(T)() { static if (is(T == int)) { goto end; } end: } void test12460() { f12460!int(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11689 void test11689() { deprecated void foo() {} } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11751 static assert(is(float == typeof(0x0.1p1F))); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11957 extern(C++) class C11957 { void x() {} } void test11957() { extern(C++) class D : C11957 { override void x() {} } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13049 enum mangle13049(T) = T.mangleof; alias FP13049 = void function(scope int); // OK static assert(mangle13049!FP13049 == mangle13049!(void function(scope int))); // OK <- NG ================================================ FILE: gcc/testsuite/gdc.test/compilable/testpostblit.d ================================================ struct Test1a { this(this) { } } struct Test1b { Test1a a; } struct Test1c { const Test1b b; @disable this(this); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/testprofile.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -profile template LaLa(E...) { class LaLa { this() { } } } void main() { // doesn't work new LaLa!("lala", "lalalalala", "lala", "lala", "lala", "lala", "lalalala", "lala", "lala", "lala", "lalala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala", "lala"); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/traits.d ================================================ // This file is intended to contain all compilable traits-related tests in an // effort to keep the number of files in the `compilable` folder to a minimum. // https://issues.dlang.org/show_bug.cgi?id=19152 class C19152 { int OnExecute() { auto name = __traits(getOverloads, this, "OnExecute").stringof; return 0; } } static assert(is(typeof(__traits(getTargetInfo, "cppRuntimeLibrary")) == string)); version (CppRuntime_Microsoft) { static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt"); } version (D_HardFloat) static assert(__traits(getTargetInfo, "floatAbi") == "hard"); version (Win64) static assert(__traits(getTargetInfo, "objectFormat") == "coff"); version (OSX) static assert(__traits(getTargetInfo, "objectFormat") == "macho"); version (linux) static assert(__traits(getTargetInfo, "objectFormat") == "elf"); ================================================ FILE: gcc/testsuite/gdc.test/compilable/uda.d ================================================ /************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15180 // [REG2.069.0-b1] Segfault with empty struct used as UDA struct foo { } @foo bar () { } /************************************************/ ================================================ FILE: gcc/testsuite/gdc.test/compilable/udamodule1.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: /* TEST_OUTPUT: --- compilable/udamodule1.d(9): Deprecation: module `imports.udamodule1` is deprecated - This module will be removed. --- */ import imports.udamodule1; void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/udamodule2.d ================================================ import imports.udamodule2; import imports.udamodule2a; enum Attrib = __traits(getAttributes, imports.udamodule2); static assert(Attrib[0] == UDA(1) && Attrib[1] == UDA(2)); ================================================ FILE: gcc/testsuite/gdc.test/compilable/verrors_spec.d ================================================ /* PERMUTE_ARGS: REQUIRED_ARGS: -verrors=spec TEST_OUTPUT: --- (spec:1) compilable/verrors_spec.d(13): Error: cannot implicitly convert expression `& i` of type `int*` to `int` --- */ void foo(int i) { int p; bool b = __traits(compiles, {p = &i;}); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/version.d ================================================ /* REQUIRED_ARGS: */ version (D_ModuleInfo) { } else { static assert(0); } version (D_Exceptions) { } else { static assert(0); } version (D_TypeInfo) { } else { static assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/vgc1.d ================================================ // REQUIRED_ARGS: -vgc -o- // PERMUTE_ARGS: /***************** NewExp *******************/ /* TEST_OUTPUT: --- compilable/vgc1.d(17): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class compilable/vgc1.d(18): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class --- */ struct S1 { } struct S2 { this(int); } struct S3 { this(int) @nogc; } struct S4 { new(size_t); } struct S5 { @nogc new(size_t); } /* TEST_OUTPUT: --- compilable/vgc1.d(35): vgc: `new` causes a GC allocation compilable/vgc1.d(37): vgc: `new` causes a GC allocation compilable/vgc1.d(38): vgc: `new` causes a GC allocation compilable/vgc1.d(40): vgc: `new` causes a GC allocation compilable/vgc1.d(41): vgc: `new` causes a GC allocation compilable/vgc1.d(42): vgc: `new` causes a GC allocation compilable/vgc1.d(46): vgc: `new` causes a GC allocation --- */ void testNew() { int* p1 = new int; int[] a1 = new int[3]; int[][] a2 = new int[][](2, 3); S1* ps1 = new S1(); S2* ps2 = new S2(1); S3* ps3 = new S3(1); S4* ps4 = new S4; // no error S5* ps5 = new S5; // no error Object o1 = new Object(); } /* TEST_OUTPUT: --- compilable/vgc1.d(63): vgc: `new` causes a GC allocation compilable/vgc1.d(65): vgc: `new` causes a GC allocation compilable/vgc1.d(66): vgc: `new` causes a GC allocation compilable/vgc1.d(68): vgc: `new` causes a GC allocation compilable/vgc1.d(69): vgc: `new` causes a GC allocation compilable/vgc1.d(70): vgc: `new` causes a GC allocation --- */ void testNewScope() { scope int* p1 = new int; scope int[] a1 = new int[3]; scope int[][] a2 = new int[][](2, 3); scope S1* ps1 = new S1(); scope S2* ps2 = new S2(1); scope S3* ps3 = new S3(1); scope S4* ps4 = new S4; // no error scope S5* ps5 = new S5; // no error scope Object o1 = new Object(); // no error scope o2 = new Object(); // no error scope Object o3; o3 = o2; // no error } /***************** DeleteExp *******************/ /* TEST_OUTPUT: --- compilable/vgc1.d(95): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. compilable/vgc1.d(95): vgc: `delete` requires the GC compilable/vgc1.d(96): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. compilable/vgc1.d(96): vgc: `delete` requires the GC compilable/vgc1.d(97): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. compilable/vgc1.d(97): vgc: `delete` requires the GC --- */ void testDelete(int* p, Object o, S1* s) { delete p; delete o; delete s; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/vgc2.d ================================================ // REQUIRED_ARGS: -vgc -o- // PERMUTE_ARGS: /***************** CatExp *******************/ /* TEST_OUTPUT: --- compilable/vgc2.d(21): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(22): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(23): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(25): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(26): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(27): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(28): vgc: operator `~` may cause a GC allocation compilable/vgc2.d(29): vgc: operator `~` may cause a GC allocation --- */ void testCat(int[] a, string s) { int[] a1 = a ~ a; int[] a2 = a ~ 1; int[] a3 = 1 ~ a; string s1 = s ~ s; string s2 = s ~ "a"; string s3 = "a" ~ s; string s4 = s ~ 'c'; string s5 = 'c' ~ s; string s6 = "a" ~ "b"; // no error string s7 = "a" ~ 'c'; // no error string s8 = 'c' ~ "b"; // no error } /***************** CatAssignExp *******************/ /* TEST_OUTPUT: --- compilable/vgc2.d(48): vgc: operator `~=` may cause a GC allocation compilable/vgc2.d(50): vgc: operator `~=` may cause a GC allocation compilable/vgc2.d(51): vgc: operator `~=` may cause a GC allocation --- */ void testCatAssign(int[] a, string s) { a ~= 1; s ~= "a"; s ~= 'c'; } /***************** ArrayLiteralExp *******************/ int* barA(); /* TEST_OUTPUT: --- compilable/vgc2.d(70): vgc: array literal may cause a GC allocation compilable/vgc2.d(71): vgc: array literal may cause a GC allocation --- */ void testArray() { enum arrLiteral = [null, null]; int* p; auto a = [p, p, barA()]; a = arrLiteral; } /***************** AssocArrayLiteralExp *******************/ /* TEST_OUTPUT: --- compilable/vgc2.d(87): vgc: associative array literal may cause a GC allocation compilable/vgc2.d(88): vgc: associative array literal may cause a GC allocation --- */ void testAssocArray() { enum aaLiteral = [10: 100]; auto aa = [1:1, 2:3, 4:5]; aa = aaLiteral; } /***************** IndexExp *******************/ /* TEST_OUTPUT: --- compilable/vgc2.d(102): vgc: indexing an associative array may cause a GC allocation compilable/vgc2.d(103): vgc: indexing an associative array may cause a GC allocation --- */ void testIndex(int[int] aa) { aa[1] = 0; int n = aa[1]; } ================================================ FILE: gcc/testsuite/gdc.test/compilable/vgc3.d ================================================ // REQUIRED_ARGS: -vgc -o- // PERMUTE_ARGS: /***************** AssignExp *******************/ /* TEST_OUTPUT: --- compilable/vgc3.d(16): vgc: setting `length` may cause a GC allocation compilable/vgc3.d(17): vgc: setting `length` may cause a GC allocation compilable/vgc3.d(18): vgc: setting `length` may cause a GC allocation --- */ void testArrayLength(int[] a) { a.length = 3; a.length += 1; a.length -= 1; } /***************** CallExp *******************/ void barCall(); /* TEST_OUTPUT: --- --- */ void testCall() { auto fp = &barCall; (*fp)(); barCall(); } /****************** Closure ***********************/ @nogc void takeDelegate2(scope int delegate() dg) {} @nogc void takeDelegate3( int delegate() dg) {} /* TEST_OUTPUT: --- compilable/vgc3.d(51): vgc: using closure causes GC allocation compilable/vgc3.d(63): vgc: using closure causes GC allocation --- */ auto testClosure1() { int x; int bar() { return x; } return &bar; } void testClosure2() { int x; int bar() { return x; } takeDelegate2(&bar); // no error } void testClosure3() { int x; int bar() { return x; } takeDelegate3(&bar); } ================================================ FILE: gcc/testsuite/gdc.test/compilable/warn3882.d ================================================ // PERMUTE_ARGS: -w -wi -debug /* TEST_OUTPUT: --- --- */ @safe pure nothrow void strictVoidReturn(T)(T x) {} @safe pure nothrow void nonstrictVoidReturn(T)(ref T x) {} void test3882() { int x = 3; strictVoidReturn(x); nonstrictVoidReturn(x); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12619 extern (C) @system nothrow pure void* memcpy(void* s1, in void* s2, size_t n); // -> weakly pure void test12619() pure { ubyte[10] a, b; debug memcpy(a.ptr, b.ptr, 5); // memcpy call should have side effect } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12760 struct S12760(T) { T i; this(T j) inout {} } struct K12760 { S12760!int nullable; this(int) { nullable = 0; // weak purity } } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12909 int f12909(immutable(int[])[int] aa) pure nothrow { //aa[0] = []; // fix for https://issues.dlang.org/show_bug.cgi?id=13701 return 0; } void test12909() { immutable(int[])[int] aa; f12909(aa); // from 12910 const(int[])[int] makeAA() { return null; } // to make r-value makeAA().rehash(); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=13899 const struct Foo13899 { int opApply(immutable int delegate(in ref int) pure nothrow dg) pure nothrow { return 1; } } void test13899() { foreach (x; Foo13899()) { } } ================================================ FILE: gcc/testsuite/gdc.test/d_do_test.exp ================================================ # Copyright (C) 2012-2018 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GCC; see the file COPYING3. If not see # . # Test using the DMD testsuite. # Load support procs. load_lib gdc-dg.exp # # Convert DMD arguments to GDC equivalent # proc gdc-convert-args { args } { set out "" foreach arg [split [lindex $args 0] " "] { # List of switches kept in ASCII collated order. if { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } { lappend out "-I$path" } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } { lappend out "-J$path" } elseif [string match "-allinst" $arg] { lappend out "-fall-instantiations" } elseif [string match "-betterC" $arg] { lappend out "-fno-druntime" } elseif { [string match "-boundscheck" $arg] || [string match "-boundscheck=on" $arg] } { lappend out "-fbounds-check" } elseif { [string match "-boundscheck=off" $arg] || [string match "-noboundscheck" $arg] } { lappend out "-fno-bounds-check" } elseif [string match "-boundscheck=safeonly" $arg] { lappend out "-fbounds-check=safeonly" } elseif [string match "-c" $arg] { lappend out "-c" } elseif [string match "-d" $arg] { lappend out "-Wno-deprecated" } elseif [string match "-de" $arg] { lappend out "-Wdeprecated" lappend out "-Werror" } elseif [string match "-debug" $arg] { lappend out "-fdebug" } elseif [regexp -- {^-debug=(\w+)} $arg pattern value] { lappend out "-fdebug=$value" } elseif [string match "-dip1000" $arg] { lappend out "-ftransition=dip1000" } elseif [string match "-dip25" $arg] { lappend out "-ftransition=dip25" } elseif [string match "-dw" $arg] { lappend out "-Wdeprecated" lappend out "-Wno-error" } elseif [string match "-fPIC" $arg] { lappend out "-fPIC" } elseif { [string match "-g" $arg] || [string match "-gc" $arg] } { lappend out "-g" } elseif [string match "-ignore" $arg] { lappend out "-fignore-unknown-pragmas" } elseif [string match "-inline" $arg] { lappend out "-finline-functions" } elseif [string match "-main" $arg] { lappend out "-fmain" } elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] { lappend out "-fmodule-file=$value" } elseif [string match "-O" $arg] { lappend out "-O2" } elseif [string match "-release" $arg] { lappend out "-frelease" } elseif [regexp -- {^-transition=(\w+)} $arg pattern value] { lappend out "-ftransition=$value" } elseif [string match "-unittest" $arg] { lappend out "-funittest" } elseif [string match "-verrors=spec" $arg] { lappend out "-Wspeculative" } elseif [regexp -- {^-verrors=(\d+)} $arg pattern num] { lappend out "-fmax-errors=$num" } elseif [regexp -- {^-version=(\w+)} $arg pattern value] { lappend out "-fversion=$value" } elseif [string match "-vtls" $arg] { lappend out "-ftransition=tls" } elseif [string match "-w" $arg] { lappend out "-Wall" lappend out "-Werror" } elseif [string match "-wi" $arg] { lappend out "-Wall" lappend out "-Wno-error" } else { # print "Unhandled Argument: $arg" } } return $out } proc gdc-copy-extra { base extra } { # Split base, folder/file. set type [file dirname $extra] # print "Filename: $base - $extra" set fdin [open $base/$extra r] fconfigure $fdin -encoding binary file mkdir $type set fdout [open $extra w] fconfigure $fdout -encoding binary while { [gets $fdin copy_line] >= 0 } { set out_line $copy_line puts $fdout $out_line } close $fdin close $fdout return $extra } # # Translate DMD test directives to dejagnu equivalent. # # COMPILE_SEPARATELY: Not handled. # EXECUTE_ARGS: Parameters to add to the execution of the test. # COMPILED_IMPORTS: List of modules files that are imported by the main # source file that should be included in compilation. # Currently handled the same as EXTRA_SOURCES. # EXTRA_SOURCES: List of extra sources to build and link along with # the test. # EXTRA_FILES: List of extra files to copy for the test runs. # PERMUTE_ARGS: The set of arguments to permute in multiple compiler # invocations. An empty set means only one permutation # with no arguments. # TEST_OUTPUT: The output expected from the compilation. # POST_SCRIPT: Not handled. # REQUIRED_ARGS: Arguments to add to the compiler command line. # DISABLED: Not handled. # proc dmd2dg { base test } { global DEFAULT_DFLAGS global PERMUTE_ARGS global GDC_EXECUTE_ARGS set PERMUTE_ARGS $DEFAULT_DFLAGS set GDC_EXECUTE_ARGS "" # Split base, folder/file. set type [file dirname $test] # print "Filename: $base - $test" set fdin [open $base/$test r] #fconfigure $fdin -encoding binary file mkdir $type set fdout [open $test w] #fconfigure $fdout -encoding binary while { [gets $fdin copy_line] >= 0 } { set out_line $copy_line if [regexp -- {COMPILE_SEPARATELY} $copy_line] { # COMPILE_SEPARATELY is not handled. regsub -- {COMPILE_SEPARATELY.*$} $copy_line "" out_line } elseif [regexp -- {DISABLED} $copy_line] { # DISABLED is not handled. regsub -- {DISABLED.*$} $copy_line "" out_line } elseif [regexp -- {POST_SCRIPT} $copy_line] { # POST_SCRIPT is not handled regsub -- {POST_SCRIPT.*$} $copy_line "" out_line } elseif [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] { # PERMUTE_ARGS is handled by gdc-do-test. set PERMUTE_ARGS [gdc-convert-args $args] regsub -- {PERMUTE_ARGS.*$} $copy_line "" out_line } elseif [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] { # EXECUTE_ARGS is handled by gdc_load. foreach arg $args { lappend GDC_EXECUTE_ARGS $arg } regsub -- {EXECUTE_ARGS.*$} $copy_line "" out_line } elseif [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] { # Convert all listed arguments to from dmd to gdc-style. set new_option "{ dg-additional-options \"[gdc-convert-args $args]\" }" regsub -- {REQUIRED_ARGS.*$} $copy_line $new_option out_line } elseif [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] { # Copy all sources to the testsuite build directory. foreach import $sources { # print "Import: $base $type/$import" gdc-copy-extra $base "$type/$import" } set new_option "{ dg-additional-sources \"$sources\" }" regsub -- {EXTRA_SOURCES.*$} $copy_line $new_option out_line } elseif [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] { # Copy all sources to the testsuite build directory. foreach import $sources { # print "Import: $base $type/$import" gdc-copy-extra $base "$type/$import" } set new_option "{ dg-additional-sources \"$sources\" }" regsub -- {EXTRA_CPP_SOURCES.*$} $copy_line $new_option out_line } elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] { # Copy all files to the testsuite build directory. foreach import $files { # print "Import: $base $type/$import" gdc-copy-extra $base "$type/$import" } set new_option "{ dg-additional-files \"$files\" }" regsub -- {EXTRA_FILES.*$} $copy_line $new_option out_line } elseif [regexp -- {COMPILED_IMPORTS\s*:\s*(.*)} $copy_line match sources] { # Copy all sources to the testsuite build directory. foreach import $sources { # print "Import: $base $type/$import" gdc-copy-extra $base "$type/$import" } set new_option "{ dg-additional-sources \"$sources\" }" regsub -- {COMPILED_IMPORTS.*$} $copy_line $new_option out_line } puts $fdout $out_line } # Add specific options for test type # DMD's testsuite is extremely verbose, compiler messages from constructs # such as pragma(msg, ...) would otherwise cause tests to fail. set out_line "// { dg-prune-output .* }" puts $fdout $out_line # Since GCC 6-20160131 blank lines are not allowed in the output by default. dg-allow-blank-lines-in-output { 1 } # Compilable files are successful if an output is generated. # Fail compilable are successful if an output is not generated. # Runnable must compile, link, and return 0 to be successful by default. switch [file dirname $test] { runnable { if ![isnative] { set out_line "// { dg-final { output-exists } }" puts $fdout $out_line } } compilable { set out_line "// { dg-final { output-exists } }" puts $fdout $out_line } fail_compilation { set out_line "// { dg-final { output-exists-not } }" puts $fdout $out_line } } close $fdin close $fdout return $test } proc gdc-permute-options { options } { set result { } set n [expr 1<<[llength $options]] for { set i 0 } { $i<$n } { incr i } { set option "" for { set j 0 } { $j<[llength $options] } { incr j } { if [expr $i & 1 << $j] { append option [lindex $options $j] append option " " } } lappend result $option } return $result } proc gdc-do-test { } { global srcdir subdir global dg-do-what-default global verbose # If a testcase doesn't have special options, use these. global DEFAULT_DFLAGS if ![info exists DEFAULT_DFLAGS] then { set DEFAULT_DFLAGS "-g -O2 -frelease" #set DEFAULT_DFLAGS "-O2" } # These are special options to use on testcase, and override DEFAULT_DFLAGS global PERMUTE_ARGS # Set if an extra option should be passed to link to shared druntime. global SHARED_OPTION # Additional arguments for gdc_load global GDC_EXECUTE_ARGS # Initialize `dg'. dg-init # Main loop. # set verbose 1 # set dg-final-code "" # Find all tests and pass to routine. foreach test [lsort [find $srcdir/$subdir *]] { regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base dir name ext # Skip invalid test directory if { [lsearch "runnable compilable fail_compilation" $dir] == -1 } { continue } # Skip invalid test extensions if { [lsearch "d" $ext] == -1 } { continue } # Convert to DG test. set imports [format "-I%s/%s" $base $dir] set filename [dmd2dg $base $dir/$name.$ext] if { $dir == "runnable" } { append PERMUTE_ARGS " $SHARED_OPTION" } set options [gdc-permute-options $PERMUTE_ARGS] switch $dir { runnable { for { set i 0 } { $i<[llength $options] } { incr i } { set flags [lindex $options $i] if [isnative] { set dg-do-what-default "run" } else { set dg-do-what-default "link" } gdc-dg-runtest $filename $flags $imports } } compilable { for { set i 0 } { $i<[llength $options] } { incr i } { set flags [lindex $options $i] #set dg-do-what-default "compile" set dg-do-what-default "assemble" gdc-dg-runtest $filename $flags $imports } } fail_compilation { for { set i 0 } { $i<[llength $options] } { incr i } { set flags [lindex $options $i] set dg-do-what-default "assemble" gdc-dg-runtest $filename $flags $imports } } } # Cleanup #file delete $filename } # All done. dg-finish } gdc-do-test ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d ================================================ /* TEST_OUTPUT: --- fail_compilation/aacmp10381.d(12): Error: `>` is not defined for associative arrays --- */ bool test10381() { int[int] aa1 = [0: 1]; int[int] aa2 = [0: 1]; return aa1 > aa2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/b17918.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/b17918a.d(7): Error: undefined identifier `_listMap` --- */ // https://issues.dlang.org/show_bug.cgi?id=17918 import imports.b17918a; class Derived : Base { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/b3841.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -w -o- /* TEST_OUTPUT: --- fail_compilation/b3841.d-mixin-31(31): Warning: `char += float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `int += float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `long += double` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `char -= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `int -= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `long -= double` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `char *= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `int *= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `long *= double` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `char /= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `int /= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `long /= double` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `char %= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `int %= float` is performing truncating conversion fail_compilation/b3841.d-mixin-31(31): Warning: `long %= double` is performing truncating conversion --- */ void f(string op, LHS, RHS)() { // pragma(msg, LHS, " += ", RHS); LHS a; RHS b; mixin("a "~op~" b;"); } template Ops(T...) { alias Ops = T; } void main() { foreach (string op; Ops!("+=", "-=", "*=", "/=", "%=")) { // OK f!(op, int, int)(); f!(op, long, int)(); f!(op, long, short)(); f!(op, float, long)(); f!(op, cfloat, long)(); f!(op, double, float)(); // Should that really be OK ? f!(op, short, int)(); f!(op, float, double)(); // Not OK, truncating conversion. f!(op, char, float)(); f!(op, int, float)(); f!(op, long, double)(); } foreach (string op; Ops!("+=", "-=")) { // OK f!(op, idouble, ifloat)(); // Should that really be OK ? f!(op, ifloat, idouble)(); } // OK f!("^^=", int, int)(); f!("^^=", long, int)(); f!("^^=", long, short)(); f!("^^=", float, long)(); f!("^^=", double, float)(); // Should that really be OK ? f!("^^=", float, double)(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/b6227.d ================================================ /* TEST_OUTPUT: --- fail_compilation/b6227.d(16): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/b6227.d(16): while evaluating: `static assert(!false)` fail_compilation/b6227.d(17): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/b6227.d(17): while evaluating: `static assert(cast(X)0 == cast(Y)0)` --- */ enum X { O, R } enum Y { U } static assert(!(X.O != Y.U)); static assert( (X.O == Y.U)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/betterc.d ================================================ /* REQUIRED_ARGS: -betterC * TEST_OUTPUT: --- fail_compilation/betterc.d(12): Error: Cannot use `throw` statements with -betterC fail_compilation/betterc.d(17): Error: Cannot use try-catch statements with -betterC fail_compilation/betterc.d(29): Error: `TypeInfo` cannot be used with -betterC --- */ void test() { throw new Exception("msg"); } void test2() { try { test(); } catch (Exception e) { } } void test3() { int i; auto ti = typeid(i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug15613.d ================================================ /* TEST_OUTPUT: --- fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` --- */ void f(int...); void g(Object, ...); void main() { f(null); g(8); } /* TEST_OUTPUT: --- fail_compilation/bug15613.d(32): Error: function `bug15613.h(int[]...)` is not callable using argument types `(int, void function(int[]...))` fail_compilation/bug15613.d(32): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` --- */ void h(int[]...); void test() { h(7, &h); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug18743.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/bug18743.d(18): Deprecation: `a ? a = 4 : a` must be surrounded by parentheses when next to operator `=` fail_compilation/bug18743.d(19): Deprecation: `a ? --a : a` must be surrounded by parentheses when next to operator `+=` --- */ void main() { int a; // ok (a ? a = 4 : a) = 5; a ? a = 4 : (a = 5); a ? a = 4 : a = 5; a ? --a : a += 1; a ? a = 4 : a++; // ok } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug4283.d ================================================ /* TEST_OUTPUT: --- fail_compilation/bug4283.d(12): Error: declaration expected, not `}` --- */ template Foo(bool b) { static if (b) enum bool Foo = 1; else } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug5.d ================================================ // REQUIRED_ARGS: int test1() { if (false) return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug5b.d ================================================ // REQUIRED_ARGS: int test1() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug8150a.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=8150: nothrow check doesn't work for constructor struct Foo { this(int) nothrow { throw new Exception("something"); } } void main() { Foo(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug8150b.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=8150: nothrow check doesn't work for constructor struct Foo { this()(int) nothrow { throw new Exception("something"); } } void main() { Foo(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug8891.d ================================================ /* TEST_OUTPUT: --- fail_compilation/bug8891.d(21): Error: need `this` for `opCall` of type `S(int n)` --- */ struct S { int value = 10; S opCall(int n) // non-static { //printf("this.value = %d\n", this.value); // prints garbage! S s; s.value = n; return s; } } void main() { S s = 10; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/bug9631.d ================================================ /* TEST_OUTPUT: --- fail_compilation/bug9631.d(20): Error: cannot implicitly convert expression `F()` of type `bug9631.T1!().F` to `bug9631.T2!().F` --- */ template T1() { struct F { } } template T2() { struct F { } } void main() { T2!().F x = T1!().F(); } /* TEST_OUTPUT: --- fail_compilation/bug9631.d(41): Error: incompatible types for `(x) == (y)`: `bug9631.S` and `bug9631.tem!().S` --- */ struct S { char c; } template tem() { struct S { int i; } } void equal() { S x; auto y = tem!().S(); bool b = x == y; } /* TEST_OUTPUT: --- fail_compilation/bug9631.d(55): Error: cannot cast expression `x` of type `bug9631.S` to `bug9631.tem!().S` because of different sizes fail_compilation/bug9631.d(58): Error: cannot cast expression `ta` of type `bug9631.tem!().S[1]` to `bug9631.S[1]` because of different sizes fail_compilation/bug9631.d(59): Error: cannot cast expression `sa` of type `S[1]` to `S[]` since sizes don't line up --- */ void test3() { S x; auto y = cast(tem!().S)x; tem!().S[1] ta; S[1] sa = cast(S[1])ta; auto t2 = cast(tem!().S[])sa; } /* TEST_OUTPUT: --- fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argument types `(int, S)` fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` fail_compilation/bug9631.d(80): Error: function literal `__lambda2(S s)` is not callable using argument types `(S)` fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using argument types `(S)` fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0` --- */ void arg() { S x; tem!().S y; void f(int i, S s); f(4, y); (tem!().S s){}(x); struct A { this(S){} } A(tem!().S()); } /* TEST_OUTPUT: --- fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)` fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0` fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are: fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)` fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`, candidates are: fail_compilation/bug9631.d(108): `bug9631.targ.ft2(T)(S, T)` --- */ void targ() { S x; tem!().S y; void ft()(tem!().S){} ft!()(x); ft(x); void ft2(T)(S, T){} ft2(y, 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ccast.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i` --- */ int i; byte b = (byte)i; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/cerrors.d ================================================ /* REQUIRED_ARGS: -wi TEST_OUTPUT: --- fail_compilation/cerrors.d(11): Error: C preprocessor directive `#if` is not supported, use `version` or `static if` fail_compilation/cerrors.d(11): Error: declaration expected, not `#` fail_compilation/cerrors.d(15): Warning: C preprocessor directive `#endif` is not supported fail_compilation/cerrors.d(15): Error: declaration expected, not `#` --- */ #if 1 void test(wchar_t u); #endif ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports1a.d ================================================ // REQUIRED_ARGS: -transition=checkimports -de /* TEST_OUTPUT: --- fail_compilation/checkimports1a.d(16): Deprecation: local import search method found struct `imports.diag12598a.lines` instead of variable `checkimports1a.C.lines` --- */ // new lookup + information class C { void f() { import imports.diag12598a; lines ~= ""; } string[] lines; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports1b.d ================================================ // REQUIRED_ARGS: -transition=import -transition=checkimports /* TEST_OUTPUT: --- fail_compilation/checkimports1b.d(16): Deprecation: local import search method found struct `imports.diag12598a.lines` instead of variable `checkimports1b.C.lines` fail_compilation/checkimports1b.d(16): Error: `lines` is a `struct` definition and cannot be modified --- */ // old lookup + information class C { void f() { import imports.diag12598a; lines ~= ""; } string[] lines; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports1c.d ================================================ // REQUIRED_ARGS: -transition=checkimports -transition=import /* TEST_OUTPUT: --- fail_compilation/checkimports1c.d(16): Deprecation: local import search method found struct `imports.diag12598a.lines` instead of variable `checkimports1c.C.lines` fail_compilation/checkimports1c.d(16): Error: `lines` is a `struct` definition and cannot be modified --- */ // old lookup + information (the order of switches is reverse) class C { void f() { import imports.diag12598a; lines ~= ""; } string[] lines; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d ================================================ // REQUIRED_ARGS: -transition=checkimports /* TEST_OUTPUT: --- fail_compilation/checkimports2a.d(26): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2a.X` fail_compilation/checkimports2a.d(32): Deprecation: local import search method found variable `imports.imp2.X` instead of nothing fail_compilation/checkimports2a.d(32): Error: no property `X` for type `checkimports2a.B` fail_compilation/checkimports2a.d(32): while evaluating: `static assert((B).X == 0)` fail_compilation/checkimports2a.d(33): Deprecation: local import search method found variable `imports.imp2.Y` instead of nothing fail_compilation/checkimports2a.d(33): Error: no property `Y` for type `checkimports2a.B` fail_compilation/checkimports2a.d(33): while evaluating: `static assert((B).Y == 2)` fail_compilation/checkimports2a.d(35): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2a.X` fail_compilation/checkimports2a.d(36): Deprecation: local import search method found variable `imports.imp2.Y` instead of variable `imports.imp1.Y` --- */ // new lookup + information import imports.imp1; enum X = 0; class B { import imports.imp2; static assert(X == 0); // imp2.X --> .X int[Y] aa; // imp2.Y } class C : B { static assert(B.X == 0); // imp2.X --> error static assert(B.Y == 2); // imp2.Y --> error static assert(X == 0); // imp2.X --> .X static assert(Y == 1); // imp2.Y --> imp1.Y } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d ================================================ // REQUIRED_ARGS: -transition=import -transition=checkimports -de /* TEST_OUTPUT: --- fail_compilation/checkimports2b.d(27): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2b.X` fail_compilation/checkimports2b.d(27): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2b.d(33): Deprecation: local import search method found variable `imports.imp2.X` instead of nothing fail_compilation/checkimports2b.d(33): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2b.d(34): Deprecation: local import search method found variable `imports.imp2.Y` instead of nothing fail_compilation/checkimports2b.d(34): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2b.d(36): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2b.X` fail_compilation/checkimports2b.d(36): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2b.d(37): Deprecation: local import search method found variable `imports.imp2.Y` instead of variable `imports.imp1.Y` fail_compilation/checkimports2b.d(37): while evaluating: `static assert(2 == 2)` --- */ // old lookup + information import imports.imp1; enum X = 0; class B { import imports.imp2; static assert(X == 2); // imp2.X --> .X (information) int[Y] aa; // imp2.Y } class C : B { static assert(B.X == 2); // imp2.X --> error (keep old lookup rule) static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule) static assert(X == 2); // imp2.X --> .X (information) static assert(Y == 2); // imp2.Y --> imp1.Y (information) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d ================================================ // REQUIRED_ARGS: -transition=checkimports -transition=import -de /* TEST_OUTPUT: --- fail_compilation/checkimports2c.d(28): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2c.X` fail_compilation/checkimports2c.d(28): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2c.d(34): Deprecation: local import search method found variable `imports.imp2.X` instead of nothing fail_compilation/checkimports2c.d(34): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2c.d(35): Deprecation: local import search method found variable `imports.imp2.Y` instead of nothing fail_compilation/checkimports2c.d(35): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2c.d(37): Deprecation: local import search method found variable `imports.imp2.X` instead of variable `checkimports2c.X` fail_compilation/checkimports2c.d(37): while evaluating: `static assert(2 == 2)` fail_compilation/checkimports2c.d(38): Deprecation: local import search method found variable `imports.imp2.Y` instead of variable `imports.imp1.Y` fail_compilation/checkimports2c.d(38): while evaluating: `static assert(2 == 2)` --- */ // old lookup + information (the order of switches is reverse) import imports.imp1; enum X = 0; class B { import imports.imp2; static assert(X == 2); // imp2.X --> .X (information) int[Y] aa; // imp2.Y } class C : B { static assert(B.X == 2); // imp2.X --> error (keep old lookup rule) static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule) static assert(X == 2); // imp2.X --> .X (information) static assert(Y == 2); // imp2.Y --> imp1.Y (information) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/circ10280.d ================================================ /* TEST_OUTPUT: --- fail_compilation/circ10280.d(11): Error: circular initialization of variable `circ10280.q10280` fail_compilation/circ10280.d(10): called from here: `foo10280()` --- */ // https://issues.dlang.org/show_bug.cgi?id=10280 const int q10280 = foo10280(); int foo10280() { return q10280; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/class1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/class1.d(11): Error: class `class1.C` identity assignment operator overload is illegal --- */ class C { // Non-templated identity opAssign void opAssign(C rhs){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/class2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/class2.d(11): Error: class `class2.C` identity assignment operator overload is illegal --- */ class C { // Templated identity opAssign void opAssign(T)(T rhs){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/commaexp.d ================================================ /* REQUIRED_ARGS: -o- TEST_OUTPUT: --- fail_compilation/commaexp.d(27): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(39): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(40): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(41): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(42): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(44): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(45): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(56): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(69): Error: Using the result of a comma expression is not allowed fail_compilation/commaexp.d(81): Error: Using the result of a comma expression is not allowed --- */ class Entry {} class MyContainerClass { bool append (Entry) { return false; } } int main () { bool ok; size_t aggr; MyContainerClass mc; // https://issues.dlang.org/show_bug.cgi?id=15997 enum WINHTTP_ERROR_BASE = 4200; enum ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = (WINHTTP_ERROR_BASE, + 44); // OK for (size_t i; i < 5; ++i, i += 1) {} for (size_t i; i < 5; ++i, i += 1, i++) {} if (!mc) mc = new MyContainerClass, mc.append(new Entry); if (Object o = cast(Object)mc) {} // Lowering ok = true, mc.append(new Entry); assert(ok); // NOPE for (size_t i; i < 5; ++i, i += (i++, 1)) {} for (; aggr++, aggr > 5;) {} if (Object o = (ok = true, null)) {} ok = (true, mc.append(new Entry)); assert(!ok); ok = true, (ok = (true, false)); return 42, 0; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=16022 bool test16022() { enum Type { Colon, Comma } Type type; return type == Type.Colon, type == Type.Comma; } bool test16022_structs() { struct A { int i; string s; } enum Type { Colon = A(0, "zero"), Comma = A(1, "one") } Type type; return type == Type.Colon, type == Type.Comma; } /********************************************/ void bar11(int*, int*) { } void test11() { static int* p; static int i; bar11((i,p), &i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/cppeh1.d ================================================ // DISABLED: win32 win64 /* TEST_OUTPUT: --- fail_compilation/cppeh1.d(26): Error: cannot catch C++ class objects in `@safe` code --- */ version (Windows) static assert(0, "This test should not run on this platform"); extern (C++, std) { class exception { } } @safe: void bar(); void abc(); void foo() { try { bar(); } catch (std.exception e) { abc(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/cppeh2.d ================================================ // DISABLED: win32 win64 /* TEST_OUTPUT: --- fail_compilation/cppeh2.d(21): Error: cannot mix catching D and C++ exceptions in the same try-catch --- */ version(Windows) static assert(0, "This test should not run on this platform"); extern (C++, std) { class exception { } } void bar(); void abc(); void foo() { try { bar(); } catch (std.exception e) { abc(); } catch (Exception e) { abc(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/cppmangle.d ================================================ /* TEST_OUTPUT: --- fail_compilation/cppmangle.d(10): Error: invalid zero length C++ namespace fail_compilation/cppmangle.d(14): Error: expected valid identifer for C++ namespace but got `0num` fail_compilation/cppmangle.d(18): Error: string expected following `,` for C++ namespace, not `)` --- */ extern(C++, "") { } extern(C++, "0num") { } extern(C++, "std", ) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe10989.d(11): Error: uncaught CTFE exception `object.Exception("abc"c)` fail_compilation/ctfe10989.d(14): called from here: `throwing()` fail_compilation/ctfe10989.d(14): while evaluating: `static assert(throwing())` --- */ int throwing() { throw new Exception(['a', 'b', 'c']); return 0; } static assert(throwing()); /* TEST_OUTPUT: --- fail_compilation/ctfe10989.d(33): Error: uncaught CTFE exception `object.Exception("abc"c)` fail_compilation/ctfe10989.d(36): called from here: `throwing2()` fail_compilation/ctfe10989.d(36): while evaluating: `static assert(throwing2())` --- */ int throwing2() { string msg = "abc"; char[] arr; arr.length = msg.length; arr = arr[0 .. $]; arr[] = msg; throw new Exception(cast(string)arr); return 0; } static assert(throwing2()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe10995.d(19): Error: cannot read uninitialized variable `a` in CTFE fail_compilation/ctfe10995.d(25): Error: cannot read uninitialized variable `a` in CTFE --- */ struct T { short a = void; } T foo() { auto t = T.init; return t; } enum i = foo().a; struct T2 { short a = void; } enum i2 = T2.init.a; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe11467.d(15): Error: overlapping slice assignment `[0..4] = [1..5]` fail_compilation/ctfe11467.d(24): called from here: `test11467a()` fail_compilation/ctfe11467.d(24): while evaluating: `static assert(test11467a())` fail_compilation/ctfe11467.d(21): Error: overlapping slice assignment `[1..5] = [0..4]` fail_compilation/ctfe11467.d(25): called from here: `test11467b()` fail_compilation/ctfe11467.d(25): while evaluating: `static assert(test11467b())` --- */ int test11467a() { auto a = [0, 1, 2, 3, 4]; a[0 .. 4] = a[1 .. 5]; return 1; } int test11467b() { auto a = [0, 1, 2, 3, 4]; a[1 .. 5] = a[0 .. 4]; return 1; } static assert(test11467a()); static assert(test11467b()); /* TEST_OUTPUT: --- fail_compilation/ctfe11467.d(41): Error: overlapping slice assignment `[0..4] = [1..5]` fail_compilation/ctfe11467.d(50): called from here: `test11467c()` fail_compilation/ctfe11467.d(50): while evaluating: `static assert(test11467c())` fail_compilation/ctfe11467.d(47): Error: overlapping slice assignment `[1..5] = [0..4]` fail_compilation/ctfe11467.d(51): called from here: `test11467d()` fail_compilation/ctfe11467.d(51): while evaluating: `static assert(test11467d())` --- */ int test11467c() { auto a = "abcde".dup; a[0 .. 4] = a[1 .. 5]; return 1; } int test11467d() { auto a = "abcde".dup; a[1 .. 5] = a[0 .. 4]; return 1; } static assert(test11467c()); static assert(test11467d()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe13612.d(15): Error: function `ctfe13612.S.recurse` CTFE recursion limit exceeded fail_compilation/ctfe13612.d(20): called from here: `s.recurse()` fail_compilation/ctfe13612.d(15): 1000 recursive calls to function `recurse` fail_compilation/ctfe13612.d(23): called from here: `(new S).recurse()` fail_compilation/ctfe13612.d(23): while evaluating: `static assert((new S).recurse())` --- */ class S { int x; int recurse() { S s; assert(!x); // Error: class 'this' is null and cannot be dereferenced s = new S(); return s.recurse(); } } static assert(new S().recurse()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe14207.d(13): Error: cannot convert `&immutable(ulong)` to `ubyte[8]*` at compile time fail_compilation/ctfe14207.d(18): called from here: `nativeToBigEndian()` fail_compilation/ctfe14207.d(22): called from here: `digest()` --- */ ubyte[8] nativeToBigEndian() { immutable ulong res = 1; return *cast(ubyte[8]*) &res; } auto digest() { ubyte[8] bits = nativeToBigEndian(); return bits; } enum h = digest(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe14465.d(19): Error: uncaught CTFE exception `ctfe14465.E("message")` fail_compilation/ctfe14465.d(22): called from here: `foo()` fail_compilation/ctfe14465.d(22): while evaluating: `static assert(foo())` --- */ class E : Exception { this(string msg) { super(msg); } } bool foo() { throw new E("message"); } static assert(foo()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `["a b"]` of type `string[]` to `string` fail_compilation/ctfe14731.d(17): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string` --- */ string[] split(string a) { return [a]; } void main() { enum string list1 = "a b".split(); string list2 = "a b".split(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ctypes.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ctypes.d(11): Error: use `real` instead of `long double` fail_compilation/ctypes.d(12): Error: use `long` for a 64 bit integer instead of `long long` --- */ void test() { long double r; long long ll; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/cwords.d ================================================ /* TEST_OUTPUT: --- fail_compilation/cwords.d(13): Error: undefined identifier `FALSE`, did you mean `false`? fail_compilation/cwords.d(14): Error: undefined identifier `TRUE`, did you mean `true`? fail_compilation/cwords.d(15): Error: undefined identifier `NULL`, did you mean `null`? fail_compilation/cwords.d(16): Error: undefined identifier `unsigned`, did you mean `uint`? --- */ void foo() { bool a = FALSE; bool b = TRUE; int* p = NULL; unsigned u; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/dephexstrings.d(8): Deprecation: Built-in hex string literals are deprecated, use `std.conv.hexString` instead. --- */ enum xstr = x"60"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/depmsg.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/depmsg.d(40): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message! fail_compilation/depmsg.d(40): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message! fail_compilation/depmsg.d(41): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message! fail_compilation/depmsg.d(41): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message! fail_compilation/depmsg.d(42): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message! fail_compilation/depmsg.d(42): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message! fail_compilation/depmsg.d(43): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message! fail_compilation/depmsg.d(43): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message! fail_compilation/depmsg.d(44): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message! fail_compilation/depmsg.d(44): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message! fail_compilation/depmsg.d(46): Deprecation: alias `depmsg.main.Inner.G` is deprecated - With message! fail_compilation/depmsg.d(47): Deprecation: variable `depmsg.main.Inner.H` is deprecated - With message! fail_compilation/depmsg.d(48): Deprecation: class `depmsg.main.Inner.I!().I` is deprecated - With message! --- */ void main() { class Inner { deprecated("With message!") { struct A { } class B { } interface C { } union D { } enum E { e }; //typedef int F; alias int G; static int H; template I() { class I {} } } } with(Inner) { A a; B b; C c; D d; E e; //F f; G g; auto h = H; I!() i; } } /* TEST_OUTPUT: --- fail_compilation/depmsg.d(94): Deprecation: function `depmsg.test12954.Foo.bar1` is deprecated - [C] Use Foo.bar42 instead fail_compilation/depmsg.d(95): Deprecation: function `depmsg.test12954.Foo.bar2` is deprecated - [E] Use Foo.bar42 instead fail_compilation/depmsg.d(96): Deprecation: function `depmsg.test12954.Foo.bar3` is deprecated - [S] Use Foo.bar42 instead fail_compilation/depmsg.d(97): Deprecation: function `depmsg.test12954.Foo.bar4` is deprecated - [F] Use Foo.bar42 instead fail_compilation/depmsg.d(98): Deprecation: variable `depmsg.test12954.Foo.v2` is deprecated - Forward reference fail_compilation/depmsg.d(105): Deprecation: class `depmsg.test12954.Obsolete` is deprecated fail_compilation/depmsg.d(105): Deprecation: function `depmsg.test12954.Obsolete.obs` is deprecated - Function is obsolete --- */ void test12954() { struct Foo { enum DeprecatedReasonEnum = "[E] Use Foo.bar42 instead"; static const DeprecatedReasonStatic = "[S] Use Foo.bar42 instead"; static immutable DeprecatedReasonFunc = reason("Foo.bar42"); static string reason (string name) { return "[F] Use " ~ name ~ " instead"; } deprecated("[C] Use " ~ `Foo.bar42 instead`) void bar1 () {} deprecated(DeprecatedReasonEnum) void bar2 () {} deprecated(DeprecatedReasonStatic) void bar3 () {} deprecated(DeprecatedReasonFunc) void bar4 () {} deprecated(Forward ~ Reference) int v2 = 2; enum Forward = "Forward ", Reference = "reference"; } Foo f; f.bar1; f.bar2; f.bar3; f.bar4; assert(f.v2 == 2); deprecated class Obsolete { deprecated("Function is obsolete") void obs() {} } (new Obsolete).obs(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/depmsg15814.d(9): Deprecation: function `depmsg15814.get15814` is deprecated - bug15814 --- */ deprecated("bug15814") int get15814() { return 0; } enum val15814 = get15814(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/depmsg15815.d(23): Deprecation: alias `depmsg15815.Alias!(const(Foo)).Alias` is deprecated - message Foo --- */ template Unqual(T) { static if (is(T U == const U)) alias Unqual = U; else alias Unqual = T; } deprecated("message") template Alias(T) { alias Alias = Unqual!T; } struct Foo {} pragma(msg, Alias!(const(Foo))); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecate12979a.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/deprecate12979a.d(14): Deprecation: `asm` statement is assumed to throw - mark it with `nothrow` if it does not --- */ void foo() nothrow { version(GNU) { asm { ""; } } else { asm { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecate12979b.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/deprecate12979b.d(13): Deprecation: `asm` statement is assumed to be impure - mark it with `pure` if it is not --- */ void foo() pure { version(GNU) { asm { ""; } } else { asm { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecate12979c.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/deprecate12979c.d(13): Deprecation: `asm` statement is assumed to use the GC - mark it with `@nogc` if it does not --- */ void foo() @nogc { version(GNU) { asm { ""; } } else { asm { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecate12979d.d ================================================ // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/deprecate12979d.d(12): Error: `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not --- */ void foo() @safe { version(GNU) { asm { ""; } } else { asm { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/deprecate1553.d(19): Deprecation: cannot use `foreach_reverse` with a delegate --- */ struct S { int dg(int delegate(ref int a)) { return 0; } } void main() { S s; foreach_reverse(a; &s.dg) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/deprecated6760.d(13): Deprecation: `deprecated6760.Foo.opEquals` cannot be annotated with `@disable` because it is overriding a function in the base class fail_compilation/deprecated6760.d(18): Deprecation: `deprecated6760.Bar.opEquals` cannot be marked as `deprecated` because it is overriding a function in the base class --- */ class Foo { @disable override bool opEquals(Object); } class Bar { deprecated override bool opEquals(Object); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/deprecateopdot.d(27): Deprecation: `opDot` is deprecated. Use `alias this` fail_compilation/deprecateopdot.d(28): Deprecation: `opDot` is deprecated. Use `alias this` fail_compilation/deprecateopdot.d(29): Deprecation: `opDot` is deprecated. Use `alias this` --- */ struct S6 { int a, b; } struct T6 { S6 s; S6* opDot() { return &s; } } void test6() { T6 t; t.a = 4; assert(t.a == 4); t.b = 5; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10089.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10089.d(15): Error: undefined identifier `chunks` in package `imports` fail_compilation/diag10089.d(17): Error: template `Foo()` does not have property `chunks` --- */ import imports.diag10089a, imports.diag10089b; template Foo() {} void main() { imports.chunks("abcdef", 2); Foo.chunks("abcdef", 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10099.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` default construction is disabled for type `S` --- */ struct S { @disable this(); } void main() { S s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10141.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10141.d(9): Error: module `imports.diag10141a` import `unexisting_symbol` not found --- */ import imports.diag10141a; import imports.diag10141a : unexisting_symbol; Tuple!(int) fun() { return Tuple!(int).init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10169.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10169.d(12): Deprecation: `imports.a10169.B.x` is not visible from module `diag10169` fail_compilation/diag10169.d(12): Error: struct `imports.a10169.B` member `x` is not accessible --- */ import imports.a10169; void main() { auto a = B.init.x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10221.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10221.d(10): Error: cannot implicitly convert expression `256` of type `int` to `ubyte` --- */ void main() { foreach(ref ubyte i; 0..256) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10221a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10221a.d(10): Error: cannot implicitly convert expression `257` of type `int` to `ubyte` --- */ void main() { foreach(ubyte i; 0..257) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10319.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10319.d(27): Error: `pure` function `D main` cannot call impure function `diag10319.foo` fail_compilation/diag10319.d(27): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` fail_compilation/diag10319.d(16): `diag10319.foo` is declared here fail_compilation/diag10319.d(28): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` fail_compilation/diag10319.d(18): `diag10319.bar!int.bar` is declared here fail_compilation/diag10319.d(27): Error: function `diag10319.foo` is not `nothrow` fail_compilation/diag10319.d(28): Error: function `diag10319.bar!int.bar` is not `nothrow` fail_compilation/diag10319.d(25): Error: `nothrow` function `D main` may throw --- */ void foo() {} void bar(T)() { static int g; g = 10; // impure int x; auto p = &x; // system throw new Exception(""); // may throw } @safe pure nothrow void main() // L23 { foo(); // L25 bar!int(); // L26 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10327.d ================================================ import imports.test10327; // package.d missing ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10359.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10359.d(10): Error: pointer slicing not allowed in safe functions --- */ void foo(int* p) @safe { auto a = p[0 .. 10]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10405.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10405.d(10): Error: cannot return non-void from `void` function --- */ void main() { return 10; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10415.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const`, candidates are: fail_compilation/diag10415.d(13): `diag10415.C.x()` fail_compilation/diag10415.d(18): `diag10415.C.x(int _param_0)` fail_compilation/diag10415.d(39): Error: d.x is not an lvalue --- */ class C { @property int x() const { return 0; } @property void x(int) { } } template AddProp() { @property int x() { return 1; } } template AddFunc() { void x(int, int) {} } class D { // overloadset mixin AddProp; mixin AddFunc; } void main() { const c = new C(); c.x = 1; auto d = new D(); d.x = 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10688.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10688.d(12): Error: function `diag10688.Bar.foo` `private` method is not virtual and cannot override fail_compilation/diag10688.d(14): Error: function `diag10688.Bar.bar` `package` method is not virtual and cannot override --- */ class Bar { private: override void foo() { } package: override void bar() { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10768.d ================================================ // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/diag10768.d(36): Error: cannot implicitly override base class method `diag10768.Frop.frop` with `diag10768.Foo.frop`; add `override` attribute --- */ struct CirBuff(T) { import std.traits: isArray; CirBuff!T opAssign(R)(R) if (isArray!R) {} T[] toArray() { T[] ret; // = new T[this.length]; return ret; } alias toArray this; } class Bar(T=int) { CirBuff!T _bar; } class Once { Bar!Foo _foobar; } class Foo : Frop { // override public int frop() { return 1; } } class Frop { public int frop() { return 0; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10783.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10783.d(14): Error: no property `type` for type `Event` fail_compilation/diag10783.d(14): Error: undefined identifier `En` --- */ struct Event { } void main() { Event event; switch (event.type) with (En) { default: } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10792.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10792.d(9): Error: semicolon expected following auto declaration, not `End of File` --- */ enum isPred(T) = asdf ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10805.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10805.d(11): Error: delimited string must end in FOO" fail_compilation/diag10805.d(13): Error: unterminated string constant starting at fail_compilation/diag10805.d(13) fail_compilation/diag10805.d(13): Error: Implicit string concatenation is deprecated, use "" ~ "" instead fail_compilation/diag10805.d(14): Error: semicolon expected following auto declaration, not `End of File` --- */ enum s = q"FOO FOO "; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10862.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10862.d(40): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(41): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(42): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(43): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(44): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(46): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(47): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(48): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(49): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(51): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(52): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(53): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(54): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(56): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(57): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(58): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(59): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(61): Error: undefined identifier `semanticError` fail_compilation/diag10862.d(71): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d(74): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-77(77): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-80(80): Error: Using the result of a comma expression is not allowed fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c` fail_compilation/diag10862.d(86): Error: undefined identifier `semanticError` fail_compilation/diag10862.d(93): Error: lazy variable `bar` cannot be modified fail_compilation/diag10862.d(95): Error: template instance `diag10862.test3.foo!int` error instantiating --- */ void test1() { int a, b; if (a = b) {} if ((a = b) = 0) {} if ((a = b) = (a = b)) {} if (a = 0, b = 0) {} // https://issues.dlang.org/show_bug.cgi?id=15384 if (auto x = a = b) {} // this is error, today while (a = b) {} while ((a = b) = 0) {} while ((a = b) = (a = b)) {} while (a = 0, b = 0) {} // https://issues.dlang.org/show_bug.cgi?id=15384 do {} while (a = b); do {} while ((a = b) = 0); do {} while ((a = b) = (a = b)); do {} while (a = 0, b = 0); // https://issues.dlang.org/show_bug.cgi?id=15384 for (; a = b; ) {} for (; (a = b) = 0; ) {} for (; (a = b) = (a = b); ) {} for (; a = 0, b = 0; ) {} // https://issues.dlang.org/show_bug.cgi?id=15384 semanticError; } void test2() { int a, b; // (a + b) cannot be an assignment target. // However checkAssignAsCondition specilatively rerites it to EqualExp, // then the pointless error "is not an lvalue" would not happen. if (a + b = a * b) {} // The suggestion error masks "undefined identifier" error if (a = undefinedIdentifier) {} // If the condition is a mixin expression if (mixin("a = b")) {} if (mixin("(a = b) = 0")) {} if (mixin("(a = b) = (a = b)")) {} if (mixin("a = 0, b = 0")) {} if (auto x = mixin("a = b")) {} // Note: no error if (mixin("a + b = a * b")) {} // Note: "a + b is not an lvalue" if (mixin("a = c")) {} semanticError; } void test3() { void foo(T)(lazy T bar) { bar = 2; } foo(1 + 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10926.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10926.d(11): Error: `cast(const(int)[])c` is not an lvalue and cannot be modified --- */ void main() { const(int)[] a, b; int[] c, d; (true ? a : c) ~= 20; // line 6, Error: a is not an lvalue } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag10984.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag10984.d(11): Error: static function diag10984.f.n cannot access frame of function diag10984.f --- */ void f() { int x; static void n() { x++; } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11078.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11078.d(19): Error: none of the overloads of `value` are callable using argument types `(double)`, candidates are: fail_compilation/diag11078.d(12): `diag11078.S1.value()` fail_compilation/diag11078.d(13): `diag11078.S1.value(int n)` --- */ struct S1 { @property int value() { return 1; } @property void value(int n) { } } void main() { S1 s1; s1.value = 1.0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11132.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11132.d(22): Error: overlapping initialization for field `a` and `b` --- */ struct S { int x; union { int a; int b; } int z; } void main() { S s = { 1, 2, 3 }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11198.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11198.d(11): Error: version conditions can only be declared at module scope fail_compilation/diag11198.d(12): Error: debug conditions can only be declared at module scope --- */ void main() { version = blah; debug = blah; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11423.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11423.d(9): Error: undefined identifier `Foo` --- */ void main() { auto foo = new shared Foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11425.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11425.d(13): Error: variable `x` is shadowing variable `diag11425.main.x` --- */ void main() { int x; { int x = 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11727.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11727.d(10): Error: type `n` is not an expression --- */ auto returnEnum() { enum n; return n; } void main() { assert(returnEnum() == 0); } /* TEST_OUTPUT: --- fail_compilation/diag11727.d(26): Error: type `void` is not an expression --- */ auto returnVoid() { alias v = void; return v; } /* TEST_OUTPUT: --- fail_compilation/diag11727.d(38): Error: template `t()` has no type --- */ auto returnTemplate() { template t() {} return t; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11756.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11756.d(15): Error: cannot read uninitialized variable `cnt` in CTFE fail_compilation/diag11756.d(34): called from here: `foo.ptr2.opAssign(Ptr(& n))` fail_compilation/diag11756.d(39): called from here: `test()` fail_compilation/diag11756.d(39): while evaluating: `static assert(test())` --- */ struct Ptr { void opAssign(Ptr other) { (*cnt)--; // error cnt = other.cnt; (*cnt)++; } size_t *cnt; } union Foo { size_t *ptr1; Ptr ptr2; } bool test() { Foo foo; size_t cnt = 1; foo.ptr1 = &cnt; size_t n; foo.ptr2 = Ptr(&n); assert(cnt == 0); return true; } static assert(test()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11759.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11759.d(8): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead --- */ ulong x = 123ul; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11769.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches both: fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring _param_0)` and: fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring _param_0)` --- */ template foo(T) { void bar(wstring) {} void bar(dstring) {} } void main() { foo!string.bar("abc"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11819a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11819a.d(30): Error: unrecognized trait `DoesNotExist` fail_compilation/diag11819a.d(31): Error: unrecognized trait `IsAbstractClass`, did you mean `isAbstractClass`? fail_compilation/diag11819a.d(32): Error: unrecognized trait `IsArithmetic`, did you mean `isArithmetic`? fail_compilation/diag11819a.d(33): Error: unrecognized trait `IsAssociativeArray`, did you mean `isAssociativeArray`? fail_compilation/diag11819a.d(34): Error: unrecognized trait `IsFinalClass`, did you mean `isFinalClass`? fail_compilation/diag11819a.d(35): Error: unrecognized trait `IsPOD`, did you mean `isPOD`? fail_compilation/diag11819a.d(36): Error: unrecognized trait `IsNested`, did you mean `isNested`? fail_compilation/diag11819a.d(37): Error: unrecognized trait `IsFloating`, did you mean `isFloating`? fail_compilation/diag11819a.d(38): Error: unrecognized trait `IsIntegral`, did you mean `isIntegral`? fail_compilation/diag11819a.d(39): Error: unrecognized trait `IsScalar`, did you mean `isScalar`? fail_compilation/diag11819a.d(40): Error: unrecognized trait `IsStaticArray`, did you mean `isStaticArray`? fail_compilation/diag11819a.d(41): Error: unrecognized trait `IsUnsigned`, did you mean `isUnsigned`? fail_compilation/diag11819a.d(42): Error: unrecognized trait `IsVirtualFunction`, did you mean `isVirtualFunction`? fail_compilation/diag11819a.d(43): Error: unrecognized trait `IsVirtualMethod`, did you mean `isVirtualMethod`? fail_compilation/diag11819a.d(44): Error: unrecognized trait `IsAbstractFunction`, did you mean `isAbstractFunction`? fail_compilation/diag11819a.d(45): Error: unrecognized trait `IsFinalFunction`, did you mean `isFinalFunction`? fail_compilation/diag11819a.d(46): Error: unrecognized trait `IsOverrideFunction`, did you mean `isOverrideFunction`? fail_compilation/diag11819a.d(47): Error: unrecognized trait `IsStaticFunction`, did you mean `isStaticFunction`? fail_compilation/diag11819a.d(48): Error: unrecognized trait `IsRef`, did you mean `isRef`? fail_compilation/diag11819a.d(49): Error: unrecognized trait `IsOut`, did you mean `isOut`? fail_compilation/diag11819a.d(50): Error: unrecognized trait `IsLazy`, did you mean `isLazy`? --- */ void main() { if (__traits(DoesNotExist)) { } if (__traits(IsAbstractClass)) { } if (__traits(IsArithmetic)) { } if (__traits(IsAssociativeArray)) { } if (__traits(IsFinalClass)) { } if (__traits(IsPOD)) { } if (__traits(IsNested)) { } if (__traits(IsFloating)) { } if (__traits(IsIntegral)) { } if (__traits(IsScalar)) { } if (__traits(IsStaticArray)) { } if (__traits(IsUnsigned)) { } if (__traits(IsVirtualFunction)) { } if (__traits(IsVirtualMethod)) { } if (__traits(IsAbstractFunction)) { } if (__traits(IsFinalFunction)) { } if (__traits(IsOverrideFunction)) { } if (__traits(IsStaticFunction)) { } if (__traits(IsRef)) { } if (__traits(IsOut)) { } if (__traits(IsLazy)) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11819b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11819b.d(28): Error: unrecognized trait `HasMember`, did you mean `hasMember`? fail_compilation/diag11819b.d(29): Error: unrecognized trait `Identifier`, did you mean `identifier`? fail_compilation/diag11819b.d(30): Error: unrecognized trait `GetProtection`, did you mean `getProtection`? fail_compilation/diag11819b.d(31): Error: unrecognized trait `Parent`, did you mean `parent`? fail_compilation/diag11819b.d(32): Error: unrecognized trait `GetMember`, did you mean `getMember`? fail_compilation/diag11819b.d(33): Error: unrecognized trait `GetOverloads`, did you mean `getOverloads`? fail_compilation/diag11819b.d(34): Error: unrecognized trait `GetVirtualFunctions`, did you mean `getVirtualFunctions`? fail_compilation/diag11819b.d(35): Error: unrecognized trait `GetVirtualMethods`, did you mean `getVirtualMethods`? fail_compilation/diag11819b.d(36): Error: unrecognized trait `ClassInstanceSize`, did you mean `classInstanceSize`? fail_compilation/diag11819b.d(37): Error: unrecognized trait `AllMembers`, did you mean `allMembers`? fail_compilation/diag11819b.d(38): Error: unrecognized trait `DerivedMembers`, did you mean `derivedMembers`? fail_compilation/diag11819b.d(39): Error: unrecognized trait `IsSame`, did you mean `isSame`? fail_compilation/diag11819b.d(40): Error: unrecognized trait `Compiles`, did you mean `compiles`? fail_compilation/diag11819b.d(41): Error: unrecognized trait `Parameters`, did you mean `parameters`? fail_compilation/diag11819b.d(42): Error: unrecognized trait `GetAliasThis`, did you mean `getAliasThis`? fail_compilation/diag11819b.d(43): Error: unrecognized trait `GetAttributes`, did you mean `getAttributes`? fail_compilation/diag11819b.d(44): Error: unrecognized trait `GetFunctionAttributes`, did you mean `getFunctionAttributes`? fail_compilation/diag11819b.d(45): Error: unrecognized trait `GetUnitTests`, did you mean `getUnitTests`? fail_compilation/diag11819b.d(46): Error: unrecognized trait `GetVirtualIndex`, did you mean `getVirtualIndex`? --- */ void main() { if (__traits(HasMember)) { } if (__traits(Identifier)) { } if (__traits(GetProtection)) { } if (__traits(Parent)) { } if (__traits(GetMember)) { } if (__traits(GetOverloads)) { } if (__traits(GetVirtualFunctions)) { } if (__traits(GetVirtualMethods)) { } if (__traits(ClassInstanceSize)) { } if (__traits(AllMembers)) { } if (__traits(DerivedMembers)) { } if (__traits(IsSame)) { } if (__traits(Compiles)) { } if (__traits(Parameters)) { } if (__traits(GetAliasThis)) { } if (__traits(GetAttributes)) { } if (__traits(GetFunctionAttributes)) { } if (__traits(GetUnitTests)) { } if (__traits(GetVirtualIndex)) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag11840.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag11840.d(12): Error: undefined identifier `i` fail_compilation/diag11840.d(12): Error: undefined identifier `j` --- */ void main() { int[10] data; data[i .. j] = 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12063.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12063.d(11): Error: no property `max` for type `Foo` fail_compilation/diag12063.d(14): Error: incompatible types for `(Foo()) + (1)`: `Bar` and `int` --- */ struct Foo {} enum Bar : Foo { a = Foo(), b } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12124.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12124.d(14): Error: struct `diag12124.S1` `static opCall` is hidden by constructors and can never be called fail_compilation/diag12124.d(14): Please use a factory method instead, or replace all constructors with `static opCall`. fail_compilation/diag12124.d(20): Error: struct `diag12124.S2` `static opCall` is hidden by constructors and can never be called fail_compilation/diag12124.d(20): Please use a factory method instead, or replace all constructors with `static opCall`. --- */ struct S1 { this(int) {} static S1 opCall() { assert(0); } } struct S2 { this(int) {} static S2 opCall()() { assert(0); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12280.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12280.d(15): Error: undefined identifier `nonexistent` fail_compilation/diag12280.d(13): Error: template instance `diag12280.f!10` error instantiating fail_compilation/diag12280.d(18): 11 recursive instantiations from here: `f!0` --- */ void f(int i)() { static if (i < 10) f!(i + 1); else nonexistent(); } alias f0 = f!0; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12312.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` `void[16]` does not have a default initializer --- */ void main() { void[16] arr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12380.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12380.d(12): Error: cannot implicitly convert expression `cast(E)0` of type `E` to `void*` --- */ enum E { a, b, } void main() { void* a = E.init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12432.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12432.d(55): Error: cannot infer argument types, expected 1 argument, not 2 fail_compilation/diag12432.d(56): Error: cannot infer argument types, expected 2 arguments, not 3 fail_compilation/diag12432.d(57): Error: cannot infer argument types, expected 1 argument, not 2 fail_compilation/diag12432.d(58): Error: cannot infer argument types, expected 1 argument, not 2 fail_compilation/diag12432.d(59): Error: cannot infer argument types, expected 2 arguments, not 3 fail_compilation/diag12432.d(60): Error: cannot infer argument types, expected 2 arguments, not 3 --- */ struct R1 { @property int front() { return 0; } enum bool empty = false; void popFront() { } } struct Tuple(T...) { T t; alias t this; } struct R2 { @property Tuple!(int, float) front() { return typeof(return).init; } enum bool empty = false; void popFront() { } } struct OpApply1Func { int opApply(int function(int)) { return 0; } } struct OpApply1Deleg { int opApply(int delegate(int)) { return 0; } } struct OpApply2Func { int opApply(int function(int, float)) { return 0; } } struct OpApply2Deleg { int opApply(int delegate(int, float)) { return 0; } } void main() { foreach (a, b; R1()) { } foreach (a, b, c; R2()) { } foreach (a, b; OpApply1Func()) { } foreach (a, b; OpApply1Deleg()) { } foreach (a, b, c; OpApply2Func()) { } foreach (a, b, c; OpApply2Deleg()) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12480.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/diag12480.d(12): Error: static assert: `2u == 3u` is false --- */ module diag12480; static immutable arr = ["a", "b"]; static assert(arr.length == 3); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12487.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12487.d(15): Error: recursive expansion of template instance `diag12487.recTemplate!int` fail_compilation/diag12487.d(25): Error: template instance `diag12487.recTemplate!int` error instantiating fail_compilation/diag12487.d(18): Error: function `diag12487.recFunction` CTFE recursion limit exceeded fail_compilation/diag12487.d(20): called from here: `recFunction(i)` fail_compilation/diag12487.d(18): 1000 recursive calls to function `recFunction` fail_compilation/diag12487.d(27): called from here: `recFunction(0)` --- */ template recTemplate(T) { enum bool recTemplate = recTemplate!T; } bool recFunction(int i) { return recFunction(i); } void main() { enum bool value1 = recTemplate!int; enum bool value2 = recFunction(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12598.d ================================================ /* REQUIRED_ARGS: -transition=import TEST_OUTPUT: --- fail_compilation/diag12598.d(14): Error: `lines` is a `struct` definition and cannot be modified --- */ class C { void f() { import imports.diag12598a; lines ~= ""; } string[] lines; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12640.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12640.d(14): Error: undefined identifier `asdf` fail_compilation/diag12640.d(23): Error: undefined identifier `asdf` --- */ void main() { switch (1) { case 0: asdf; break; default: } switch (1) { default: asdf; break; case 0: } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12678.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12678.d(21): Error: const field `cf1` initialized multiple times fail_compilation/diag12678.d(20): Previous initialization is here. fail_compilation/diag12678.d(24): Error: immutable field `if1` initialized multiple times fail_compilation/diag12678.d(23): Previous initialization is here. fail_compilation/diag12678.d(27): Error: const field `cf2` initialization is not allowed in loops or after labels --- */ struct S { const int cf1; const int cf2; immutable int if1; this(int x) { cf1 = x; cf1 = x; if1 = x; if1 = x; foreach (i; 0 .. 5) cf2 = x; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12777.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12777.d(14): Error: cannot modify `this.v` in `const` function fail_compilation/diag12777.d(15): Error: cannot modify `this.v` in `immutable` function fail_compilation/diag12777.d(21): Error: cannot modify `this.v` in `const` function fail_compilation/diag12777.d(22): Error: cannot modify `this.v` in `immutable` function --- */ struct S { int v; void fun() const { v++; } void gun() immutable { v++; } } class C { int v; void fun() const { v++; } void gun() immutable { v++; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag12829.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closures with the GC fail_compilation/diag12829.d(15): diag12829.test1.__lambda1 closes over variable x at fail_compilation/diag12829.d(14) fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14) fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closures with the GC fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28) --- */ auto test1() @nogc { int x; void delegate() @nogc foo = () { int y = x; }; void bar() { int y = x; } auto dg = &bar; } auto test2() @nogc { int x; struct S { void foo() { int y = x; } } return S(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13028.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13028.d(15): Error: variable `dg` cannot be read at compile time fail_compilation/diag13028.d(22): Error: variable `a` cannot be read at compile time fail_compilation/diag13028.d(28): Error: CTFE failed because of previous errors in `foo` fail_compilation/diag13028.d(28): while evaluating: `static assert(foo(() => 1) == 1)` fail_compilation/diag13028.d(29): Error: CTFE failed because of previous errors in `bar` fail_compilation/diag13028.d(29): while evaluating: `static assert(bar(delegate int() => 1) == 1)` --- */ int foo(int delegate() dg) { enum b = dg(); return b; } int bar(lazy int a) { enum b = a; return a; } void main() { static assert(foo(() => 1) == 1); static assert(bar(1) == 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13082.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13082.d(24): Error: constructor `diag13082.C.this(int a)` is not callable using argument types `(string)` fail_compilation/diag13082.d(24): cannot pass argument `b` of type `string` to parameter `int a` fail_compilation/diag13082.d(25): Error: constructor `diag13082.S.this(int a)` is not callable using argument types `(string)` fail_compilation/diag13082.d(25): cannot pass argument `b` of type `string` to parameter `int a` --- */ class C { this(int a) {} } struct S { this(int a) {} } void main() { string b; auto c = new C(b); auto s = new S(b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13142.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13142.d(25): Error: cannot implicitly convert expression `3` of type `int` to `TYPE` --- */ class Button { enum TYPE // button type { COMMAND, CHECK, OPTION, } } class Toolbar { enum ButtonTYPE // button type { COMMAND = Button.TYPE.COMMAND, CHECK = Button.TYPE.CHECK, OPTION = Button.TYPE.OPTION, DELIMETER = Button.TYPE.max + 1 } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13281.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13281.d(20): Error: cannot implicitly convert expression `123` of type `int` to `string` fail_compilation/diag13281.d(21): Error: cannot implicitly convert expression `123u` of type `uint` to `string` fail_compilation/diag13281.d(22): Error: cannot implicitly convert expression `123L` of type `long` to `string` fail_compilation/diag13281.d(23): Error: cannot implicitly convert expression `123LU` of type `ulong` to `string` fail_compilation/diag13281.d(24): Error: cannot implicitly convert expression `123.4` of type `double` to `int` fail_compilation/diag13281.d(25): Error: cannot implicitly convert expression `123.4F` of type `float` to `int` fail_compilation/diag13281.d(26): Error: cannot implicitly convert expression `123.4L` of type `real` to `int` fail_compilation/diag13281.d(27): Error: cannot implicitly convert expression `123.4i` of type `idouble` to `int` fail_compilation/diag13281.d(28): Error: cannot implicitly convert expression `123.4Fi` of type `ifloat` to `int` fail_compilation/diag13281.d(29): Error: cannot implicitly convert expression `123.4Li` of type `ireal` to `int` fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `(123.4+5.6i)` of type `cdouble` to `int` fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `(123.4F+5.6Fi)` of type `cfloat` to `int` fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `(123.4L+5.6Li)` of type `creal` to `int` --- */ string x1 = 123; string x2 = 123u; string x3 = 123L; string x4 = 123uL; int y1 = 123.4; int y2 = 123.4f; int y3 = 123.4L; int y4 = 123.4i; int y5 = 123.4fi; int y6 = 123.4Li; int y7 = 123.4 +5.6i; int y8 = 123.4f+5.6fi; int y9 = 123.4L+5.6Li; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13320.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13320.d(13): Error: `f` is not a scalar, it is a `Foo` --- */ struct Foo {} void main() { Foo f; ++f; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13333.d ================================================ /* TEST_OUTPUT* --- fail_compilation/diag13333.d(29): Error: template instance `VariantN!(maxSize!(S), T)` recursive template expansion fail_compilation/diag13333.d(29): Error: template instance `diag13333.maxSize!(S)` error instantiating fail_compilation/diag13333.d(34): instantiated from here: `Algebraic!(S)` --- */ template maxSize(T...) { static if (T.length == 1) { enum size_t maxSize = T[0].sizeof; } else { enum size_t maxSize = T[0].sizeof >= maxSize!(T[1 .. $]) ? T[0].sizeof : maxSize!(T[1 .. $]); } } struct VariantN(size_t maxDataSize, AllowedTypesX...) { } template Algebraic(T...) { alias Algebraic = VariantN!(maxSize!T, T); } struct DummyScope { alias A = Algebraic!S; static struct S // <- class { A entity; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13528.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13528.d(13): Error: value of `this` is not known at compile time fail_compilation/diag13528.d(13): while evaluating `pragma(msg, __traits(getMember, A, "foo"))` --- */ mixin template MyTemplate() { void foo() { pragma(msg, __traits(getMember, typeof(this), "foo")); } } class A { mixin MyTemplate; } void main() { auto a = new A(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13609a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13609a.d(11): Error: `}` expected following members in `class` declaration at fail_compilation/diag13609a.d(8) --- */ class C { void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13609b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13609b.d(10): Error: base classes are not allowed for `struct`, did you mean `;`? fail_compilation/diag13609b.d(11): Error: basic type expected, not `End of File` fail_compilation/diag13609b.d(11): Error: { } expected following `struct` declaration --- */ struct S : ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13787.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/diag13787.d(12): Error: cannot slice function pointer `& main` fail_compilation/diag13787.d(13): Error: cannot index function pointer `& main` --- */ void main() { auto a = (&main)[0..1]; auto x = (&main)[0]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13884.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13884.d(14): Error: functions cannot return a tuple fail_compilation/diag13884.d(21): instantiated from here: `MapResult!((t) => t.tupleof, Foo[])` fail_compilation/diag13884.d(14): instantiated from here: `map!(Foo[])` --- */ struct Foo { int x; } void main() { [Foo(1)].map!(t => t.tupleof); } template map(fun...) { auto map(Range)(Range r) { return MapResult!(fun, Range)(r); } } struct MapResult(alias fun, R) { R _input; @property auto ref front() { return fun(_input[0]); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag13942.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/diag13942.d(17): `diag13942.to!double.to(A...)(A args) if (!isRawStaticArray!A)` --- */ template isRawStaticArray(T, A...) { enum isRawStaticArray = false; } template to(T) { T to(A...)(A args) if (!isRawStaticArray!A) { return 0; } } void main(string[] args) { auto t = to!double(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14102.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag14102.d(14): Error: `-x` is not an lvalue and cannot be modified fail_compilation/diag14102.d(15): Error: `-(x -= 1)` is not an lvalue and cannot be modified fail_compilation/diag14102.d(16): Error: `-(x -= 1 -= 1)` is not an lvalue and cannot be modified fail_compilation/diag14102.d(17): Error: `-(x -= 1 -= 1 -= 1)` is not an lvalue and cannot be modified --- */ int main() { int x; return -- -x; // error: -x is not an lvalue return -- - --x; // error: -(x -= 1) is not an lvalue return -- - -- --x; // error: -((x -= 1 , x) -= 1) is not an lvalue return -- - -- -- --x; // error: -((ref int __assignop1 = x -= 1 , __assignop1 = x; , __assignop1 -= 1 , __assignop1) -= 1) is not an lvalue } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14163.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag14163.d(16): Error: constructor `diag14163.Bar.this` cannot call `super()` implicitly because it is annotated with `@disable` --- */ class Foo { @disable this(); } class Bar : Foo { @disable this(); this(int i) {} } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14235.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag14235.d(11): Error: template identifier `Undefined` is not a member of module `imports.a14235` fail_compilation/diag14235.d(12): Error: template identifier `Something` is not a member of module `imports.a14235`, did you mean struct `SomeThing(T...)`? fail_compilation/diag14235.d(13): Error: `imports.a14235.SomeClass` is not a template, it is a class --- */ import imports.a14235; imports.a14235.Undefined!Object a; imports.a14235.Something!Object b; imports.a14235.SomeClass!Object c; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14818.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag14818.d(34): Error: none of the overloads of `func` are callable using argument types `(string)`, candidates are: fail_compilation/diag14818.d(12): `diag14818.foo(int _param_0)` fail_compilation/diag14818.d(13): `diag14818.bar(double _param_0)` fail_compilation/diag14818.d(35): Error: overload alias `diag14818.X` does not match any template declaration fail_compilation/diag14818.d(36): Error: overloadset `diag14818.M` does not match any template declaration --- */ void foo(int) {} void bar(double) {} alias func = foo; alias func = bar; // in here, func is a FuncAliasDeclaration; template Foo(T) if (is(T == int)) {} template Bar(T) if (is(T == double)) {} alias X = Foo; alias X = Bar; // in here, X is an OverDeclaration template Mix1() { alias M = Foo; } template Mix2() { alias M = Bar; } mixin Mix1; mixin Mix2; alias Y = M; // in here, Y is an OverloadSet void main() { func("abc"); alias x = X!string; alias y = Y!string; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14875.d ================================================ // REQUIRED_ARGS: -o- deprecated class Dep { } deprecated immutable int depVar = 10; /* TEST_OUTPUT: --- fail_compilation/diag14875.d(16): Deprecation: class `diag14875.Dep` is deprecated 1: Dep 2: Dep 3: Dep --- */ alias X = Foo!Dep; // deprecation template Foo(T) { pragma(msg, "1: ", T); // no message enum Foo = cast(void*)Bar!T; } template Bar(T) { pragma(msg, "2: ", T); // no message enum Bar = &Baz!T; } template Baz(T) { pragma(msg, "3: ", T); // no message immutable Baz = 1234; } // --- /* TEST_OUTPUT: --- fail_compilation/diag14875.d(47): Deprecation: class `diag14875.Dep` is deprecated fail_compilation/diag14875.d(51): Deprecation: variable `diag14875.depVar` is deprecated 4: Dep fail_compilation/diag14875.d(58): Deprecation: variable `diag14875.depVar` is deprecated fail_compilation/diag14875.d(59): Deprecation: variable `diag14875.Vaz!(Dep).Vaz` is deprecated --- */ alias Y = Voo!Dep; // deprecation template Voo(T) { enum n = depVar; // deprecation struct A { alias B = T; } // no message pragma(msg, "4: ", A.B); // B is not deprecated enum Voo = cast(void*)Var!T; } template Var(T) { enum n = depVar; // deprecation enum Var = &Vaz!T; // deprecation } deprecated template Vaz(T) { enum n = depVar; // no message immutable Vaz = 1234; } /* TEST_OUTPUT: --- fail_compilation/diag14875.d(75): Error: static assert: `0` is false --- */ void main() { static assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag14876.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag14876.d(17): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(18): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(19): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(20): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(21): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(22): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(23): Deprecation: class `diag14876.Dep` is deprecated fail_compilation/diag14876.d(23): Error: can only slice tuple types, not `diag14876.Dep` --- */ deprecated class Dep { class Mem {} } alias X1 = Foo!(Dep[]); alias X2 = Foo!(Dep[1]); alias X3 = Foo!(Dep[int]); alias X4 = Foo!(int[Dep]); alias X5 = Foo!(Dep*); alias X6 = Foo!(Dep.Mem); alias X7 = Foo!(Dep[3..4]); template Foo(T) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15001.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/diag15001.d(11): Error: undefined identifier `X` --- */ void main() { if (X x = 1) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15186.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag15186.d(14): Error: use `.` for member lookup, not `::` fail_compilation/diag15186.d(15): Error: use `.` for member lookup, not `->` --- */ void main() { struct S { static int x; int y; } S* s; S::x = 1; s->y = 2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15209.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag15209.d(18): Error: need `this` for `x` of type `int` fail_compilation/diag15209.d(21): Error: need `this` for `x` of type `int` --- */ class C1 { int x; } struct S1 { alias y = C1.x; } struct S2 { int x; } class C2 { alias y = S2.x; } void main() { S1 s1; s1.y = 10; // invalid field variable access auto c2 = new C2(); c2.y = 10; // invalid field variable access } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15340.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag15340.d(11): Error: undefined identifier `undef1` fail_compilation/diag15340.d(12): Error: undefined identifier `undef2` --- */ class C { auto a = undef1; auto b = undef2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15411.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/diag15411.d(13): Error: function diag15411.test15411.__funcliteral1 cannot access frame of function diag15411.test15411 fail_compilation/diag15411.d(14): Error: function diag15411.test15411.__funcliteral2 cannot access frame of function diag15411.test15411 --- */ void test15411() { auto i = 0; auto j = (function() { return i; })(); auto f = function() { return i; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag1566.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag1566.d(23): Error: multiple ! arguments are not allowed fail_compilation/diag1566.d(24): Error: multiple ! arguments are not allowed fail_compilation/diag1566.d(25): Error: multiple ! arguments are not allowed fail_compilation/diag1566.d(26): Error: multiple ! arguments are not allowed fail_compilation/diag1566.d(28): Error: multiple ! arguments are not allowed fail_compilation/diag1566.d(29): Error: multiple ! arguments are not allowed --- */ template T(int n) { template T(char c) { alias long T; } } void main() { static assert(is(long == T!(3)!('b'))); static assert(is(long == T! 3 ! 'b' )); static assert(is(long == T!(3)! 'b' )); static assert(is(long == T! 3 !('b'))); static assert(is(long == T!(3)! 'b' !"s")); static assert(is(long == T! 3 !('b')!"s")); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15669.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag15669.d(14): Error: variable `__b_field_0` cannot be read at compile time --- */ alias AliasSeq(A ...) = A; void foo() { AliasSeq!int a; AliasSeq!int b; a[b]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15713.d ================================================ /* --- fail_compilation/diag15713.d(18): Error: no property 'widthSign' for type 'Data' fail_compilation/diag15713.d(38): Error: template instance test.conwritefImpl!("parse-int", "width", "\x0a", Data()) error instantiating fail_compilation/diag15713.d(43): instantiated from here: `conwritefImpl!("main", "\x0a", Data())` fail_compilation/diag15713.d(48): instantiated from here: `fdwritef!()` --- */ void wrWriteWidthChar() {} auto WrData(int , int ) { struct Data { auto initInt(string name)() { __traits(getMember, this, name ~ "Sign"); } } return Data(); } template conwritefImpl(string state, string field, string fmt, alias data, AA...) if (state == "parse-int") { enum conwritefImpl = data.initInt!field; } template baz(string state, string fmt, alias data, AA...) {} template bar(string state, string fmt, alias data, AA...) {} enum a = "parse-format"; template conwritefImpl(string state, string fmt, alias data, AA...) if (state == "main") { enum conwritefImpl = conwritefImpl!("parse-int", "width", fmt, data); } void fdwritef()() { conwritefImpl!("main", "\n", WrData(0, 0)); } void conwriteln() { fdwritef(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag15974.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag15974.d(21): Error: variable `f` cannot be read at compile time fail_compilation/diag15974.d(21): called from here: `format("%s", f)` fail_compilation/diag15974.d(26): Error: variable `f` cannot be read at compile time fail_compilation/diag15974.d(26): called from here: `format("%s", f)` --- */ void test15974() { string format(Args...)(string fmt, Args args) { return ""; } string f = "vkCreateSampler"; // CompileStatement mixin(format("%s", f)); struct S { // CompileDeclaration mixin(format("%s", f)); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag16499.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag16499.d(22): Error: incompatible types for `(2) in (foo)`: `int` and `A` fail_compilation/diag16499.d(24): Error: incompatible types for `(1.00000) in (bar)`: `double` and `B` --- */ struct A {} struct B { void* opBinaryRight(string op)(int b) if (op == "in") { return null; } } void main() { A foo; B bar; 2 in foo; 2 in bar; // OK 1.0 in bar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag16977.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag16977.d(22): Error: undefined identifier `undefined`, did you mean function `undefinedId`? fail_compilation/diag16977.d(23): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` fail_compilation/diag16977.d(24): Error: template `diag16977.templ` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/diag16977.d(17): `diag16977.templ(S)(S s) if (false)` fail_compilation/diag16977.d(25): Error: cannot implicitly convert expression `5` of type `int` to `string` fail_compilation/diag16977.d(27): Error: template instance `diag16977.test.funcTemplate!string` error instantiating --- */ // when copying the expression of a default argument, location information is // replaced by the location of the caller to improve debug information // verify error messages are displayed for the original location only string templ(S)(S s) if(false) { return null; } void test() { // local functions to defer evaluation into semantic3 pass void undefinedId(int x, int y = undefined) {} void badOp(int x, int y = 1 ~ "string") {} void lazyTemplate(int x, lazy int y = 4.templ) {} void funcTemplate(T)(T y = 5) {} funcTemplate!string(); undefinedId(1); badOp(2); lazyTemplate(3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag1730.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag1730.d(51): Error: mutable method `diag1730.S.func` is not callable using a `inout` object fail_compilation/diag1730.d(51): Consider adding `const` or `inout` to diag1730.S.func fail_compilation/diag1730.d(53): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `inout` object fail_compilation/diag1730.d(54): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a non-shared `inout` object fail_compilation/diag1730.d(54): Consider adding `const` or `inout` to diag1730.S.sFunc fail_compilation/diag1730.d(55): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared `inout` object fail_compilation/diag1730.d(70): Error: `immutable` method `diag1730.S.iFunc` is not callable using a mutable object fail_compilation/diag1730.d(71): Error: `shared` method `diag1730.S.sFunc` is not callable using a non-shared object fail_compilation/diag1730.d(72): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared mutable object fail_compilation/diag1730.d(75): Error: mutable method `diag1730.S.func` is not callable using a `const` object fail_compilation/diag1730.d(75): Consider adding `const` or `inout` to diag1730.S.func fail_compilation/diag1730.d(77): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `const` object fail_compilation/diag1730.d(78): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a non-shared `const` object fail_compilation/diag1730.d(78): Consider adding `const` or `inout` to diag1730.S.sFunc fail_compilation/diag1730.d(79): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared `const` object fail_compilation/diag1730.d(82): Error: mutable method `diag1730.S.func` is not callable using a `immutable` object fail_compilation/diag1730.d(82): Consider adding `const` or `inout` to diag1730.S.func fail_compilation/diag1730.d(85): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a `immutable` object fail_compilation/diag1730.d(85): Consider adding `const` or `inout` to diag1730.S.sFunc fail_compilation/diag1730.d(89): Error: non-shared method `diag1730.S.func` is not callable using a `shared` object fail_compilation/diag1730.d(89): Consider adding `shared` to diag1730.S.func fail_compilation/diag1730.d(90): Error: non-shared `const` method `diag1730.S.cFunc` is not callable using a `shared` mutable object fail_compilation/diag1730.d(90): Consider adding `shared` to diag1730.S.cFunc fail_compilation/diag1730.d(91): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `shared` mutable object fail_compilation/diag1730.d(94): Error: non-shared `inout` method `diag1730.S.wFunc` is not callable using a `shared` mutable object fail_compilation/diag1730.d(94): Consider adding `shared` to diag1730.S.wFunc fail_compilation/diag1730.d(96): Error: non-shared mutable method `diag1730.S.func` is not callable using a `shared` `const` object fail_compilation/diag1730.d(96): Consider adding `shared` to diag1730.S.func fail_compilation/diag1730.d(97): Error: non-shared `const` method `diag1730.S.cFunc` is not callable using a `shared` `const` object fail_compilation/diag1730.d(97): Consider adding `shared` to diag1730.S.cFunc fail_compilation/diag1730.d(98): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `shared` `const` object fail_compilation/diag1730.d(99): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a `shared` `const` object fail_compilation/diag1730.d(99): Consider adding `const` or `inout` to diag1730.S.sFunc fail_compilation/diag1730.d(101): Error: non-shared `inout` method `diag1730.S.wFunc` is not callable using a `shared` `const` object fail_compilation/diag1730.d(101): Consider adding `shared` to diag1730.S.wFunc --- */ struct S { void func() { } void cFunc() const { } void iFunc() immutable { } void sFunc() shared { } void scFunc() shared const { } void wFunc() inout { } static void test(inout(S) s) { s.func(); // ng s.cFunc(); s.iFunc(); // ng s.sFunc(); // ng s.scFunc(); // ng s.wFunc(); } } void main() { S obj; const(S) cObj; immutable(S) iObj; shared(S) sObj; shared(const(S)) scObj; obj.func(); obj.cFunc(); obj.iFunc(); // ng obj.sFunc(); // ng obj.scFunc(); // ng obj.wFunc(); cObj.func(); // ng cObj.cFunc(); cObj.iFunc(); // ng cObj.sFunc(); // ng cObj.scFunc(); // ng cObj.wFunc(); iObj.func(); // ng iObj.cFunc(); iObj.iFunc(); iObj.sFunc(); // ng iObj.scFunc(); iObj.wFunc(); sObj.func(); // ng sObj.cFunc(); // ng sObj.iFunc(); // ng sObj.sFunc(); sObj.scFunc(); sObj.wFunc(); // ng scObj.func(); // ng scObj.cFunc(); // ng scObj.iFunc(); // ng scObj.sFunc(); // ng scObj.scFunc(); scObj.wFunc(); // ng } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag18460.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag18460.d(12): Error: no property `opCall` for type `diag18460.Foo`, did you mean `new Foo`? --- */ // https://issues.dlang.org/show_bug.cgi?id=18460 class Foo {} void main() { auto f = Foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag18574.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag18574.d(16): Error: `diag18574.Test`: multiple class inheritance is not supported. Use multiple interface inheritance and/or composition. fail_compilation/diag18574.d(16): `diag18574.Bar` has no fields, consider making it an `interface` fail_compilation/diag18574.d(16): `diag18574.Baz` has fields, consider making it a member of `diag18574.Test` fail_compilation/diag18574.d(16): Error: `diag18574.Test`: base type must be `interface`, not `int` --- */ // https://issues.dlang.org/show_bug.cgi?id=18574 class Foo {} class Bar {} class Baz { int a; } class Test : Foo, Bar, Baz, int {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag19022.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag19022.d(16): Error: immutable field `b` initialized multiple times fail_compilation/diag19022.d(15): Previous initialization is here. --- */ // https://issues.dlang.org/show_bug.cgi?id=19022 struct Foo { immutable int b; this(int a) { b = 2; b = 2; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag19196.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag19196.d(11): Error: unable to determine fields of `B` because of forward references fail_compilation/diag19196.d(15): Error: template instance `diag19196.Foo!(B)` error instantiating --- */ module diag19196; struct Foo(T) { alias F = typeof(T.tupleof); } struct B { Foo!B b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag19225.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag19225.d(14): Error: basic type expected, not `else` fail_compilation/diag19225.d(14): There's no `static else`, use `else` instead. fail_compilation/diag19225.d(14): Error: found `else` without a corresponding `if`, `version` or `debug` statement fail_compilation/diag19225.d(15): Error: unrecognized declaration --- */ void main() { static if (true) {} static else {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag2452.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag2452.d(14): Error: class `diag2452.C` interface function `void f(float p)` is not implemented --- */ interface I { void f(int p); void f(float p); } class C : I { void f(int p) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3013.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag3013.d(11): Error: cannot pass type `string` as a function argument --- */ int format(string, string, string); void main() { int s = string.format("abc", "def"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3438.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/diag3438.d(16): Deprecation: constructor `diag3438.F1.this` all parameters have default arguments, but structs cannot have default constructors. fail_compilation/diag3438.d(17): Deprecation: constructor `diag3438.F2.this` all parameters have default arguments, but structs cannot have default constructors. fail_compilation/diag3438.d(20): Deprecation: constructor `diag3438.F5.this` is marked `@disable`, so it cannot have default arguments for all parameters. fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization. fail_compilation/diag3438.d(21): Deprecation: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters. fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization. --- */ import core.vararg; struct F1 { this(int x = 1) { } } struct F2 { this(int x = 1, ...) { } } struct F3 { this(...) { } } // ok struct F4 { this(int[] x...) { } } // ok struct F5 { @disable this(int x = 1); } struct F6 { @disable this(int x = 1) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3438b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag3438b.d(9): Error: default argument expected for `y` --- */ // Make sure the deprecation doesn't interfere w/ the check for default arguments struct S { this(int x = 1, int y) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3672.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/diag3672.d(36): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(x, 1)` instead. fail_compilation/diag3672.d(37): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(x, 1)` instead. fail_compilation/diag3672.d(38): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(x, 1)` instead. fail_compilation/diag3672.d(39): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(x, 1)` instead. fail_compilation/diag3672.d(40): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(x, 1)` instead. fail_compilation/diag3672.d(41): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(x, 2)` instead. fail_compilation/diag3672.d(42): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(x, 3)` instead. fail_compilation/diag3672.d(43): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"|="(x, y)` instead. fail_compilation/diag3672.d(44): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"*="(x, y)` instead. fail_compilation/diag3672.d(45): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"/="(x, y)` instead. fail_compilation/diag3672.d(46): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"%="(x, y)` instead. fail_compilation/diag3672.d(47): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"&="(x, y)` instead. fail_compilation/diag3672.d(48): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"^="(x, y)` instead. fail_compilation/diag3672.d(49): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"<<="(x, y)` instead. fail_compilation/diag3672.d(50): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!">>="(x, y)` instead. fail_compilation/diag3672.d(51): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!">>>="(x, y)` instead. fail_compilation/diag3672.d(52): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"^^="(x, y)` instead. fail_compilation/diag3672.d(53): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(ptr, 1)` instead. fail_compilation/diag3672.d(54): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(ptr, 1)` instead. fail_compilation/diag3672.d(55): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(ptr, 1)` instead. fail_compilation/diag3672.d(56): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(ptr, 1)` instead. --- */ shared int x; shared int y; shared int* ptr; shared static this() { ptr = new int; } // silence null-dereference errors void main() { ++x; x++; --x; x--; x += 1; x += 2; x -= 3; x |= y; x *= y; x /= y; x %= y; x &= y; x ^= y; x <<= y; x >>= y; x >>>= y; x ^^= y; ++ptr; ptr++; --ptr; ptr--; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3672a.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/diag3672a.d(16): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(ns.x, 1)` instead. fail_compilation/diag3672a.d(18): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(s.sx, 1)` instead. --- */ class NS { shared int x; } shared class S { int sx; } void main() { NS ns = new NS; ns.x++; S s = new S; s.sx++; } /* TEST_OUTPUT: --- fail_compilation/diag3672a.d(32): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(s.var, 1)` instead. fail_compilation/diag3672a.d(33): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"-="(s.var, 2)` instead. --- */ void test13003() { struct S { int var; } shared S s; s.var++; s.var -= 2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3673.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag3673.d(9): Error: template constraints appear both before and after BaseClassList, put them before --- */ class A {} class B(T) if(false) : A if (true) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3869.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag3869.d(10): Error: template instance `diag3869.sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!int))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))` recursive expansion --- */ struct sum(A) { auto blah(int a) { return .sum!(sum)(); } } sum!(int) z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag3913.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag3913.d(12): Error: no property `foobardoo` for type `Foo` fail_compilation/diag3913.d(13): Error: no property `secon` for type `Foo`. Did you mean `Foo.second` ? --- */ void main() { enum Foo { first, second } auto a = Foo.foobardoo; auto b = Foo.secon; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag4479.d ================================================ // EXTRA_SOURCES: imports/fail4479.d /* TEST_OUTPUT: --- fail_compilation/diag4479.d(10): Error: module `imports.fail4479mod` from file fail_compilation/imports/fail4479.d must be imported with 'import imports.fail4479mod;' --- */ module diag4479; import imports.fail4479; void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag4528.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag4528.d(14): Error: function `diag4528.Foo.pva` `private` functions cannot be `abstract` fail_compilation/diag4528.d(15): Error: function `diag4528.Foo.pka` `package` functions cannot be `abstract` fail_compilation/diag4528.d(16): Error: function `diag4528.Foo.pvsa` `static` functions cannot be `abstract` fail_compilation/diag4528.d(17): Error: function `diag4528.Foo.pksa` `static` functions cannot be `abstract` fail_compilation/diag4528.d(18): Error: function `diag4528.Foo.pbsa` `static` functions cannot be `abstract` --- */ class Foo { private abstract void pva(); package abstract void pka(); private static abstract void pvsa(); package static abstract void pksa(); public static abstract void pbsa(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag4540.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag4540.d(11): Error: `x` must be of integral or string type, it is a `float` --- */ void main() { float x; switch (x) { default: } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag4596.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified fail_compilation/diag4596.d(16): Error: `1 ? this : this` is not an lvalue and cannot be modified fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified fail_compilation/diag4596.d(19): Error: `1 ? super : super` is not an lvalue and cannot be modified --- */ class NoGo4596 { void fun() { this = new NoGo4596; (1?this:this) = new NoGo4596; super = new Object; (1?super:super) = new Object; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag5385.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag5385.d(27): Deprecation: `imports.fail5385.C.privX` is not visible from module `diag5385` fail_compilation/diag5385.d(27): Error: class `imports.fail5385.C` member `privX` is not accessible fail_compilation/diag5385.d(28): Deprecation: `imports.fail5385.C.packX` is not visible from module `diag5385` fail_compilation/diag5385.d(28): Error: class `imports.fail5385.C` member `packX` is not accessible fail_compilation/diag5385.d(29): Deprecation: `imports.fail5385.C.privX2` is not visible from module `diag5385` fail_compilation/diag5385.d(29): Error: class `imports.fail5385.C` member `privX2` is not accessible fail_compilation/diag5385.d(30): Deprecation: `imports.fail5385.C.packX2` is not visible from module `diag5385` fail_compilation/diag5385.d(30): Error: class `imports.fail5385.C` member `packX2` is not accessible fail_compilation/diag5385.d(31): Deprecation: `imports.fail5385.S.privX` is not visible from module `diag5385` fail_compilation/diag5385.d(31): Error: struct `imports.fail5385.S` member `privX` is not accessible fail_compilation/diag5385.d(32): Deprecation: `imports.fail5385.S.packX` is not visible from module `diag5385` fail_compilation/diag5385.d(32): Error: struct `imports.fail5385.S` member `packX` is not accessible fail_compilation/diag5385.d(33): Deprecation: `imports.fail5385.S.privX2` is not visible from module `diag5385` fail_compilation/diag5385.d(33): Error: struct `imports.fail5385.S` member `privX2` is not accessible fail_compilation/diag5385.d(34): Deprecation: `imports.fail5385.S.packX2` is not visible from module `diag5385` fail_compilation/diag5385.d(34): Error: struct `imports.fail5385.S` member `packX2` is not accessible --- */ import imports.fail5385; void main() { C.privX = 1; C.packX = 1; C.privX2 = 1; C.packX2 = 1; S.privX = 1; S.packX = 1; S.privX2 = 1; S.packX2 = 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag5450.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag5450.d(18): Error: class `diag5450.C` cannot implicitly generate a default constructor when base class `diag5450.B` is missing a default constructor --- */ class A { this() { } } class B : A { this(int f) {} } class C : B { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6373.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/diag6373.d(15): Error: class `diag6373.Bar` use of `diag6373.Foo.method(double x)` is hidden by `Bar`; use `alias method = Foo.method;` to introduce base class overload set --- */ class Foo { void method(int x) { } void method(double x) { } } class Bar : Foo { override void method(int x) { } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6539.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag6539.d(21): Error: overloadset `diag6539.Rectangle` is used as a type --- */ mixin template foo() { struct Rectangle(T) {} } mixin template bar() { bool Rectangle(bool, int, int, int, int) {} } mixin foo; mixin bar; void test(Rectangle rect) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6677.d ================================================ // REQUIRED_ARGS: /* TEST_OUTPUT: --- fail_compilation/diag6677.d(18): Error: static constructor cannot be `const` fail_compilation/diag6677.d(19): Error: static constructor cannot be `inout` fail_compilation/diag6677.d(20): Error: static constructor cannot be `immutable` fail_compilation/diag6677.d(21): Error: use `shared static this()` to declare a shared static constructor fail_compilation/diag6677.d(22): Error: use `shared static this()` to declare a shared static constructor fail_compilation/diag6677.d(24): Error: shared static constructor cannot be `const` fail_compilation/diag6677.d(25): Error: shared static constructor cannot be `inout` fail_compilation/diag6677.d(26): Error: shared static constructor cannot be `immutable` fail_compilation/diag6677.d(27): Error: redundant attribute `shared` fail_compilation/diag6677.d(28): Error: redundant attribute `shared` --- */ static this() const { } static this() inout { } static this() immutable { } static this() shared { } static this() const shared { } shared static this() const { } shared static this() inout { } shared static this() immutable { } shared static this() shared { } shared static this() const shared { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6699.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag6699.d(8): Error: no property `x` for type `int` --- */ alias int b6699; alias b6699.x b6699a; /* TEST_OUTPUT: --- fail_compilation/diag6699.d(18): Error: undefined identifier `junk1` fail_compilation/diag6699.d(18): Error: undefined identifier `junk2` fail_compilation/diag6699.d(19): Error: undefined identifier `junk3` --- */ class X : junk1, junk2 {} interface X2 : junk3 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6707.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag6707.d(17): Error: mutable method `diag6707.Foo.value` is not callable using a `const` object fail_compilation/diag6707.d(17): Consider adding `const` or `inout` to diag6707.Foo.value --- */ module diag6707; struct Foo { @property bool value() { return true; } void test() const { auto x = value; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6717.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag6717.d(12): Error: end of instruction expected, not `h` --- */ void main() { version(GNU) { asm { ""h; } } else { asm { mov AX, 12h ; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag6796.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag6796.d(11): Error: cannot implicitly convert expression `0` of type `int` to `int[]` fail_compilation/diag6796.d(11): Error: cannot implicitly convert expression `1` of type `int` to `int[]` --- */ void main() { enum int[][] array = [0, 1]; array[0] *= 10; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7050a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7050a.d(15): Error: `@safe` function `diag7050a.foo` cannot call `@system` constructor `diag7050a.Foo.this` fail_compilation/diag7050a.d(11): `diag7050a.Foo.this` is declared here --- */ struct Foo { this (int a) {} } @safe void foo() { auto f = Foo(3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7050b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7050b.d(12): Error: `pure` function `diag7050b.f.g` cannot call impure function `diag7050b.f` --- */ void f() { pure void g() { f(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7050c.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7050c.d(14): Error: `@safe` destructor `diag7050c.B.~this` cannot call `@system` destructor `diag7050c.A.~this` fail_compilation/diag7050c.d(11): `diag7050c.A.~this` is declared here --- */ struct A { ~this(){} } @safe struct B { A a; } @safe void f() { auto x = B.init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7420.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/diag7420.d(21): Error: static variable `x` cannot be read at compile time fail_compilation/diag7420.d(21): while evaluating: `static assert(x < 4)` fail_compilation/diag7420.d(22): Error: static variable `y` cannot be read at compile time fail_compilation/diag7420.d(22): called from here: `__equals(y, "abc")` fail_compilation/diag7420.d(22): while evaluating: `static assert(y == "abc")` fail_compilation/diag7420.d(23): Error: static variable `y` cannot be read at compile time fail_compilation/diag7420.d(23): while evaluating: `static assert(cast(ubyte[])y != null)` fail_compilation/diag7420.d(24): Error: static variable `y` cannot be read at compile time fail_compilation/diag7420.d(24): while evaluating: `static assert(cast(int)y[0] == 1)` fail_compilation/diag7420.d(25): Error: static variable `y` cannot be read at compile time fail_compilation/diag7420.d(25): while evaluating: `static assert(y[0..1].length == 1u)` --- */ int x = 2; char[] y = "abc".dup; static assert(x < 4); static assert(y == "abc"); static assert(cast(ubyte[])y != null); static assert(y[0] == 1); static assert(y[0..1].length == 1); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7477.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7477.d(13): Error: integral constant must be scalar type, not `Foo` fail_compilation/diag7477.d(20): Error: integral constant must be scalar type, not `string` --- */ struct Foo { int x; } enum Bar : Foo { a, b, c } enum Baz : string { a, b, } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7747.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call `fact(n - 1)` --- */ auto fact(int n) { return n > 1 ? fact(n - 1) : 0; } void main() { fact(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag7998.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag7998.d(10): Error: static assert: "abcxe" --- */ module diag7998; static assert(false, "abc" ~['x'] ~ "e"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8101.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8101.d(56): Error: function `diag8101.f_0(int)` is not callable using argument types `()` fail_compilation/diag8101.d(57): Error: none of the overloads of `f_1` are callable using argument types `()`, candidates are: fail_compilation/diag8101.d(32): `diag8101.f_1(int)` fail_compilation/diag8101.d(33): `diag8101.f_1(int, int)` fail_compilation/diag8101.d(58): Error: none of the overloads of `f_2` are callable using argument types `()`, candidates are: fail_compilation/diag8101.d(35): `diag8101.f_2(int)` fail_compilation/diag8101.d(36): `diag8101.f_2(int, int)` fail_compilation/diag8101.d(37): `diag8101.f_2(int, int, int)` fail_compilation/diag8101.d(38): `diag8101.f_2(int, int, int, int)` fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int, int)` fail_compilation/diag8101.d(58): ... (1 more, -v to show) ... fail_compilation/diag8101.d(60): Error: template `diag8101.t_0` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/diag8101.d(42): `diag8101.t_0(T1)()` fail_compilation/diag8101.d(61): Error: template `diag8101.t_1` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/diag8101.d(44): `diag8101.t_1(T1)()` fail_compilation/diag8101.d(45): `diag8101.t_1(T1, T2)()` fail_compilation/diag8101.d(62): Error: template `diag8101.t_2` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/diag8101.d(47): `diag8101.t_2(T1)()` fail_compilation/diag8101.d(48): `diag8101.t_2(T1, T2)()` fail_compilation/diag8101.d(49): `diag8101.t_2(T1, T2, T3)()` fail_compilation/diag8101.d(50): `diag8101.t_2(T1, T2, T3, T4)()` fail_compilation/diag8101.d(51): `diag8101.t_2(T1, T2, T3, T4, T5)()` fail_compilation/diag8101.d(62): ... (1 more, -v to show) ... --- */ void f_0(int); void f_1(int); void f_1(int, int); void f_2(int); void f_2(int, int); void f_2(int, int, int); void f_2(int, int, int, int); void f_2(int, int, int, int, int); void f_2(int, int, int, int, int, int); void t_0(T1)(); void t_1(T1)(); void t_1(T1, T2)(); void t_2(T1)(); void t_2(T1, T2)(); void t_2(T1, T2, T3)(); void t_2(T1, T2, T3, T4)(); void t_2(T1, T2, T3, T4, T5)(); void t_2(T1, T2, T3, T4, T5, T6)(); void main() { f_0(); f_1(); f_2(); t_0(); t_1(); t_2(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8101b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8101b.d(28): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are: fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0)` fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)` fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)` fail_compilation/diag8101b.d(30): cannot pass argument `1.00000` of type `double` to parameter `int _param_0` fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object, candidates are: fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0)` fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)` fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object fail_compilation/diag8101b.d(35): Consider adding `const` or `inout` to diag8101b.S.bar --- */ struct S { void foo(int) { } void foo(int, int) { } void bar(int) { } } void main() { S s; s.foo(1.0); s.bar(1.0); const(S) cs; cs.foo(1); cs.bar(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8178.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8178.d(14): Error: cannot modify manifest constant `s` --- */ struct Foo { enum string s = ""; } void main() { Foo.s = ""; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8318.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8318.d(13): Error: function `diag8318.Bar8318.foo` return type inference is not supported if may override base class function --- */ class Foo8318 { auto foo() { return "Foo.foo"; } } class Bar8318 : Foo8318 { override auto foo() { return "Bar.foo"; } } /* TEST_OUTPUT: --- fail_compilation/diag8318.d(24): Error: function `diag8318.C10021.makeI` return type inference is not supported if may override base class function --- */ interface I10021 { I10021 makeI(); } class D10021 : I10021 { D10021 makeI() { return this; } } class C10021 : I10021 { auto makeI() { return this; } } /* TEST_OUTPUT: --- fail_compilation/diag8318.d(38): Error: function `diag8318.Bar10195.baz` return type inference is not supported if may override base class function --- */ interface Foo10195 { int baz(); } class Bar10195 : Foo10195 { override auto baz() { return 1; } } /* TEST_OUTPUT: --- fail_compilation/diag8318.d(50): Error: function `diag8318.B14173.foo` does not override any function --- */ class A14173 {} class B14173 : A14173 { override foo() {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8425.d ================================================ /* REQUIRED_ARGS: -m64 -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/diag8425.d(13): Error: T in __vector(T) must be a static array, not `void` fail_compilation/diag8425.d(14): Error: 1 byte vector type `__vector(void[1])` is not supported on this platform fail_compilation/diag8425.d(15): Error: 99 byte vector type `__vector(void[99])` is not supported on this platform fail_compilation/diag8425.d(16): Error: vector type `__vector(void*[4])` is not supported on this platform --- */ alias a = __vector(void); // not static array alias b = __vector(void[1]); // wrong size alias c = __vector(void[99]); // wrong size alias d = __vector(void*[4]); // wrong base type ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8510.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8510.d(10): Error: alias `diag8510.a` conflicts with alias `diag8510.a` at fail_compilation/diag8510.d(9) fail_compilation/diag8510.d(15): Error: alias `diag8510.S.a` conflicts with alias `diag8510.S.a` at fail_compilation/diag8510.d(14) --- */ alias int a; alias int a; int g; struct S { alias g a; alias g a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8559.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8559.d(12): Error: `void` does not have a default initializer fail_compilation/diag8559.d(13): Error: `function` does not have a default initializer --- */ void foo(){} void main() { auto x = void.init; auto y = typeof(foo).init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8648.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` fail_compilation/diag8648.d(29): Error: template `diag8648.foo` cannot deduce function from argument types `!()(Foo!(int, 1))`, candidates are: fail_compilation/diag8648.d(18): `diag8648.foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` fail_compilation/diag8648.d(31): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, 1))`, candidates are: fail_compilation/diag8648.d(20): `diag8648.bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` fail_compilation/diag8648.d(32): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, f))`, candidates are: fail_compilation/diag8648.d(20): `diag8648.bar(T)(Foo!(T, a))` --- */ struct Foo(T, alias a) {} void foo(T, n)(X!(T, n) ) {} // undefined identifier 'X' void bar(T)(Foo!(T, a) ) {} // undefined identifier 'a' void main() { template f() {} Foo!(int, 1) x; Foo!(int, f) y; foo(x); bar(x); // expression '1' vs undefined Type 'a' bar(y); // symbol 'f' vs undefined Type 'a' } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8697.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8697.d(10): Error: no property `Invalid` for type `diag8697.Base` --- */ interface InterBase : InterRoot { } class Base : InterBase { } void test(Base.Invalid) { } interface InterRoot { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8714.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8714.d(9): Error: function `diag8714.foo` circular dependency. Functions cannot be interpreted while being compiled fail_compilation/diag8714.d(15): called from here: `foo("somestring")` --- */ string foo(string f) { if (f == "somestring") { return "got somestring"; } return bar!(foo("somestring")); } template bar(string s) { enum bar = s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8777.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8777.d(12): Error: constructor `diag8777.Foo1.this` missing initializer for immutable field `x` fail_compilation/diag8777.d(12): Error: constructor `diag8777.Foo1.this` missing initializer for const field `y` --- */ class Foo1 { immutable int[5] x; const int[5] y; this() {} } /* TEST_OUTPUT: --- fail_compilation/diag8777.d(25): Error: cannot modify `immutable` expression `x` fail_compilation/diag8777.d(28): Error: cannot modify `const` expression `y` --- */ void test2() { immutable int x; x = 1; const int y; y = 1; } /* TEST_OUTPUT: --- fail_compilation/diag8777.d(42): Error: cannot remove key from `immutable` associative array `hashx` fail_compilation/diag8777.d(43): Error: cannot remove key from `const` associative array `hashy` --- */ immutable(int[int]) hashx; const(int[int]) hashy; void test3() { hashx.remove(1); hashy.remove(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8787.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8787.d(10): Error: function `diag8787.I.f` function body only allowed in `final` functions in interface `I` --- */ interface I { void f() { } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8825.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8825.d(13): Error: undefined identifier `foo` --- */ template t(alias a){ alias int t; } void main(){ t!(foo // line 13 ) i; // line 19 return; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8892.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8892.d(14): Error: cannot implicitly convert expression `['A']` of type `char[]` to `char[2]` --- */ struct Foo { char[2] data; } void main() { auto f = Foo(['A']); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8894.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8894.d(16): Error: no property `x` for type `Foo` fail_compilation/diag8894.d(17): Error: no property `y` for type `Foo` fail_compilation/diag8894.d(18): Error: no property `x` for type `Foo` fail_compilation/diag8894.d(19): Error: no property `x` for type `Foo` --- */ struct Foo { } void main() { Foo f; f.x; // UFCS getter1 f.y!int; // UFCS getter2 f.x = 10; // UFCS setter1 f.x!int = 10; // UFCS setter2 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag8928.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag8928.d(18): Error: class `diag8928.Z` cannot implicitly generate a default constructor when base class `diag8928.X` is missing a default constructor --- */ class X { this(int n) {} } class Y : X { this() {} } class Z : X { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9004.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9004.d(21): Error: template `diag9004.bar` cannot deduce function from argument types `!()(Foo!int, int)`, candidates are: fail_compilation/diag9004.d(14): `diag9004.bar(FooT)(FooT foo, FooT.T x)` --- */ struct Foo(_T) { alias _T T; } void bar(FooT)(FooT foo, FooT.T x) { } void main() { Foo!int foo; bar(foo, 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9148.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9148.d(19): Error: `pure` function `diag9148.test9148a.foo` cannot access mutable static data `g` fail_compilation/diag9148.d(23): Error: `pure` function `diag9148.test9148a.bar` cannot access mutable static data `g` fail_compilation/diag9148.d(24): Error: `immutable` function `diag9148.test9148a.bar` cannot access mutable data `x` fail_compilation/diag9148.d(31): Error: `pure` function `diag9148.test9148a.S.foo` cannot access mutable static data `g` fail_compilation/diag9148.d(35): Error: `pure` function `diag9148.test9148a.S.bar` cannot access mutable static data `g` fail_compilation/diag9148.d(36): Error: `immutable` function `diag9148.test9148a.S.bar` cannot access mutable data `x` --- */ void test9148a() pure { static int g; int x; void foo() /+pure+/ { g++; } void bar() immutable /+pure+/ { g++; x++; } struct S { void foo() /+pure+/ { g++; } void bar() immutable /+pure+/ { g++; x++; } } } /* TEST_OUTPUT: --- fail_compilation/diag9148.d(53): Error: static function diag9148.test9148b.foo cannot access frame of function diag9148.test9148b --- */ void test9148b() { int x; static void foo() pure { int y = x; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9191.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9191.d(16): Error: function `void diag9191.C1.aaa()` does not override any function, did you mean to override `void diag9191.B1.aa()`? fail_compilation/diag9191.d(21): Error: function `diag9191.C2.aaa` does not override any function fail_compilation/diag9191.d(31): Error: function `void diag9191.C3.foo()` does not override any function, did you mean to override `void diag9191.B2._foo()`? fail_compilation/diag9191.d(36): Error: function `void diag9191.C4.toStringa()` does not override any function, did you mean to override `string object.Object.toString()`? --- */ interface I1 { void a(); } class B1 { void aa(); } class C1 : B1, I1 { override void aaa(); } class C2 : I1 { override void aaa(); } class B2 { void _foo(){} } class C3 : B2 { override void foo(){} } class C4 { override void toStringa(){} } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9210a.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/imports/diag9210b.d(6): Error: undefined identifier `A` --- */ import imports.diag9210b; interface A {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9247.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9247.d(11): Error: functions cannot return opaque type `S` by value fail_compilation/diag9247.d(12): Error: functions cannot return opaque type `S` by value --- */ struct S; S foo(); S function() bar; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9250.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/diag9250.d(19): Error: cannot implicitly convert expression `10u` of type `uint` to `Foo` fail_compilation/diag9250.d(22): Error: cannot implicitly convert expression `10u` of type `uint` to `void*` --- */ struct Foo { ubyte u; } void main() { uint[10] bar; Foo x = bar.length; // error here void* y = bar.length ? bar.length : // error here bar.length; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9312.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9312.d(10): Error: `with` expressions must be aggregate types or pointers to them, not `int` --- */ void main() { with (1) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9357.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9357.d(14): Error: cannot implicitly convert expression `1.00000` of type `double` to `int` fail_compilation/diag9357.d(15): Error: cannot implicitly convert expression `10.0000` of type `double` to `int` fail_compilation/diag9357.d(16): Error: cannot implicitly convert expression `11.0000` of type `double` to `int` fail_compilation/diag9357.d(17): Error: cannot implicitly convert expression `99.0000` of type `double` to `int` fail_compilation/diag9357.d(18): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int` fail_compilation/diag9357.d(19): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int` --- */ void main() { { int x = 1.0; } { int x = 10.0; } { int x = 11.0; } { int x = 99.0; } { int x = 1048575.0L; } { int x = 1048576.0L; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9358.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9358.d(12): Error: `x` must be of integral or string type, it is a `double` fail_compilation/diag9358.d(14): Error: `case` must be a `string` or an integral constant, not `1.1` fail_compilation/diag9358.d(15): Error: `case` must be a `string` or an integral constant, not `2.1` --- */ void main() { double x; switch (x) { case 1.1: break; case 2.1: break; default: } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9398.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9398.d(11): Error: incompatible types for `(f) : (s)`: `float` and `string` --- */ void main() { float f; string s; auto a = (true ? f : s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9420.d ================================================ /* TEST_OUTPUT --- fail_compilation/diag9420.d(20): Error: function `diag9420.S.t3!().tx()` is not callable using argument types `(int)` --- */ mixin template Mixin() { } struct S { template t3(T...) { void tx(T){} alias t3 = tx; } } void main() { S s1; s1.t3!()(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9451.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9451.d(26): Error: cannot create instance of abstract class `C2` fail_compilation/diag9451.d(26): function `void f1()` is not implemented fail_compilation/diag9451.d(26): function `void f2(int)` is not implemented fail_compilation/diag9451.d(26): function `void f2(float) const` is not implemented fail_compilation/diag9451.d(26): function `int f2(float) pure` is not implemented --- */ class C1 { abstract void f1(); abstract void f2(int); abstract void f2(float) const; abstract int f2(float) pure; } class C2 : C1 { } void main() { auto c2 = new C2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9479.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9479.d(10): Error: undefined identifier `something_undefined` --- */ int delegate() bug9479() { return { return something_undefined; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9574.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9574.d(12): Error: cannot use syntax `alias this = x`, use `alias x this` instead fail_compilation/diag9574.d(18): Error: cannot use syntax `alias this = x`, use `alias x this` instead --- */ struct S { int x; alias this = x; } class C { int x; alias this = x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9620.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9620.d(18): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1` fail_compilation/diag9620.d(19): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2` --- */ int x; void foo1() { x = 3; } void foo2()() { x = 3; } void main() pure { void bar() { foo1(); foo2(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9635.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/diag9635.d(17): Error: need `this` for `i` of type `int` fail_compilation/diag9635.d(18): Error: need `this` for `foo` of type `pure nothrow @nogc @safe void()` --- */ struct Foo { int i; void foo()() { } static void bar() { i = 4; foo(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9679.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` only parameters or `foreach` declarations can be `ref` fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` storage class `auto` has no effect if type is not inferred, did you mean `scope`? --- */ void main() { if (ref n = 1) {} if (auto int n = 1) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9765.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9765.d(9): Error: cannot implicitly convert expression `'x'` of type `char` to `char[]` --- */ struct S9765 { char[] x; } const S9765 s9765 = S9765('x'); const char s9765b = s9765.x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9831.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9831.d(12): Error: function diag9831.main.__lambda1 cannot access frame of function D main --- */ void main() { immutable int c; int function(int x) func; func = x => c; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9861.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9861.d(8): Error: no property `epsilon` for type `int` fail_compilation/diag9861.d(9): while looking for match for `Foo!int` --- */ struct Foo(T, real x = T.epsilon) {} Foo!(int) q; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9880.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9880.d(9): Error: template instance `diag9880.foo!string` does not match template declaration `foo(T)(int) if (is(T == int))` --- */ void foo(T)(int) if (is(T == int)) {} void main() { alias f = foo!string; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag9961.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int` fail_compilation/diag9961.d(14): Error: template instance `diag9961.foo!int` error instantiating fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int` fail_compilation/diag9961.d(15): Error: template instance `diag9961.foo!char` error instantiating --- */ void foo(T)(T) { int x = ""; } void main() { 100.foo(); 'a'.foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d ================================================ // REQUIRED_ARGS: /* TEST_OUTPUT: --- fail_compilation/diag_cstyle.d(14): Error: instead of C-style syntax, use D-style `int function(int) fp1` fail_compilation/diag_cstyle.d(15): Error: instead of C-style syntax, use D-style `int function(int)* fp3` fail_compilation/diag_cstyle.d(17): Error: instead of C-style syntax, use D-style `int function(int) FP` fail_compilation/diag_cstyle.d(19): Error: instead of C-style syntax, use D-style `int function() fp` fail_compilation/diag_cstyle.d(19): Error: instead of C-style syntax, use D-style `int[] arr` fail_compilation/diag_cstyle.d(21): Error: instead of C-style syntax, use D-style `string[] result` --- */ int (*fp1)(int); int (*(*fp3))(int); alias int(*FP)(int); void foo(int(*fp)(), int arr[]) {} string result[]() = "abc"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/diag_err1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/diag_err1.d(21): Error: undefined identifier `x` fail_compilation/diag_err1.d(21): while evaluating `pragma(msg, [1, 2, x].length)` fail_compilation/diag_err1.d(22): Error: undefined identifier `x` fail_compilation/diag_err1.d(22): Error: undefined identifier `y` fail_compilation/diag_err1.d(22): while evaluating `pragma(msg, (x + y).sizeof)` fail_compilation/diag_err1.d(23): Error: undefined identifier `x` fail_compilation/diag_err1.d(23): while evaluating `pragma(msg, (n += x).sizeof)` fail_compilation/diag_err1.d(24): Error: incompatible types for `(s) ~ (n)`: `string` and `int` fail_compilation/diag_err1.d(24): while evaluating `pragma(msg, (s ~ n).sizeof)` --- */ void main() { int n; string s; pragma(msg, [1,2,x].length); pragma(msg, (x + y).sizeof); pragma(msg, (n += x).sizeof); pragma(msg, (s ~ n).sizeof); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/dip22a.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/dip22a.d(21): Deprecation: `imports.dip22a.Klass.bar` is not visible from module `dip22a` fail_compilation/dip22a.d(21): Error: class `imports.dip22a.Klass` member `bar` is not accessible fail_compilation/dip22a.d(22): Deprecation: `imports.dip22a.Struct.bar` is not visible from module `dip22a` fail_compilation/dip22a.d(22): Error: struct `imports.dip22a.Struct` member `bar` is not accessible fail_compilation/dip22a.d(23): Error: `imports.dip22a.bar` is not visible from module `dip22a` fail_compilation/dip22a.d(23): Error: function `imports.dip22a.bar` is not accessible from module `dip22a` fail_compilation/dip22a.d(24): Error: `imports.dip22a.Template!int.bar` is not visible from module `dip22a` fail_compilation/dip22a.d(24): Error: function `imports.dip22a.Template!int.bar` is not accessible from module `dip22a` fail_compilation/dip22a.d(25): Deprecation: `imports.dip22a.bar` is not visible from module `dip22a` fail_compilation/dip22a.d(25): Error: function `imports.dip22a.bar` is not accessible from module `dip22a` --- */ import imports.dip22a; void test() { new Klass().bar(); Struct().bar(); imports.dip22a.bar(); Template!int.bar(); 12.bar(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/dip22b.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/dip22b.d(12): Deprecation: `pkg.dip22c.Foo` is not visible from module `dip22` --- */ module pkg.dip22; import imports.dip22b; Foo foo; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/dip22d.d ================================================ /* REQUIRED_ARGS: -transition=import TEST_OUTPUT: --- fail_compilation/dip22d.d(12): Error: `imports.dip22d.Foo` at fail_compilation/imports/dip22d.d(3) conflicts with `imports.dip22e.Foo` at fail_compilation/imports/dip22e.d(3) fail_compilation/dip22d.d(12): Error: module `dip22d` struct `imports.dip22d.Foo` is `private` --- */ import imports.dip22d; import imports.dip22e; Foo foo; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/dip22e.d ================================================ /* REQUIRED_ARGS: -transition=checkimports -de TEST_OUTPUT: --- fail_compilation/dip22e.d(16): Deprecation: `imports.dip22d.foo` is not visible from module `dip22e` fail_compilation/dip22e.d(16): Error: function `imports.dip22d.foo` is not accessible from module `dip22e` fail_compilation/dip22e.d(17): Deprecation: local import search method found overloadset `dip22e.bar` (1 overloads) instead of function `imports.dip22e.bar` --- */ import imports.dip22d; import imports.dip22e; void test() { foo(); bar(12); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/disable.d ================================================ /* TEST_OUTPUT: --- fail_compilation/disable.d(56): Error: function `disable.DisabledOpAssign.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(59): Error: function `disable.DisabledPostblit.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(62): Error: function `disable.HasDtor.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(66): Error: generated function `disable.Nested!(DisabledOpAssign).Nested.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(69): Error: generated function `disable.Nested!(DisabledPostblit).Nested.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(72): Error: generated function `disable.Nested!(HasDtor).Nested.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(76): Error: generated function `disable.NestedDtor!(DisabledOpAssign).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(79): Error: generated function `disable.NestedDtor!(DisabledPostblit).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(82): Error: generated function `disable.NestedDtor!(HasDtor).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` fail_compilation/disable.d(84): Error: enum member `disable.Enum1.value` cannot be used because it is annotated with `@disable` --- */ struct DisabledOpAssign { int x; @disable void opAssign(const DisabledOpAssign); } struct DisabledPostblit { int x; @disable void opAssign(const DisabledPostblit); // Doesn't require opAssign @disable this(this); } struct HasDtor { int x; @disable void opAssign(const HasDtor); ~this() {} // Makes opAssign mandatory } struct Nested (T) { T b; } struct NestedDtor (T) { T b; // Requires an identity opAssign ~this() {} } enum Enum1 { @disable value } void main () { DisabledOpAssign o; o = DisabledOpAssign(); DisabledPostblit p; p = DisabledPostblit(); HasDtor d; d = HasDtor(); Nested!(DisabledOpAssign) no; no = Nested!(DisabledOpAssign)(); Nested!(DisabledPostblit) np; np = Nested!(DisabledPostblit)(); Nested!(HasDtor) nd; nd = Nested!(HasDtor)(); NestedDtor!(DisabledOpAssign) ndo; ndo = NestedDtor!(DisabledOpAssign)(); NestedDtor!(DisabledPostblit) ndp; ndp = NestedDtor!(DisabledPostblit)(); NestedDtor!(HasDtor) ndd; ndd = NestedDtor!(HasDtor)(); auto v1 = Enum1.value; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/disable_new.d ================================================ /* TEST_OUTPUT: --- fail_compilation/disable_new.d(23): Error: allocator `disable_new.C.new` cannot be used because it is annotated with `@disable` fail_compilation/disable_new.d(24): Error: allocator `disable_new.S.new` cannot be used because it is annotated with `@disable` --- */ class C { // force user of a type to use an external allocation strategy @disable new(); } struct S { // force user of a type to use an external allocation strategy @disable new(); } void main() { auto c = new C(); auto s = new S(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/enum9921.d ================================================ /* TEST_OUTPUT: --- fail_compilation/enum9921.d(9): Error: enum `enum9921.X` base type must not be `void` fail_compilation/enum9921.d(11): Error: enum `enum9921.Z` base type must not be `void` --- */ enum X : void; enum Z : void { Y }; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d ================================================ module a14446; struct CDBMaker { import ice14446; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/bar11453.d ================================================ module foo11453.bar11453; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/foo11453.d ================================================ module foo11453; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/minimal/object.d ================================================ module object; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/no_Throwable/object.d ================================================ module object; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/extra-files/no_TypeInfo/object.d ================================================ module object; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10.d(18): Error: mixin `Foo!y` cannot resolve forward reference --- */ template Foo(alias b) { int a() { return b; } } void test() { mixin Foo!(y) y; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail100.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail100.d(24): Error: cannot implicitly convert expression `f` of type `Class[]` to `I[]` --- */ // https://issues.dlang.org/show_bug.cgi?id=85 // Array of classes doesn't function as array of interfaces interface I { I[] foo(); uint x(); } class Class : I { I[] foo() { // changing this to I[] f = new Class[1] fixes the bug Class[] f = new Class[1]; //I[] f = new Class[1]; f[0] = new Class; return f; } uint x() { return 0; } } void main() { Class c = new Class(); assert(c.x == 0); assert(c.foo[0].x == 0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10082.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10082.d(24): Error: cannot infer type from overloaded function symbol `&foo` --- */ mixin template T() { int foo() { return 0; } } class A { mixin T; mixin T; } void main() { auto x = &A.foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail101.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail101.d(8): Error: cannot implicitly convert expression `1` of type `int` to `creal` --- */ creal c = 1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10102.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` default construction is disabled for type `NotNull!(int*)` fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` default construction is disabled for type `NotNull!(int*)[3]` fail_compilation/fail10102.d(50): Error: default construction is disabled for type `NotNull!(int*)` fail_compilation/fail10102.d(51): Error: field `S.m` must be initialized because it has no default constructor --- */ struct NotNull(T) { T p; alias p this; this(T p) { assert(p != null, "pointer is null"); this.p = p; } @disable this(); NotNull opAssign(T p) { assert(p != null, "assigning null to NotNull"); this.p = p; return this; } } void main() { struct S { NotNull!(int *) m; // should fail: an explicit constructor must be required for S } int i; NotNull!(int*) n = &i; *n = 3; assert(i == 3); n = &i; n += 1; NotNull!(int*) m; // should fail NotNull!(int*)[3] a; // should fail auto b = new NotNull!(int*)[3]; // should fail S s = S(); // should fail } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10115.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `S` because the default construction is disabled fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `E` because the default construction is disabled fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `U` because the default construction is disabled fail_compilation/fail10115.d(40): Error: struct `fail10115.S` default construction is disabled fail_compilation/fail10115.d(41): Error: struct `fail10115.S` default construction is disabled fail_compilation/fail10115.d(42): Error: union `fail10115.U` default construction is disabled --- */ struct S { int a; @disable this(); //this(int) { a = 1; } //~this() { assert(a !is 0); } } enum E : S { A = S.init } union U { S s; //this(this) { assert (s.a !is 0); } //~this() { assert (s.a !is 0); } } void main() { void foo(out S s, out E e, out U u) { } S[] a; E[] e; U[] u; a.length = 5; // compiles -> NG e.length = 5; // compiles -> NG u.length = 5; // compiles -> NG S[1] x = (S[1]).init; foo(a[0], // compiles -> NG e[0], // compiles -> NG u[0]); // compiles -> NG } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10207.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10207.d(7): Error: user-defined attributes not allowed for `alias` declarations --- */ alias @Safe int __externC; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10254.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10254.d(20): Error: `pure` function `fail10254.foo` cannot call impure constructor `fail10254.C.this` fail_compilation/fail10254.d(20): Error: `@safe` function `fail10254.foo` cannot call `@system` constructor `fail10254.C.this` fail_compilation/fail10254.d(15): `fail10254.C.this` is declared here fail_compilation/fail10254.d(21): Error: `pure` function `fail10254.foo` cannot call impure constructor `fail10254.S.this` fail_compilation/fail10254.d(21): Error: `@safe` function `fail10254.foo` cannot call `@system` constructor `fail10254.S.this` fail_compilation/fail10254.d(16): `fail10254.S.this` is declared here --- */ int a; class C { this() { a = 2; } } struct S { this(int) { a = 2; } } void foo() pure @safe { auto c = new C; // This line should be a compilation error. auto s = new S(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10277.d ================================================ module fail10227; /* TEST_OUTPUT: --- fail_compilation/imports/fail10277.d(3): Error: class `TypeInfo` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(4): Error: class `TypeInfo_Class` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(5): Error: class `TypeInfo_Interface` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(6): Error: class `TypeInfo_Struct` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(8): Error: class `TypeInfo_Pointer` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(9): Error: class `TypeInfo_Array` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(10): Error: class `TypeInfo_AssociativeArray` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(11): Error: class `TypeInfo_Enum` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(12): Error: class `TypeInfo_Function` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(13): Error: class `TypeInfo_Delegate` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(14): Error: class `TypeInfo_Tuple` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(15): Error: class `TypeInfo_Const` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(16): Error: class `TypeInfo_Invariant` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(17): Error: class `TypeInfo_Shared` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(18): Error: class `TypeInfo_Inout` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(19): Error: class `TypeInfo_Vector` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(20): Error: class `Object` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(21): Error: class `Throwable` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(22): Error: class `Exception` only object.d can define this reserved class name fail_compilation/imports/fail10277.d(23): Error: class `Error` only object.d can define this reserved class name --- */ import imports.fail10277; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10285.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10285.d(9): Error: no identifier for declarator `int` --- */ enum { int = 5 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10299.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10299.d(11): Error: `foo!string` is not an lvalue and cannot be modified --- */ template foo(T) { } auto fp = &foo!string; // ICE ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10346.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10346.d(9): Error: undefined identifier `T` --- */ struct Foo(T) {} void bar(T x, T)(Foo!T) {} void main() { Foo!int spam; bar!10(spam); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail104.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=76 // Using a non-template struct as a template // Compiling leads to "Assertion failure: 's->parent' on line 1694 in file // 'template.c'" struct S { template T() { void x(int i) { } } } class C(P) { mixin P!().T!(); } int main(char[][] args) { auto c = new C!(S); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10481.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10481.d(11): Error: undefined identifier `T1`, did you mean alias `T0`? fail_compilation/fail10481.d(15): Error: cannot infer type from template instance `get!(A)` --- */ struct A {} void get(T0 = T1.Req, Params...)(Params , T1) {} void main() { auto xxx = get!A; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail105.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail105.d(11): Error: cannot cast `"bar"` to `int` at compile time --- */ //int foo = "foo"; // just Access Violation happens. int bar = cast(int)cast(char*)"bar"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10528.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10528.d(23): Error: module `fail10528` variable `a10528.a` is `private` fail_compilation/fail10528.d(23): Deprecation: `a10528.a` is not visible from module `fail10528` fail_compilation/fail10528.d(24): Error: `a10528.a` is not visible from module `fail10528` fail_compilation/fail10528.d(26): Error: module `fail10528` enum member `a10528.b` is `private` fail_compilation/fail10528.d(26): Deprecation: `a10528.b` is not visible from module `fail10528` fail_compilation/fail10528.d(27): Error: `a10528.b` is not visible from module `fail10528` fail_compilation/fail10528.d(29): Deprecation: `a10528.S.c` is not visible from module `fail10528` fail_compilation/fail10528.d(29): Error: variable `a10528.S.c` is not accessible from module `fail10528` fail_compilation/fail10528.d(30): Error: variable `a10528.S.c` is not accessible from module `fail10528` fail_compilation/fail10528.d(32): Deprecation: `a10528.C.d` is not visible from module `fail10528` fail_compilation/fail10528.d(32): Error: variable `a10528.C.d` is not accessible from module `fail10528` fail_compilation/fail10528.d(33): Error: variable `a10528.C.d` is not accessible from module `fail10528` --- */ import imports.a10528; void main() { auto a1 = a; auto a2 = imports.a10528.a; auto b1 = b; auto b2 = imports.a10528.b; auto c1 = S.c; with (S) auto c2 = c; auto d1 = C.d; with (C) auto d2 = d; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10534.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10534.d(28): Error: `a` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(28): Error: `b` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(29): Error: `a` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(29): Error: `b` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(30): Error: `a` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(30): Error: `b` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(31): Error: `a` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(31): Error: `b` is not of arithmetic type, it is a `int delegate()` fail_compilation/fail10534.d(36): Error: `a` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(36): Error: `b` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(37): Error: `a` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(37): Error: `b` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(38): Error: `a` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(38): Error: `b` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(39): Error: `a` is not of arithmetic type, it is a `int function()` fail_compilation/fail10534.d(39): Error: `b` is not of arithmetic type, it is a `int function()` --- */ void main() { { int delegate() a = ()=>5; int delegate() b = ()=>5; auto c1 = a + b; // passes (and will crash if c1() called) auto c2 = a - b; // passes (and will crash if c2() called) auto c3 = a / b; // a & b not of arithmetic type auto c4 = a * b; // a & b not of arithmetic type } { int function() a = ()=>5; int function() b = ()=>5; auto c1 = a + b; auto c2 = a - b; auto c3 = a / b; auto c4 = a * b; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail106.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail106.d(12): Error: cannot modify `immutable` expression `'C'` --- */ // https://issues.dlang.org/show_bug.cgi?id=239 // Internal error: changing string literal elements void main() { "ABC"[2] = 's'; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10630.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10630.d(12): Error: cannot have `out` parameter of type `S` because the default construction is disabled --- */ struct S { @disable this(); } void foo(out S) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10666.d ================================================ // REQUIRED_ARGS: -c /* TEST_OUTPUT: --- fail_compilation/fail10666.d(16): Error: variable `fail10666.foo10666.s1` has scoped destruction, cannot build closure --- */ struct S10666 { int val; ~this() {} } void foo10666(S10666 s1) { auto f1 = (){ return () => s1.val; }(); // NG S10666 s2; auto f2 = (){ return () => s2.val; }(); // (should be NG) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail109.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail109.d(12): Error: enum member `fail109.Bool.Unknown` initialization with `Bool.True+1` causes overflow for type `bool` --- */ enum Bool : bool { False, True, Unknown } /* https://issues.dlang.org/show_bug.cgi?id=11088 TEST_OUTPUT: --- fail_compilation/fail109.d(25): Error: enum member `fail109.E.B` initialization with `E.A+1` causes overflow for type `int` fail_compilation/fail109.d(31): Error: enum member `fail109.E1.B` initialization with `E1.A+1` causes overflow for type `short` --- */ enum E { A = int.max, B } enum E1 : short { A = short.max, B } /* https://issues.dlang.org/show_bug.cgi?id=14950 TEST_OUTPUT: --- fail_compilation/fail109.d(50): Error: Comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/fail109.d(50): Error: enum member `fail109.B.end` initialization with `B.start+1` causes overflow for type `C` --- */ enum C { start, end } enum B { start = C.end, end } /* https://issues.dlang.org/show_bug.cgi?id=11849 TEST_OUTPUT: --- fail_compilation/fail109.d(72): Error: enum `fail109.RegValueType1a` recursive definition of `.max` property fail_compilation/fail109.d(79): Error: enum `fail109.RegValueType1b` recursive definition of `.max` property fail_compilation/fail109.d(84): Error: enum `fail109.RegValueType2a` recursive definition of `.min` property fail_compilation/fail109.d(91): Error: enum `fail109.RegValueType2b` recursive definition of `.min` property --- */ alias DWORD = uint; enum : DWORD { REG_DWORD = 4 } enum RegValueType1a : DWORD { Unknown = DWORD.max, DWORD = REG_DWORD, } enum RegValueType1b : DWORD { DWORD = REG_DWORD, Unknown = DWORD.max, } enum RegValueType2a : DWORD { Unknown = DWORD.min, DWORD = REG_DWORD, } enum RegValueType2b : DWORD { DWORD = REG_DWORD, Unknown = DWORD.min, } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10905.d ================================================ struct Foo { enum __vector(long[2]) y = 1; } struct Bar { __vector(long[2]) x; bool spam() const { return x == Foo.y; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10947.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10947.d(21): Error: cannot have `immutable out` parameter of type `immutable(S)` fail_compilation/fail10947.d(22): Error: cannot have `immutable out` parameter of type `immutable(S)` fail_compilation/fail10947.d(23): Error: cannot have `immutable out` parameter of type `immutable(S)` fail_compilation/fail10947.d(25): Error: cannot have `const out` parameter of type `const(S)` fail_compilation/fail10947.d(26): Error: cannot have `const out` parameter of type `const(S)` fail_compilation/fail10947.d(27): Error: cannot have `const out` parameter of type `const(S)` fail_compilation/fail10947.d(29): Error: cannot have `inout out` parameter of type `inout(S)` fail_compilation/fail10947.d(30): Error: cannot have `inout out` parameter of type `inout(S)` fail_compilation/fail10947.d(31): Error: cannot have `inout out` parameter of type `inout(S)` --- */ struct S {} alias SI = immutable S; alias SC = const S; alias SW = inout S; void fooi1(out SI) {} void fooi2(out immutable(S)) {} void fooi3(out immutable S) {} void fooc1(out SC) {} void fooc2(out const(S)) {} void fooc3(out const S) {} void foow1(out SW) {} void foow2(out inout(S)) {} void foow3(out inout S) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10964.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not `nothrow` fail_compilation/fail10964.d(22): Error: `nothrow` function `fail10964.foo` may throw --- */ struct S { this(this) { throw new Exception("BOOM!"); } } void foo() nothrow { S ss; S[1] sa; // TOKassign ss = ss; sa = ss; sa = sa; // TOKconstruct S ss2 = ss; S[1] sa2 = ss; S[1] sa3 = sa; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10968.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10968.d(39): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(39): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(40): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(40): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(41): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(41): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(46): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(46): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here --- */ struct SA { this(this) { throw new Exception("BOOM!"); } } void bar() pure @safe { SA ss; SA[1] sa; // TOKassign ss = ss; sa = ss; sa = sa; // TOKconstruct SA ss2 = ss; SA[1] sa2 = ss; SA[1] sa3 = sa; } /* TEST_OUTPUT: --- fail_compilation/fail10968.d(72): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` fail_compilation/fail10968.d(73): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` fail_compilation/fail10968.d(74): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` fail_compilation/fail10968.d(78): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` fail_compilation/fail10968.d(79): Error: struct `fail10968.SD` is not copyable because it is annotated with `@disable` --- */ struct SD { this(this) @disable; } void baz() { SD ss; SD[1] sa; // TOKassign ss = ss; sa = ss; sa = sa; // TOKconstruct SD ss2 = ss; SD[1] sa2 = ss; SD[1] sa3 = sa; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail10980.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail10980.d(22): Error: variable `fail10980.s1b` of type struct `immutable(S1)` uses `this(this)`, which is not allowed in static initialization fail_compilation/fail10980.d(28): Error: variable `fail10980.s1d` of type struct `immutable(S1)` uses `this(this)`, which is not allowed in static initialization fail_compilation/fail10980.d(27): Error: static variable `s1x` cannot be read at compile time fail_compilation/fail10980.d(28): called from here: `bar1()` fail_compilation/fail10980.d(38): Error: variable `fail10980.s2b` of type struct `immutable(S2)` uses `this(this)`, which is not allowed in static initialization fail_compilation/fail10980.d(44): Error: variable `fail10980.s2d` of type struct `immutable(S2)` uses `this(this)`, which is not allowed in static initialization fail_compilation/fail10980.d(43): Error: static variable `s2x` cannot be read at compile time fail_compilation/fail10980.d(44): called from here: `bar2()` --- */ struct S1 { this(int) immutable {} this(this) {} } alias immutable(S1) IS1; static immutable S1 s1a = IS1(1); // OK static immutable S1 s1b = s1a; // NG S1 foo1() { S1 s1x; S1 s1y = s1x; return s1y; } static immutable S1 s1c = foo1(); // OK ref S1 bar1() { static S1 s1x; return s1x; } static immutable S1 s1d = bar1(); // NG struct S2 { int val; this(this) {} } alias immutable(S2) IS2; static immutable S2 s2a = IS2(1); // OK static immutable S2 s2b = s2a; // NG S2 foo2() { S2 s2x; S2 s2y = s2x; return s2y; } static immutable S2 s2c = foo2(); // OK ref S2 bar2() { static S2 s2x; return s2x; } static immutable S2 s2d = bar2(); // NG ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11.d(12): Error: `int*` has no effect --- */ // http://forum.dlang.org/thread/c738o9$1p7i$1@digitaldaemon.com void main() { TFoo!(int).t; // should produce a "no identifier" error. } template TFoo(T) { alias T* t; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail110.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail110.d(16): Error: variable `i` is shadowing variable `fail110.main.i` fail_compilation/fail110.d(17): Error: variable `i` is shadowing variable `fail110.main.i` fail_compilation/fail110.d(18): Error: variable `i` is shadowing variable `fail110.main.i` --- */ // https://issues.dlang.org/show_bug.cgi?id=297 // Shadowing declarations allowed in foreach type lists void main() { int i; int[] a; foreach (i; a) {} foreach (int i, n; a) {} for (int i;;) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11042.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11042.d(8): Error: undefined identifier `error`, did you mean class `Error`? fail_compilation/fail11042.d(9): Error: undefined identifier `error`, did you mean class `Error`? --- */ static if ({ return true || error; }()) {} // NG static if ({ return false && error; }()) {} // NG ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail111.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail111.d(12): Error: cannot have array of `int(int)` --- */ // https://issues.dlang.org/show_bug.cgi?id=289 // Compiler allows (and crashes on) dynamic arrays of typedefs of "immediate"-function types alias int ft(int); ft[] x; // is allowed void test() { x.length = 2; // crashes DMD } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11125.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11125.d(20): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun) if (is(ReturnType!predfun == bool))` fail_compilation/fail11125.d(21): Error: template instance `fail11125.filter!(function (int a) => a + 1)` does not match template declaration `filter(alias predfun) if (is(ReturnType!predfun == bool))` --- */ template ReturnType(alias fun) { alias int ReturnType; } template filter(alias predfun) if (is(ReturnType!predfun == bool)) { static assert(is(ReturnType!predfun == bool)); auto filter(Range)(Range r) { } } void main() { filter!((int a) => a + 1)([1]); // fails in constraint [1].filter!((int a) => a + 1); // fails internally in static assert! } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11151.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11151.d(30): Error: overlapping initialization for field `a` and `y` --- */ //extern(C) int printf(const char*, ...); union U { struct { align(1) long a; align(1) int b; } struct { align(1) int x; align(1) long y; } } void main() { static assert(U.a.offsetof == 0); static assert(U.b.offsetof == 8); static assert(U.x.offsetof == 0); static assert(U.y.offsetof == 4); U u = {a:1, y:2}; // overlapped initializing U.a and U.y //printf("u.a = %lld\n", u.a); // 8589934593 , Wrong! //printf("u.b = %d\n", u.b); // 0 //printf("u.x = %d\n", u.x); // 1 //printf("u.y = %lld\n", u.y); // 2 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11163.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11163.d(12): Error: cannot implicitly convert expression `foo()` of type `int[]` to `immutable(int[])` fail_compilation/fail11163.d(13): while evaluating `pragma(msg, a)` --- */ int[] foo() { return [1]; } void main() { immutable a = foo(); pragma(msg, a); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail113.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail113.d(10): Error: forward reference to `test` --- */ // https://issues.dlang.org/show_bug.cgi?id=370 // Compiler stack overflow on recursive typeof in function declaration. void test(typeof(test) p) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11355.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11355.d(28): Error: struct `fail11355.A` is not copyable because it is annotated with `@disable` --- */ T move(T)(ref T source) { return T.init; // Dummy rvalue } struct A { ~this() {} @disable this(this); // Prevent copying } struct B { A a; alias a this; } void main() { B b; A a = move(b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11375.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow` fail_compilation/fail11375.d(15): Error: `nothrow` function `D main` may throw --- */ class B { this() {} } class D() : B {} void main() nothrow { auto d = new D!()(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail114.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail114.d(12): Error: forward reference to `funcA` --- */ // https://issues.dlang.org/show_bug.cgi?id=371 // ICE on mutual recursive typeof in function declarations void funcA(typeof(&funcB) p) {} void funcB(typeof(&funcA) p) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11426.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11426.d(15): Error: cannot implicitly convert expression `udarr` of type `uint[]` to `int[]` fail_compilation/fail11426.d(16): Error: cannot implicitly convert expression `usarr` of type `uint[1]` to `int[]` fail_compilation/fail11426.d(18): Error: cannot implicitly convert expression `udarr` of type `uint[]` to `int[]` fail_compilation/fail11426.d(19): Error: cannot implicitly convert expression `usarr` of type `uint[1]` to `int[]` --- */ void main() { uint[] udarr; uint[1] usarr; int[1] arr1; arr1 = udarr; // Error, OK int[1] arr2; arr2 = usarr; // Error, OK int[1] arr3 = udarr; // accepted, BAD! int[1] arr4 = usarr; // accepted, BAD! } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11445.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11445.d(11): Error: incompatible types for `(a) + (b)`: both operands are of type `double[string]` --- */ void main() { double[string] a = [ "foo" : 22.2 ]; double[string] b = [ "bar" : 22.2 ]; auto c = a + b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11453a.d ================================================ // REQUIRED_ARGS: -Ifail_compilation/extra-files // EXTRA_SOURCES: extra-files/foo11453.d extra-files/bar11453.d /* TEST_OUTPUT --- fail_compilation/extra-files/bar11453.d(1): Error: package name 'foo11453' conflicts with usage as a module name in file fail_compilation/extra-files/foo11453.d --- */ void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11453b.d ================================================ // REQUIRED_ARGS: -Ifail_compilation/extra-files // EXTRA_SOURCES: extra-files/bar11453.d extra-files/foo11453.d /* TEST_OUTPUT --- fail_compilation/extra-files/foo11453.d(1): Error: module `foo11453` from file fail_compilation/extra-files/foo11453.d conflicts with package name foo11453 --- */ void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail115.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=402 // compiler crash with mixin and forward reference template Foo(alias b) { int a() { return b; } } void main() { mixin Foo!(y) y; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11503a.d ================================================ struct S { immutable(S)* s; this(int) immutable pure { s = &this; } int data; } immutable(S)* makes() pure { return new immutable S(0); } void main() { S* s = makes(); // s is mutable and contains an immutable reference to itself //s.s.data = 7; // this is immutable s.data = 3; // but this is not!!! } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11503b.d ================================================ immutable int[] x = [1, 2, 3]; auto makes() pure { return x; } int main() { auto a = x; int[] b = makes(); return b[1]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11503c.d ================================================ struct Data { char[256] buffer; @property const(char)[] filename() const pure nothrow { return buffer[]; } } void main() { Data d; string f = d.filename; d.buffer[0] = 'a'; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11503d.d ================================================ struct Data2 { char buffer; } @property const(char)[] filename(const ref Data2 d) pure nothrow { return (&d.buffer)[0 .. 1]; } @property const(char)[] filename2(const Data2* d) pure nothrow { return (&d.buffer)[0 .. 1]; } void main() { Data2 d; string f = d.filename; string g = (&d).filename2; d.buffer = 'a'; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11510.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11510.d(25): Error: reinterpretation through overlapped field `y` is not allowed in CTFE fail_compilation/fail11510.d(29): called from here: `test11510a()` fail_compilation/fail11510.d(36): Error: reinterpretation through overlapped field `y` is not allowed in CTFE fail_compilation/fail11510.d(40): called from here: `test11510b()` --- */ struct S11510 { union { size_t x; int* y; // pointer field } } bool test11510a() { S11510 s; s.y = [1,2,3].ptr; auto x = s.x; // reinterpretation return true; } enum a = test11510a(); bool test11510b() { S11510 s; s.x = 10; auto y = s.y; // reinterpretation return true; } enum b = test11510b(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11532.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11532.d(17): Error: cannot pass static arrays to `extern(C)` vararg functions fail_compilation/fail11532.d(18): Error: cannot pass dynamic arrays to `extern(C)` vararg functions fail_compilation/fail11532.d(19): Error: cannot pass static arrays to `extern(C++)` vararg functions fail_compilation/fail11532.d(20): Error: cannot pass dynamic arrays to `extern(C++)` vararg functions --- */ extern(C) void cvararg(int, ...); extern(C++) void cppvararg(int, ...); void main() { int[2] arr = [0x99999999, 0x88888888]; cvararg(0, arr); cvararg(0, arr[]); cppvararg(0, arr); cppvararg(0, arr[]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11542.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/fail11542.d(16): Error: `object.Exception` is thrown but not caught fail_compilation/fail11542.d(13): Error: `nothrow` function `fail11542.test_success1` may throw fail_compilation/fail11542.d(26): Error: `object.Exception` is thrown but not caught fail_compilation/fail11542.d(23): Error: `nothrow` function `fail11542.test_success3` may throw --- */ void test_success1() nothrow { scope(success) {} throw new Exception(""); // error } void test_success2() nothrow { scope(success) {} throw new Error(""); // no error } void test_success3() nothrow { scope(success) assert(0); throw new Exception(""); // error } /* TEST_OUTPUT: --- fail_compilation/fail11542.d(39): Error: `object.Exception` is thrown but not caught fail_compilation/fail11542.d(36): Error: `nothrow` function `fail11542.test_failure1` may throw --- */ void test_failure1() nothrow { scope(failure) {} throw new Exception(""); // error } void test_failure2() nothrow { scope(failure) {} throw new Error(""); // no error } void est_failure3() nothrow { scope(failure) assert(0); throw new Exception(""); // no error } /* TEST_OUTPUT: --- fail_compilation/fail11542.d(62): Error: `object.Exception` is thrown but not caught fail_compilation/fail11542.d(59): Error: `nothrow` function `fail11542.test_exit1` may throw --- */ void test_exit1() nothrow { scope(exit) {} throw new Exception(""); // error } void test_exit2() nothrow { scope(exit) {} throw new Error(""); // no error } void test_exit3() nothrow { scope(exit) assert(0); throw new Exception(""); // no error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11545.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11545.d(14): Error: need `this` for `x` of type `int` fail_compilation/fail11545.d(18): Error: need `this` for `x` of type `int` --- */ class C { int x = 42; int function() f1 = function() { return x; }; int function() f2 = { return x; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11552.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/fail11552.d(12): Error: label `label` is undefined --- */ void main() { goto label; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11562.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/fail11562.d(16): Error: cannot `goto` in or out of `finally` block fail_compilation/fail11562.d(37): Error: cannot `goto` in or out of `finally` block fail_compilation/fail11562.d(49): Error: cannot `goto` in or out of `finally` block fail_compilation/fail11562.d(64): Error: cannot `goto` in or out of `finally` block --- */ // Goto into finally block (forwards) int w(bool b) { if (b) goto label; try { } finally { label: {} } return 1; } // // Goto into finally block (backwards) int x(bool b) { try { } finally { label: {} } if (b) goto label; return 1; } // Goto out of finally block (forwards) int y(bool b) { try { } finally { if (b) goto label; } label: {} return 1; } // // Goto out of finally block (backwards) int z(bool b) { label: {} try { } finally { if (b) goto label; } return 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11591b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11591b.d(16): Error: AA key type `S11591` does not have `bool opEquals(ref const S11591) const` --- */ struct S11591 { bool opEquals(int i) { return false; } Object o; // needed to suppress compiler generated opEquals } void test11591() { int[S11591] aa; } /* TEST_OUTPUT: --- fail_compilation/fail11591b.d(30): Error: AA key type `S12307a` does not have `bool opEquals(ref const S12307a) const` fail_compilation/fail11591b.d(31): Error: AA key type `S12307b` does not have `bool opEquals(ref const S12307b) const` --- */ struct S12307a { bool opEquals(T : typeof(this))(T) { return false; } } void test12307() { int[S12307a] aa1; // a int[S12307b] aa2; // b } struct S12307b { bool opEquals(T : typeof(this))(T) { return false; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail116.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail116.d(11): Error: circular `typeof` definition fail_compilation/fail116.d(16): Error: template instance `square!1.2` does not match template declaration `square(_error_ x)` --- */ // https://issues.dlang.org/show_bug.cgi?id=405 // typeof in TemplateParameterList causes compiletime segmentfault template square(typeof(x) x) { const square = x * x; } const b = square!(1.2); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11653.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail11653.d(19): Deprecation: switch case fallthrough - use 'goto case;' if intended fail_compilation/fail11653.d(24): Deprecation: switch case fallthrough - use 'goto default;' if intended --- */ void main() { int test = 12412; int output = 0; switch(test) { case 1: output = 1; //break; //Oops.. case 2: .. case 3: output = 2; break; case 4: output = 3; default: output = 4; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail117.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail117.d(35): Error: expression has no value fail_compilation/fail117.d(36): Error: expression has no value --- */ // https://issues.dlang.org/show_bug.cgi?id=420 // mixin make dmd break //import std.stdio; template MGettor(alias Fld) { typeof(Fld) opCall() { //writefln("getter"); return Fld; } } class Foo { int a = 1, b = 2; mixin MGettor!(a) geta; mixin MGettor!(b) getb; } void main() { auto foo = new Foo; int a = foo.geta; int b = foo.getb; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11714.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11714.d(14): Error: variable `fail11714.c` is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead. fail_compilation/fail11714.d(21): Error: variable `fail11714.s` is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead. --- */ class C11714 { int data; }; C11714 c = new C11714; // mutable class reference. struct S11714 { int data; }; S11714* s = new S11714; // mutable pointer to struct. ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11717.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11717.d(13): Error: cannot interpret array literal expression `[1, 2, 3, 4] + [1, 2, 3, 4]` at compile time --- */ // https://issues.dlang.org/show_bug.cgi?id=11717 enum int[4] A = [1,2,3,4]; enum int[4] B = [1,2,3,4]; // Internal Compiler Error: non-constant value [1, 2, 3, 4] enum int[4] C = A[] + B[]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11720.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail11720.d(23): Error: declaration `fail11720.foo!().foo.temp` is already defined in another scope in `foo` at line `23` fail_compilation/fail11720.d(13): Error: template instance `fail11720.foo!()` error instantiating fail_compilation/fail11720.d(31): Error: declaration `fail11720.bar.temp` is already defined in another scope in `bar` at line `31` --- */ void main() { foo(); bar(); } alias TypeTuple(T...) = T; void foo()() { foreach (T; TypeTuple!(int, double)) { static temp = T.stringof; } } void bar() { foreach (T; TypeTuple!(int, double)) { static temp = T.stringof; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11746.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11746.d(18): Error: cannot implicitly convert expression `1` of type `int` to `string` fail_compilation/fail11746.d(25): Error: cannot implicitly convert expression `1` of type `int` to `string` fail_compilation/fail11746.d(26): Error: cannot implicitly convert expression `2` of type `int` to `string` --- */ string bb(T, U)(T x, U y) { return "3"; } enum E1 { foo = bb(bar, baz), bar = 1, baz = "2", } enum E2 { foo = bb(bar, baz), bar = 1, baz = 2 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11748.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11748.d(12): Error: expression `my_function(0)` is `void` and has no value --- */ void main() { enum my_template(alias T) = T.stringof; void my_function(int i) { } my_template!(my_function(0)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail11751.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail11751.d(10): Error: missing exponent fail_compilation/fail11751.d(10): Error: semicolon expected following auto declaration, not `ABC` fail_compilation/fail11751.d(10): Error: no identifier for declarator `ABC` --- */ auto x = 0x1.FFFFFFFFFFFFFpABC; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail118.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail118.d(26): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof` fail_compilation/fail118.d(27): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof` --- */ // https://issues.dlang.org/show_bug.cgi?id=441 // Crash on foreach of mixed-in aggregate. template opHackedApply() { struct Iter { } } class Foo { mixin opHackedApply!() oldIterMix; } void main() { Foo f = new Foo; foreach (int i; f.oldIterMix.Iter) {} foreach ( i; f.oldIterMix.Iter) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12.d ================================================ template Foo(alias b) { int abc() { return b; } } void main() { int y = 8; mixin Foo!(y); mixin Foo!(y); assert(abc() == 8); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail120.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail120.d(12): Error: need `this` for `nodes` of type `int[2]` fail_compilation/fail120.d(13): Error: need `this` for `nodes` of type `int[2]` --- */ class Foo { int[2] nodes; auto left = (){ return nodes[0]; }; auto right = (){ return nodes[1]; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12047.d ================================================ // REQUIRED_ARGS: -d /* TEST_OUTPUT: --- fail_compilation/fail12047.d(15): Error: undefined identifier `asdf` fail_compilation/fail12047.d(16): Error: undefined identifier `asdf` fail_compilation/fail12047.d(17): Error: undefined identifier `asdf` fail_compilation/fail12047.d(18): Error: undefined identifier `asdf` fail_compilation/fail12047.d(19): Error: undefined identifier `asdf` fail_compilation/fail12047.d(20): Error: undefined identifier `asdf` fail_compilation/fail12047.d(21): Error: undefined identifier `asdf` --- */ @asdf void func() { } @asdf int var = 1; @asdf enum E : int { a } @asdf struct S {} @asdf class C {} @asdf interface I {} @asdf alias int myint; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail121.d ================================================ // PERMUTE_ARGS: -d -dw // segfault on DMD0.150, never failed if use typeid() instead. struct myobject { TypeInfo objecttype; void* offset; } myobject[] list; void foo() { int i; list[1].typeinfo = i.typeinfo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail122.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail122.d(12): Error: undefined identifier `y` --- */ // https://issues.dlang.org/show_bug.cgi?id=228 // Crash on inferring function literal return type after prior errors void main() { y = 2; auto x = function(){}; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12236.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function `f1` fail_compilation/fail12236.d(16): while evaluating `pragma(msg, f1.mangleof)` fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function `f2` fail_compilation/fail12236.d(21): while evaluating `pragma(msg, f2(T)(T).mangleof)` fail_compilation/fail12236.d(27): Error: template instance `fail12236.f2!int` error instantiating fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda1` fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1.mangleof)` --- */ auto f1(int) { pragma(msg, f1.mangleof); // forward reference error } auto f2(T)(T) { pragma(msg, f2.mangleof); // error <- weird output: "v" } void main() { f1(1); f2(1); (a) { int x; pragma(msg, __traits(parent, x).mangleof); } (1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12255.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12255.d(29): Error: AA key type `SC1` does not have `bool opEquals(ref const SC1) const` fail_compilation/fail12255.d(30): Error: AA key type `SC2` does not support const equality fail_compilation/fail12255.d(35): Error: AA key type `SD1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(36): Error: AA key type `SD2` supports const equality but doesn't support const hashing fail_compilation/fail12255.d(40): Error: AA key type `SE1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(41): Error: AA key type `SE2` supports const equality but doesn't support const hashing --- */ void main() { /* Key comparison and hashing are based on object bit representation, * and they fully supported in runtime (TypeInfo.equals and TypeInfo.getHash) */ int[SA1] a1; // OK int[SA2] a2; // OK /* If only toHash is defined, AA assumes that is customized object hashing. */ int[SB1] b1; // OK int[SB2] b2; // OK /* If key does not support const equality, * it is disallowed, because TypeInfo.equals will throw Error. */ int[SC1] c1; // NG int[SC2] c2; // NG /* If opEquals defined for const equality, corresponding toHash method * is required to guarantee (a != b || a.toHash() == b.toHash()). */ int[SD1] d1; // NG int[SD2] d2; // NG /* same as SD cases */ int[SE1] e1; // NG int[SE2] e2; // NG } struct SA1 { int val; } struct SA2 { SA1 s; } struct SB1 { // AA assumes this is specialized hashing (?) size_t toHash() const nothrow @safe { return 0; } } struct SB2 { SB1 s; // implicit generated toHash() calls s.toHash(). } struct SC1 { // does not support const equality bool opEquals(typeof(this)) /*const*/ { return true; } } struct SC2 { SC1 s; } struct SD1 { // Supports const equality, but // does not have corresponding toHash() bool opEquals(typeof(this)) const { return true; } } struct SD2 { SD1 s; } struct SE1 { // Supports const equality, but // does not have corresponding valid toHash() bool opEquals(typeof(this)) const { return true; } size_t toHash() @system { return 0; } } struct SE2 { SE1 s; } /* TEST_OUTPUT: --- fail_compilation/fail12255.d(108): Error: bottom of AA key type `SC1` does not have `bool opEquals(ref const SC1) const` fail_compilation/fail12255.d(109): Error: bottom of AA key type `SC2` does not support const equality fail_compilation/fail12255.d(110): Error: bottom of AA key type `SD1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(111): Error: bottom of AA key type `SD2` supports const equality but doesn't support const hashing fail_compilation/fail12255.d(112): Error: bottom of AA key type `SE1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(113): Error: bottom of AA key type `SE2` supports const equality but doesn't support const hashing --- */ void testSArray() { int[SA1[1]] a1; // OK int[SA2[1]] a2; // OK int[SB1[1]] b1; // OK int[SB2[1]] b2; // OK int[SC1[1]] c1; // NG int[SC2[1]] c2; // NG int[SD1[1]] d1; // NG int[SD2[1]] d2; // NG int[SE1[1]] e1; // NG int[SE2[1]] e2; // NG } /* TEST_OUTPUT: --- fail_compilation/fail12255.d(133): Error: bottom of AA key type `SC1` does not have `bool opEquals(ref const SC1) const` fail_compilation/fail12255.d(134): Error: bottom of AA key type `SC2` does not support const equality fail_compilation/fail12255.d(135): Error: bottom of AA key type `SD1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(136): Error: bottom of AA key type `SD2` supports const equality but doesn't support const hashing fail_compilation/fail12255.d(137): Error: bottom of AA key type `SE1` should have `size_t toHash() const nothrow @safe` if `opEquals` defined fail_compilation/fail12255.d(138): Error: bottom of AA key type `SE2` supports const equality but doesn't support const hashing --- */ void testDArray() { int[SA1[]] a1; // OK int[SA2[]] a2; // OK int[SB1[]] b1; // OK int[SB2[]] b2; // OK int[SC1[]] c1; // NG int[SC2[]] c2; // NG int[SD1[]] d1; // NG int[SD2[]] d2; // NG int[SE1[]] e1; // NG int[SE2[]] e2; // NG } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail123.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail123.d(11): Error: undefined identifier `type` fail_compilation/fail123.d(17): Error: enum `fail123.foo2` base type must not be `void` --- */ // https://issues.dlang.org/show_bug.cgi?id=355 // ICE from enum : nonexistent type enum foo : type { blah1, blah2 } enum foo2 : void { a, b } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12378.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12378.d(18): Error: undefined identifier `ANYTHING` fail_compilation/fail12378.d(18): Error: undefined identifier `GOES` fail_compilation/fail12378.d(91): instantiated from here: `MapResultS!((x0) => ANYTHING - GOES, Result)` fail_compilation/fail12378.d(17): instantiated from here: `mapS!(Result)` fail_compilation/fail12378.d(100): instantiated from here: `__lambda1!int` fail_compilation/fail12378.d(91): instantiated from here: `MapResultS!((y0) => iota(2).mapS!((x0) => ANYTHING - GOES), Result)` fail_compilation/fail12378.d(16): instantiated from here: `mapS!(Result)` --- */ void testS() { auto r = iota(1).mapS!(y0 => iota(2).mapS!(x0 => ANYTHING-GOES ) ); } /* TEST_OUTPUT: --- fail_compilation/fail12378.d(40): Error: undefined identifier `ANYTHING` fail_compilation/fail12378.d(40): Error: undefined identifier `GOES` fail_compilation/fail12378.d(112): instantiated from here: `MapResultC!((x0) => ANYTHING - GOES, Result)` fail_compilation/fail12378.d(39): instantiated from here: `mapC!(Result)` fail_compilation/fail12378.d(123): instantiated from here: `__lambda1!int` fail_compilation/fail12378.d(112): instantiated from here: `MapResultC!((y0) => iota(2).mapC!((x0) => ANYTHING - GOES), Result)` fail_compilation/fail12378.d(38): instantiated from here: `mapC!(Result)` --- */ void testC() { auto r = iota(1).mapC!(y0 => iota(2).mapC!(x0 => ANYTHING-GOES ) ); } /* TEST_OUTPUT: --- fail_compilation/fail12378.d(64): Error: undefined identifier `ANYTHING` fail_compilation/fail12378.d(64): Error: undefined identifier `GOES` fail_compilation/fail12378.d(135): instantiated from here: `MapResultI!((x0) => ANYTHING - GOES, Result)` fail_compilation/fail12378.d(63): instantiated from here: `mapI!(Result)` fail_compilation/fail12378.d(143): instantiated from here: `__lambda1!int` fail_compilation/fail12378.d(135): instantiated from here: `MapResultI!((y0) => iota(2).mapI!((x0) => ANYTHING - GOES), Result)` fail_compilation/fail12378.d(62): instantiated from here: `mapI!(Result)` --- */ void testI() { auto r = iota(1).mapI!(y0 => iota(2).mapI!(x0 => ANYTHING-GOES ) ); } auto iota(E)(E end) { alias Value = E; static struct Result { private Value current, pastLast; @property inout(Value) front() inout { return current; } } return Result(0, end); } template mapS(fun...) { auto mapS(R)(R r) { alias AppliedReturnType(alias f) = typeof(f(r.front)); static assert(!is(AppliedReturnType!fun == void), "Mapping function must not return void."); return MapResultS!(fun, R)(r); } } struct MapResultS(alias fun, R) { R _input; @property auto ref front() { return fun(_input.front); } } template mapC(fun...) { auto mapC(R)(R r) { alias AppliedReturnType(alias f) = typeof(f(r.front)); static assert(!is(AppliedReturnType!fun == void), "Mapping function must not return void."); return new MapResultC!(fun, R)(r); } } class MapResultC(alias fun, R) { R _input; this(R r) { _input = r; } @property auto ref front() { return fun(_input.front); } } template mapI(fun...) { auto mapI(R)(R r) { alias AppliedReturnType(alias f) = typeof(f(r.front)); static assert(!is(AppliedReturnType!fun == void), "Mapping function must not return void."); return MapResultI!(fun, R).init; } } interface MapResultI(alias fun, R) { static @property auto ref front() { R _input; return fun(_input.front); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12390.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12390.d(14): Error: `fun().i == 4` has no effect --- */ struct S { int i; } S fun() { return S(42); } void main() { fun().i == 4; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail124.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail124.d(15): Error: class `fail124.CC` inherits from duplicate interface `C` --- */ //import std.stdio; interface C { void f(); } class CC : C, C { void f() { /*writefln("hello");*/ } } void main() { CC cc = new CC(); cc.f(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12436.d ================================================ alias void FuncType(); struct Opaque; template Tuple(T...) { alias T Tuple; } alias Tuple!(int, int) TupleType; /******************************************/ // return type /* TEST_OUTPUT: --- fail_compilation/fail12436.d(18): Error: functions cannot return a function fail_compilation/fail12436.d(19): Error: functions cannot return a tuple --- */ FuncType test1(); TupleType test2(); /* TEST_OUTPUT: --- fail_compilation/fail12436.d(28): Error: functions cannot return opaque type `Opaque` by value fail_compilation/fail12436.d(29): Error: functions cannot return opaque type `Opaque[1]` by value --- */ Opaque ret12436a(); // error Opaque[1] ret12436b(); // error Opaque* ret12436c(); // no error Opaque[] ret12436d(); // no error Opaque[]* ret12436e(); // no error ref Opaque ret12436f(); // no error ref Opaque[1] ret12436g(); // no error /******************************************/ // parameter type /* TEST_OUTPUT: --- fail_compilation/fail12436.d(46): Error: cannot have parameter of function type `void()` --- */ void test3(FuncType) {} /* TEST_OUTPUT: --- fail_compilation/fail12436.d(55): Error: cannot have parameter of opaque type `Opaque` by value fail_compilation/fail12436.d(56): Error: cannot have parameter of opaque type `Opaque[1]` by value --- */ void param12436a(Opaque); // error void param12436b(Opaque[1]); // error void param12436c(Opaque*); // no error void param12436d(Opaque[]); // no error void param12436e(Opaque[]*); // no error void param12436f(ref Opaque); // no error void param12436g(ref Opaque[1]); // no error void param12436h(out Opaque); // no error void param12436i(out Opaque[1]); // no error /* TEST_OUTPUT: --- fail_compilation/fail12436.d(75): Error: cannot have parameter of opaque type `A14906` by value fail_compilation/fail12436.d(76): Error: cannot have parameter of opaque type `A14906[3]` by value fail_compilation/fail12436.d(77): Error: cannot have parameter of opaque type `A14906[3][3]` by value --- */ enum A14906; void f14906a(A14906) {} void f14906b(A14906[3]) {} void f14906c(A14906[3][3]) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12485.d ================================================ void dorecursive() { recursive!"ratherLongSymbolNameToHitTheMaximumSymbolLengthEarlierThanTheTemplateRecursionLimit_"; } void recursive(string name)() { struct S {} // define type to kick off mangler static if (name.length <= (4 << 20)) recursive!(name ~ name); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail125.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail125.d(15): Error: array index `[2]` is outside array bounds `[0 .. 2]` fail_compilation/fail125.d(18): Error: template instance `fail125.main.recMove!(1, a, b)` error instantiating fail_compilation/fail125.d(25): instantiated from here: `recMove!(0, a, b)` --- */ template recMove(int i, X...) { void recMove() { X[i] = X[i+1]; // I know the code is logically wrong, should test (i+2 < X.length) static if (i+1 < X.length) recMove!(i+1, X); } } void main() { int a, b; recMove!(0, a, b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12567.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail12567.d(8): Error: string expected, not '"a" ~ "b"' --- */ deprecated("a" ~ "b") module fail12567; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail126.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail126.d(8): Error: forward reference to `test` --- */ void test(typeof(test) p) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12604.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12604.d(14): Error: mismatched array lengths, 1 and 3 fail_compilation/fail12604.d(15): Error: mismatched array lengths, 1 and 3 fail_compilation/fail12604.d(17): Error: mismatched array lengths, 1 and 3 fail_compilation/fail12604.d(18): Error: mismatched array lengths, 1 and 3 fail_compilation/fail12604.d(20): Error: cannot implicitly convert expression `[65536]` of type `int[]` to `short[]` fail_compilation/fail12604.d(21): Error: cannot implicitly convert expression `[65536, 2, 3]` of type `int[]` to `short[]` --- */ void main() { int[1] a1 = [1,2,3]; short[1] a2 = [1,2,3]; int[1] b1; b1 = [1,2,3]; short[1] b2; b2 = [1,2,3]; short[1] c = [65536]; short[1] d = [65536,2,3]; } /* TEST_OUTPUT: --- fail_compilation/fail12604.d(39): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(40): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(41): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(42): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(43): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(44): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(45): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(46): Error: mismatched array lengths, 2 and 3 --- */ void test12606a() // AssignExp::semantic { uint[2] a1 = [1, 2, 3][]; ushort[2] a2 = [1, 2, 3][]; uint[2] a3 = [1, 2, 3][0 .. 3]; ushort[2] a4 = [1, 2, 3][0 .. 3]; a1 = [1, 2, 3][]; a2 = [1, 2, 3][]; a3 = [1, 2, 3][0 .. 3]; a4 = [1, 2, 3][0 .. 3]; } /* TEST_OUTPUT: --- fail_compilation/fail12604.d(60): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(61): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(62): Error: mismatched array lengths, 2 and 3 fail_compilation/fail12604.d(63): Error: mismatched array lengths, 2 and 3 --- */ void test12606b() // ExpInitializer::semantic { static uint[2] a1 = [1, 2, 3][]; static uint[2] a2 = [1, 2, 3][0 .. 3]; static ushort[2] a3 = [1, 2, 3][]; static ushort[2] a4 = [1, 2, 3][0 .. 3]; } /* TEST_OUTPUT: --- fail_compilation/fail12604.d(77): Error: mismatched array lengths, 4 and 3 fail_compilation/fail12604.d(78): Error: mismatched array lengths, 4 and 3 --- */ void testc() { int[4] sa1; int[3] sa2; sa1[0..4] = [1,2,3]; sa1[0..4] = sa2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12622.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12622.d(26): Error: `pure` function `fail12622.foo` cannot call impure function pointer `fp` fail_compilation/fail12622.d(26): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function pointer `fp` fail_compilation/fail12622.d(26): Error: `@safe` function `fail12622.foo` cannot call `@system` function pointer `fp` fail_compilation/fail12622.d(28): Error: `pure` function `fail12622.foo` cannot call impure function pointer `fp` fail_compilation/fail12622.d(28): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function pointer `fp` fail_compilation/fail12622.d(28): Error: `@safe` function `fail12622.foo` cannot call `@system` function pointer `fp` fail_compilation/fail12622.d(30): Error: `pure` function `fail12622.foo` cannot call impure function `fail12622.bar` fail_compilation/fail12622.d(30): Error: `@safe` function `fail12622.foo` cannot call `@system` function `fail12622.bar` fail_compilation/fail12622.d(20): `fail12622.bar` is declared here fail_compilation/fail12622.d(30): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function `fail12622.bar` --- */ // Note that, today nothrow violation errors are accidentally hidden. void bar(); pure nothrow @nogc @safe void foo() { auto fp = &bar; (*fp)(); fp(); bar(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12636.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12636.d(13): Error: C++ class `fail12636.C` cannot implement D interface `fail12636.D` --- */ interface D { void foo(); } extern(C++) class C : D { extern(D) override void foo() { } } void main() { auto c = new C; c.foo(); // works D d = c; d.foo(); // segfault } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail127.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail127.d(9): Error: a struct is not a valid initializer for a `char[][]` fail_compilation/fail127.d(10): Error: a struct is not a valid initializer for a `string[]` --- */ char[][] Level2Text1 = {"LOW", "MEDIUM", "HIGH"}; string[] Level2Text2 = {"LOW", "MEDIUM", "HIGH"}; // for D2 ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12744.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes `ref` and `out` fail_compilation/fail12744.d(52): Error: template instance `fail12744.bar12744R!(foo12744O)` error instantiating fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes `ref` and `lazy` fail_compilation/fail12744.d(53): Error: template instance `fail12744.bar12744R!(foo12744L)` error instantiating fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes `out` and `ref` fail_compilation/fail12744.d(56): Error: template instance `fail12744.bar12744O!(foo12744R)` error instantiating fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes `out` and `lazy` fail_compilation/fail12744.d(58): Error: template instance `fail12744.bar12744O!(foo12744L)` error instantiating fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `ref` fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L!(foo12744R)` error instantiating fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out` fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744O)(int)`, candidates are: fail_compilation/fail12744.d(41): `fail12744.bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744L)(int)`, candidates are: fail_compilation/fail12744.d(41): `fail12744.bar12744A(alias f)(auto ref PTT12744!f args)` --- */ template PTT12744(func...) { static if (is(typeof(func[0]) P == function)) alias PTT12744 = P; else static assert(0); } void foo12744N( int x) {} void foo12744R( ref int x) {} void foo12744O( out int x) {} void foo12744L(lazy int x) {} void bar12744N(alias f)( PTT12744!f args) {} void bar12744R(alias f)( ref PTT12744!f args) {} void bar12744O(alias f)( out PTT12744!f args) {} void bar12744L(alias f)( lazy PTT12744!f args) {} void bar12744A(alias f)(auto ref PTT12744!f args) {} void main() { alias bNN = bar12744N!foo12744N; alias bNR = bar12744N!foo12744R; alias bNO = bar12744N!foo12744O; alias bNL = bar12744N!foo12744L; alias bRN = bar12744R!foo12744N; alias bRR = bar12744R!foo12744R; alias bRO = bar12744R!foo12744O; // error alias bRL = bar12744R!foo12744L; // error alias bON = bar12744O!foo12744N; alias bOR = bar12744O!foo12744R; // error alias bOO = bar12744O!foo12744O; alias bOL = bar12744O!foo12744L; // error alias bLN = bar12744L!foo12744N; alias bLR = bar12744L!foo12744R; // error alias bLO = bar12744L!foo12744O; // error alias bLL = bar12744L!foo12744L; bar12744A!foo12744N(1); bar12744A!foo12744R(1); bar12744A!foo12744O(1); // error bar12744A!foo12744L(1); // error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12749.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12749.d(19): Error: immutable field `inum` initialization is not allowed in foreach loop fail_compilation/fail12749.d(20): Error: const field `cnum` initialization is not allowed in foreach loop fail_compilation/fail12749.d(25): Error: immutable field `inum` initialization is not allowed in nested function `set` fail_compilation/fail12749.d(26): Error: const field `cnum` initialization is not allowed in nested function `set` --- */ struct S { immutable int inum; const int cnum; this(int i) { foreach (n; Aggr()) { inum = i; cnum = i; } void set(int i) { inum = i; cnum = i; } } } /* TEST_OUTPUT: --- fail_compilation/fail12749.d(48): Error: immutable variable `inum` initialization is not allowed in foreach loop fail_compilation/fail12749.d(49): Error: const variable `cnum` initialization is not allowed in foreach loop fail_compilation/fail12749.d(54): Error: immutable variable `inum` initialization is not allowed in nested function `set` fail_compilation/fail12749.d(55): Error: const variable `cnum` initialization is not allowed in nested function `set` --- */ immutable int inum; const int cnum; static this() { int i = 10; foreach (n; Aggr()) { inum = i; cnum = i; } void set(int i) { inum = i; cnum = i; } } struct Aggr { int opApply(int delegate(int) dg) { return dg(1); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12764.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=12764 /* TEST_OUTPUT: --- fail_compilation/fail12764.d(20): Error: field `s` must be initialized in constructor --- */ struct S { @disable this(); this(string) { } int f; } class C { this(int) { s.f = 1; // circumvents default ctor! } S s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12809.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: bool cond; /* TEST_OUTPUT: --- fail_compilation/fail12809.d(19): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(16): Error: `nothrow` function `fail12809.test_finally1` may throw fail_compilation/fail12809.d(35): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(39): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(32): Error: `nothrow` function `fail12809.test_finally3` may throw --- */ void test_finally1() nothrow { try throw new Exception(""); // error finally {} } void test_finally2() nothrow { try throw new Exception(""); // no error finally assert(0); // unconditional halt } void test_finally3() nothrow { try throw new Exception(""); // error finally { if (cond) throw new Exception(""); // error assert(0); // conditional halt } } /* TEST_OUTPUT: --- fail_compilation/fail12809.d(59): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(54): Error: `nothrow` function `fail12809.test_finally4` may throw fail_compilation/fail12809.d(75): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(79): Error: `object.Exception` is thrown but not caught fail_compilation/fail12809.d(70): Error: `nothrow` function `fail12809.test_finally6` may throw --- */ void test_finally4() nothrow { try {} finally throw new Exception(""); // error } void test_finally5() nothrow { try assert(0); // unconditional halt finally throw new Exception(""); // no error } void test_finally6() nothrow { try { if (cond) throw new Exception(""); // error assert(0); // conditional halt } finally throw new Exception(""); // error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail129.d ================================================ Ä ä; /* TEST_OUTPUT: --- fail_compilation/fail129.d: Error: module `fail129` source file must start with BOM or ASCII character, not \xC3 --- */ class Ä { } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12901.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12901.d(11): Error: constructor `fail12901.S.this` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract --- */ struct S { int a; this(int n) in { a = n; } // no body } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12908.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12908.d(14): Error: `pure` delegate `fail12908.main.__foreachbody1` cannot call impure function `fail12908.g` --- */ void g() {} void main() pure { foreach (k, v; ["": ""]) { g(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail12932.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail12932.d(11): Error: array literal in `@nogc` function `fail12932.foo` may cause a GC allocation fail_compilation/fail12932.d(15): Error: array literal in `@nogc` function `fail12932.foo` may cause a GC allocation --- */ int* foo() @nogc { foreach (ref e; [1,2,3]) { } foreach (ref e; [1,2,3]) { return &e; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13064.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13064.d(8): Error: function `fail13064.f` storage class `auto` has no effect if return type is not inferred --- */ auto void f() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail131.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail131.d(8): Error: function `D main` parameters must be `main()` or `main(string[] args)` --- */ int main(lazy char[][] args) { return args.length; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13116.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified --- */ struct S { ref S notEvil() { return this; } // this should be accepted } class C { ref C evil() { return this; } // this should be rejected } void main() { } class Base { } class Derived : Base { ref Base evil() { return super; } // should be rejected } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13120.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13120.d(13): Error: `pure` delegate `fail13120.g1.__foreachbody2` cannot call impure function `fail13120.f1` fail_compilation/fail13120.d(13): Error: `@nogc` delegate `fail13120.g1.__foreachbody2` cannot call non-@nogc function `fail13120.f1` --- */ void f1() {} void g1(char[] s) pure @nogc { foreach (dchar dc; s) f1(); } /* TEST_OUTPUT: --- fail_compilation/fail13120.d(35): Error: `pure` function `fail13120.h2` cannot call impure function `fail13120.g2!().g2` fail_compilation/fail13120.d(35): Error: `@safe` function `fail13120.h2` cannot call `@system` function `fail13120.g2!().g2` fail_compilation/fail13120.d(27): `fail13120.g2!().g2` is declared here fail_compilation/fail13120.d(35): Error: `@nogc` function `fail13120.h2` cannot call non-@nogc function `fail13120.g2!().g2` --- */ void f2() {} void g2()(char[] s) { foreach (dchar dc; s) f2(); } void h2() @safe pure @nogc { g2(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13187.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13187.d(12): Error: `pure` function `fail13187.test` cannot access mutable static data `my_func_ptr` --- */ int function(int) pure my_func_ptr; void test() pure { my_func_ptr(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail132.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail132.d(19): Error: outer class `A` `this` needed to `new` nested class `B` --- */ //import std.stdio; class A { class B { } } void main() { A.B c = new A.B; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13203.d ================================================ int v1, v2; /* TEST_OUTPUT: --- fail_compilation/fail13203.d(15): Error: alias `fail13203.FA1!1.T` conflicts with alias `fail13203.FA1!1.T` at fail_compilation/fail13203.d(14) fail_compilation/fail13203.d(22): Error: template instance `fail13203.FA1!1` error instantiating fail_compilation/fail13203.d(20): Error: alias `fail13203.FA2!1.T` conflicts with alias `fail13203.FA2!1.T` at fail_compilation/fail13203.d(19) fail_compilation/fail13203.d(23): Error: template instance `fail13203.FA2!1` error instantiating --- */ template FA1(int b) { alias T = int; static if (b) alias T = uint; } template FA2(int b) { alias T = v1; static if (b) alias T = v2; } alias A1 = FA1!1; // type is not overloadable alias A2 = FA2!1; // variable symbol is not overloadable /* TEST_OUTPUT: --- fail_compilation/fail13203.d(36): Error: alias `fail13203.FB1!1.T` conflicts with alias `fail13203.FB1!1.T` at fail_compilation/fail13203.d(37) fail_compilation/fail13203.d(44): Error: template instance `fail13203.FB1!1` error instantiating fail_compilation/fail13203.d(41): Error: alias `fail13203.FB2!1.T` conflicts with alias `fail13203.FB2!1.T` at fail_compilation/fail13203.d(42) fail_compilation/fail13203.d(45): Error: template instance `fail13203.FB2!1` error instantiating --- */ template FB1(int b) { static if (b) alias T = uint; alias T = int; } template FB2(int b) { static if (b) alias T = v2; alias T = v1; } alias B1 = FB1!1; alias B2 = FB2!1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail133.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail133.d(13): Error: function `D main` circular dependency. Functions cannot be interpreted while being compiled fail_compilation/fail133.d(15): called from here: `main()` --- */ template t(int t) { } int main() { return t!(main() + 8); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13336a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13336a.d(28): Error: `choose(true)` is not an lvalue and cannot be modified --- */ class Animal {} class Cat : Animal {} class Dog : Animal {} Animal animal; Cat cat; auto ref choose(bool f) { if (f) return cat; else return animal; } void main() { //pragma(msg, typeof(&choose)); static assert(is(typeof(&choose) == Animal function(bool) nothrow @nogc @safe)); // pass choose(true) = new Dog(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13336b.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: int sx; double sy; /* TEST_OUTPUT: --- fail_compilation/fail13336b.d(17): Error: `cast(double)sx` is not an lvalue and cannot be modified fail_compilation/fail13336b.d(25): Error: `cast(double)sx` is not an lvalue and cannot be modified --- */ ref f1(bool f) { if (f) return sx; return sy; } ref f2(bool f) { if (f) return sy; return sx; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail134.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail134.d(13): Error: template instance `foo!(f)` does not match template declaration `foo(T)` fail_compilation/fail134.d(14): Error: template instance `fail134.bar!(f)` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=651 // Assertion failure: 'global.errors' on line 2622 in file 'template.c' void f() {} template foo(T) {} template bar(T...) { alias foo!(T) buz; } alias bar!(f) a; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13424.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13424.d(12): Error: delegate `fail13424.S.__lambda2` cannot be struct members fail_compilation/fail13424.d(17): Error: delegate `fail13424.U.__lambda2` cannot be union members fail_compilation/fail13424.d(22): Error: delegate `fail13424.C.__lambda2` cannot be class members --- */ struct S { void delegate(dchar) onChar = (dchar) {}; } union U { void delegate(dchar) onChar = (dchar) {}; } class C { void delegate(dchar) onChar = (dchar) {}; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13434_m32.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/fail13434_m32.d(13): Error: cannot implicitly convert expression `()` of type `()` to `uint` --- */ alias tuple(A...) = A; void main() { float[] arr; arr[tuple!()] = 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13434_m64.d ================================================ // REQUIRED_ARGS: -m64 /* TEST_OUTPUT: --- fail_compilation/fail13434_m64.d(13): Error: cannot implicitly convert expression `()` of type `()` to `ulong` --- */ alias tuple(A...) = A; void main() { float[] arr; arr[tuple!()] = 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13435.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=13435 /* TEST_OUTPUT: --- fail_compilation/fail13435.d(22): Error: cannot implicitly convert expression `d` of type `int[]` to `S!int` fail_compilation/fail13435.d(22): `this._a = d` is the first assignment of `this._a` therefore it represents its initialization fail_compilation/fail13435.d(22): `opAssign` methods are not used for initialization, but for subsequent assignments --- */ struct S(T) { void opAssign(T[] arg) {} } class B { this(int[] d) { S!int c; _a = d; // Error: cannot implicitly convert expression (d) of type int[] to S!int c = d; // compiles OK } S!int _a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13498.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13498.d(11): Error: cannot implicitly convert expression `"foo"` of type `string` to `int` fail_compilation/fail13498.d(16): Error: template instance `fail13498.foo!()` error instantiating --- */ int foo()() { return "foo"; // should fail as well } void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13574.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13574.d(21): Error: cannot modify operator `$` fail_compilation/fail13574.d(27): Error: cannot modify operator `$` --- */ struct Foo { void opSlice(size_t a, size_t b) { } alias opDollar = length; size_t length; } void main() { Foo foo; foo[0 .. foo.length = 1]; assert(foo.length == 1); foo[0 .. $ = 2]; // assigns to the temporary dollar variable //assert(foo.length == 2); int[] arr = [1,2,3]; auto x = arr[0 .. arr.length = 1]; assert(arr.length == 1); auto y = arr[0 .. $ = 2]; // should also be disallowed //assert(arr.length == 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail136.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail136.d(11): Deprecation: Built-in hex string literals are deprecated, use `std.conv.hexString` instead. fail_compilation/fail136.d(11): Error: `"\xef\xbb\xbf"` has no effect --- */ void main() { x"EF BB BF"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13601.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13601.d(13): Error: variable `__ctfe` cannot be read at compile time fail_compilation/fail13601.d(14): Error: variable `__ctfe` cannot be read at compile time fail_compilation/fail13601.d(15): Error: variable `__ctfe` cannot be read at compile time fail_compilation/fail13601.d(16): Error: variable `__ctfe` cannot be read at compile time --- */ void test() { static if (__ctfe) {} enum a = __ctfe ? "a" : "b"; static int b = __ctfe * 2; int[__ctfe] sarr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail137.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=751 // Compiler segfault on template expansion template TypeTuple( TList... ) { alias TList TypeTuple; } template IndexOf( T, TList... ) { static if( TList.length == 0 ) const size_t IndexOf = 1; else static if( is( T == typeof( TList[0] ) ) ) const size_t IndexOf = 0; else const size_t IndexOf = 1 + IndexOf!( T, (TList[1 .. $]) ); } void main() { TypeTuple!(int, long) T; printf( "%u\n", IndexOf!(long, T) ); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13701.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13701.d(16): Error: cannot modify `immutable` expression `this.aa[10]` fail_compilation/fail13701.d(23): Error: cannot modify `immutable` expression `aa[10]` fail_compilation/fail13701.d(24): Error: cannot modify `immutable` expression `aa[10]` --- */ struct S { immutable(int)[int] aa; this(int n) { aa[10] = 20; // initializing aa[10] = 30; // assignment } } void main() { immutable(int)[int] aa; aa[10] = 20; aa[10]++; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13756.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail13756.d(11): Error: `foreach`: index must be type `const(int)`, not `int` --- */ void maiin() { int[int] aa = [1:2]; foreach (ref int k, v; aa) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13775.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail13775.d(17): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `ubyte[1]` fail_compilation/fail13775.d(18): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `ubyte[3]` fail_compilation/fail13775.d(19): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `byte[1]` fail_compilation/fail13775.d(20): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `byte[3]` --- */ void main() { ubyte[4] ubytes = [1,2,3,4]; // CT-known slicing succeeds but sizes cannot match auto ng1 = cast(ubyte[1]) ubytes[0 .. 2]; // ubyte[2] to ubyte[1] auto ng2 = cast(ubyte[3]) ubytes[0 .. 2]; // ubyte[2] to ubyte[3] auto ng3 = cast( byte[1]) ubytes[0 .. 2]; // ubyte[2] to byte[1] auto ng4 = cast( byte[3]) ubytes[0 .. 2]; // ubyte[2] to byte[3] } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail139.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail139.d(8): Error: forward reference to `test` --- */ void test(typeof(&test) p) { } void main() { test(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail13902.d ================================================ // REQUIRED_ARGS: -o- -d -m64 struct S1 { int v; } struct S2 { int* p; } class C { int v; } #line 6 /* TEST_OUTPUT: --- fail_compilation/fail13902.d(45): Error: Using the result of a comma expression is not allowed fail_compilation/fail13902.d(32): Error: returning `& x` escapes a reference to local variable `x` fail_compilation/fail13902.d(33): Error: returning `&s1.v` escapes a reference to local variable `s1` fail_compilation/fail13902.d(38): Error: returning `& sa1` escapes a reference to local variable `sa1` fail_compilation/fail13902.d(39): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(40): Error: returning `& x` escapes a reference to local variable `x` fail_compilation/fail13902.d(41): Error: returning `(& x+4)` escapes a reference to local variable `x` fail_compilation/fail13902.d(42): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x` fail_compilation/fail13902.d(45): Error: returning `& y` escapes a reference to local variable `y` --- */ int* testEscape1() { int x, y; int[] da1; int[][] da2; int[1] sa1; int[1][1] sa2; int* ptr; S1 s1; S2 s2; C c; if (0) return &x; // VarExp if (0) return &s1.v; // DotVarExp if (0) return s2.p; // no error if (0) return &c.v; // no error if (0) return &da1[0]; // no error if (0) return &da2[0][0]; // no error if (0) return &sa1[0]; // IndexExp if (0) return &sa2[0][0]; // IndexExp if (0) return &x; if (0) return &x + 1; // optimized to SymOffExp == (& x+4) if (0) return &x + x; //if (0) return ptr += &x + 1; // semantic error if (0) ptr -= &x - &y; // no error if (0) return (&x, &y); // CommaExp return null; // ok } #line 49 /* TEST_OUTPUT: --- fail_compilation/fail13902.d(88): Error: Using the result of a comma expression is not allowed fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return` fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return` fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y`, perhaps annotate with `return` --- */ int* testEscape2( int x, int y, int[] da1, int[][] da2, int[1] sa1, int[1][1] sa2, int* ptr, S1 s1, S2 s2, C c, ) { if (0) return &x; // VarExp if (0) return &s1.v; // DotVarExp if (0) return s2.p; // no error if (0) return &c.v; // no error if (0) return &da1[0]; // no error if (0) return &da2[0][0]; // no error if (0) return &sa1[0]; // IndexExp if (0) return &sa2[0][0]; // IndexExp if (0) return &x; if (0) return &x + 1; // optimized to SymOffExp == (& x+4) if (0) return &x + x; //if (0) return ptr += &x + 1; // semantic error if (0) ptr -= &x - &y; // no error if (0) return (&x, &y); // CommaExp return null; // ok } #line 92 /* TEST_OUTPUT: --- fail_compilation/fail13902.d(123): Error: Using the result of a comma expression is not allowed --- */ int* testEscape3( ref int x, ref int y, ref int[] da1, ref int[][] da2, ref int[1] sa1, ref int[1][1] sa2, ref int* ptr, ref S1 s1, ref S2 s2, ref C c, ) { if (0) return &x; // VarExp if (0) return &s1.v; // DotVarExp if (0) return s2.p; // no error if (0) return &c.v; // no error if (0) return &da1[0]; // no error if (0) return &da2[0][0]; // no error if (0) return &sa1[0]; // IndexExp if (0) return &sa2[0][0]; // IndexExp if (0) return ptr = &x; if (0) return ptr = &x + 1; // optimized to SymOffExp == (& x+4) if (0) return ptr = &x + x; //if (0) return ptr += &x + 1; // semantic error if (0) return ptr -= &x - &y; // no error if (0) return (&x, &y); // CommaExp return null; // ok } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to parameter `sa1`, perhaps annotate with `return` fail_compilation/fail13902.d(155): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(156): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(157): Error: returning `sa2[]` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(161): Error: returning `cast(int[])s.sa` escapes a reference to local variable `s` fail_compilation/fail13902.d(162): Error: returning `cast(int[])s.sa` escapes a reference to local variable `s` fail_compilation/fail13902.d(163): Error: returning `s.sa[]` escapes a reference to local variable `s` fail_compilation/fail13902.d(166): Error: escaping reference to stack allocated value returned by `makeSA()` fail_compilation/fail13902.d(167): Error: escaping reference to stack allocated value returned by `makeSA()` fail_compilation/fail13902.d(168): Error: escaping reference to stack allocated value returned by `makeSA()` fail_compilation/fail13902.d(171): Error: escaping reference to stack allocated value returned by `makeS()` fail_compilation/fail13902.d(172): Error: escaping reference to stack allocated value returned by `makeS()` fail_compilation/fail13902.d(173): Error: escaping reference to stack allocated value returned by `makeS()` --- */ int[] testEscape4(int[3] sa1) // https://issues.dlang.org/show_bug.cgi?id=9279 { if (0) return sa1; // error <- no error if (0) return cast(int[])sa1; // error <- no error if (0) return sa1[]; // error int[3] sa2; if (0) return sa2; // error if (0) return cast(int[])sa2; // error if (0) return sa2[]; // error struct S { int[3] sa; } S s; if (0) return s.sa; // error <- no error if (0) return cast(int[])s.sa; // error <- no error if (0) return s.sa[]; // error int[3] makeSA() { int[3] ret; return ret; } if (0) return makeSA(); // error <- no error if (0) return cast(int[])makeSA(); // error <- no error if (0) return makeSA()[]; // error <- no error S makeS() { S s; return s; } if (0) return makeS().sa; // error <- no error if (0) return cast(int[])makeS().sa; // error <- no error if (0) return makeS().sa[]; // error <- no error return null; } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(201): Error: returning `x` escapes a reference to local variable `x` fail_compilation/fail13902.d(202): Error: returning `s1.v` escapes a reference to local variable `s1` fail_compilation/fail13902.d(206): Error: returning `sa1[0]` escapes a reference to local variable `sa1` fail_compilation/fail13902.d(207): Error: returning `sa2[0][0]` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(208): Error: returning `x = 1` escapes a reference to local variable `x` fail_compilation/fail13902.d(209): Error: returning `x += 1` escapes a reference to local variable `x` fail_compilation/fail13902.d(210): Error: returning `s1.v = 1` escapes a reference to local variable `s1` fail_compilation/fail13902.d(211): Error: returning `s1.v += 1` escapes a reference to local variable `s1` --- */ ref int testEscapeRef1() { int x; int[] da1; int[][] da2; int[1] sa1; int[1][1] sa2; S1 s1; C c; if (0) return x; // VarExp if (0) return s1.v; // DotVarExp if (0) return c.v; // no error if (0) return da1[0]; // no error if (0) return da2[0][0]; // no error if (0) return sa1[0]; // IndexExp if (0) return sa2[0][0]; // IndexExp if (0) return x = 1; // AssignExp if (0) return x += 1; // BinAssignExp if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) static int g; return g; // ok } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return` fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to parameter `sa1`, perhaps annotate with `return` fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return` fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to parameter `x`, perhaps annotate with `return` fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to parameter `s1`, perhaps annotate with `return` fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to parameter `s1`, perhaps annotate with `return` --- */ ref int testEscapeRef2( int x, int[] da1, int[][] da2, int[1] sa1, int[1][1] sa2, S1 s1, C c, ) { if (0) return x; // VarExp if (0) return s1.v; // DotVarExp if (0) return c.v; // no error if (0) return da1[0]; // no error if (0) return da2[0][0]; // no error if (0) return sa1[0]; // IndexExp if (0) return sa2[0][0]; // IndexExp if (0) return x = 1; // AssignExp if (0) return x += 1; // BinAssignExp if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) static int g; return g; // ok } /* TEST_OUTPUT: --- --- */ ref int testEscapeRef2( ref int x, ref int[] da1, ref int[][] da2, ref int[1] sa1, ref int[1][1] sa2, ref S1 s1, ref C c, ) { if (0) return x; // VarExp if (0) return s1.v; // DotVarExp if (0) return c.v; // no error if (0) return da1[0]; // no error if (0) return da2[0][0]; // no error if (0) return sa1[0]; // IndexExp if (0) return sa2[0][0]; // IndexExp if (0) return x = 1; // AssignExp if (0) return x += 1; // BinAssignExp if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) static int g; return g; // ok } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(294): Error: returning `[& x]` escapes a reference to local variable `x` fail_compilation/fail13902.d(295): Error: returning `[& x]` escapes a reference to local variable `x` --- */ int*[] testArrayLiteral1() { int x; return [&x]; } int*[1] testArrayLiteral2() { int x; return [&x]; } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(304): Error: returning `S2(& x)` escapes a reference to local variable `x` fail_compilation/fail13902.d(305): Error: returning `new S2(& x)` escapes a reference to local variable `x` --- */ S2 testStructLiteral1() { int x; return S2(&x); } S2* testStructLiteral2() { int x; return new S2(&x); } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(314): Error: returning `sa[]` escapes a reference to local variable `sa` fail_compilation/fail13902.d(315): Error: returning `sa[cast(ulong)n..2][1..2]` escapes a reference to local variable `sa` --- */ int[] testSlice1() { int[3] sa; return sa[]; } int[] testSlice2() { int[3] sa; int n; return sa[n..2][1..2]; } /* TEST_OUTPUT: --- fail_compilation/fail13902.d(323): Error: returning `vda[0]` escapes a reference to parameter `vda`, perhaps annotate with `return` --- */ ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; } @safe int[] testDynamicArrayVariadic2(int[] vda...) { return vda[]; } int[3] testDynamicArrayVariadic3(int[] vda...) { return vda[0..3]; } // no error /* TEST_OUTPUT: --- fail_compilation/fail13902.d(334): Error: returning `vsa[0]` escapes a reference to parameter `vsa`, perhaps annotate with `return` fail_compilation/fail13902.d(335): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa` --- */ ref int testStaticArrayVariadic1(int[3] vsa...) { return vsa[0]; } int[] testStaticArrayVariadic2(int[3] vsa...) { return vsa[]; } int[3] testStaticArrayVariadic3(int[3] vsa...) { return vsa[0..3]; } // no error ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14.d ================================================ class A(T) { .A!(A) x; } void main() { A!(int); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14009.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14009.d(12): Error: expression expected not `:` --- */ void main() { version(GNU) { asm { "" : : "r" 1 ? 2 : 3; // accepted "" : : "r" 1 ? 2 : : 3; // rejected } } else { asm { mov EAX, FS: 1 ? 2 : 3; // accepted mov EAX, FS: 1 ? 2 : : 3; // rejected } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14089.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14089.d(41): Error: `1` has no effect fail_compilation/fail14089.d(41): Error: `1` has no effect fail_compilation/fail14089.d(42): Error: `1` has no effect fail_compilation/fail14089.d(42): Error: `n` has no effect fail_compilation/fail14089.d(43): Error: `1` has no effect fail_compilation/fail14089.d(43): Error: `s.val` has no effect fail_compilation/fail14089.d(44): Error: `n` has no effect fail_compilation/fail14089.d(44): Error: `1` has no effect fail_compilation/fail14089.d(45): Error: `s.val` has no effect fail_compilation/fail14089.d(45): Error: `1` has no effect --- */ bool cond; void main() { int foo() { return 0; } int n; struct S { int val; } S s; // The whole of each CondExps has side effects, So no error. cond ? foo() : n; cond ? foo() : s.val; cond ? 1 : foo(); cond ? n : foo(); cond ? s.val : foo(); cond ? (n = 1) : 1; cond ? (n = 1) : n; cond ? (n = 1) : s.val; cond ? 1 : (n = 1); cond ? n : (n = 1); cond ? s.val : (n = 1); // errors cond ? 1 : 1; cond ? 1 : n; cond ? 1 : s.val; cond ? n : 1; cond ? s.val : 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail142.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail142.d(20): Error: cannot create instance of abstract class `B` fail_compilation/fail142.d(20): function `void test()` is not implemented --- */ class A { abstract void test() {} } class B : A { } void main() { B b = new B(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14249.d ================================================ /* REQUIRED_ARGS: -unittest TEST_OUTPUT: --- fail_compilation/fail14249.d(25): Error: `shared static` constructor can only be member of module/aggregate/template, not function `main` fail_compilation/fail14249.d(26): Error: `shared static` destructor can only be member of module/aggregate/template, not function `main` fail_compilation/fail14249.d(27): Error: `static` constructor can only be member of module/aggregate/template, not function `main` fail_compilation/fail14249.d(28): Error: `static` destructor can only be member of module/aggregate/template, not function `main` fail_compilation/fail14249.d(29): Error: `unittest` can only be a member of module/aggregate/template, not function `main` fail_compilation/fail14249.d(30): Error: `invariant` can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(31): Error: alias this can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(32): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class fail_compilation/fail14249.d(32): Error: allocator can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(33): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14249.d(33): Error: deallocator can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(34): Error: constructor can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(35): Error: destructor can only be a member of aggregate, not function `main` fail_compilation/fail14249.d(36): Error: postblit can only be a member of struct, not function `main` fail_compilation/fail14249.d(37): Error: anonymous union can only be a part of an aggregate, not function `main` fail_compilation/fail14249.d(41): Error: mixin `fail14249.main.Mix!()` error instantiating --- */ mixin template Mix() { shared static this() {} shared static ~this() {} static this() {} // from fail197.d, 1510 ICE: Assertion failure: 'ad' on line 925 in file 'func.c' static ~this() {} unittest {} invariant {} alias a this; new(size_t sz) { return null; } delete(void* p) { } this() {} // from fail268.d ~this() {} // from fail268.d this(this) {} union { int x; double y; } } void main() { mixin Mix!(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail143.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail143.d(23): Error: need `this` for `next` of type `uint()` fail_compilation/fail143.d(30): Error: template instance `fail143.Foo!int` error instantiating --- */ class Quux { uint x; final uint next() { return x; } } template Foo(T) { void bar() { int r = Quux.next; } } int main(char[][] args) { auto prng = new Quux(); alias Foo!(int).bar baz; int x = prng.next; baz(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14304.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14304.d(26): Error: cannot modify read-only constant `S14304(1)` fail_compilation/fail14304.d(58): called from here: `sle14304.modify()` fail_compilation/fail14304.d(35): Error: cannot modify read-only constant `[1:1, 2:2]` fail_compilation/fail14304.d(61): called from here: `modify14304(aae14304)` fail_compilation/fail14304.d(41): Error: cannot modify read-only constant `[1, 2, 3]` fail_compilation/fail14304.d(64): called from here: `modify14304(cast(const(int)[])index14304)` fail_compilation/fail14304.d(47): Error: cannot modify read-only constant `[1.414, 1.732, 2.00000]` fail_compilation/fail14304.d(67): called from here: `modify14304(cast(const(double)[])slice14304)` fail_compilation/fail14304.d(53): Error: cannot modify read-only string literal `"abc"` fail_compilation/fail14304.d(70): called from here: `modify14304(cast(const(char)[])str14304)` --- */ struct S14304 { int x; int modify() const { assert(x == 1); // This force modification must not affect to ghe s14304 value. (cast(S14304*)&this).x = 10; assert(x == 10); return x; } } int modify14304(immutable int[int] aa) { auto p = cast(int*)&aa[1]; *p = 10; return aa[1]; } int modify14304(const(int)[] arr) { auto a = cast(int[])arr; a[0] = 10; return arr[0]; } int modify14304(const(double)[] arr) { auto a = cast(double[])arr; a[] = 3.14; return cast(int)arr[0]; } int modify14304(const(char)[] str) { auto s = cast(char[])str; s[0] = 'z'; return str[0]; } static immutable sle14304 = immutable S14304(1); static immutable v14304 = sle14304.modify(); static immutable aae14304 = [1:1, 2:2]; static immutable w14304 = modify14304(aae14304); static immutable index14304 = [1, 2, 3]; static immutable x14304 = modify14304(index14304); static immutable slice14304 = [1.414, 1.732, 2]; static immutable y14304 = modify14304(slice14304); static immutable str14304 = "abc"; static immutable z14304 = modify14304(str14304); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail144.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail144.d(13): Error: `"message"` fail_compilation/fail144.d(26): called from here: `bar(7)` --- */ //import core.stdc.stdio : printf; int bar(int i) { assert(i < 0, "message"); foreach_reverse (k, v; "hello") { i <<= 1; if (k == 2) break; i += v; } return i; } void main() { static b = bar(7); auto c = bar(7); //printf("b = %d, %d\n", b, c); assert(b == 674); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14406.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14406.d-mixin-20(20): Error: variable `fail14406.CFrop.bar_obj` cannot be further field because it will change the determined CFrop size fail_compilation/fail14406.d-mixin-25(25): Error: variable `fail14406.IFrop.bar_obj` field not allowed in interface --- */ class Foo {} string strMixin(T)() { static if (T.tupleof.length) {} return "Bar bar_obj; static class Bar { Foo foo; }"; } class CFrop { mixin(strMixin!(typeof(this))); } interface IFrop { mixin(strMixin!(typeof(this))); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14407.d ================================================ import imports.a14407; /* TEST_OUTPUT: --- fail_compilation/fail14407.d(23): Deprecation: class `imports.a14407.C` is deprecated fail_compilation/fail14407.d(23): Deprecation: allocator `imports.a14407.C.new` is deprecated fail_compilation/fail14407.d(23): Error: `pure` function `fail14407.testC` cannot call impure allocator `imports.a14407.C.new` fail_compilation/fail14407.d(23): Error: `@safe` function `fail14407.testC` cannot call `@system` allocator `imports.a14407.C.new` fail_compilation/imports/a14407.d(5): `imports.a14407.C.new` is declared here fail_compilation/fail14407.d(23): Error: `@nogc` function `fail14407.testC` cannot call non-@nogc allocator `imports.a14407.C.new` fail_compilation/fail14407.d(23): Error: class `imports.a14407.C` member `new` is not accessible fail_compilation/fail14407.d(23): Error: `pure` function `fail14407.testC` cannot call impure constructor `imports.a14407.C.this` fail_compilation/fail14407.d(23): Error: `@safe` function `fail14407.testC` cannot call `@system` constructor `imports.a14407.C.this` fail_compilation/imports/a14407.d(9): `imports.a14407.C.this` is declared here fail_compilation/fail14407.d(23): Error: `@nogc` function `fail14407.testC` cannot call non-@nogc constructor `imports.a14407.C.this` fail_compilation/fail14407.d(23): Error: class `imports.a14407.C` member `this` is not accessible fail_compilation/fail14407.d(23): Error: allocator `imports.a14407.C.new` is not `nothrow` --- */ void testC() pure nothrow @safe @nogc { new("arg") C(0); } /* TEST_OUTPUT: --- fail_compilation/fail14407.d(23): Error: constructor `imports.a14407.C.this` is not `nothrow` fail_compilation/fail14407.d(21): Error: `nothrow` function `fail14407.testC` may throw fail_compilation/fail14407.d(50): Deprecation: struct `imports.a14407.S` is deprecated fail_compilation/fail14407.d(50): Deprecation: allocator `imports.a14407.S.new` is deprecated fail_compilation/fail14407.d(50): Error: `pure` function `fail14407.testS` cannot call impure allocator `imports.a14407.S.new` fail_compilation/fail14407.d(50): Error: `@safe` function `fail14407.testS` cannot call `@system` allocator `imports.a14407.S.new` fail_compilation/imports/a14407.d(14): `imports.a14407.S.new` is declared here fail_compilation/fail14407.d(50): Error: `@nogc` function `fail14407.testS` cannot call non-@nogc allocator `imports.a14407.S.new` fail_compilation/fail14407.d(50): Error: struct `imports.a14407.S` member `new` is not accessible fail_compilation/fail14407.d(50): Error: `pure` function `fail14407.testS` cannot call impure constructor `imports.a14407.S.this` fail_compilation/fail14407.d(50): Error: `@safe` function `fail14407.testS` cannot call `@system` constructor `imports.a14407.S.this` fail_compilation/imports/a14407.d(18): `imports.a14407.S.this` is declared here fail_compilation/fail14407.d(50): Error: `@nogc` function `fail14407.testS` cannot call non-@nogc constructor `imports.a14407.S.this` fail_compilation/fail14407.d(50): Error: struct `imports.a14407.S` member `this` is not accessible fail_compilation/fail14407.d(50): Error: allocator `imports.a14407.S.new` is not `nothrow` fail_compilation/fail14407.d(50): Error: constructor `imports.a14407.S.this` is not `nothrow` fail_compilation/fail14407.d(48): Error: `nothrow` function `fail14407.testS` may throw --- */ void testS() pure nothrow @safe @nogc { new("arg") S(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14416.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14416.d(13): Error: template `S(T)` does not have property `sizeof` --- */ struct S(T) { int x; } enum n = S.sizeof; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14486.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail14486.d(102): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(103): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(104): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(108): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(109): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(110): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(114): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(115): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(116): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(120): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(121): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(122): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail14486.d(126): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(126): Error: `delete c0` is not `@safe` but is used in `@safe` function `test1a` fail_compilation/fail14486.d(127): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(127): Error: `pure` function `fail14486.test1a` cannot call impure destructor `fail14486.C1a.~this` fail_compilation/fail14486.d(127): Error: `@safe` function `fail14486.test1a` cannot call `@system` destructor `fail14486.C1a.~this` fail_compilation/fail14486.d(101): `fail14486.C1a.~this` is declared here fail_compilation/fail14486.d(127): Error: `@nogc` function `fail14486.test1a` cannot call non-@nogc destructor `fail14486.C1a.~this` fail_compilation/fail14486.d(128): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(128): Error: `pure` function `fail14486.test1a` cannot call impure destructor `fail14486.C2a.~this` fail_compilation/fail14486.d(128): Error: `@safe` function `fail14486.test1a` cannot call `@system` destructor `fail14486.C2a.~this` fail_compilation/fail14486.d(102): `fail14486.C2a.~this` is declared here fail_compilation/fail14486.d(128): Error: `@nogc` function `fail14486.test1a` cannot call non-@nogc destructor `fail14486.C2a.~this` fail_compilation/fail14486.d(129): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(129): Error: `pure` function `fail14486.test1a` cannot call impure deallocator `fail14486.C3a.delete` fail_compilation/fail14486.d(129): Error: `@safe` function `fail14486.test1a` cannot call `@system` deallocator `fail14486.C3a.delete` fail_compilation/fail14486.d(103): `fail14486.C3a.delete` is declared here fail_compilation/fail14486.d(129): Error: `@nogc` function `fail14486.test1a` cannot call non-@nogc deallocator `fail14486.C3a.delete` fail_compilation/fail14486.d(130): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(130): Error: `delete c4` is not `@safe` but is used in `@safe` function `test1a` fail_compilation/fail14486.d(135): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(136): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(137): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(138): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(139): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(136): Error: destructor `fail14486.C1b.~this` is not `nothrow` fail_compilation/fail14486.d(137): Error: destructor `fail14486.C2b.~this` is not `nothrow` fail_compilation/fail14486.d(138): Error: deallocator `fail14486.C3b.delete` is not `nothrow` fail_compilation/fail14486.d(133): Error: `nothrow` function `fail14486.test1b` may throw fail_compilation/fail14486.d(144): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(144): Error: `delete s0` is not `@safe` but is used in `@safe` function `test2a` fail_compilation/fail14486.d(145): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(145): Error: `pure` function `fail14486.test2a` cannot call impure destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(145): Error: `@safe` function `fail14486.test2a` cannot call `@system` destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(113): `fail14486.S1a.~this` is declared here fail_compilation/fail14486.d(145): Error: `@nogc` function `fail14486.test2a` cannot call non-@nogc destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(146): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(146): Error: `pure` function `fail14486.test2a` cannot call impure destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(146): Error: `@safe` function `fail14486.test2a` cannot call `@system` destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(114): `fail14486.S2a.~this` is declared here fail_compilation/fail14486.d(146): Error: `@nogc` function `fail14486.test2a` cannot call non-@nogc destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(147): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(147): Error: `pure` function `fail14486.test2a` cannot call impure deallocator `fail14486.S3a.delete` fail_compilation/fail14486.d(147): Error: `@safe` function `fail14486.test2a` cannot call `@system` deallocator `fail14486.S3a.delete` fail_compilation/fail14486.d(115): `fail14486.S3a.delete` is declared here fail_compilation/fail14486.d(147): Error: `@nogc` function `fail14486.test2a` cannot call non-@nogc deallocator `fail14486.S3a.delete` fail_compilation/fail14486.d(148): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(153): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(154): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(155): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(156): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(157): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(154): Error: destructor `fail14486.S1b.~this` is not `nothrow` fail_compilation/fail14486.d(155): Error: destructor `fail14486.S2b.~this` is not `nothrow` fail_compilation/fail14486.d(156): Error: deallocator `fail14486.S3b.delete` is not `nothrow` fail_compilation/fail14486.d(151): Error: `nothrow` function `fail14486.test2b` may throw fail_compilation/fail14486.d(162): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(162): Error: `delete a0` is not `@safe` but is used in `@safe` function `test3a` fail_compilation/fail14486.d(163): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(163): Error: `pure` function `fail14486.test3a` cannot call impure destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(163): Error: `@safe` function `fail14486.test3a` cannot call `@system` destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(113): `fail14486.S1a.~this` is declared here fail_compilation/fail14486.d(163): Error: `@nogc` function `fail14486.test3a` cannot call non-@nogc destructor `fail14486.S1a.~this` fail_compilation/fail14486.d(164): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(164): Error: `pure` function `fail14486.test3a` cannot call impure destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(164): Error: `@safe` function `fail14486.test3a` cannot call `@system` destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(114): `fail14486.S2a.~this` is declared here fail_compilation/fail14486.d(164): Error: `@nogc` function `fail14486.test3a` cannot call non-@nogc destructor `fail14486.S2a.~this` fail_compilation/fail14486.d(165): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(165): Error: `delete a3` is not `@safe` but is used in `@safe` function `test3a` fail_compilation/fail14486.d(166): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(166): Error: `delete a4` is not `@safe` but is used in `@safe` function `test3a` fail_compilation/fail14486.d(171): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(172): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(173): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(174): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(175): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail14486.d(172): Error: destructor `fail14486.S1b.~this` is not `nothrow` fail_compilation/fail14486.d(173): Error: destructor `fail14486.S2b.~this` is not `nothrow` fail_compilation/fail14486.d(169): Error: `nothrow` function `fail14486.test3b` may throw --- */ class C0a { } class C1a { ~this() {} } class C2a { ~this() {} @nogc pure @safe delete(void* p) {} } class C3a { @nogc pure @safe ~this() {} delete(void* p) {} } class C4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} } class C0b { } class C1b { ~this() {} } class C2b { ~this() {} nothrow delete(void* p) {} } class C3b { nothrow ~this() {} delete(void* p) {} } class C4b { nothrow ~this() {} nothrow delete(void* p) {} } struct S0a { } struct S1a { ~this() {} } struct S2a { ~this() {} @nogc pure @safe delete(void* p) {} } struct S3a { @nogc pure @safe ~this() {} delete(void* p) {} } struct S4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} } struct S0b { } struct S1b { ~this() {} } struct S2b { ~this() {} nothrow delete(void* p) {} } struct S3b { nothrow ~this() {} delete(void* p) {} } struct S4b { nothrow ~this() {} nothrow delete(void* p) {} } void test1a() @nogc pure @safe { C0a c0; delete c0; // error C1a c1; delete c1; // error C2a c2; delete c2; // error C3a c3; delete c3; // error C4a c4; delete c4; // no error } void test1b() nothrow { C0b c0; delete c0; // no error C1b c1; delete c1; // error C2b c2; delete c2; // error C3b c3; delete c3; // error C4b c4; delete c4; // no error } void test2a() @nogc pure @safe { S0a* s0; delete s0; // error S1a* s1; delete s1; // error S2a* s2; delete s2; // error S3a* s3; delete s3; // error S4a* s4; delete s4; // no error } void test2b() nothrow { S0b* s0; delete s0; // no error S1b* s1; delete s1; // error S2b* s2; delete s2; // error S3b* s3; delete s3; // error S4b* s4; delete s4; // no error } void test3a() @nogc pure @safe { S0a[] a0; delete a0; // error S1a[] a1; delete a1; // error S2a[] a2; delete a2; // error S3a[] a3; delete a3; // error S4a[] a4; delete a4; // error } void test3b() nothrow { S0b[] a0; delete a0; // no error S1b[] a1; delete a1; // error S2b[] a2; delete a2; // error S3b[] a3; delete a3; // no error S4b[] a4; delete a4; // no error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail145.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail145.d(13): Error: `assert(i < 0)` failed fail_compilation/fail145.d(26): called from here: `bar(7)` --- */ //import core.stdc.stdio : printf; int bar(int i) { assert(i < 0); foreach_reverse (k, v; "hello") { i <<= 1; if (k == 2) break; i += v; } return i; } void main() { static b = bar(7); auto c = bar(7); //printf("b = %d, %d\n", b, c); assert(b == 674); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14554.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail14554.d(28): Error: `fail14554.issue14554_1.foo` called with argument types `(int)` matches both: fail_compilation/fail14554.d(17): `fail14554.issue14554_1.foo!bool.foo(int j)` and: fail_compilation/fail14554.d(18): `fail14554.issue14554_1.foo!bool.foo(int j)` fail_compilation/fail14554.d(29): Error: `fail14554.issue14554_2.foo` called with argument types `(int)` matches both: fail_compilation/fail14554.d(22): `fail14554.issue14554_2.foo!bool.foo(int j)` and: fail_compilation/fail14554.d(23): `fail14554.issue14554_2.foo!bool.foo(int j)` --- */ struct issue14554_1 { void foo(T)(int j) {} static void foo(T)(int j) {} } struct issue14554_2 { static void foo(T)(int j) {} void foo(T)(int j) {} } void test14554() { issue14554_1.foo!bool(1); issue14554_2.foo!bool(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14669.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/fail14669.d(12): `fail14669.foo2()(auto int a)` --- */ void foo1()(auto int a) {} void foo2()(auto int a) {} void test1() { alias f1 = foo1!(); foo2(1); } /* TEST_OUTPUT: --- fail_compilation/fail14669.d(29): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(38): Error: template instance `fail14669.bar1!int` error instantiating fail_compilation/fail14669.d(30): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(40): Error: template instance `fail14669.bar2!int` error instantiating --- */ void bar1(T)(auto ref T x) {} void bar2(T)(auto ref T x) {} void test2() { int n; bar1(1); bar1(n); alias b1 = bar1!(int); alias b2 = bar2!(int); bar2(n); bar2(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14965.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail14965.d(19): Error: forward reference to inferred return type of function `foo1` fail_compilation/fail14965.d(20): Error: forward reference to inferred return type of function `foo2` fail_compilation/fail14965.d(22): Error: forward reference to inferred return type of function `bar1` fail_compilation/fail14965.d(23): Error: forward reference to inferred return type of function `bar2` fail_compilation/fail14965.d(25): Error: forward reference to inferred return type of function `baz1` fail_compilation/fail14965.d(26): Error: forward reference to inferred return type of function `baz2` fail_compilation/fail14965.d(30): Error: forward reference to inferred return type of function `foo1` fail_compilation/fail14965.d(31): Error: forward reference to inferred return type of function `foo2` fail_compilation/fail14965.d(33): Error: forward reference to inferred return type of function `bar1` fail_compilation/fail14965.d(34): Error: forward reference to inferred return type of function `bar2` fail_compilation/fail14965.d(36): Error: forward reference to inferred return type of function `baz1` fail_compilation/fail14965.d(37): Error: forward reference to inferred return type of function `baz2` --- */ auto foo1() { alias F = typeof(foo1); } // TypeTypeof auto foo2() { alias FP = typeof(&foo2); } // TypeTypeof auto bar1() { auto fp = &bar1; } // ExpInitializer auto bar2() { auto fp = cast(void function())&bar2; } // castTo auto baz1() { return &baz1; } // ReturnStatement auto baz2() { (&baz2); } // ExpStatement class C { auto foo1() { alias F = typeof(this.foo1); } auto foo2() { alias FP = typeof(&this.foo2); } auto bar1() { auto fp = &this.bar1; } auto bar2() { auto dg = cast(void delegate())&this.bar2; } auto baz1() { return &baz1; } auto baz2() { (&baz2); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail14997.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=14997 /* TEST_OUTPUT: --- fail_compilation/fail14997.d(19): Error: none of the overloads of `this` are callable using argument types `()`, candidates are: fail_compilation/fail14997.d(14): `fail14997.Foo.this(int a)` fail_compilation/fail14997.d(15): `fail14997.Foo.this(string a)` --- */ class Foo { this (int a) {} this (string a) {} } void main() { auto a = new Foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15.d ================================================ /* Segfault on DMD 0.095 http://www.digitalmars.com/d/archives/digitalmars/D/bugs/926.html */ module test; template Test() { bool opIndex(bool x) { return !x; } } void main() { mixin Test!() xs; bool x = xs[false]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail150.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail150.d(22): Error: `.new` is only for allocating nested classes --- */ //import std.stdio; class Class1 { } class Foo { } int main(char[][] argv) { Class1 myclass = new Class1; myclass.new Foo(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15044.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15044.d(30): Error: generated function `fail15044.V.opAssign` cannot be used because it is annotated with `@disable` --- */ struct S { void opAssign(S) {} } struct V { // `s` has opAssign, so struct V needs to generate member-wise opAssign. // But S.opAssign is not callable on const object, so V.opAssign should be // @disable. const S s; // Here, the initializer of x is evaluated in V.semantic2. But // V.opAssign.semantic3 is not yet invoked, so its attribute should be // lazily inferred in functionSemantic even though it's non-instantiated function. enum int x = () { // Here, the initializer of x is evaluated in V.semantic2, and // V.opAssign.semantic3 is not yet invoked in this time. // Therefore its @disable attribute needs to be inferred by // functionSemantic, even though it's non-instantiated function. V v; v = v; }(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15068.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15068.d(17): Error: `T!int` is not a valid template instance, because `T` is not a template declaration but a type (`T == int`) fail_compilation/fail15068.d(13): Error: template instance `fail15068.Stuff!int` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=15068 void main() { Stuff!int s; } struct Stuff(T) { T!int var; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15089.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `130` of type `int` to `byte` --- */ enum Pieces {Rook = 2} /* line 1 */ immutable int color = 0b10000000; byte piece = Pieces.Rook ^ color; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail152.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail152.d(15): Error: cannot use type `double` as an operand --- */ // https://issues.dlang.org/show_bug.cgi?id=1028 // Segfault using tuple inside asm code. void a(X...)(X expr) { alias X[0] var1; version(GNU) { asm { "" : "=m" (X[0]); "" : "=m" (var1); } } else { asm { //fld double ptr X[0]; // (1) segfaults fstp double ptr var1; // (2) ICE } } } void main() { a(3.6); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15292.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail15292.d(27): Error: cannot compare `S15292` because its auto generated member-wise equality has recursive definition --- */ struct NullableRef15292(T) { inout(T) get() inout { assert(false); } alias get this; } struct S15292 { NullableRef15292!S15292 n; } void main() { S15292 s; assert(s == s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail153.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail153.d(10): Error: class `fail153.Bar` cannot inherit from class `Foo` because it is `final` --- */ final class Foo { } class Bar : Foo { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail154.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail154.d(18): Error: template instance `X!(MYP!int)` does not match template declaration `X(T : Policy!T, alias Policy)` --- */ class X(T:Policy!(T), alias Policy) { mixin Policy!(T); } template MYP(T) { void foo(T); } X!(MYP!(int)) x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail155.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail155.d(19): Error: overlapping initialization for `y` --- */ struct S { int i; union { int x; int y; } int j; } S s = S( 1, 2, 3, 4 ); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15535.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15535.d(17): Error: `goto default` not allowed in `final switch` statement --- */ void test() { int i; switch (i) { case 0: final switch (i) { case 1: goto default; } default: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15550.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15550.d(25): Error: partial template instance `foo!int` has no type fail_compilation/fail15550.d(26): Error: partial template instance `opDispatch!"_isMatrix"` has no type fail_compilation/fail15550.d(27): Error: partial template instance `baz!"_isMatrix"` has no type --- */ T foo(T, T2)(T2) { } struct Vector { void opDispatch(string, U)(U) { } void baz(string, U)(U) { } } alias T1 = typeof(foo!int); alias T2 = typeof(Vector._isMatrix); alias T3 = typeof(Vector.baz!"_isMatrix"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail156.d ================================================ // REQUIRED_ARGS: -d /* TEST_OUTPUT: --- fail_compilation/fail156.d(33): Error: overlapping initialization for `y` fail_compilation/fail156.d(40): Error: overlapping initialization for `y` --- */ alias int myint; struct S { int i; union { int x = 2; int y; } int j = 3; myint k = 4; } void main() { S s = S( 1, 5 ); assert(s.i == 1); assert(s.x == 5); assert(s.y == 5); assert(s.j == 3); assert(s.k == 4); static S t = S( 1, 6, 6 ); assert(t.i == 1); assert(t.x == 6); assert(t.y == 6); assert(t.j == 3); assert(t.k == 4); S u = S( 1, 5, 6 ); assert(u.i == 1); assert(u.x == 5); assert(u.y == 5); assert(u.j == 3); assert(u.k == 4); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15616a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15616a.d(41): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are: fail_compilation/fail15616a.d(14): `fail15616a.foo(int a)` fail_compilation/fail15616a.d(17): `fail15616a.foo(int a, int b)` fail_compilation/fail15616a.d(26): `fail15616a.foo(int a, int b, int c)` fail_compilation/fail15616a.d(29): `fail15616a.foo(string a)` fail_compilation/fail15616a.d(32): `fail15616a.foo(string a, string b)` fail_compilation/fail15616a.d(41): ... (3 more, -v to show) ... --- */ void foo(int a) {} void foo(int a, int b) {} void foo(T)(T a) if (is(T == float)) {} void foo(T)(T a) if (is(T == char)) {} void foo(int a, int b, int c) {} void foo(string a) {} void foo(string a, string b) {} void foo(string a, string b, string c) {} void main() { foo(3.14); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15616b.d ================================================ /* REQUIRED_ARGS: -v --- fail_compilation/fail15616b.d(43): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are: fail_compilation/fail15616b.d(16): `fail15616b.foo(int a)` fail_compilation/fail15616b.d(19): `fail15616b.foo(int a, int b)` fail_compilation/fail15616b.d(28): `fail15616b.foo(int a, int b, int c)` fail_compilation/fail15616b.d(31): `fail15616b.foo(string a)` fail_compilation/fail15616b.d(34): `fail15616b.foo(string a, string b)` fail_compilation/fail15616b.d(37): `fail15616b.foo(string a, string b, string c)` fail_compilation/fail15616b.d(22): `fail15616b.foo(T)(T a) if (is(T == float))` fail_compilation/fail15616b.d(25): `fail15616b.foo(T)(T a) if (is(T == char))` --- */ void foo(int a) {} void foo(int a, int b) {} void foo(T)(T a) if (is(T == float)) {} void foo(T)(T a) if (is(T == char)) {} void foo(int a, int b, int c) {} void foo(string a) {} void foo(string a, string b) {} void foo(string a, string b, string c) {} void main() { foo(3.14); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15626.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15626.d(12): Error: class `fail15626.D` C++ base class `C` needs at least one virtual function --- */ extern (C++) { class C { } interface I { void f(); } class D : C, I { void f() { } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15667.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/imports/a15667.d(16): Error: basic type expected, not `;` fail_compilation/imports/a15667.d(19): Error: declaration expected following attribute, not end of file --- */ void main() { import imports.a15667; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15691.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15691.d(15): Error: `c` is not a member of `Foo` fail_compilation/fail15691.d(20): Error: `bc` is not a member of `Foo`, did you mean variable `abc`? --- */ struct Foo { int a; int abc; } void main() { Foo z = { // line 13 a: 3, c: 4, // line 15 }; Foo z2 = { // line 18 a: 3, bc: 4, // line 20 }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15755.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail15755.d(28): Error: `tuple(123)` has no effect --- */ // https://issues.dlang.org/show_bug.cgi?id=15755 struct Foo { @(123) int a; } template Attributes(As...) { alias Attributes = As; } template getattribute(alias member, alias attrs = Attributes!(__traits(getAttributes, member))) { alias getattribute = attrs; } void main() { getattribute!(__traits(getMember, Foo, "a")); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail158.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail158.d(17): Error: more initializers than fields (2) of `S` --- */ struct S { int i; int j = 3; } void main() { S s = S( 1, 5, 6 ); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail15896.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail15896.d(11): Deprecation: module `imports.imp15896` member `thebar` is not visible from module `fail15896` fail_compilation/fail15896.d(11): Deprecation: module `imports.imp15896` member `packagebar` is not visible from module `fail15896` --- */ import imports.imp15896 : thebar, packagebar; int func() { thebar +=1; packagebar += 1; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail159.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail159.d(24): Error: static assert: `foo(S(1, 5), S(1, 4)) == 0` is false --- */ struct S { int i; int j = 3; int opEquals(S e2) { return 1; } } int foo(S s1, S s2) { return s1 == s2; } void main() { static assert(foo( S(1,5), S(1,5) ) == 1); static assert(foo( S(1,5), S(1,4) ) == 0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail16.d ================================================ // ICE(template.c) in DMD0.080 int i; template bar(T) { void bar(int x) {} } template foo(alias X) { bar!(typeof(X))(X); } void main() { foo!(i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail160.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail160.d(22): Error: `typeid(fail160.Foo).vtbl` is not yet implemented at compile time --- */ interface Foo { void work(); } template Wrapper(B, alias Func, int func) { alias typeof(&Func) FuncPtr; private static FuncPtr get_funcptr() { return func; } } int main(char[][] args) { auto x = new Wrapper!(Foo, Foo.work, cast(int)(Foo.classinfo.vtbl[0]))(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail161.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail161.d(15): Error: template instance `MetaString!"2 == 1"` does not match template declaration `MetaString(String)` --- */ template MetaString(String) { alias String Value; } void main() { alias MetaString!("2 == 1") S; assert(mixin(S.Value)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail162.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail162.d(25): Error: template `fail162.testHelper` cannot deduce function from argument types `!()(string, string)`, candidates are: fail_compilation/fail162.d(10): `fail162.testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- */ template testHelper(A ...) { char[] testHelper() { char[] result; foreach (t; a) { result ~= "int " ~ t ~ ";\r\n"; } return result; } } template test(A...) { const char[] test = testHelper(A); } int main(char[][] args) { mixin(test!("hello", "world")); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail16206a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail16206a.d(14): Error: `bool` expected as third argument of `__traits(getOverloads)`, not `"Not a bool"` of type `string` --- */ struct S { static int foo()() { return 0; } } alias AliasSeq(T...) = T; alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", "Not a bool")); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail16206b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail16206b.d(14): Error: expected 2 arguments for `hasMember` but had 3 --- */ struct S { static int foo()() { return 0; } } alias AliasSeq(T...) = T; alias allFoos = AliasSeq!(__traits(hasMember, S, "foo", true)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail163.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail163.d(11): Error: cannot implicitly convert expression `q` of type `const(char)[]` to `char[]` --- */ void test1() { char[] p; const(char)[] q; p = q; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(24): Error: cannot implicitly convert expression `p` of type `const(int***)` to `const(int)***` --- */ void test2() { const int*** p; const(int)*** cp; cp = p; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(37): Error: cannot modify `const` expression `p` --- */ void test3() { const(uint***) p; const(int)*** cp; p = cp; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(50): Error: cannot implicitly convert expression `cp` of type `const(int)***[]` to `const(uint***)[]` --- */ void test4() { const(uint***)[] p; const(int)***[] cp; p = cp; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(63): Error: cannot modify `const` expression `*p` --- */ void test5() { int x; const(int)* p = &x; *p = 3; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(76): Error: cannot implicitly convert expression `& x` of type `int*` to `immutable(int)*` fail_compilation/fail163.d(77): Error: cannot modify `immutable` expression `*p` --- */ void test6() { int x; immutable(int)* p = &x; *p = 3; } /* TEST_OUTPUT: --- fail_compilation/fail163.d(89): Error: cannot implicitly convert expression `& x` of type `const(int)*` to `int*` --- */ void test7() { const(int) x = 3; int* p = &x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail16600.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches both: fail_compilation/fail16600.d(16): `fail16600.S.this(string _param_0)` and: fail_compilation/fail16600.d(17): `fail16600.S.this(string _param_0) immutable` --- */ // https://issues.dlang.org/show_bug.cgi?id=16600 struct S { int i; this(string) { i = 1; } this(string) immutable { i = 2; } } void main() { auto a = const(S)("abc"); assert(a.i == 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail169.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail169.d(8): Error: cannot have `const out` parameter of type `const(int)` --- */ void foo(const out int x) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail16997.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, use '-transition=intpromote' switch or `~cast(int)(c)` fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, use '-transition=intpromote' switch or `-cast(int)(c)` fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, use '-transition=intpromote' switch or `+cast(int)(c)` fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, use '-transition=intpromote' switch or `~cast(int)(w)` fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, use '-transition=intpromote' switch or `-cast(int)(w)` fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, use '-transition=intpromote' switch or `+cast(int)(w)` fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, use '-transition=intpromote' switch or `~cast(int)(sb)` fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, use '-transition=intpromote' switch or `-cast(int)(sb)` fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, use '-transition=intpromote' switch or `+cast(int)(sb)` fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, use '-transition=intpromote' switch or `~cast(int)(ub)` fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, use '-transition=intpromote' switch or `-cast(int)(ub)` fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, use '-transition=intpromote' switch or `+cast(int)(ub)` fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, use '-transition=intpromote' switch or `~cast(int)(s)` fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, use '-transition=intpromote' switch or `-cast(int)(s)` fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, use '-transition=intpromote' switch or `+cast(int)(s)` fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, use '-transition=intpromote' switch or `~cast(int)(us)` fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, use '-transition=intpromote' switch or `-cast(int)(us)` fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, use '-transition=intpromote' switch or `+cast(int)(us)` --- */ void test() { int x; char c; x = ~c; x = -c; x = +c; wchar w; x = ~w; x = -w; x = +w; byte sb; x = ~sb; x = -sb; x = +sb; ubyte ub; x = ~ub; x = -ub; x = +ub; short s; x = ~s; x = -s; x = +s; ushort us; x = ~us; x = -us; x = +us; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17.d ================================================ struct A(T) { mixin B!(T, A!(T)); } A!(int) x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail170.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail170.d(8): Error: variable `fail170.foo.x` cannot be `final`, perhaps you meant `const`? --- */ void foo(final out int x) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail172.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail172.d(25): Error: cannot modify `const` expression `c1.x` fail_compilation/fail172.d(26): Error: cannot modify `const` expression `c2.x` fail_compilation/fail172.d(30): Error: cannot modify `const` expression `s1.x` fail_compilation/fail172.d(31): Error: cannot modify `const` expression `s2.x` --- */ class C { int x; } struct S { int x; } void main() { const(C) c1 = new C(); const C c2 = new C(); c1.x = 3; c2.x = 3; const(S) s1; const S s2; s1.x = 3; s2.x = 3; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17275.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17275.d(12): Error: undefined identifier `ModuleGroup`, did you mean function `moduleGroup`? fail_compilation/fail17275.d(12): Error: `inout` on `return` means `inout` must be on a parameter as well for `inout(ModuleGroup)()` --- */ // https://issues.dlang.org/show_bug.cgi?id=17275 struct DSO { inout(ModuleGroup) moduleGroup() { } } struct ThreadDSO { DSO* _pdso; void[] _tlsRange; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17354.d ================================================ /* REQUIRED_ARGS: -de * TEST_OUTPUT: --- fail_compilation/fail17354.d(13): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Foo.opEquals`; add `override` attribute fail_compilation/fail17354.d(18): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Bar.opEquals`; add `override` attribute --- */ // https://issues.dlang.org/show_bug.cgi?id=17354 final class Foo { bool opEquals(const Object) const {return true;} } class Bar { bool opEquals(const Object) const {return true;} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17382.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17382.d(9): Error: Cannot pass argument `main()` to `pragma msg` because it is `void` --- */ void main() {} pragma(msg, main()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17419.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17419 /* TEST_OUTPUT: --- fail_compilation/fail17419.d(10): Error: argument to `__traits(getLinkage, 64)` is not a declaration fail_compilation/fail17419.d(11): Error: expected 1 arguments for `getLinkage` but had 2 --- */ enum s = __traits(getLinkage, 8 * 8); enum t = __traits(getLinkage, 8, 8); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17421.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17421.d(14): Error: argument to `__traits(getFunctionVariadicStyle, 1)` is not a function fail_compilation/fail17421.d(14): while evaluating: `static assert(__traits(getFunctionVariadicStyle, 1) == "none")` fail_compilation/fail17421.d(15): Error: argument to `__traits(getFunctionVariadicStyle, int*)` is not a function fail_compilation/fail17421.d(15): while evaluating: `static assert(__traits(getFunctionVariadicStyle, int*) == "none")` --- */ // https://issues.dlang.org/show_bug.cgi?id=17421 alias int* x; static assert(__traits(getFunctionVariadicStyle, 1) == "none"); static assert(__traits(getFunctionVariadicStyle, x) == "none"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17491.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17491.d(24): Error: `(S17491).init` is not an lvalue and cannot be modified fail_compilation/fail17491.d(25): Error: `S17491(0)` is not an lvalue and cannot be modified fail_compilation/fail17491.d(27): Error: cannot modify constant `S17491(0).field` fail_compilation/fail17491.d(28): Error: cannot modify constant `*&S17491(0).field` fail_compilation/fail17491.d(33): Error: `S17491(0)` is not an lvalue and cannot be modified fail_compilation/fail17491.d(34): Error: `S17491(0)` is not an lvalue and cannot be modified fail_compilation/fail17491.d(36): Error: cannot modify constant `S17491(0).field` fail_compilation/fail17491.d(37): Error: cannot modify constant `*&S17491(0).field` --- */ // https://issues.dlang.org/show_bug.cgi?id=17491 struct S17491 { int field; static int var; } void test17491() { S17491.init = S17491(42); // NG *&S17491.init = S17491(42); // NG S17491.init.field = 42; // NG *&S17491.init.field = 42; // Should be NG S17491.init.var = 42; // OK *&S17491.init.var = 42; // OK S17491(0) = S17491(42); // NG *&S17491(0) = S17491(42); // NG S17491(0).field = 42; // NG *&S17491(0).field = 42; // Should be NG S17491(0).var = 42; // OK *&S17491(0).var = 42; // OK } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17492.d ================================================ /* https://issues.dlang.org/show_bug.cgi?id=18385 Disabled for 2.079, s.t. a deprecation cycle can be started with 2.080 DISABLED: win32 win64 osx linux freebsd dragonflybsd TEST_OUTPUT: --- fail_compilation/fail17492.d(20): Error: class `fail17492.C.testE.I` already exists at fail17492.d(13). Perhaps in another function with the same name? fail_compilation/fail17492.d(37): Error: struct `fail17492.S.testE.I` already exists at fail17492.d(30). Perhaps in another function with the same name? --- https://issues.dlang.org/show_bug.cgi?id=17492 */ class C { void testE() { class I { } } void testE() { class I { } } } class S { void testE() { struct I { } } void testE() { struct I { } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17502.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17502.d(13): Error: function `fail17502.Foo.foo` `void` functions have no result fail_compilation/fail17502.d(13): Error: undefined identifier `res` fail_compilation/fail17502.d(17): Error: function `fail17502.Foo.bar` `void` functions have no result fail_compilation/fail17502.d(17): Error: undefined identifier `res` --- */ class Foo { void foo() out (res) { assert(res > 5); } body {} auto bar() out (res) { assert (res > 5); } body { return; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17570.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17570.d(11): Error: cannot use function constraints for non-template functions. Use `static if` instead fail_compilation/fail17570.d(11): Error: declaration expected, not `if` fail_compilation/fail17570.d(14): Error: `}` expected following members in `struct` declaration at fail_compilation/fail17570.d(10) --- */ struct S(T) { void func() if(isIntegral!T) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail176.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail176.d(13): Error: cannot modify `immutable` expression `a[1]` fail_compilation/fail176.d(16): Error: cannot modify `immutable` expression `b[1]` fail_compilation/fail176.d(19): Error: cannot modify `const` expression `c[1]` --- */ void foo() { auto a = "abc"; a[1] = 'd'; immutable char[3] b = "abc"; b[1] = 'd'; const char[3] c = "abc"; c[1] = 'd'; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17602.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17602.d(16): Error: cannot implicitly convert expression `cast(Status)0` of type `imports.imp17602.Status` to `fail17602.Status` --- */ // https://issues.dlang.org/show_bug.cgi?id=17602 import imports.imp17602; enum Status { off } void main() { Status status = imports.imp17602.Status.on; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17612.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17612.d(14): Error: undefined identifier `string` fail_compilation/fail17612.d(17): Error: class `object.TypeInfo` missing or corrupt object.d --- */ // https://issues.dlang.org/show_bug.cgi?id=17612 module object; class Object { string toString(); } class TypeInfo {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17625.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17625.d(16): Deprecation: `b17625.boo` is not visible from module `fail17625` fail_compilation/fail17625.d(16): Error: function `b17625.boo` is not accessible from module `fail17625` --- */ module fail17625; import imports.a17625; import imports.b17625; void main() { boo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17630.d ================================================ // REQUIRED_ARGS: -de // EXTRA_SOURCES: imports/b17630.d /* TEST_OUTPUT: --- fail_compilation/fail17630.d(12): Deprecation: Symbol `b17630.Erase` is not visible from module `fail17630` because it is privately imported in module `a17630` --- */ void main() { import imports.a17630 : Erase; assert(Erase == 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17646.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/imports/fail17646.d(10): Error: found `}` instead of statement fail_compilation/imports/fail17646.d(7): Error: function `imports.fail17646.allTestData!"".allTestData` has no `return` statement, but is expected to return a value of type `const(TestData)[]` fail_compilation/fail17646.d(16): Error: template instance `imports.fail17646.allTestData!""` error instantiating fail_compilation/fail17646.d(19): instantiated from here: `runTests!""` --- */ int runTests(Modules...)() { import imports.fail17646; allTestData!Modules; } alias fail = runTests!""; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17689.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17689.d(10): Error: undefined identifier `x` --- */ void main(){ try{} finally int x=3; assert(x==3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail177.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail177.d(22): Error: cannot modify `immutable` expression `j` fail_compilation/fail177.d(24): Error: cannot modify `const` expression `i` fail_compilation/fail177.d(26): Error: cannot modify `const` expression `s1.x` fail_compilation/fail177.d(27): Error: cannot modify `const` expression `*s1.p` fail_compilation/fail177.d(29): Error: cannot modify `const` expression `s2.x` fail_compilation/fail177.d(30): Error: cannot modify `const` expression `*s2.p` --- */ struct S { int x; int* p; } void test(const(S) s1, const S s2, const(int) i) { immutable int j = 3; j = 4; i = 4; s1.x = 3; *s1.p = 4; s2.x = 3; *s2.p = 4; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17722a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17722a.d(12): Error: static assert: `__traits(compiles, a1 && a2)` is false --- */ // https://issues.dlang.org/show_bug.cgi?id=17722 void fail17722a() { byte[16] a1, a2; static assert(__traits(compiles, a1 && a2)); // diagnostic was (__error) && (__error) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17722b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17722b.d(12): Error: static assert: `__traits(compiles, a1 || a2)` is false --- */ // https://issues.dlang.org/show_bug.cgi?id=17722 void fail17722b() { byte[16] a1, a2; static assert(__traits(compiles, a1 || a2)); // diagnostic was (__error) || (__error) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17842.d ================================================ /* REQUIRED_ARGS: -dip1000 * TEST_OUTPUT: --- fail_compilation/fail17842.d(14): Error: scope variable `p` assigned to non-scope `*q` fail_compilation/fail17842.d(23): Error: scope variable `obj` may not be copied into allocated memory --- */ // https://issues.dlang.org/show_bug.cgi?id=17842 void* testp(scope void* p) @safe { scope void** q; *q = p; // error void** t; *t = *q; return *t; } Object testobj(scope Object obj) @safe { scope Object[] arr; arr ~= obj; // error Object[] array; array ~= arr; return array[0]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail179.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail179.d(11): Error: variable `fail179.main.px` cannot be `final`, perhaps you meant `const`? --- */ void main() { int x = 3; final px = &x; *px = 4; auto ppx = &px; **ppx = 5; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17927.d ================================================ /* REQUIRED_ARGS: -dip1000 * TEST_OUTPUT: --- fail_compilation/fail17927.d(13): Error: scope variable `this` may not be returned fail_compilation/fail17927.d(21): Error: scope variable `ptr` may not be returned fail_compilation/fail17927.d(23): Error: scope variable `ptr` may not be returned --- */ // https://issues.dlang.org/show_bug.cgi?id=17927 struct String { const(char)* mem1() const scope @safe { return ptr; } inout(char)* mem2() inout scope @safe { return ptr; } // no error because `ref inout` implies `return` char* ptr; } const(char)* foo1(scope const(char)* ptr) @safe { return ptr; } inout(char)* foo2(scope inout(char)* ptr) @safe { return ptr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17955.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=17955 alias Alias(alias a) = a; template isISOExtStringSerializable(T) { enum isISOExtStringSerializable = T.fromISOExtString(""); } template RedisObjectCollection(){} struct RedisStripped(T, bool strip_id = true) { alias unstrippedMemberIndices = indicesOf!(Select!(strip_id, isRedisTypeAndNotID, isRedisType), T.tupleof); } template indicesOf(alias PRED, T...) { template impl(size_t i) { static if (PRED!T) impl TypeTuple; } alias indicesOf = impl!0; } template isRedisType(alias F) { enum isRedisType = toRedis!(typeof(F)); } template isRedisTypeAndNotID(){} string toRedis(T)() { static if (isISOExtStringSerializable!T) return; } struct User { SysTime resetCodeExpireTime; } class RedisUserManController { RedisObjectCollection!(RedisStripped!User) m_users; } class TimeZone { abstract bool hasDST(); } class SimpleTimeZone : TimeZone { unittest {} immutable(SimpleTimeZone) fromISOExtString(S)(S) { new SimpleTimeZone; } } struct SysTime { static fromISOExtString(S)(S) { dstring zoneStr; try SimpleTimeZone.fromISOExtString(zoneStr); catch DateTimeException; } } template Select(bool condition, T...) { alias Select = Alias!(T[condition]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17969.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17969.d(9): Error: no property `sum` for type `MapResult2!((b) => b)` --- * https://issues.dlang.org/show_bug.cgi?id=17969 */ alias fun = a => MapResult2!(b => b).sum; int[] e; static assert(!is(typeof(fun(e)) == void)); void foo() { fun(e); } struct MapResult2(alias fun) { int[] _input; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail17976.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail17976.d(11): Error: constructor `fail17976.S.this` parameter `this.a` is already defined fail_compilation/fail17976.d(11): Error: constructor `fail17976.S.this` parameter `this.a` is already defined --- */ struct S { this(string a, string a, string a) { } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18.d(14): Error: need upper and lower bound to slice pointer --- */ // 7/25 // Internal error: ..\ztc\cgcod.c 1464 void main () { int x = 3; int[] a = (&x)[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail180.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail180.d(23): Error: cannot modify `this.x` in `const` function fail_compilation/fail180.d(24): Error: cannot modify `this.x` in `const` function fail_compilation/fail180.d(38): Error: cannot modify `this.x` in `const` function fail_compilation/fail180.d(39): Error: cannot modify `this.x` in `const` function fail_compilation/fail180.d(50): Error: variable `fail180.main.t` cannot be `final`, perhaps you meant `const`? fail_compilation/fail180.d(62): Error: variable `fail180.test.d` cannot be `final`, perhaps you meant `const`? --- */ struct S59 { int x; void foo() { x = 3; } const void bar() { x = 4; this.x = 5; } } class C { int x; void foo() { x = 3; } const void bar() { x = 4; this.x = 5; } } void main() { S59 s; s.foo(); s.bar(); final S59 t; t.foo(); t.bar(); } void test() { C c = new C; c.foo(); c.bar(); final C d = new C; d.foo(); d.bar(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18057.d ================================================ /** TEST_OUTPUT: --- fail_compilation/fail18057.d(16): Error: template instance `RBNode!int` `RBNode` is not a template declaration, it is a struct fail_compilation/fail18057.d(13): Error: variable `fail18057.RBNode.copy` recursive initialization of field --- */ // https://issues.dlang.org/show_bug.cgi?id=18057 // Recursive field initializer causes segfault. struct RBNode { RBNode *copy = new RBNode; } alias bug18057 = RBNode!int; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18093.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18093.d(19): Error: function `void fail18093.GenericTransitiveVisitor!(ASTCodegen).GenericTransitiveVisitor.ParseVisitMethods!(ASTCodegen).visit()` does not override any function, did you mean to override `extern (C++) void fail18093.ParseTimeVisitor!(ASTCodegen).ParseTimeVisitor.visit()`? fail_compilation/fail18093.d(24): Error: mixin `fail18093.GenericTransitiveVisitor!(ASTCodegen).GenericTransitiveVisitor.ParseVisitMethods!(ASTCodegen)` error instantiating fail_compilation/fail18093.d(27): Error: template instance `fail18093.GenericTransitiveVisitor!(ASTCodegen)` error instantiating --- * https://issues.dlang.org/show_bug.cgi?id=18093 */ struct ASTCodegen {} extern (C++) class ParseTimeVisitor(AST) { void visit() {} } template ParseVisitMethods(AST) { override void visit() {} } class GenericTransitiveVisitor(AST) : ParseTimeVisitor!AST { mixin ParseVisitMethods!AST; } alias SemanticTimeTransitiveVisitor = GenericTransitiveVisitor!ASTCodegen; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18143.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18143.d(20): Error: variable `fail18143.S.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(21): Error: variable `fail18143.S.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(25): Error: variable `fail18143.S.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(26): Error: variable `fail18143.S.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(35): Error: variable `fail18143.C.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(36): Error: variable `fail18143.C.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(40): Error: variable `fail18143.C.a` cannot modify parameter 'this' in contract fail_compilation/fail18143.d(41): Error: variable `fail18143.C.a` cannot modify parameter 'this' in contract --- */ struct S { int a; this(int n) in { a = n; } // error, modifying this.a in contract out { a = n; } // error, modifying this.a in contract do { } void foo(int n) in { a = n; } // error, modifying this.a in contract out { a = n; } // error, modifying this.a in contract do { } } class C { int a; this(int n) in { a = n; } // error, modifying this.a in contract out { a = n; } // error, modifying this.a in contract do { } void foo(int n) in { a = n; } // error, modifying this.a in contract out { a = n; } // error, modifying this.a in contract do { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18219.d ================================================ // EXTRA_SOURCES: imports/b18219.d /* TEST_OUTPUT: --- fail_compilation/fail18219.d(15): Deprecation: `b18219.Foobar` is not visible from module `fail18219` fail_compilation/fail18219.d(16): Error: no property `Bar` for type `AST` fail_compilation/fail18219.d(17): Error: no property `fun` for type `AST`, did you mean `b18219.fun`? fail_compilation/fail18219.d(18): Error: no property `Foobar` for type `AST`, did you mean `b18219.Foobar`? --- */ import imports.a18219; void main() { AST.Foobar t; AST.Bar l; AST.fun(); AST.Foobar.smeth(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18228.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail18228.d(13): Deprecation: Using `this` as a type is deprecated. Use `typeof(this)` instead fail_compilation/fail18228.d(14): Deprecation: Using `this` as a type is deprecated. Use `typeof(this)` instead fail_compilation/fail18228.d(15): Deprecation: Using `super` as a type is deprecated. Use `typeof(super)` instead --- */ class C { this(this a) {} this(int a, this b) {} this(super a) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18236.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18236.d(20): Error: cannot cast expression `V(12)` of type `V` to `int` --- */ struct V { int a; } struct S { enum A = V(12); } void main() { int b = cast(int)S.A; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18243.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18243.d(14): Error: none of the overloads of `isNaN` are callable using argument types `!()(float)` --- */ module fail18243; import imports.a18243; void main() { bool b = isNaN(float.nan); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18266.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18266.d(22): Error: declaration `fail18266.main.S` is already defined in another scope in `main` at line `14` --- */ // https://issues.dlang.org/show_bug.cgi?id=18266 void main() { foreach (i; 0 .. 10) { struct S { int x; } auto s = S(i); } foreach (i; 11 .. 20) { struct S { int y; } auto s = S(i); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail183.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail183.d(10): Error: redundant attribute `const` fail_compilation/fail183.d(10): Error: redundant attribute `scope` fail_compilation/fail183.d(11): Error: redundant attribute `in` --- */ void f(in final const scope int x) {} void g(final const scope in int x) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail184.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail184.d(8): Error: redundant attribute `final` --- */ final final int x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18417.d ================================================ // REQUIRED_ARGS : -de /* TEST_OUTPUT: --- fail_compilation/fail18417.d(11): Deprecation: `const` postblit is deprecated. Please use an unqualified postblit. fail_compilation/fail18417.d(12): Deprecation: `immutable` postblit is deprecated. Please use an unqualified postblit. fail_compilation/fail18417.d(13): Deprecation: `shared` postblit is deprecated. Please use an unqualified postblit. --- */ struct A { this(this) const {} } struct B { this(this) immutable {} } struct C { this(this) shared {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail185.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail185.d(10): Error: static assert: "An error message that spans multiple lines, and also contains such characters as a tab, \ and "." --- */ static assert (false, "An error message \tthat spans multiple lines, and also contains such characters as a tab, \\ and \"."); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18620.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18620.d(14): Error: `strlen` cannot be interpreted at compile time, because it has no available source code fail_compilation/fail18620.d(19): compile time context created here fail_compilation/fail18620.d(14): Error: `strlen` cannot be interpreted at compile time, because it has no available source code fail_compilation/fail18620.d(20): compile time context created here --- */ class A{ this(const(char)* s) { import core.stdc.string; auto a=strlen(s); } } void main(){ static a = new A("a"); __gshared b = new A("b"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail187.d ================================================ // REQUIRED_ARGS: -d /* TEST_OUTPUT: --- fail_compilation/fail187.d(16): Error: `catch` at fail_compilation/fail187.d(20) hides `catch` at fail_compilation/fail187.d(24) --- */ // On DMD 2.000 bug only with typedef, not alias alias Exception A; alias Exception B; void main() { try { throw new A("test"); } catch (B) { // this shouldn't happen, but does } catch (A) { // this ought to happen? } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18719.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=18719 // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail18719.d(29): Deprecation: immutable field `x` was initialized in a previous constructor call --- */ struct S { int x = -1; this(int y) immutable { x = y; import std.stdio; writeln("Ctor called with ", y); } void opAssign(int) immutable; } class C { S x; this() immutable { this(42); /* Initializes x. */ x = 13; /* Breaking immutable, or ok? */ } this(int x) immutable { this.x = x; } } void main() { new immutable C; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail188.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail188.d(15): Error: function `fail188.Derived.foo` cannot override `final` function `fail188.Base.foo` --- */ class Base { final void foo() {} } class Derived : Base { void foo() {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18892.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18892.d(20): Error: no property `foo` for type `MT` fail_compilation/fail18892.d(21): Error: no property `foo` for type `MT` --- */ // https://issues.dlang.org/show_bug.cgi?id=18892 struct MT { int _payload; alias _payload this; } void main() { MT a; a.foo = 3; MT.foo = 3; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail189.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail189.d(10): Error: undefined identifier `foo` --- */ void bar() { foo(); // should fail } version(none): void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18970.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18970.d(22): Error: no property `y` for type `S` fail_compilation/fail18970.d(29): Error: no property `yyy` for type `S2` --- */ // https://issues.dlang.org/show_bug.cgi?id=18970 struct S { auto opDispatch(string name)(int) { alias T = typeof(x); static assert(!is(T.U)); return 0; } } void f() { S().y(1); } struct S2 { this(int) { this.yyy; } auto opDispatch(string name)() { alias T = typeof(x); static if(is(T.U)) {} } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18985.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18985.d(16): Error: `foo` is not a scalar, it is a `object.Object` fail_compilation/fail18985.d(17): Error: `bar` is not a scalar, it is a `shared(Object)` --- */ // https://issues.dlang.org/show_bug.cgi?id=18985 Object foo; shared Object bar; void main() { foo += 1; bar += 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail18994.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail18994.d(19): Error: struct `fail18994.Type1` is not copyable because it is annotated with `@disable` --- */ struct Type2 { int opApply(int delegate(ref Type1)) { return 0; } } struct Type1 { @disable this(this); } void test() { foreach(b; Type2()) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail190.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail190.d(9): Error: cannot have pointer to `(int, int, int)` fail_compilation/fail190.d(16): Error: template instance `fail190.f!(int, int, int)` error instantiating --- */ T* f(T...)(T x) { return null; } void main() { auto x = f(2,3,4); *x = *x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail1900.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail1900.d(26): Error: template `fail1900.Mix1a!().Foo` matches more than one template declaration: fail_compilation/fail1900.d(13): `Foo(ubyte x)` and fail_compilation/fail1900.d(14): `Foo(byte x)` --- */ template Mix1a() { template Foo(ubyte x) {} template Foo(byte x) {} } template Mix1b() { template Foo(int x) {} } mixin Mix1a; mixin Mix1b; void test1900a() { alias x = Foo!1; } /* TEST_OUTPUT: --- fail_compilation/fail1900.d(41): Error: `imports.fail1900b.Bar(short n)` at fail_compilation/imports/fail1900b.d(2) conflicts with `imports.fail1900a.Bar(int n)` at fail_compilation/imports/fail1900a.d(2) --- */ import imports.fail1900a; import imports.fail1900b; void test1900b() { enum x = Bar!1; } /* TEST_OUTPUT: --- fail_compilation/fail1900.d(65): Error: `fail1900.Mix2b!().Baz(int x)` at fail_compilation/fail1900.d(57) conflicts with `fail1900.Mix2a!().Baz(byte x)` at fail_compilation/fail1900.d(53) --- */ template Mix2a() { template Baz(byte x) {} } template Mix2b() { template Baz(int x) {} } mixin Mix2a; mixin Mix2b; void test1900c() { alias x = Baz!1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19038.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail19038.d(21): Error: cannot implicitly convert expression `a` of type `string[][]` to `const(string)[][]` fail_compilation/fail19038.d(23): Error: cannot modify `const` expression `c[0]` --- * Credit: yshui * https://github.com/dlang/dmd/pull/8413#issuecomment-401104961 * https://issues.dlang.org/show_bug.cgi?id=19038 */ void test() { /* string[][] is not implicitly converible to const(string)[][], * and there is good reason why: * * https://stackoverflow.com/questions/5055655/double-pointer-const-correctness-warnings-in-c */ string[][] a = [["Lord"]]; const(string)[][] b = a; // assume this works (and it should not) const(string)[] c = ["Sauron"]; c[0] = "Mordor"; // invalid, because c[0] is const(string) b[0] = c; // valid, b[0] is const(string)[] // But now, a[0] has become c a[0][0] = "Nazgul"; // valid, because a[0][0] is string // But this also changes c[0], which shouldn't be possible } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19076.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail19076.d(11): Error: no property `V` for type `fail19076.I` fail_compilation/fail19076.d(11): Error: `(I).V` cannot be resolved --- */ interface P { } interface I : P { } auto F = __traits(getVirtualFunctions, I, "V"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19098.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail19098.d(18): Error: cannot modify struct instance `a` of type `A` because it contains `const` or `immutable` members --- */ struct A { const int a; this(int) {} } void main() { A a = A(2); A b = A(3); a = b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19181.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail19181.d(15): Error: undefined identifier `LanguageError` --- */ struct S { void opDispatch(string name, T)(T arg) { } } void main() { S s; s.foo(LanguageError); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19182.d ================================================ // REQUIRED_ARGS: -c /* TEST_OUTPUT: --- gigi fail_compilation/fail19182.d(12): Error: `pragma(msg)` is missing a terminating `;` --- */ void foo() { pragma(msg, "gigi") // Here static foreach (e; []) { pragma(msg, "lili"); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail192.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail192.d(15): Error: outer function context of `fail192.foo` is needed to `new` nested class `fail192.foo.DummyClass` fail_compilation/fail192.d(26): Error: template instance `fail192.X!(DummyClass)` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=1336 // Internal error when trying to construct a class declared within a unittest from a templated class. class X(T) { void bar() { auto t = new T; } } void foo() { class DummyClass { } //auto x = new X!(DummyClass); X!(DummyClass) x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19209.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail19209.d(16): Error: function `fail19209.Spammer.method()` does not override any function, did you mean to override variable `fail19209.Spam.method`? fail_compilation/fail19209.d(16): Functions are the only declarations that may be overriden --- */ class Spam { int method; } class Spammer : Spam { override method() {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail193.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail193.d(14): Error: cannot infer type from overloaded function symbol `& foo` --- */ void foo() { } void foo(int) { } void main() { //void function(int) fp = &foo; auto fp = &foo; fp(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19319a.d ================================================ /* DFLAGS: REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal TEST_OUTPUT: --- fail_compilation/fail19319a.d(16): Error: `7 ^^ g19319` requires `std.math` for `^^` operators fail_compilation/fail19319a.d(17): Error: `g19319 ^^ 7` requires `std.math` for `^^` operators --- */ __gshared int g19319 = 0; static assert(!__traits(compiles, 7 ^^ g19319)); static assert(!__traits(compiles, g19319 ^^= 7)); __gshared int e19319 = 7 ^^ g19319; __gshared int a19319 = g19319 ^^= 7;; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail19319b.d ================================================ /* DFLAGS: REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal TEST_OUTPUT: --- fail_compilation/fail19319b.d(16): Error: `7 ^^ x` requires `std.math` for `^^` operators fail_compilation/fail19319b.d(17): Error: `x ^^ 7` requires `std.math` for `^^` operators --- */ void test19319(int x) { static assert(!__traits(compiles, 7 ^^ x)); static assert(!__traits(compiles, x ^^= 7)); int i = 7 ^^ x; x ^^= 7; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail194.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail194.d(18): Error: function `& foo` is overloaded --- */ import core.vararg; void bar(int i, ...) { } void foo() { } void foo(int) { } void main() { //bar(1, cast(void function())&foo); bar(1, &foo); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail195.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail195.d(22): Error: struct `Foo` does not overload () --- */ // https://issues.dlang.org/show_bug.cgi?id=1384 // Compiler segfaults when using struct variable like a function with no opCall member. struct Foo { union { int a; int b; } } void bla() { Foo next; next(); // Error: structliteral has no effect in expression (Foo(0)) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail196.d ================================================ void main() { string s = q"(foo(xxx)) "; assert(s == "foo(xxx)"); s = q"[foo[xxx]]"; assert(s == "foo[xxx]"); s = q"{foo{xxx}}"; assert(s == "foo{xxx}"); s = q">"; assert(s == "foo"); s = q"[foo(]"; assert(s == "foo("); s = q"/foo]/"; assert(s == "foo]"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail198.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail198.d(8): Error: template instance `test!42` template `test` is not defined --- */ int x = test!(42); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail199.d ================================================ // REQUIRED_ARGS: -de //import std.stdio; deprecated class DepClass { void test() { //writefln("Accessing what's deprecated!"); } } class Derived : DepClass {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail20.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail20.d(16): Error: need member function `opCmp()` for struct `FOO` to compare --- */ // ICE(cod3) DMD0.080 struct FOO{} void main() { FOO one; FOO two; if (one < two){} // This should tell me that there // is no opCmp() defined instead // of crashing. } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail200.d ================================================ // REQUIRED_ARGS: -de //import std.stdio; deprecated interface DepClass { void test(); } class Derived : DepClass { void test() { //writefln("Accessing what's deprecated!"); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail201.d ================================================ void main() { int c; c = c >>> 33; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail202.d ================================================ void main() { int c; c = c >> 33; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail203.d ================================================ void main() { int c; c = c << 33; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail204.d ================================================ void main() { long c; c >>= 65; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail205.d ================================================ void main() { long c; c <<= 65; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail206.d ================================================ void main() { long c; c >>>= 65; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail207.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail207.d(10): Error: found end of file instead of initializer fail_compilation/fail207.d(10): Error: semicolon expected, not `End of File` --- */ int x = { ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail208.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail208.d(18): Error: `return` expression expected fail_compilation/fail208.d(21): called from here: `MakeA()` --- */ // https://issues.dlang.org/show_bug.cgi?id=1593 // ICE compiler crash empty return statement in function struct A { } A MakeA() { return ; } static const A aInstance = MakeA(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail209.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail209.d(20): Error: incompatible types for `(a) -= (x)`: `float` and `fail209.X` --- */ // https://issues.dlang.org/show_bug.cgi?id=725 // expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed class X { float a; } void main() { X x; float a; a -= x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail212.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail212.d(14): Error: function `fail212.S.bar` without `this` cannot be `const` --- */ struct S { void foo() const { } static void bar() const { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail213.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail213.d(18): Error: template instance `Foo!int` does not match template declaration `Foo(T : immutable(T))` fail_compilation/fail213.d(25): Error: template instance `Foo!(const(int))` does not match template declaration `Foo(T : immutable(T))` --- */ template Foo(T:immutable(T)) { alias T Foo; } void main() { { int x; alias Foo!(typeof(x)) f; //printf("%s\n", typeid(f).toString().ptr); assert(is(typeof(x) == int)); assert(is(f == int)); } { const int x; alias Foo!(typeof(x)) f; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail215.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail215.d(10): Error: function `fail215.b.k` cannot be both `final` and `abstract` --- */ class b { final abstract void k(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail216.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail216.d(16): Error: expression `foo()` is `void` and has no value fail_compilation/fail216.d(14): Error: function `fail216.bar` has no `return` statement, but is expected to return a value of type `int` fail_compilation/fail216.d(19): called from here: `bar()` --- */ // https://issues.dlang.org/show_bug.cgi?id=1744 // CTFE: crash on assigning void-returning function to variable void foo() {} int bar() { int x = foo(); } const y = bar(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail217.d ================================================ class Message { public int notifier; this( int notifier_object ) { notifier = notifier_object; } } void main() { auto m2 = new immutable(Message)(2); m2.notifier = 3; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail218.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail218.d(15): Error: cannot modify string literal `", "` --- */ // https://issues.dlang.org/show_bug.cgi?id=1788 // dmd segfaults without info void main() { string a = "abc"; double b = 7.5; a ~= ", " ~= b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail22.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail22.d(13): Error: no identifier for declarator `char` --- */ // infinite loop on DMD0.080 void main() { char[] bug = "Crash"; foreach(char ; bug) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail220.d ================================================ template types (T) { static if (is (T V : V[K], K == class)) { static assert (false, "assoc"); } static const int types = 4; } int i = types!(int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail221.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail221.d(11): Error: expression `cast(void)0` is `void` and has no value --- */ void main() { void[] data; data ~= cast(void) 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail222.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail222.d(10): Error: template `fail222.getMixin(TArg..., int i = 0)()` template tuple parameter must be last one fail_compilation/fail222.d(17): Error: template instance `getMixin!()` does not match template declaration `getMixin(TArg..., int i = 0)()` fail_compilation/fail222.d(20): Error: template instance `fail222.Thing!()` error instantiating --- */ string getMixin(TArg..., int i = 0)() { return ``; } class Thing(TArg...) { mixin(getMixin!(TArg)()); } public Thing!() stuff; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail223.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail223.d(14): Error: cannot modify `this.x` in `const` function --- */ //import std.stdio; class A { public: int x = 0; void setX(int nx) const { x = nx; } } void foo(const A a) { a.setX(1); } int main(char[][] args) { A a = new A; foo(a); //writefln(a.x); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail224.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail224.d(22): Error: need `this` of type `A` to access member `x` from static function `f` --- */ int gi; class A { int x = 42; void am() { static void f() { class B { void bm() { gi = x; } } (new B).bm(); } f(); } } void main() { (new A).am(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail225.d ================================================ struct Struct { char* chptr; } void main() { char ch = 'd'; immutable Struct iStruct = {1, &ch}; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail228.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail228.d(22): Error: undefined identifier `localVariable` --- */ //import core.stdc.stdio : printf; int ToTypeString(T : int)() { return 1; } int ToTypeString(T : string)() { return 2; } void main() { auto x = ToTypeString!(typeof(localVariable))(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail229.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail229.d(11): Error: array index 18446744073709551615 overflow fail_compilation/fail229.d(11): Error: array dimension overflow --- */ // https://issues.dlang.org/show_bug.cgi?id=1936 // Error with no line number (array dimension overflow) static int[] x = [-1: 1]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail23.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail23.d(14): Error: `break` is not inside a loop or `switch` --- */ // ICE(s2ir.c) DMD0.100 void main() { try { break; } catch (Throwable) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail231.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail231.d(15): Error: class `fail231.Derived` cannot implicitly generate a default constructor when base class `fail231.Base` is missing a default constructor --- */ // https://issues.dlang.org/show_bug.cgi?id=951 // Missing line number: no constructor provided for a class derived from a class with no default constructor class Base { this(int x) {} } class Derived : Base { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail232.d ================================================ void bug1601() { int i; i = i >> 33; i = i << 33; i = i >>> 33; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail233.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail233.d(11): Error: variable `fail233.bug1176.v` `void[1]` does not have a default initializer --- */ void bug1176() { void[1] v; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail235.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail235.d(12): Error: expression `typeid(char)` is not a valid template value argument --- */ template Tuple(TPL...) { alias TPL Tuple; } auto K = Tuple!(typeid(char)); /* TEST_OUTPUT: --- fail_compilation/fail235.d(24): Error: expression `typeid(char)` is not a valid template value argument --- */ template Alias(alias A) { alias A Alias; } auto A = Alias!(typeid(char)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail236.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` fail_compilation/fail236.d(22): Error: template `fail236.Templ2` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/fail236.d(12): `fail236.Templ2(alias a)(x)` --- */ // https://issues.dlang.org/show_bug.cgi?id=870 // contradictory error messages for templates template Templ2(alias a) { void Templ2(x) { } } void main() { int i; Templ2(i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2361.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail2361.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail2361.d(14): Error: cannot modify `immutable` expression `c` --- */ class C {} void main() { immutable c = new immutable(C); delete c; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail237.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail237.d(11): Error: undefined identifier `a` in module `fail237` fail_compilation/fail237.d(11): while evaluating: `static assert(module fail237.a!().b)` --- */ // https://issues.dlang.org/show_bug.cgi?id=581 // Error message w/o line number in dot-instantiated template static assert(.a!().b); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/fail238_m32.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `uint` fail_compilation/fail238_m32.d(24): Error: cannot interpret `X!()` at compile time fail_compilation/fail238_m32.d(29): Error: template instance `fail238_m32.A!"a"` error instantiating fail_compilation/fail238_m32.d(35): instantiated from here: `M!(q)` fail_compilation/fail238_m32.d(35): while evaluating `pragma(msg, M!(q))` --- */ // https://issues.dlang.org/show_bug.cgi?id=581 // Error message w/o line number in dot-instantiated template template X(){} template D(string str){} template A(string str) { static if (D!(str[str])) {} else const string A = .X!(); } template M(alias B) { const string M = A!("a"); } void main() { int q = 3; pragma(msg, M!(q)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d ================================================ // REQUIRED_ARGS: -m64 /* TEST_OUTPUT: --- fail_compilation/fail238_m64.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `ulong` fail_compilation/fail238_m64.d(24): Error: cannot interpret `X!()` at compile time fail_compilation/fail238_m64.d(29): Error: template instance `fail238_m64.A!"a"` error instantiating fail_compilation/fail238_m64.d(35): instantiated from here: `M!(q)` fail_compilation/fail238_m64.d(35): while evaluating `pragma(msg, M!(q))` --- */ // https://issues.dlang.org/show_bug.cgi?id=581 // Error message w/o line number in dot-instantiated template template X(){} template D(string str){} template A(string str) { static if (D!(str[str])) {} else const string A = .X!(); } template M(alias B) { const string M = A!("a"); } void main() { int q = 3; pragma(msg, M!(q)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail239.d ================================================ class F { int x; } alias typeof(F).x b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail24.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail24.d(11): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(10) fail_compilation/fail24.d(12): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(11) fail_compilation/fail24.d(13): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(12) --- */ alias char[] strtype; alias char[64] strtype; alias char[128] strtype; alias char[256] strtype; int main() { printf("%u", strtype.sizeof); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail240.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail240.d(9): Error: type `F` is not an expression --- */ class F { int x; } alias typeof(typeof(F).x) b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail241.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail241.d(18): Error: mutable method `fail241.Foo.f` is not callable using a `const` object fail_compilation/fail241.d(18): Consider adding `const` or `inout` to fail241.Foo.f fail_compilation/fail241.d(19): Error: mutable method `fail241.Foo.g` is not callable using a `const` object fail_compilation/fail241.d(19): Consider adding `const` or `inout` to fail241.Foo.g --- */ class Foo { public void f() { } private void g() { } invariant() { f(); // error, cannot call public member function from invariant g(); // ok, g() is not public } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail243.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail243.d(23): Deprecation: class `fail243.DepClass` is deprecated fail_compilation/fail243.d(24): Deprecation: struct `fail243.DepStruct` is deprecated fail_compilation/fail243.d(25): Deprecation: union `fail243.DepUnion` is deprecated fail_compilation/fail243.d(26): Deprecation: enum `fail243.DepEnum` is deprecated fail_compilation/fail243.d(27): Deprecation: alias `fail243.DepAlias` is deprecated --- */ deprecated { class DepClass {} struct DepStruct {} union DepUnion {} enum DepEnum { A } alias int DepAlias; //typedef int DepTypedef; } void func(DepClass obj) {} void func(DepStruct obj) {} void func(DepUnion obj) {} void func(DepEnum obj) {} void func(DepAlias obj) {} //void func(DepTypedef obj) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail244.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail244.d(27): Deprecation: variable `fail244.StructWithDeps.value` is deprecated fail_compilation/fail244.d(28): Deprecation: variable `fail244.StructWithDeps.value` is deprecated fail_compilation/fail244.d(29): Deprecation: variable `fail244.StructWithDeps.value` is deprecated fail_compilation/fail244.d(30): Deprecation: variable `fail244.StructWithDeps.value` is deprecated fail_compilation/fail244.d(32): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated fail_compilation/fail244.d(33): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated fail_compilation/fail244.d(34): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated fail_compilation/fail244.d(35): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated fail_compilation/fail244.d(36): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated fail_compilation/fail244.d(37): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated --- */ //import std.stdio; struct StructWithDeps { deprecated int value; deprecated static int staticValue; void test(StructWithDeps obj) { obj.value = 666; this.value = 666; auto n1 = obj.value; auto n2 = this.value; obj.staticValue = 102; this.staticValue = 103; StructWithDeps.staticValue = 104; auto n3 = obj.staticValue; auto n4 = this.staticValue; auto n5 = StructWithDeps.staticValue; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail245.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail245.d(27): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated fail_compilation/fail245.d(28): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated fail_compilation/fail245.d(29): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated fail_compilation/fail245.d(30): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated fail_compilation/fail245.d(32): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated fail_compilation/fail245.d(33): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated fail_compilation/fail245.d(34): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated fail_compilation/fail245.d(35): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated fail_compilation/fail245.d(36): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated fail_compilation/fail245.d(37): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated --- */ //import std.stdio; class ClassWithDeps { deprecated int value; deprecated static int staticValue; void test(ClassWithDeps obj) { obj.value = 666; this.value = 666; auto n1 = obj.value; auto n2 = this.value; obj.staticValue = 102; this.staticValue = 103; ClassWithDeps.staticValue = 104; auto n3 = obj.staticValue; auto n4 = this.staticValue; auto n5 = ClassWithDeps.staticValue; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2456.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail2456.d(14): Error: cannot put `scope(success)` statement inside `finally` block --- */ void test_success() { try { } finally { scope(success) {} // NG } } /* TEST_OUTPUT: --- fail_compilation/fail2456.d(31): Error: cannot put `scope(failure)` statement inside `finally` block --- */ void test_failure() { try { } finally { scope(failure) {} // NG } } /* TEST_OUTPUT: --- --- */ void test_exit() { try { } finally { scope(exit) {} // OK } } /* TEST_OUTPUT: --- fail_compilation/fail2456.d(64): Error: cannot put `scope(success)` statement inside `scope(success)` fail_compilation/fail2456.d(65): Error: cannot put `scope(failure)` statement inside `scope(success)` fail_compilation/fail2456.d(78): Error: cannot put `scope(success)` statement inside `scope(exit)` fail_compilation/fail2456.d(79): Error: cannot put `scope(failure)` statement inside `scope(exit)` --- */ void test2456a() { scope(success) { scope(success) {} // NG scope(failure) {} // NG scope(exit) {} // OK } scope(failure) { scope(success) {} // OK scope(failure) {} // OK scope(exit) {} // OK } scope(exit) { scope(success) {} // NG scope(failure) {} // NG scope(exit) {} // OK } } /* TEST_OUTPUT: --- fail_compilation/fail2456.d(96): Error: cannot put `catch` statement inside `scope(success)` fail_compilation/fail2456.d(108): Error: cannot put `catch` statement inside `scope(exit)` --- */ void test2456b() { scope(success) { try {} catch (Throwable) {} // NG } scope(failure) { try {} catch (Throwable) {} // OK } scope(exit) { try {} catch (Throwable) {} // NG } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail246.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail246.d-mixin-11(11): Error: identifier expected, not `End of File` fail_compilation/fail246.d-mixin-11(11): Error: `;` expected after mixin --- */ void a() { mixin(`mixin`); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail247.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail247.d-mixin-9(9): Error: identifier expected, not `End of File` fail_compilation/fail247.d-mixin-9(9): Error: `;` expected after mixin --- */ mixin(`mixin`); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail248.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail248.d(9): Error: type `int` is not an expression --- */ alias int foo; typeof(foo) a; // ok ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail249.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()` --- */ module main; public void bar() { } void main() { foreach (Object o; bar()) { debug Object foo = null; //error } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail25.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail25.d(14): Error: need `this` for `yuiop` of type `int` --- */ class Qwert { int yuiop; static int asdfg() { return Qwert.yuiop + 105; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail250.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail250.d(10): Error: constructor `fail250.A.this` default constructor for structs only allowed with `@disable`, no body, and no parameters --- */ struct A { this() {} } void main() { auto a = A(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail251.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail251.d(12): Error: undefined identifier `xs` fail_compilation/fail251.d(16): called from here: `foo()` fail_compilation/fail251.d(16): while evaluating: `static assert(foo())` --- */ bool foo() { foreach (x; xs) {} return true; } static assert(foo()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail252.d ================================================ class Timer { abstract class Task { public abstract void run(); } private Task IDLE = new class() Task { int d; public void run(){ } }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail253.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail253.d(13): Error: variable `fail253.main.x` `inout` variables can only be declared inside `inout` functions fail_compilation/fail253.d(16): Error: cannot modify `inout` expression `x` --- */ void main() { foreach (i; 0 .. 2) { foreach (inout char x; "hola") { //printf("%c", x); x = '?'; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail254.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail254.d(12): Error: integer overflow fail_compilation/fail254.d(13): Error: integer overflow fail_compilation/fail254.d(14): Error: integer overflow fail_compilation/fail254.d(15): Error: integer overflow fail_compilation/fail254.d(16): Error: integer overflow --- */ ulong v1 = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; ulong v2 = 0x1_0000_0000_0000_0000; ulong v3 = 0x1_FFFF_FFFF_FFFF_FFFF; ulong v4 = 0x7_FFFF_FFFF_FFFF_FFFF; ulong v5 = 0x1_0000_FFFF_FFFF_FFFF; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail256.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail256.d(8): Error: incompatible types for `("foo"d) ~ ("bar"c)`: `dstring` and `string` --- */ auto s = "foo"d ~ "bar"c; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail257.d ================================================ pragma(msg, "foo"d == "bar"c ? "A" : "B"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail258.d ================================================ q" X X" ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail259.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail259.d(11): Error: function `fail259.C.foo` does not override any function --- */ class C { final override void foo(){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail261.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail261.d(18): Error: invalid `foreach` aggregate `range`, define `opApply()`, range primitives, or use `.tupleof` --- */ //import std.stdio; struct MyRange { } void main() { MyRange range; foreach (r; range) { //writefln("%s", r.toString()); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail262.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail262.d(23): Error: function `fail262.B.f` does not override any function --- */ // https://issues.dlang.org/show_bug.cgi?id=1645 // can override base class' const method with non-const method import core.stdc.stdio; class A { int x; shared const void f() { printf("A\n"); } } class B : A { override const void f() { //x = 2; printf("B\n"); } } void main() { A y = new B; y.f; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail263.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail263.d(19): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` --- */ // https://issues.dlang.org/show_bug.cgi?id=2766 // DMD hangs with 0%cpu const byte[] A = [ cast(byte)0 ]; void f(byte* p) { } void func() { f(A.ptr); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail264.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail264.d(10): Error: undefined identifier `undef` --- */ void main() { foreach (element; undef) { fn(element); } } void fn(int i) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail265.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail265.d-mixin-10(10): Error: found `End of File` instead of statement --- */ void main() { mixin(`for(;;)`); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2656.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!123` instead fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!1000000000000000000000` instead fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!100000L` instead fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!1777777777777777777777u` instead fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!17777777777uL` instead fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!177777` instead fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!20000000000L` instead fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!200000u` instead fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!37777777777uL` instead fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!40000000000` instead fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!777777777777777777777L` instead fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!77777u` instead fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead --- */ auto a = 0123; auto b = 01000000000000000000000; auto c = 0100000L; auto d = 01777777777777777777777u; auto e = 017777777777uL; auto f = 0177777; auto g = 020000000000L; auto h = 0200000u; auto i = 037777777777uL; auto j = 040000000000; auto k = 0777777777777777777777L; auto l = 077777u; auto m = 077777uL; auto n = 0_7_7_7_7_7uL; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail267.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail267.d(15): Error: template `Bar()` does not have property `foo` --- */ class C { template Bar() { } } typeof(C.Bar.foo) quux; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail27.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail27.d(15): Error: cannot implicitly convert expression `-32769` of type `int` to `short` fail_compilation/fail27.d(16): Error: cannot implicitly convert expression `-129` of type `int` to `byte` fail_compilation/fail27.d(17): Error: cannot implicitly convert expression `-1` of type `int` to `char` fail_compilation/fail27.d(18): Error: cannot implicitly convert expression `65536` of type `int` to `wchar` fail_compilation/fail27.d(19): Error: cannot implicitly convert expression `-1` of type `int` to `wchar` fail_compilation/fail27.d(21): Error: cannot implicitly convert expression `-1` of type `int` to `dchar` --- */ void main() { short a = -32769; // short.min-1 byte b = -129; // byte.min-1 char c = -1; // char.min-1 wchar D = 65536; // wchar.max+1 wchar d = -1; // wchar.min-1 dchar E = 1114111; // dchar.max+1 dchar e = -1; // dchar.min-1 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail270.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail270.d(12): Error: string slice `[1 .. 0]` is out of bounds fail_compilation/fail270.d(12): Error: mixin `fail270.Tuple!int.Tuple.Tuple!()` error instantiating fail_compilation/fail270.d(14): Error: mixin `fail270.Tuple!int` error instantiating --- */ struct Tuple(TList...) { mixin .Tuple!((TList[1 .. $])) tail; } mixin Tuple!(int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail272.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail272.d(9): Error: circular reference to variable `fail272.Ins!(Ins).Ins` fail_compilation/fail272.d(10): Error: template instance `fail272.Ins!(Ins)` error instantiating --- */ template Ins(alias x) { const Ins = Ins!(Ins); } alias Ins!(Ins) x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail273.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail273.d(10): Error: alias `fail273.b` recursive alias declaration --- */ // https://issues.dlang.org/show_bug.cgi?id=1054 // regression: circular aliases cause compiler stack overflow alias a b; alias b a; b x; // ICE #1 a y; // ICE #2 ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail274.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail274.d(10): Error: expression expected not `;` --- */ void main() { version(GNU) asm { "" : [; } else asm { inc [; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2740.d ================================================ interface IFoo { int foo(); } mixin template MFoo(int N) { int foo() { return N; } } class Foo : IFoo { mixin MFoo!(1) t1; mixin MFoo!(2) t2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail275.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail275.d(10): Error: circular reference to variable `fail275.C.x` --- */ // REQUIRED_ARGS: -d struct C { const x = C.x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail276.d ================================================ class C { this() { auto i = new class() { auto k = new class() { void func() { this.outer.outer; } }; }; } int i; } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail278.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail278.d(11): Error: template instance `NONEXISTENT!()` template `NONEXISTENT` is not defined fail_compilation/fail278.d(12): Error: template instance `fail278.F!()` error instantiating fail_compilation/fail278.d(13): instantiated from here: `Bar!(Foo)` --- */ template Id(xs...) { const Id = xs[0]; } template Foo() { mixin Id!(NONEXISTENT!()); } template Bar(alias F) { const int Bar = F!(); } alias Bar!(Foo) x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2789.d ================================================ /* DISABLED: win32 win64 osx linux freebsd dragonflybsd https://issues.dlang.org/show_bug.cgi?id=18385 Disabled for 2.079, s.t. a deprecation cycle can be started with 2.080 TEST_OUTPUT: --- fail_compilation/fail2789.d(15): Error: function `fail2789.A2789.m()` conflicts with previous declaration at fail_compilation/fail2789.d(10) fail_compilation/fail2789.d(25): Error: function `fail2789.A2789.m()` conflicts with previous declaration at fail_compilation/fail2789.d(10) --- */ class A2789 { int m() { return 1; } float m() // conflict { return 2.0; } float m() const // doen't conflict { return 3.0; } static void m() // conflict { } } /* TEST_OUTPUT: --- fail_compilation/fail2789.d(46): Error: function `fail2789.f3()` conflicts with previous declaration at fail_compilation/fail2789.d(45) fail_compilation/fail2789.d(49): Error: function `fail2789.f4()` conflicts with previous declaration at fail_compilation/fail2789.d(48) fail_compilation/fail2789.d(52): Error: function `fail2789.f5()` conflicts with previous declaration at fail_compilation/fail2789.d(51) fail_compilation/fail2789.d(55): Error: function `fail2789.f6()` conflicts with previous declaration at fail_compilation/fail2789.d(54) --- */ void f1(); void f1() {} // ok void f2() {} void f2(); // ok void f3(); void f3(); // ok void f4() {} void f4() {} // conflict void f5() @safe {} void f5() @system {} // conflict auto f6() { return 10; } // int() auto f6() { return ""; } // string(), conflict /* TEST_OUTPUT: --- fail_compilation/fail2789.d(67): Error: function `fail2789.f_ExternC1()` cannot be overloaded with another `extern(C)` function at fail_compilation/fail2789.d(66) fail_compilation/fail2789.d(70): Error: function `fail2789.f_ExternC2(int)` cannot be overloaded with another `extern(C)` function at fail_compilation/fail2789.d(69) fail_compilation/fail2789.d(73): Error: function `fail2789.f_ExternC3()` cannot be overloaded with another `extern(C)` function at fail_compilation/fail2789.d(72) fail_compilation/fail2789.d(76): Error: function `fail2789.f_MixExtern1()` conflicts with previous declaration at fail_compilation/fail2789.d(75) --- */ extern(C) void f_ExternC1() {} extern(C) void f_ExternC1() {} // conflict extern(C) void f_ExternC2() {} extern(C) void f_ExternC2(int) {} // conflict extern(C) void f_ExternC3(int) {} extern(C) void f_ExternC3() {} // conflict extern (D) void f_MixExtern1() {} extern (C) void f_MixExtern1() {} // conflict extern (D) void f_MixExtern2(int) {} extern (C) void f_MixExtern2() {} // no error extern (C) void f_ExternC4(int sig); extern (C) void f_ExternC4(int sig) @nogc; // no error extern (C) void f_ExternC5(int sig) {} extern (C) void f_ExternC5(int sig) @nogc; // no error extern (C) void f_ExternC6(int sig); extern (C) void f_ExternC6(int sig) @nogc {} // no error /* TEST_OUTPUT: --- fail_compilation/fail2789.d(103): Error: function `fail2789.mul14147(const(int[]) left, const(int[]) right)` conflicts with previous declaration at fail_compilation/fail2789.d(99) --- */ struct S14147(alias func) { } pure auto mul14147(const int[] left, const int[] right) { S14147!(a => a) s; } pure auto mul14147(const int[] left, const int[] right) { S14147!(a => a) s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail279.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=2920 // recursive templates blow compiler stack // template_16 template Template(int i) { mixin Template!(i + 1); } mixin Template!(0); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail280.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=2920 // recursive templates blow compiler stack // template_17_A. template t(int i) { const int x = t!(i + 1).x; } void main() { int i = t!(0).x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail281.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=2920 // recursive templates blow compiler stack // template_29_B. template foo(uint i) { static if (i > 0) { const uint bar = foo!(i - 1).bar; } else { const uint bar = 1; } } int main() { return foo!(uint.max).bar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail282.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail282.d(13): Error: template instance `fail282.Template!500` recursive expansion --- */ // https://issues.dlang.org/show_bug.cgi?id=2920 // recursive templates blow compiler stack // template_class_09. template Template(int i) { class Class : Template!(i + 1).Class { } } alias Template!(0).Class Class0; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail284.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail284.d(19): Error: `pure` function `fail284.foo` cannot call impure function pointer `a` --- */ static int nasty; int impure_evil_function(int x) { nasty++; return nasty; } pure int foo(int x) { int function(int) a = &impure_evil_function; return a(x); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail285.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail285.d(19): Error: with symbol `fail285.S.x` is shadowing local symbol `fail285.main.x` --- */ struct S { int x; } void main() { int x; S s; with (s) { x++; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail287.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail287.d(14): Error: had 299 cases which is more than 256 cases in case range --- */ void main() { int i = 2; switch (i) { case 1: .. case 300: i = 5; break; } if (i != 5) assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail288.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail288.d(14): Error: case ranges not allowed in `final switch` --- */ void main() { enum E { a, b } E i = E.a; final switch (i) { case E.a: .. case E.b: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail289.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail289.d(12): Error: cannot cast from function pointer to delegate --- */ alias void delegate() Dg; void fun() {} void gun() { Dg d = cast(void delegate())&fun; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail290.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail290.d(15): Error: no `this` to create delegate for `foo` --- */ struct Foo { void foo(int x) {} } void main() { void delegate (int) a = &Foo.foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail291.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail291.d(9): Error: variable `fail291.X` cannot be declared to be a function --- */ auto a() { return 0; } typeof(a) X; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail296.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail296.d(10): Error: can only `*` a pointer, not a `int` --- */ // https://issues.dlang.org/show_bug.cgi?id=3117 // dmd crash by *1 void main(){ *1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail2962.d ================================================ // EXTRA_SOURCES: imports/fail2962a.d // comment 6 /* TEST_OUTPUT: --- fail_compilation/fail2962.d(14): Error: variable `y` cannot be read at compile time fail_compilation/fail2962.d(14): while looking for match for `baz6!(int, y)` fail_compilation/fail2962.d(22): Error: template instance `fail2962.bar6!int` error instantiating --- */ T bar6(T)(T y) { return baz6!(T, y)(); } T baz6(T, T z)() { return z * z; } void test6() { assert(bar6(4) != 0); } // comment 4 /* TEST_OUTPUT: --- fail_compilation/fail2962.d(36): Error: variable `x` cannot be read at compile time fail_compilation/fail2962.d(36): while looking for match for `baz4!(int, x)` fail_compilation/imports/fail2962a.d(6): Error: template instance `fail2962.bar4!int` error instantiating --- */ T bar4(T)(T x) { return baz4!(T, x)(); } T baz4(T, T x)() { return x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail297.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail297.d(30): Error: incompatible types for `(Bar()) + (baz())`: `Bar` and `const(Bar)` --- */ // https://issues.dlang.org/show_bug.cgi?id=1969 // ICE(cod1.c) using undefined operator with one const operand // ICE or wrong-code. D2 only. Internal error: backend\cod1.c 1673 /* Root cause: BinExp::typeCombine() is checking for an _exact_ match, but typeMerge() will return success. PATCH: cast.c BinExp::typeCombine(). Compare the immutable versions of the types, instead of the types themselves. if (op == TOKmin || op == TOKadd) { if (t1->ito == t2->ito && (t1->ty == Tstruct || t1->ty == Tclass)) goto Lerror; } */ struct Bar {} const(Bar) baz() { return Bar(); } void foo() { Bar result = Bar() + baz(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail298.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail298.d(12): Error: cannot implicitly convert expression `num1 / cast(ulong)num2` of type `ulong` to `int` --- */ void main() { ulong num1 = 100; int num2 = 10; int result = num1 / num2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail299.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail299.d(14): Error: more initializers than fields (0) of `Foo` --- */ struct Foo {} void foo (Foo b, void delegate ()) {} void main () { foo(Foo(1), (){}); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail3.d(41): Error: incompatible types for `(a) + (b)`: both operands are of type `vec2` --- */ // DMD 0.79 linux: Internal error: ../ztc/cgcod.c 1459 template vector(T) { struct vec2 { T x, y; } // not struct member vec2 opAdd(vec2 a, vec2 b) { vec2 r; r.x = a.x + b.x; r.y = a.y + b.y; return r; } vec2 make2(T x, T y) { vec2 a; a.x = x; a.y = y; return a; } } alias vector!(float).vec2 vec2f; int main() { vec2f a, b; b.x = 3; a = a + b; //printf("%f\n", a.x); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail301.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail301.d(11): Error: need `this` for `guard` of type `int` fail_compilation/fail301.d(22): Error: template instance `fail301.bug3305!0` error instantiating --- */ struct bug3305(alias X = 0) { auto guard = bug3305b!(0).guard; } struct bug3305b(alias X = 0) { bug3305!(X) goo; auto guard = 0; } void test() { bug3305!(0) a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail302.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail302.d(23): Error: cannot implicitly convert expression `1` of type `int` to `Bar` fail_compilation/fail302.d(23): `bar = 1` is the first assignment of `bar` therefore it represents its initialization fail_compilation/fail302.d(23): `opAssign` methods are not used for initialization, but for subsequent assignments --- */ struct Bar { uint num; Bar opAssign(uint otherNum) { num = otherNum; return this; } } void main() { Bar bar = 1; // disallow because construction is not assignment auto x = bar.num; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail303.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail303.d(19): Error: `double /= cdouble` is undefined. Did you mean `double /= cdouble.re`? fail_compilation/fail303.d(20): Error: `ireal *= ireal` is an undefined operation fail_compilation/fail303.d(21): Error: `ireal *= creal` is undefined. Did you mean `ireal *= creal.im`? fail_compilation/fail303.d(22): Error: `ireal %= creal` is undefined. Did you mean `ireal %= creal.im`? fail_compilation/fail303.d(23): Error: `ireal += real` is undefined (result is complex) fail_compilation/fail303.d(24): Error: `ireal -= creal` is undefined (result is complex) fail_compilation/fail303.d(25): Error: `double -= idouble` is undefined (result is complex) --- */ void main() { ireal x = 3.0i; double y = 3; y /= 2.0 + 6i; x *= 7.0i; x *= 3.0i + 2; x %= (2 + 6.0i); x += 2.0; x -= 1 + 4i; y -= 3.0i; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail304.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail304.d(15): Error: cannot cast expression `foo()` of type `Small` to `Large` because of different sizes --- */ struct Small { uint x; } struct Large { uint x, y, z; } Small foo() { return Small(); } void main() { Large l; Small s; l = cast(Large)foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail305.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail305.d(10): Error: cannot return non-void from `void` function --- */ void main() { return "a"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail306.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail306.d(11): Error: cannot perform array operations on `void[]` arrays --- */ void bar() { void [] x; x[] = -x[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail307.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail307.d(11): Error: cannot implicitly convert expression `cast(int)(cast(double)cast(int)b + 6.1)` of type `int` to `short` --- */ void main() { ubyte b = 6; short c5 = cast(int)(b + 6.1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail308.d ================================================ // REQUIRED_ARGS: -unittest void main() { MinHeap!(int) foo = new MinHeap!(int)(); } class MinHeap(NodeType) { unittest { struct TestType {} MinHeap!(TestType) foo = new MinHeap!(TestType)(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail309.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail309.d(10): Error: circular reference to variable `fail309.S.x` --- */ // REQUIRED_ARGS: -d struct S { const x = S.x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail310.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail310.d(10): Error: undefined identifier `Foo`, did you mean function `foo`? fail_compilation/fail310.d(14): Error: template instance `fail310.foo!(1, 2)` error instantiating fail_compilation/fail310.d(14): while evaluating: `static assert(foo!(1, 2)())` --- */ Foo foo(A...)() { } static assert(foo!(1, 2)()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail311.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail311.d(16): Error: undefined identifier `undefined` fail_compilation/fail311.d(25): Error: template instance `fail311.foo!()` error instantiating --- */ template Tuple(T...) { alias T Tuple; } void foo()() { undefined x; foreach (i; Tuple!(2)) { static assert(true); } } void main() { foo!()(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail312.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail312.d(13): Error: incompatible types for `(a[]) == (b)`: `int[]` and `short` fail_compilation/fail312.d(14): Error: incompatible types for `(a[]) <= (b)`: `int[]` and `short` --- */ void main() { int[1] a = 1; short b = 1; assert(a[] == b); assert(a[] <= b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail313.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail313.d(17): Error: module `imports.b313` is not accessible here, perhaps add `static import imports.b313;` fail_compilation/fail313.d(24): Deprecation: `imports.a313.core` is not visible from module `test313` fail_compilation/fail313.d(24): Error: package `core.stdc` is not accessible here fail_compilation/fail313.d(24): Error: module `core.stdc.stdio` is not accessible here, perhaps add `static import core.stdc.stdio;` fail_compilation/fail313.d(29): Error: package `imports.pkg313` is not accessible here, perhaps add `static import imports.pkg313;` --- */ module test313; import imports.a313; void test1() { imports.b313.bug(); import imports.b313; imports.b313.bug(); } void test2() { core.stdc.stdio.printf(""); } void test3() { imports.pkg313.bug(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail314.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail314.d(11): Error: declaration `T` is already defined --- */ struct foo { static if (is(int T == int)) {} static if (is(int T == int)) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3144.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail3144.d(12): Error: `break` is not inside a loop or `switch` fail_compilation/fail3144.d(15): Error: `break` is not inside a loop or `switch` --- */ void main() { switch (1) default: {} break; final switch (1) case 1: {} break; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail315.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail315.d-mixin-16(16): Error: found `;` when expecting `,` fail_compilation/fail315.d-mixin-16(16): Error: expression expected, not `}` fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `,` fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `]` fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `;` following `return` statement fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `}` following compound statement fail_compilation/fail315.d(21): Error: template instance `fail315.foo!()` error instantiating --- */ void foo(S...)(S u) { alias typeof(mixin("{ return a[1;}()")) z; } void main() { foo!()(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3150.d ================================================ // REQUIRED_ARGS: -de void main() { ulong u = cast(ulong)[1,2]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail316.d ================================================ template BadImpl(T, alias thename) { void a_bad_idea(T t) { thename.a_bad_idea(t); } } class foo { mixin BadImpl!(uint,Mix1) Mix1; } int main() { return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail317.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail317.d(10): Error: function `fail317.I.f` has no function body with return type inference --- */ interface I { auto f() in {} out {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail318.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail318.d(8): Error: function `D main` must return `int` or `void` --- */ auto main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail319.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail319.d(13): Error: template instance `fail319.f!(int, int)` does not match template declaration `f(T...)() if (T.length > 20)` --- */ void f(T...)() if (T.length > 20) {} void main() { f!(int, int)(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail320.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail320.d(10): Error: no overload matches for `foo` --- */ import imports.fail320a; import imports.fail320b; void main() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail322.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail322.d(13): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` fail_compilation/fail322.d(13): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` fail_compilation/fail322.d(15): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(const(char[16]))` fail_compilation/fail322.d(15): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` --- */ void main() { digestToString2("1234567890123456"); const char[16] s; digestToString2(s); } void digestToString2(ref char[16] digest) { assert(digest[0] == 0xc3); assert(digest[15] == 0x3b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail324.d ================================================ /* test_output: --- fail_compilation/fail324.d(16): Error: template instance doStuff!((i){ return i; }) cannot use local `__lambda1` as parameter to non-global template `doStuff(alias fun)()` --- */ struct Foo { void doStuff(alias fun)() {} } void main() { Foo foo; foo.doStuff!( (i) { return i; })(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail325.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail325.d(12): Error: template `fun(T = int)(int w, int z)` has no type --- */ void fun(T = int)(int w, int z) {} void main() { auto x = cast(void function(int, int))fun; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail327.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail327.d(10): Error: `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not --- */ @safe void foo() { version(GNU) asm { ""; } else asm { xor EAX,EAX; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail328.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail328.d(13): Error: `@safe` function `fail328.foo` cannot call `@system` function `fail328.bar` fail_compilation/fail328.d(9): `fail328.bar` is declared here --- */ void bar(); @safe void foo() { bar(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail329.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail329.d(28): Error: variable `fail329.A.foo.__ensure.result` cannot modify result `result` in contract --- */ //import core.stdc.stdio; /*******************************************/ class A { int x = 7; int foo(int i) in { //printf("A.foo.in %d\n", i); assert(i == 2); assert(x == 7); //printf("A.foo.in pass\n"); } out (result) { assert(result & 1); assert(x == 7); result++; } body { return i; } } class B : A { override int foo(int i) in { float f; //printf("B.foo.in %d\n", i); assert(i == 4); assert(x == 7); f = f + i; } out (result) { assert(result < 8); assert(x == 7); } body { return i - 1; } } void test1() { auto b = new B(); b.foo(2); b.foo(4); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3290.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=3290 void main() { const(int)[] array; foreach (ref int i; array) { //i = 42; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail330.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail330.d(9): Error: variable `fail330.fun.result` cannot modify result `result` in contract --- */ int fun() out(result) { result = 2; } body { return 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail331.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail331.d(10): Error: cannot use `typeof(return)` inside function `foo` with inferred return type --- */ auto foo() { typeof(return) result; return result; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail332.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail332.d(14): Error: function `fail332.foo(int _param_0, ...)` is not callable using argument types `()` --- */ import core.vararg; void foo(int, ...) {} void bar() { foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail333.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail333.d(8): Error: forward reference to `test` --- */ void test(typeof(test) p) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail334.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail334.d(10): Error: properties can only have zero, one, or two parameter --- */ struct S { @property int foo(int a, int b, int c) { return 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail335.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail335.d(9): Error: cannot overload both property and non-property functions --- */ void foo(); @property void foo(int); void main() { foo(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail336.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail336.d(16): Error: struct `S` has constructors, cannot use `{ initializers }`, use `S( initializers )` instead --- */ // https://issues.dlang.org/show_bug.cgi?id=3476 // C-style initializer for structs must be disallowed for structs with a constructor struct S { int a; this(int) {} } S s = { 1 }; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail337.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail337.d(13): Error: static assert: `0` is false fail_compilation/fail337.d(26): instantiated from here: `bar!()` fail_compilation/fail337.d(33): 100 recursive instantiations from here: `foo!196` fail_compilation/fail337.d(41): 253 recursive instantiations from here: `baz!300` --- */ template bar() { static assert(0); } template foo(int N) { static if (N > 0) { static if (N & 1) alias foo!(N - 3) foo; else alias foo!(N - 1) foo; } else alias bar!() foo; } template baz(int M) { static if (M < 50) { alias foo!(M * 4) baz; } else alias baz!(M - 1) baz; } void main() { int x = baz!(300); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail34.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail34.d(31): Error: duplicate `case "123"` in `switch` statement --- */ // $HeadURL$ // $Date$ // $Author$ // @author@ Thomas Kuehne // @date@ 2004-11-17 // @uri@ news:u1gr62-kjv.ln1@kuehne.cn // @url@ nntp://digitalmars.com/digitalmars.D.bugs/2288 // duplicate case "123" in switch statement module switch_12; int main() { string array = "123"; switch(array) { case "123": { assert(0); break; } case "123": { assert(1); break; } default: { return -1; // dummy } } return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail340.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail340.d(18): Error: variable `fail340.w` of type struct `const(CopyTest)` uses `this(this)`, which is not allowed in static initialization fail_compilation/fail340.d(19): while evaluating: `static assert(w.x == 55.0000)` --- */ struct CopyTest { double x; this(double a) { x = a * 10.0;} this(this) { x += 2.0; } } const CopyTest z = CopyTest(5.3); const CopyTest w = z; static assert(w.x == 55.0); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail341.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail341.d(26): Error: struct `fail341.S` is not copyable because it is annotated with `@disable` fail_compilation/fail341.d(27): Error: function `fail341.foo` cannot be used because it is annotated with `@disable` --- */ struct T { @disable this(this) { } } struct S { T t; } @disable void foo() { } void main() { S s; auto t = s; foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail343.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail343.d(22): Error: function `fail343.TimedApp.run` cannot override `final` function `I.fail343.Timer.run` fail_compilation/fail343.d(22): Error: function `fail343.TimedApp.run` cannot override `final` function `Application.fail343.Application.run` --- */ interface Timer { final void run() { } } interface I : Timer { } interface Application { final void run() { } } class TimedApp : I, Application { // cannot define run() void run() { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail344.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=3737 int crayon; struct SIB(alias junk) { template Alike(V) { enum bool Alike = Q == V.garbage; } void opDispatch(string s)() { static assert(Alike!(SIB!(crayon))); } } void main() { SIB!(SIB!(crayon).E)(3.0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail346.d ================================================ struct S { int x; template T(int val) { const P T = { val }; // the P here is an error it should be S } } template V(R,int val){ const R V=R.T!(val); } const S x = V!(S,0); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail347.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail347.d(21): Error: undefined identifier `bbr`, did you mean variable `bar`? fail_compilation/fail347.d(22): Error: no property `ofo` for type `S`, did you mean `fail347.S.foo`? fail_compilation/fail347.d(23): Error: undefined identifier `strlenx`, did you mean function `strlen`? --- */ //import core.stdc.string; import imports.fail347a; struct S { int foo; } void main() { S bar; bbr.foo = 3; bar.ofo = 4; auto s = strlenx("hello"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail349.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not `nothrow` fail_compilation/fail349.d(13): Error: `nothrow` function `fail349.bug6109noThrow` may throw --- */ int bug6109throwing() { throw new Exception("throws"); } int bug6109noThrow() nothrow { auto g = [4][0 .. bug6109throwing()]; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail35.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail35.d(15): Error: variable `t` cannot be read at compile time --- */ // http://www.digitalmars.com/d/archives/digitalmars/D/bugs/2372.html // allegedly crashes, but cannot reproduce void main() { for (int t = 0; t < 33; t++) { size_t n = (bool[t]).sizeof; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail351.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail351.d(14): Error: `cast(uint)this.num[index]` is not an lvalue and cannot be modified --- */ // https://issues.dlang.org/show_bug.cgi?id=2780 struct Immutable { immutable uint[2] num; ref uint opIndex(size_t index) immutable { return num[index]; } } void main() { immutable Immutable foo; //foo[0]++; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail352.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail352.d(18): Error: cannot infer argument types, expected 1 argument, not 2 --- */ struct Range { bool empty; int front() { return 0; } void popFront() { empty = true; } } void main() { // no index for range foreach foreach(i, v; Range()) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail354.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail354.d(11): Error: template instance `T!N` template `T` is not defined fail_compilation/fail354.d(13): Error: template instance `fail354.S!1` error instantiating --- */ struct S(int N) { this(T!N) { } } alias S!1 M; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail355.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail355.d(8): Error: module `imports.fail355` import `nonexistent` not found --- */ import imports.fail355 : nonexistent; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail356a.d ================================================ import imports.fail356; int imports; // collides with package name ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail356b.d ================================================ import imports.fail356 : bar; int bar; // collides with selective import ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail356c.d ================================================ import foo = imports.fail356; int foo; // collides with renamed import ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3581a.d ================================================ class A { void f() {} } class B : A { static override void f() {}; } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3581b.d ================================================ class A { void f() {} } class B : A { private override void f() {}; } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail359.d ================================================ #line 5 _BOOM void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail36.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail36.d(13): Error: template `t(int L)` does not have property `a` fail_compilation/fail36.d(18): Error: mixin `fail36.func.t!10` error instantiating --- */ template t(int L) { int a; // void foo(int b = t!(L).a) {} // correct void foo(int b = t.a) {} // wrong } void func() { mixin t!(10); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3672.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail3672.d(27): Error: read-modify-write operations are not allowed for `shared` variables. Use `core.atomic.atomicOp!"+="(*p, 1)` instead. fail_compilation/fail3672.d(31): Error: none of the `opOpAssign` overloads of `SF` are callable for `*sfp` of type `shared(SF)` --- */ struct SF // should fail { void opOpAssign(string op, T)(T rhs) { } } struct SK // ok { void opOpAssign(string op, T)(T rhs) shared { } } void main() { shared int x; auto p = &x; *p += 1; // fail shared SF sf; auto sfp = &sf; *sfp += 1; // fail shared SK sk; auto skp = &sk; sk += 1; // ok *skp += 1; // ok } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3673a.d ================================================ class A {} class B : A if(false) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3673b.d ================================================ class A {} class B : if(false) A { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3703.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=3703 // static array assignment /* TEST_OUTPUT: --- fail_compilation/fail3703.d(18): Error: mismatched array lengths, 2 and 1 fail_compilation/fail3703.d(20): Error: mismatched array lengths, 2 and 1 fail_compilation/fail3703.d(22): Error: mismatched array lengths, 3 and 2 fail_compilation/fail3703.d(23): Error: mismatched array lengths, 2 and 3 fail_compilation/fail3703.d(25): Error: mismatched array lengths, 3 and 2 fail_compilation/fail3703.d(26): Error: mismatched array lengths, 2 and 3 --- */ void main() { int[1] a = [1]; int[2] b = a; // should make compile error b = a; // should make compile error int[3] sa3 = [1,2][]; int[2] sa2 = sa3[][]; sa3 = [1,2][]; sa2 = sa3[][]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3731.d ================================================ void main() { class C {} class D : C {} auto x = new immutable(D); C y = x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3753.d ================================================ /* --- Error: cannot mix core.std.stdlib.alloca() and exception handling in _Dmain() --- */ import core.stdc.stdlib : alloca; import core.stdc.stdio; struct TheStruct { ~this() { printf("dtor()\n"); } } void bar() { printf("bar()\n"); } void main() { auto s = TheStruct(); bar(); auto a = alloca(16); printf("test()\n"); version (DigitalMars) { version (Win32) static assert(0); version (linux) { static assert(0); } version (FreeBSD) { static assert(0); } version (DragonFlyBSD) { static assert(0); } version (OSX) { static assert(0); } } else static assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/fail37_m32.d(9): Error: `cast(float)4u / cast(float)8u - cast(float)2147483647` is not of integral type, it is a `float` --- */ ulong[cast(uint)((cast(float)int.sizeof/ulong.sizeof)-int.max>>2)+int.max>>2] hexarray; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d ================================================ // REQUIRED_ARGS: -m64 /* TEST_OUTPUT: --- fail_compilation/fail37_m64.d(9): Error: `cast(float)4LU / cast(float)8LU - cast(float)2147483647` is not of integral type, it is a `float` --- */ ulong[cast(uint)((cast(float)int.sizeof/ulong.sizeof)-int.max>>2)+int.max>>2] hexarray; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail38.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail38.d(12): Error: `super` is only allowed in non-static class member functions --- */ int x; void test() { super.x = 2; } int main() { test(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3882.d ================================================ // REQUIRED_ARGS: -w // PERMUTE_ARGS: -debug /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=3882 /* TEST_OUTPUT: --- fail_compilation/fail3882.d(23): Warning: calling fail3882.strictlyPure!int.strictlyPure without side effects discards return value of type int, prepend a cast(void) if intentional fail_compilation/fail3882.d(27): Warning: calling fp without side effects discards return value of type int, prepend a cast(void) if intentional --- */ @safe pure nothrow T strictlyPure(T)(T x) { return x*x; } void main() { int x = 3; strictlyPure(x); // https://issues.dlang.org/show_bug.cgi?id=12649 auto fp = &strictlyPure!int; fp(x); } /******************************************/ // bugfix in TypeFunction::purityLevel /* TEST_OUTPUT: --- fail_compilation/fail3882.d(46): Warning: calling fail3882.f1 without side effects discards return value of type int, prepend a cast(void) if intentional fail_compilation/fail3882.d(47): Warning: calling fail3882.f2 without side effects discards return value of type int, prepend a cast(void) if intentional --- */ nothrow pure int f1(immutable(int)[] a) { return 0; } nothrow pure int f2(immutable(int)* p) { return 0; } void test_bug() { f1([]); f2(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3895.d ================================================ import std.stdio; void main() { double[] stuff = [1.,2.,3.,4.,5.]; float[] otherStuff; otherStuff ~= stuff; writeln(otherStuff); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail39.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail39.d(11): Error: function fail39.main.__funcliteral2 cannot access frame of function D main --- */ void main() { void foo() {} void function() bar = function void() { foo(); }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail3990.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail3990.d(12): Error: using `*` on an array is no longer supported; use `*(arr1).ptr` instead fail_compilation/fail3990.d(14): Error: using `*` on an array is no longer supported; use `*(arr2).ptr` instead --- */ void main() { int[] arr1 = [1, 2, 3]; assert(*arr1 == 1); int[3] arr2 = [1, 2, 3]; assert(*arr2 == 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail40.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail40.d(11): Error: variable `yuiop` cannot be read at compile time --- */ struct Qwert { int[20] yuiop; int* asdfg = yuiop.ptr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4082.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not `nothrow` fail_compilation/fail4082.d(12): Error: `nothrow` function `fail4082.test1` may throw --- */ struct Foo { ~this() { throw new Exception(""); } } nothrow void test1() { Foo f; goto NEXT; NEXT: ; } /* TEST_OUTPUT: --- fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not `nothrow` fail_compilation/fail4082.d(32): Error: `nothrow` function `fail4082.test2` may throw --- */ struct Bar { ~this() { throw new Exception(""); } } nothrow void test2(Bar t) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail41.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail41.d(17): Error: cannot return non-void from `void` function --- */ class MyClass { } MyClass[char[]] myarray; void fn() { foreach (MyClass mc; myarray) return mc; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail42.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail42.d(22): Error: struct `fail42.Qwert` no size because of forward reference --- */ /+ struct Qwert { Qwert asdfg; } +/ struct Qwert { Yuiop asdfg; } struct Yuiop { Qwert hjkl; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4206.d ================================================ struct s {} enum var = s; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269a.d ================================================ enum bool WWW = is(typeof(A.x)); interface A { B blah; void foo(B b){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269b.d ================================================ enum bool WWW = is(typeof(A.x)); struct A { B blah; void foo(B b){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269c.d ================================================ enum bool WWW = is(typeof(A.x)); class A { B blah; void foo(B b){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269d.d ================================================ static if(is(typeof(X6.init))) {} alias Y X6; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269e.d ================================================ static if(is(typeof(X5.init))) {} typedef Y X5; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269f.d ================================================ static if(is(typeof(X16))) {} alias X16 X16; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4269g.d ================================================ int[2] d; static if(is(typeof(Xg.init))) {} alias d[1] Xg; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4374.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail4374.d(11): Error: terminating `;` required after do-while statement --- */ void main() { do {} while(0) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375a.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) if (false) assert(3); else assert(4); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375b.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { // disallowed if (true) foreach (i; 0 .. 5) if (true) assert(5); else assert(6); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375c.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) if (false) { assert(6.1); } else { assert(6.2); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375d.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) label2: if (true) assert(15); else assert(16); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375e.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { version (A) if (true) assert(24); else assert(25); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375f.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { version (A) version (B) assert(25.1); else assert(25.2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375g.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { static if (true) static if (true) assert(33); else assert(34); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375h.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { switch (4) { default: if (true) // disallowed if (false) assert(48); else assert(49); break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375i.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) switch (1) // o_O default: if (false) assert(115); else assert(116); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375j.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) final switch (1) // o_O case 1: if (false) assert(119); else assert(120); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375k.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { mixin(q{ if(true) if(true) assert(54); else assert(55); }); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375l.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) while (false) if (true) assert(70); else assert(71); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375m.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { do if (true) if (true) assert(76); else assert(77); while (false); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375o.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) for (; false;) if (true) assert(82); else assert(83); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375p.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) while (false) for (;;) scope (exit) synchronized (x) if (true) assert(90); else assert(89); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375q.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { auto x = 1; if (true) with (x) if (false) assert(90); else assert(91); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375r.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) try assert(103); finally if (true) assert(104); else assert(105); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375s.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else void main() { if (true) try assert(106); catch(Exception e) if (true) assert(107); else assert(108); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375t.d ================================================ // REQUIRED_ARGS: -w -unittest // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else unittest { // disallowed if (true) if (false) assert(52); else assert(53); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375u.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else static if (true) static if (false) struct G1 {} else struct G2 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375v.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else version (A) version (B) struct G3 {} else struct G4 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375w.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else static if (true) version (B) struct G1 {} else struct G2 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375x.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else static if (true) abstract: static if (false) class G5 {} else class G6 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4375y.d ================================================ // REQUIRED_ARGS: -w // https://issues.dlang.org/show_bug.cgi?id=4375: Dangling else static if (true) align(1) extern(C) pure static if (false) void G10(){} else void G11(){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail44.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail44.d(18): Error: expression `bar[i]` is `void` and has no value --- */ void Foo() { void[] bar; void[] foo; bar.length = 50; foo.length = 50; for(size_t i=0; i<50; i++) { foo[i] = bar[i]; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4421.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail4421.d(16): Error: function `fail4421.U1.__postblit` destructors, postblits and invariants are not allowed in union `U1` fail_compilation/fail4421.d(17): Error: destructor `fail4421.U1.~this` destructors, postblits and invariants are not allowed in union `U1` fail_compilation/fail4421.d(18): Error: function `fail4421.U1.__invariant1` destructors, postblits and invariants are not allowed in union `U1` --- */ union U1 { this(this); ~this(); invariant() { } } struct S1 { this(this); ~this(); invariant() { } } union U2 { S1 s1; } struct S2 { union { S1 s1; int j; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4448.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail4448.d(19): Error: label `L1` has no `break` fail_compilation/fail4448.d(26): called from here: `bug4448()` fail_compilation/fail4448.d(26): while evaluating: `static assert(bug4448() == 3)` --- */ int bug4448() { int n=2; L1:{ switch(n) { case 5: return 7; default: n = 5; break L1; } int w = 7; } return 3; } static assert(bug4448()==3); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail45.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail45.d(10): Error: variable `fail45.main.O` cannot be declared to be a function --- */ void main() { typeof(main) O = 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4510.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=4510 void main() { float[] arr = [1.0, 2.5, 4.0]; foreach (ref double elem; arr) { //elem /= 2; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4511.d ================================================ void test72() { class A {} class B : A {} class X { abstract A func(); } class Y : X { B func() { return new A(); } } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4517.d ================================================ enum E : ushort { A, B } void main() { E e; final switch(e) { case E.A: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4559.d ================================================ /* REQUIRED_ARGS: -o- -de TEST_OUTPUT: --- fail_compilation/fail4559.d(13): Deprecation: use `{ }` for an empty statement, not `;` fail_compilation/fail4559.d(19): Deprecation: use `{ }` for an empty statement, not `;` fail_compilation/fail4559.d(21): Deprecation: use `{ }` for an empty statement, not `;` --- */ void foo() { int x;; enum A { a, b, c }; void bar() {}; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail46.d ================================================ // PERMUTE_ARGS: -inline /* TEST_OUTPUT: --- fail_compilation/fail46.d(19): Error: need `this` for `bug` of type `int()` --- */ struct MyStruct { int bug() { return 3; } } int main() { assert(MyStruct.bug() == 3); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4611.d ================================================ /* --- fail_compilation/fail4611.d(15): Error: `Vec[2147483647]` size 4 * 2147483647 exceeds 0x7fffffff size limit for static array --- */ struct Vec { int x; } void main() { Vec[ptrdiff_t.max] a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail47.d ================================================ void foo() {} int _foo; alias _foo foo; void main() { foo = 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail4958.d ================================================ enum FloatEnum : float { A = float.max/2, B, C } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail50.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail50.d(12): Error: need `this` for address of `a` fail_compilation/fail50.d(12): Error: variable `a` cannot be read at compile time --- */ struct Marko { int a; int* m = &a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail51.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail51.d(11): Error: interface `fail51.B` circular inheritance of interface --- */ // interface A { void f(); } interface A : B { void f(); } interface B : A { void g(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5153.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=5153 /* TEST_OUTPUT: --- fail_compilation/fail5153.d(26): Error: cannot implicitly convert expression `new Foo(0)` of type `Foo*` to `Foo` fail_compilation/fail5153.d(26): Perhaps remove the `new` keyword? --- */ class Foo2 { this(int) {} } struct Foo { int x; this(int x_) { this.x = x_; } this(Foo2) {} } void main() { Foo f = new Foo(0); Foo f2 = new Foo2(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail52.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail52.d(10): Error: class `fail52.C` circular inheritance --- */ class A : B { void f(); } class B : C { override void g(); } class C : A { void g(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail53.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail53.d(26): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `(int)` fail_compilation/fail53.d(26): cannot pass argument `i` of type `int` to parameter `Object o` --- */ // $HeadURL$ // $Date$ // $Author$ // @author@ Thomas Kuehne // @date@ 2005-01-22 // @uri@ news:csvvet$2g4$1@digitaldaemon.com // @url@ nntp://news.digitalmars.com/digitalmars.D.bugs/2741 // __DSTRESS_ELINE__ 17 module dstress.nocompile.bug_mtype_507_A; int main() { Object o; int i; if (i == o) { return -1; } return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail54.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail54.d(22): Error: incompatible types for `(0) == (Exception)`: cannot use `==` with types --- */ // $HeadURL$ // $Date$ // $Author$ // @author@ zwang // @date@ 2005-02-03 // @uri@ news:ctthp6$25b$1@digitaldaemon.com // __DSTRESS_ELINE__ 14 module dstress.nocompile.bug_mtype_507_C; void test() { 0 == Exception; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5435.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=5435 template Tuple5435(E...) { alias E Tuple5435; } enum Enum5435 { A, B, C }; void main() { alias Tuple5435!(Enum5435.A, Enum5435.B, Enum5435.C, "foo", 3.0) tup; foreach (Enum5435 foo; tup) pragma(msg, foo); foreach ( string foo; tup) pragma(msg, foo); foreach ( int foo; tup) pragma(msg, foo); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail55.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail55.d(23): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `(int)` fail_compilation/fail55.d(23): cannot pass argument `0` of type `int` to parameter `Object o` --- */ // $HeadURL$ // $Date$ // $Author$ // @author@ zwang // @date@ 2005-02-03 // @uri@ news:cttjjg$4i0$2@digitaldaemon.com // __DSTRESS_ELINE__ 14 module dstress.nocompile.bug_mtype_507_D; void test() { 0 < Exception; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail56.d ================================================ // $HeadURL$ // $Date$ // $Author$ // @author@ Regan Heath // @date@ 2005-03-30 // @uri@ news:opsof4hwgy23k2f5@nrage.netwin.co.nz // __DSTRESS_ELINE__ 14 module dstress.nocompile.bug_20050330_A; template Blah(int a, alias B){ mixin Blah!(a, B) Foo; } int main(){ int a; mixin Blah!(5,a); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5634.d ================================================ void main() { } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail57.d ================================================ int main() { int x = 1 / 0; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5733.d ================================================ struct Test { struct opDispatch(string dummy) { enum opDispatch = 1; } } auto temp = Test().foo!(int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail58.d ================================================ debug(1) import std.stdio; const int anything = -1000; // Line #2 dchar[] SomeFunc( dchar[] pText, out int pStopPosn) { if (pText.length == 0) pStopPosn = 0; else pStopPosn = -1; debug(1) writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); return pText.dup; } int main(char[][] pArgs) { int sp; SomeFunc("123", sp); debug(1) writefln("DEBUG: got %d", sp); assert(sp == -1); SomeFunc("", sp); // if (sp != 0){} // Line #22 debug(1) writefln("DEBUG: got %d", sp); assert(sp == -1); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5851.d ================================================ class Foo { Object o; alias o this; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail59.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail59.d(50): Error: outer class `C1` `this` needed to `new` nested class `C2` --- */ class C1 { int c1; this() { c1 = 2; } class C2 { class C3 { int c3; this(int n) { c3 = n + c1 + c2; } } int c2; C3 foo() { return new C3(8); } this(int k) { c2 = k + 7; } } C2 bar() { return new C2(17); } } void main() { C1.C2 q = new C1.C2(3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5953a1.d ================================================ void main() { auto a2 = [,]; // invalid, but compiles } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5953a2.d ================================================ void main() { auto a3 = [,,,]; // invalid, but compiles } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5953s1.d ================================================ void main() { struct S{} S s2 = {,}; // invalid, but compiles } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail5953s2.d ================================================ void main() { struct S{} S s3 = {,,,}; // invalid, but compiles } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail60.d ================================================ class A { class B { } B b=new B; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6029.d ================================================ struct A { static A a; alias a this; } void foo(A a) { } void main() { // foo(A); // Error: type A is not an expression int s = A; // Error: type A has no value + stack overflow } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail61.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail61.d(22): Error: no property `B` for type `fail61.A.B` fail_compilation/fail61.d(23): Error: no property `B` for type `fail61.A.B` fail_compilation/fail61.d(32): Error: no property `A2` for type `fail61.B2` fail_compilation/fail61.d(41): Error: `this` for `foo` needs to be type `B3` not type `fail61.C3` --- */ class A { class B : A { static const int C = 5; } } void main() { int n1 = A.B.C; int n2 = A.B.B.C; // Line22 int n3 = A.B.B.B.C; // Line23 } class A2 { void foo(){ assert(0);} } class B2 : A2 { override void foo(){} } class C2 : B2 { void bar() { B2.A2.foo(); // Line32 } } class B3 { void foo(){ assert(0); } } class C3 { void bar() { B3.foo(); // Line41 } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6107.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail6107.d(10): Error: variable `fail6107.Foo.__ctor` is not a constructor; identifiers starting with `__` are reserved for the implementation fail_compilation/fail6107.d(14): Error: variable `fail6107.Bar.__ctor` is not a constructor; identifiers starting with `__` are reserved for the implementation --- */ struct Foo { enum __ctor = 4; } class Bar { int __ctor = 4; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail62.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail62.d(11): Error: version `Foo` defined after use --- */ version (Foo) int x; version = Foo; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6242.d ================================================ class A { void fun(int) {} } class B : A { void fun(int x) in { assert(x > 0); } body {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail63.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail63.d(11): Error: debug `Foo` defined after use --- */ debug (Foo) int x; debug = Foo; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6334.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail6334.d(12): Error: static assert: `0` is false --- */ mixin template T1() { mixin T2; //compiles if these lines mixin T2!(a, bb, ccc, dddd); //are before T2 declaration mixin template T2() { static assert(0); } } void main() { mixin T1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6451.d ================================================ version(GNU) { static assert(0); } version(Win64) { static assert(0); } else version(X86_64) { void error(...){} } else { static assert(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6453.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail6453.d(13): Error: struct `fail6453.S6453x` mixing invariants with different `shared`/`synchronized` qualifiers is not supported fail_compilation/fail6453.d(18): Error: class `fail6453.C6453y` mixing invariants with different `shared`/`synchronized` qualifiers is not supported fail_compilation/fail6453.d(23): Error: class `fail6453.C6453z` mixing invariants with different `shared`/`synchronized` qualifiers is not supported --- */ struct S6453x { invariant() {} shared invariant() {} } class C6453y { invariant() {} synchronized invariant() {} } class C6453z { shared invariant() {} synchronized invariant() {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6458.d ================================================ void main() { char d = ''; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6497.d ================================================ void main() @safe { int n; auto b = &(0 ? n : n); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6561.d ================================================ struct S { alias x this; // should cause undefined identifier error } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail66.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail66.d(11): Error: constructor `fail66.C1.this` missing initializer for const field `y` --- */ class C1 { const int y; this() {} } /* TEST_OUTPUT: --- fail_compilation/fail66.d(28): Error: cannot modify `const` expression `c.y` --- */ class C2 { const int y; this() { y = 7; } } void test2() { C2 c = new C2(); c.y = 3; } /* TEST_OUTPUT: --- fail_compilation/fail66.d(43): Error: cannot modify `const` expression `this.y` --- */ class C3 { const int y; this() { y = 7; } void foo() { y = 6; } } /* TEST_OUTPUT: --- fail_compilation/fail66.d(59): Error: cannot modify `const` expression `x` --- */ class C4 { static const int x; static this() { x = 5; } void foo() { x = 4; } } /* TEST_OUTPUT: --- fail_compilation/fail66.d(73): Error: cannot modify `const` expression `z5` --- */ const int z5; static this() { z5 = 3; } void test5() { z5 = 4; } /* TEST_OUTPUT: --- fail_compilation/fail66.d(89): Error: cannot modify `const` expression `c.y` --- */ class C6 { const int y; this() { C6 c = this; y = 7; c.y = 8; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6611.d ================================================ void main() { auto x = new int[](10); x[]++; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6652.d ================================================ // PERMUTE_ARGS: -w -dw -de -d /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=6652 /* TEST_OUTPUT: --- fail_compilation/fail6652.d(20): Error: cannot modify `const` expression `i` fail_compilation/fail6652.d(25): Error: cannot modify `const` expression `i` fail_compilation/fail6652.d(30): Error: cannot modify `const` expression `i` fail_compilation/fail6652.d(35): Error: cannot modify `const` expression `i` --- */ void main() { foreach (const i; 0..2) { ++i; } foreach (ref const i; 0..2) { ++i; } foreach (const i, e; [1,2,3,4,5]) { ++i; } foreach (ref const i, e; [1,2,3,4,5]) { ++i; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6781.d ================================================ void bug6781(alias xxx)() { some_error; } struct C6781 { void makeSortedIndices() { int greater; bug6781!greater(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6795.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=6795 /* TEST_OUTPUT: --- fail_compilation/fail6795.d(12): Error: cannot modify constant `0` fail_compilation/fail6795.d(13): Error: cannot modify constant `0` --- */ void main() { enum int[] array = [0]; array[0]++; array[0] += 3; } /* TEST_OUTPUT: --- fail_compilation/fail6795.d(31): Error: cannot modify constant `0` fail_compilation/fail6795.d(32): Error: cannot modify constant `0` fail_compilation/fail6795.d(33): Error: cannot modify constant `0` --- */ void test_wrong_line_num() { enum int[] da = [0]; enum int[1] sa = [0]; enum int[int] aa = [0:0]; da[0] += 3; sa[0] += 3; aa[0] += 3; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6889.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail6889.d(16): Error: cannot `goto` out of `scope(success)` block fail_compilation/fail6889.d(17): Error: cannot `goto` in to `scope(success)` block fail_compilation/fail6889.d(19): Error: `return` statements cannot be in `scope(success)` bodies fail_compilation/fail6889.d(23): Error: `continue` is not inside `scope(success)` bodies fail_compilation/fail6889.d(24): Error: `break` is not inside `scope(success)` bodies fail_compilation/fail6889.d(29): Error: `continue` is not inside `scope(success)` bodies fail_compilation/fail6889.d(30): Error: `break` is not inside `scope(success)` bodies --- */ void test_success() { L1: scope(success) { L2: goto L1; } // NG goto L2; // NG scope(success) { return; } // NG (from fail102.d) foreach (i; 0..1) { scope(success) continue; // NG scope(success) break; // NG } foreach (i; Aggr()) { scope(success) continue; // NG scope(success) break; // NG } /+ // is equivalent with: switch ( Aggr().opApply((int i){ scope(success) return 0; // NG scope(success) return 1; // NG return 0; })) { default: break; } +/ } /* TEST_OUTPUT: --- fail_compilation/fail6889.d(56): Error: cannot `goto` in to `scope(failure)` block --- */ void test_failure() { L1: scope(failure) { L2: goto L1; } // OK goto L2; // NG scope(failure) { return; } // OK foreach (i; 0..1) { scope(failure) continue; // OK scope(failure) break; // OK } foreach (i; Aggr()) { scope(failure) continue; // OK scope(failure) break; // OK } /+ // is equivalent with: switch ( Aggr().opApply((int i){ scope(failure) return 0; // OK scope(failure) return 1; // OK return 0; })) { default: break; } +/ } /* TEST_OUTPUT: --- fail_compilation/fail6889.d(100): Error: cannot `goto` out of `scope(exit)` block fail_compilation/fail6889.d(101): Error: cannot `goto` in to `scope(exit)` block fail_compilation/fail6889.d(103): Error: `return` statements cannot be in `scope(exit)` bodies fail_compilation/fail6889.d(107): Error: `continue` is not inside `scope(exit)` bodies fail_compilation/fail6889.d(108): Error: `break` is not inside `scope(exit)` bodies fail_compilation/fail6889.d(113): Error: `continue` is not inside `scope(exit)` bodies fail_compilation/fail6889.d(114): Error: `break` is not inside `scope(exit)` bodies --- */ void test_exit() { L1: scope(exit) { L2: goto L1; } // NG goto L2; // NG scope(exit) { return; } // NG (from fail102.d) foreach (i; 0..1) { scope(exit) continue; // NG scope(exit) break; // NG } foreach (i; Aggr()) { scope(exit) continue; // NG scope(exit) break; // NG } /+ // is equivalent with: switch ( Aggr().opApply((int i){ scope(exit) return 0; // NG scope(exit) return 1; // NG return 0; })) { default: break; } +/ } struct Aggr { int opApply(int delegate(int) dg) { return dg(0); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail6968.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=6968 template Pred(A, B) { static if(is(B == int)) enum bool Pred = true; else enum bool Pred = false; } template PredAny(A, B...) { static if(B.length == 0) enum bool PredAny = false; else enum bool PredAny = Pred(A, B[0]) || PredAny(A, B[1..$]); } void main() { pragma(msg, PredAny!(int, long, float)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7077.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail7077.d(11): Error: undefined identifier `x` --- */ void main() { if(0) mixin("auto x = 2;"); assert(x == 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7173.d ================================================ struct A{ A opBinary(string op)(A a){ A rt; return rt; } void fun(){ } } struct B{ A _a; alias _a this; } void main(){ B b1, b2, b3; b3 = (b1 - b2).fun(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7178.d ================================================ template populate(overloads...) { mixin populate!(.contents); } public mixin populate!int; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail72.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail72.d(10): Error: undefined identifier `foo` --- */ void main() { synchronized( foo ) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7234.d ================================================ struct Contract { void opDispatch()(){} } void foo() { Contract* r; if (r.empty) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail73.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail73.d(20): Error: `case` not in `switch` statement --- */ // segfault DMD 0.120 // http://www.digitalmars.com/d/archives/digitalmars/D/bugs/4634.html void main() { int u=2; switch(u) { case 1: void j() { case 2: u++; } break; default: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7369.d ================================================ struct S7369 { int a; invariant() { a += 5; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail74.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail74.d(13): Error: cannot append type `C[1]` to type `C[1]` --- */ class C { C[1] c; this() { c ~= c; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424b.d ================================================ struct S7424b { @property int g()() { return 0; } void test() const { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424c.d ================================================ struct S7424c { @property int g()() { return 0; } void test() immutable { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424d.d ================================================ struct S7424d { @property int g()() immutable { return 0; } void test() const { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424e.d ================================================ struct S7424e { @property int g()() immutable { return 0; } void test() { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424f.d ================================================ struct S7424f { @property int g()() shared { return 0; } void test() { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424g.d ================================================ struct S7424g { @property int g()() { return 0; } void test() shared { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424h.d ================================================ struct S7424g { @property int g()() { return 0; } void test() inout { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7424i.d ================================================ struct S7424g { @property int g()() immutable { return 0; } void test() inout { int f = g; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7443.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/fail7443.d(12): Deprecation: `static` has no effect on a constructor inside a `static` block. Use `static this()` fail_compilation/fail7443.d(13): Deprecation: `shared static` has no effect on a constructor inside a `shared static` block. Use `shared static this()` --- */ class Foo { public static { this() {}} public shared static { this() {}} public {this() {}} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail75.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail75.d(13): Error: cannot append type `fail75.C` to type `C[1]` --- */ class C { C[1] c; this() { c ~= this; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7524a.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7524 #line 47 __DATE__ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7524b.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7524 #line 47 __VERSION__ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail76.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail76.d(9): Error: alias `fail76.a` conflicts with alias `fail76.a` at fail_compilation/fail76.d(8) --- */ alias main a; alias void a; void main() { a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7603a.d ================================================ void test(ref bool val = true) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7603b.d ================================================ void test(out bool val = true) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7603c.d ================================================ enum x = 3; void test(ref int val = x) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail77.d ================================================ void test() { int i; ubyte[4] ub; ub[] = cast(ubyte[4]) &i; //ub[] = (cast(ubyte*) &i)[0..4]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7702.d ================================================ struct S { template opDispatch (string name) {} } void main() { S s; s.x!int; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7751.d ================================================ class Foo(T) { T x; Foo y; } auto foo(T)(T x, Foo!T y=null) { return new Foo!T(x, y); } void bar(U)(U foo, U[] spam=[]) { spam ~= []; } void main() { bar(foo(0)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail78.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail78.d(9): Error: undefined identifier `inch` --- */ auto yd = ft * 3; auto ft = inch * 12; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7848.d ================================================ // REQUIRED_ARGS: -unittest /* TEST_OUTPUT: --- fail_compilation/fail7848.d(49): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class fail_compilation/fail7848.d(55): Deprecation: class deallocators have been deprecated, consider moving the deallocation strategy outside of the class fail_compilation/fail7848.d(41): Error: `pure` function `fail7848.C.__unittest_L39_C30` cannot call impure function `fail7848.func` fail_compilation/fail7848.d(41): Error: `@safe` function `fail7848.C.__unittest_L39_C30` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(35): `fail7848.func` is declared here fail_compilation/fail7848.d(41): Error: `@nogc` function `fail7848.C.__unittest_L39_C30` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(41): Error: function `fail7848.func` is not `nothrow` fail_compilation/fail7848.d(39): Error: `nothrow` function `fail7848.C.__unittest_L39_C30` may throw fail_compilation/fail7848.d(46): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func` fail_compilation/fail7848.d(46): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(35): `fail7848.func` is declared here fail_compilation/fail7848.d(46): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(46): Error: function `fail7848.func` is not `nothrow` fail_compilation/fail7848.d(44): Error: `nothrow` function `fail7848.C.__invariant1` may throw fail_compilation/fail7848.d(51): Error: `pure` allocator `fail7848.C.new` cannot call impure function `fail7848.func` fail_compilation/fail7848.d(51): Error: `@safe` allocator `fail7848.C.new` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(35): `fail7848.func` is declared here fail_compilation/fail7848.d(51): Error: `@nogc` allocator `fail7848.C.new` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(51): Error: function `fail7848.func` is not `nothrow` fail_compilation/fail7848.d(49): Error: `nothrow` allocator `fail7848.C.new` may throw fail_compilation/fail7848.d(57): Error: `pure` deallocator `fail7848.C.delete` cannot call impure function `fail7848.func` fail_compilation/fail7848.d(57): Error: `@safe` deallocator `fail7848.C.delete` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(35): `fail7848.func` is declared here fail_compilation/fail7848.d(57): Error: `@nogc` deallocator `fail7848.C.delete` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(57): Error: function `fail7848.func` is not `nothrow` fail_compilation/fail7848.d(55): Error: `nothrow` deallocator `fail7848.C.delete` may throw --- */ void func() {} class C { @safe pure nothrow @nogc unittest { func(); } @safe pure nothrow @nogc invariant { func(); } @safe pure nothrow @nogc new (size_t sz) { func(); return null; } @safe pure nothrow @nogc delete (void* p) { func(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7851.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=7851 template TypeTuple(TList...) { alias TList TypeTuple; } struct Tuple(Specs...) { TypeTuple!(int, long, float) mem; alias Identity!(mem[0]) _0; alias Identity!(mem[1]) _1; alias Identity!(mem[2]) _2; alias mem this; enum length = mem.length; } private template Identity(alias T) { alias T Identity; } void main() { alias Tuple!(int, long, float) TL; foreach (i; TL) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7859.d ================================================ template A(alias B) {} mixin template C(alias B = cast(NonExistent)null) { alias A!B D; } mixin C!(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7861.d ================================================ module test; mixin template A() { import test; } struct B { mixin A!(); } enum C = B.nonexistent; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7862.d ================================================ /* TEST_OUTPUT: --- A: false A: false fail_compilation/fail7862.d(26): Error: template instance `nonExistent!()` template `nonExistent` is not defined fail_compilation/fail7862.d(25): Error: template instance `fail7862.B!(A)` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=7862 template B(T) { mixin( { foreach (name; __traits(derivedMembers, T)) {} return "struct B {}"; }() ); } struct A { pragma(msg, "A: " ~ (__traits(compiles, B!A) ? "true" : "false")); pragma(msg, "A: " ~ (__traits(compiles, B!A) ? "true" : "false")); B!A c; static if (nonExistent!()) {} } auto d = A.init.c; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail79.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail79.d(13): Error: incompatible types for `(& a) + (& b)`: both operands are of type `int*` --- */ void main() { int a, b; int* p; p = &a + &b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail7903.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail7903.d(21): Error: variable `fail7903.F1.x` Field members of a `synchronized` class cannot be `public` fail_compilation/fail7903.d(22): Error: variable `fail7903.F1.y` Field members of a `synchronized` class cannot be `export` fail_compilation/fail7903.d(27): Error: variable `fail7903.F2.x` Field members of a `synchronized` class cannot be `public` --- */ synchronized class K1 { public struct S { } } synchronized class K2 { struct S { } } synchronized class F1 { public int x; export int y; } synchronized class F2 { int x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8009.d ================================================ void filter(R)(scope bool delegate(ref BAD!R) func) { } void main() { filter(r => r); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8032.d ================================================ mixin template T() { void f() { } } class A { mixin T; mixin T; } class B : A { override void f() { } // raises "cannot determine overridden function" error. } void main(){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d ================================================ // REQUIRED_ARGS: -m32 /* TEST_OUTPUT: --- fail_compilation/fail80_m32.d(28): Error: cannot implicitly convert expression `"progress_rem"` of type `string` to `uint` fail_compilation/fail80_m32.d(29): Error: cannot implicitly convert expression `"redo"` of type `string` to `uint` --- */ module paintshop; class Image{} class ResourceManager { Image getImage(char[] name) { return null; } } class Test { import std.file; import std.path; static Image[] images; static void initIcons() { images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis images["redo"] = ResourceManager.getImage("redo.gif"); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d ================================================ // REQUIRED_ARGS: -m64 /* TEST_OUTPUT: --- fail_compilation/fail80_m64.d(28): Error: cannot implicitly convert expression `"progress_rem"` of type `string` to `ulong` fail_compilation/fail80_m64.d(29): Error: cannot implicitly convert expression `"redo"` of type `string` to `ulong` --- */ module paintshop; class Image{} class ResourceManager { Image getImage(char[] name) { return null; } } class Test { import std.file; import std.path; static Image[] images; static void initIcons() { images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis images["redo"] = ResourceManager.getImage("redo.gif"); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8168.d ================================================ void main() { asm { unknown; // wrong opcode } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8179b.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail8179b.d(10): Error: cannot cast expression `[1, 2]` of type `int[]` to `int[2][1]` --- */ void foo(int[2][1]) {} void main() { foo(cast(int[2][1])[1, 2]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8217.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail8217.d(22): Error: `this` for `foo` needs to be type `D` not type `fail8217.D.C` --- */ class D { int x; template bar() { int foo() { return x; } } static class C { int foo() { return bar!().foo(); } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8262.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail8262.d(32): Error: cannot interpret `Tuple8262!1` at compile time fail_compilation/fail8262.d(27): Error: template instance `fail8262.T8262!(Tuple8262!1)` error instantiating fail_compilation/fail8262.d(19): Error: cannot implicitly convert expression `S(0)` of type `S` to `int` --- * https://issues.dlang.org/show_bug.cgi?id=8262 */ template Seq(T...) { alias T Seq; } struct S { int s; alias Seq!s _; alias _ this; } int si = S.init; struct Tuple8262(T...) { alias T expand; alias expand this; } auto data = T8262!(Tuple8262!1); //pragma(msg, data); template T8262(T) { immutable(int) T8262 = T; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8313.d ================================================ auto bar()(int x){return x;} auto bar()(int x = bar()){return x;} static assert(bar(1)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8373.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail8373.d(21): Error: `fail8373.fun1` called with argument types `(int)` matches both: fail_compilation/fail8373.d(15): `fail8373.fun1!().fun1!int.fun1(int)` and: fail_compilation/fail8373.d(16): `fail8373.fun1!int.fun1(int)` fail_compilation/fail8373.d(22): Error: `fail8373.fun2` called with argument types `(int)` matches both: fail_compilation/fail8373.d(18): `fail8373.fun2!int.fun2(int)` and: fail_compilation/fail8373.d(19): `fail8373.fun2!().fun2!int.fun2(int)` --- */ template fun1(a...) { auto fun1(T...)(T args){ return 1; } } auto fun1(T...)(T args){ return 2; } auto fun2(T...)(T args){ return 2; } template fun2(a...) { auto fun2(T...)(T args){ return 1; } } enum x1 = fun1(0); enum x2 = fun2(0); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail86.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail86.d(12): Error: alias `Foo` recursive alias declaration --- */ template Foo(TYPE) {} void main() { alias Foo!(int) Foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8631.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail8631.d(14): Error: function `shared const int fail8631.D.foo()` does not override any function, did you mean to override `immutable int fail8631.B.foo()`? --- */ class B { int foo() immutable { return 2; } int foo() const { return 2; } } class D : B { override int foo() immutable { return 2; } override int foo() const shared { return 2; } // doesn't override any override int foo() const { return 2; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8691.d ================================================ struct Foo { Foo[1] f; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail8724.d ================================================ // REQUIRED_ARGS: -w /* TEST_OUTPUT: --- fail_compilation/fail8724.d(14): Error: `object.Exception` is thrown but not caught fail_compilation/fail8724.d(12): Error: `nothrow` constructor `fail8724.Foo.this` may throw --- */ struct Foo { this(int) nothrow { throw new Exception("something"); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9.d(23): Error: no property `Vector` for type `fail9.Vector!int` --- */ template Vector(T) { int x; class Vector { } } struct Sorter { } void Vector_test_int() { alias Vector!(int).Vector vector_t; vector_t v; Sorter sorter; v.sort_with!(int)(sorter); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9063.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9063.d(9): Error: static assert: "msg" --- */ @property string bar() { return "msg"; } static assert(false, bar); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9081.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9081.d(12): Error: package `core` has no type fail_compilation/fail9081.d(13): Error: package `stdc` has no type fail_compilation/fail9081.d(14): Error: module `stdio` has no type --- */ import core.stdc.stdio; typeof(core) a; typeof(core.stdc) b; typeof(core.stdc.stdio) c; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail91.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail91.d(12): Error: struct `fail91.S` unknown size --- */ struct S; void main() { S* s = new S(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9199.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail9199.d(13): Error: function `fail9199.fc` without `this` cannot be `const` fail_compilation/fail9199.d(14): Error: function `fail9199.fi` without `this` cannot be `immutable` fail_compilation/fail9199.d(15): Error: function `fail9199.fw` without `this` cannot be `inout` fail_compilation/fail9199.d(16): Error: function `fail9199.fs` without `this` cannot be `shared` fail_compilation/fail9199.d(17): Error: function `fail9199.fsc` without `this` cannot be `shared const` fail_compilation/fail9199.d(18): Error: function `fail9199.fsw` without `this` cannot be `shared inout` --- */ void fc() const {} void fi() immutable {} void fw() inout {} void fs() shared {} void fsc() shared const {} void fsw() shared inout {} /* TEST_OUTPUT: --- fail_compilation/fail9199.d(33): Error: function `fail9199.C.fc` without `this` cannot be `const` fail_compilation/fail9199.d(34): Error: function `fail9199.C.fi` without `this` cannot be `immutable` fail_compilation/fail9199.d(35): Error: function `fail9199.C.fw` without `this` cannot be `inout` fail_compilation/fail9199.d(36): Error: function `fail9199.C.fs` without `this` cannot be `shared` fail_compilation/fail9199.d(37): Error: function `fail9199.C.fsc` without `this` cannot be `shared const` fail_compilation/fail9199.d(38): Error: function `fail9199.C.fsw` without `this` cannot be `shared inout` --- */ class C { static void fc() const {} static void fi() immutable {} static void fw() inout {} static void fs() shared {} static void fsc() shared const {} static void fsw() shared inout {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail92.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t` fail_compilation/fail92.d(23): Error: template instance `fail92.crash!(typeof(null))` error instantiating --- */ // [25] template crash(T) { void crash(T t) { foreach (u; t) { } } } void main() { crash(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9279.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9279.d(10): Error: escaping reference to stack allocated value returned by `b()` fail_compilation/fail9279.d(13): Error: escaping reference to stack allocated value returned by `getArr()` --- */ char[2] b()() { char[2] ret; return ret; } string a() { return b(); } char[12] getArr() { return "Hello World!"; } string getString() { return getArr(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9290.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9290.d(15): Error: slice `s1[]` is not mutable, struct `S` has immutable members fail_compilation/fail9290.d(16): Error: array `s1` is not mutable, struct `S` has immutable members --- */ struct S { immutable int i; } void main() { S[1] s1 = S(1); S[1] s2 = S(2); s1 = S(3); s1 = s2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail93.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail93.d(13): Error: variable `i` is shadowing variable `fail93.main.i` --- */ // accepts-valid with DMD0.120. volatile as well as synchronized void main() { int i = 1; synchronized int i = 2; // should fail to compile } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9301.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: */ void main() { __vector(void[16]) x = 0x0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9346.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9346.d(26): Error: struct `fail9346.S` is not copyable because it is annotated with `@disable` fail_compilation/fail9346.d(27): Error: struct `fail9346.S` is not copyable because it is annotated with `@disable` --- */ struct S { @disable this(this); } struct SS1 { S s; } struct SS2 { S s; this(this){} } void main() { S s; SS1 ss1 = SS1(s); SS2 ss2 = SS2(s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9368.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -d /* TEST_OUTPUT: --- fail_compilation/fail9368.d(20): Error: `enum` member `b` not represented in `final switch` --- */ enum E { a, b } void main() { alias E F; F f; final switch (f) { case F.a: } } /* TEST_OUTPUT: --- fail_compilation/fail9368.d(41): Error: `enum` member `B` not represented in `final switch` --- */ enum G { A,B,C } void test286() { G e; final switch (e) { case G.A: // case G.B: case G.C: {} } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail94.d ================================================ interface I { int foo(); } class IA : I { int foo() { return 1; } } class A { I i; I clone() { return i; } } class B : A { IA ia; IA clone() out (result) { printf("B.clone()\n"); } body { return ia; } } void main() { IA ia = new IA; assert(ia.foo() == 1); I i = ia; assert(i.foo() == 1); A a = new A; a.i = i; assert(a.clone().foo() == 1); B b = new B; b.ia = ia; assert(b.clone().foo() == 1); a = b; assert(a.clone().foo() == 1); bar(&b.clone); } void bar(IA delegate() dg) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9413.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9413.d(45): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(32): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(33): Error: variable `fail9413.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9413.d(38): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(39): Error: variable `fail9413.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9413.d(40): Error: variable `fail9413.foo.bar.s` cannot modify result `s` in contract fail_compilation/fail9413.d(50): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(73): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(74): Error: variable `fail9413.foo.r` cannot modify result `r` in contract fail_compilation/fail9413.d(58): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(59): Error: variable `fail9413.foo.r` cannot modify result `r` in contract fail_compilation/fail9413.d(60): Error: variable `fail9413.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9413.d(65): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(66): Error: variable `fail9413.foo.r` cannot modify result `r` in contract fail_compilation/fail9413.d(67): Error: variable `fail9413.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9413.d(68): Error: variable `fail9413.foo.baz.s` cannot modify result `s` in contract fail_compilation/fail9413.d(79): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9413.d(80): Error: variable `fail9413.foo.r` cannot modify result `r` in contract --- */ int foo(int x) in { int a; int bar(int y) in { x = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err } out(r) { int a; int baz(int y) in { x = 10; // err r = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err r = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err r = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err r = 10; // err } body { return 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9414a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9414a.d(47): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(34): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(35): Error: variable `fail9414a.C.foo.__require.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414a.d(40): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(41): Error: variable `fail9414a.C.foo.__require.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414a.d(42): Error: variable `fail9414a.C.foo.__require.bar.s` cannot modify result `s` in contract fail_compilation/fail9414a.d(52): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(75): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(76): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414a.d(60): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(61): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414a.d(62): Error: variable `fail9414a.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414a.d(67): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(68): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414a.d(69): Error: variable `fail9414a.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414a.d(70): Error: variable `fail9414a.C.foo.__ensure.baz.s` cannot modify result `s` in contract fail_compilation/fail9414a.d(81): Error: variable `fail9414a.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414a.d(82): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract --- */ class C { int foo(int x) in { int a; int bar(int y) in { x = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err } out(r) { int a; int baz(int y) in { x = 10; // err r = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err r = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err r = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err r = 10; // err } body { return 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9414b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9414b.d(47): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(34): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(35): Error: variable `fail9414b.C.foo.__require.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414b.d(40): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(41): Error: variable `fail9414b.C.foo.__require.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414b.d(42): Error: variable `fail9414b.C.foo.__require.bar.s` cannot modify result `s` in contract fail_compilation/fail9414b.d(52): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(75): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(76): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414b.d(60): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(61): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414b.d(62): Error: variable `fail9414b.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414b.d(67): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(68): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract fail_compilation/fail9414b.d(69): Error: variable `fail9414b.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414b.d(70): Error: variable `fail9414b.C.foo.__ensure.baz.s` cannot modify result `s` in contract fail_compilation/fail9414b.d(81): Error: variable `fail9414b.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414b.d(82): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract --- */ class C { final int foo(int x) in { int a; int bar(int y) in { x = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err } out(r) { int a; int baz(int y) in { x = 10; // err r = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err r = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err r = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err r = 10; // err } body { return 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9414c.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9414c.d(47): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(34): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(35): Error: variable `fail9414c.C.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414c.d(40): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(41): Error: variable `fail9414c.C.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414c.d(42): Error: variable `fail9414c.C.foo.bar.s` cannot modify result `s` in contract fail_compilation/fail9414c.d(52): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(75): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(76): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414c.d(60): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(61): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414c.d(62): Error: variable `fail9414c.C.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414c.d(67): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(68): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414c.d(69): Error: variable `fail9414c.C.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414c.d(70): Error: variable `fail9414c.C.foo.baz.s` cannot modify result `s` in contract fail_compilation/fail9414c.d(81): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414c.d(82): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract --- */ class C { private int foo(int x) in { int a; int bar(int y) in { x = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err } out(r) { int a; int baz(int y) in { x = 10; // err r = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err r = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err r = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err r = 10; // err } body { return 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9414d.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9414d.d(47): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(34): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(35): Error: variable `fail9414d.C.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414d.d(40): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(41): Error: variable `fail9414d.C.foo.bar.y` cannot modify parameter `y` in contract fail_compilation/fail9414d.d(42): Error: variable `fail9414d.C.foo.bar.s` cannot modify result `s` in contract fail_compilation/fail9414d.d(52): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(75): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(76): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414d.d(60): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(61): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414d.d(62): Error: variable `fail9414d.C.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414d.d(67): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(68): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract fail_compilation/fail9414d.d(69): Error: variable `fail9414d.C.foo.baz.y` cannot modify parameter `y` in contract fail_compilation/fail9414d.d(70): Error: variable `fail9414d.C.foo.baz.s` cannot modify result `s` in contract fail_compilation/fail9414d.d(81): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract fail_compilation/fail9414d.d(82): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract --- */ class C { static int foo(int x) in { int a; int bar(int y) in { x = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err } out(r) { int a; int baz(int y) in { x = 10; // err r = 10; // err y = 10; // err a = 1; // OK } out(s) { x = 10; // err r = 10; // err y = 10; // err s = 10; // err a = 1; // OK } body { x = 10; // err r = 10; // err y = 1; // OK a = 1; // OK return 2; } x = 10; // err r = 10; // err } body { return 1; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail95.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail95.d(19): Error: template `fail95.A` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/fail95.d(11): `fail95.A(alias T)(T)` --- */ // https://issues.dlang.org/show_bug.cgi?id=142 // Assertion failure: '0' on line 610 in file 'template.c' template A(alias T) { void A(T) { T = 2; } } void main() { int i; A(i); assert(i == 2); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9537.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9537.d(26): Error: `foo(tuple(1, 2))` is not an lvalue and cannot be modified --- */ struct Tuple(T...) { T field; alias field this; } Tuple!T tuple(T...)(T args) { return Tuple!T(args); } auto ref foo(T)(auto ref T t) { return t[0]; // t[0] is deduced to non-ref } void main() { int* p = &foo(tuple(1, 2)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9562.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/fail9562.d(17): Error: `int[]` is not an expression fail_compilation/fail9562.d(18): Error: no property `reverse` for type `int[]` fail_compilation/fail9562.d(19): Error: no property `sort` for type `int[]` fail_compilation/fail9562.d(20): Error: no property `dup` for type `int[]` fail_compilation/fail9562.d(21): Error: no property `idup` for type `int[]` --- */ void main() { alias A = int[]; auto len = A.length; auto rev = A.reverse; auto sort = A.sort; auto dup = A.dup; auto idup = A.idup; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9572.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9572.d(10): Error: index type `ubyte` cannot cover index range 0..300 --- */ void main() { int[300] data; foreach (ubyte i, x; data) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail96.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail96.d(21): Error: template instance `foo!long` `foo` is not a template declaration, it is a function alias --- */ // https://issues.dlang.org/show_bug.cgi?id=153 template bar(T) { void foo() {} } alias bar!(long).foo foo; alias bar!(char).foo foo; void main() { foo!(long); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9613.d ================================================ // PREMUTE_ARGS: void main() { auto x = const byte.init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9665a.d ================================================ // REQUIRED_ARGS: // PERMUTE_ARGS: /+ TEST_OUTPUT: --- fail_compilation/fail9665a.d(45): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(44): Previous initialization is here. fail_compilation/fail9665a.d(55): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(54): Previous initialization is here. fail_compilation/fail9665a.d(60): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(59): Previous initialization is here. fail_compilation/fail9665a.d(65): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(64): Previous initialization is here. fail_compilation/fail9665a.d(75): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(74): Previous initialization is here. fail_compilation/fail9665a.d(80): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(79): Previous initialization is here. fail_compilation/fail9665a.d(85): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(84): Previous initialization is here. fail_compilation/fail9665a.d(98): Error: immutable field `v` initialization is not allowed in loops or after labels fail_compilation/fail9665a.d(103): Error: immutable field `v` initialization is not allowed in loops or after labels fail_compilation/fail9665a.d(108): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(107): Previous initialization is here. fail_compilation/fail9665a.d(113): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(112): Previous initialization is here. fail_compilation/fail9665a.d(118): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(117): Previous initialization is here. fail_compilation/fail9665a.d(132): Error: immutable field `v` initialized multiple times fail_compilation/fail9665a.d(131): Previous initialization is here. fail_compilation/fail9665a.d(136): Error: immutable field `w` initialized multiple times fail_compilation/fail9665a.d(135): Previous initialization is here. fail_compilation/fail9665a.d(150): Error: static assert: `__traits(compiles, this.v = 1)` is false --- +/ /***************************************************/ // immutable field struct S1A { immutable int v; this(int) { v = 1; v = 2; // multiple initialization } } struct S1B { immutable int v; this(int) { if (true) v = 1; else v = 2; v = 3; // multiple initialization } this(long) { if (true) v = 1; v = 3; // multiple initialization } this(string) { if (true) {} else v = 2; v = 3; // multiple initialization } } struct S1C { immutable int v; this(int) { true ? (v = 1) : (v = 2); v = 3; // multiple initialization } this(long) { auto x = true ? (v = 1) : 2; v = 3; // multiple initialization } this(string) { auto x = true ? 1 : (v = 2); v = 3; // multiple initialization } } /***************************************************/ // with control flow struct S2 { immutable int v; this(int) { L: v = 1; // after labels } this(long) { foreach (i; 0..1) v = 1; // in loops } this(string) { v = 1; // initialization L: v = 2; // assignment after labels } this(wstring) { v = 1; // initialization foreach (i; 0..1) v = 2; // assignment in loops } this(dstring) { v = 1; return; v = 2; // multiple initialization } } /***************************************************/ // with immutable constructor struct S3 { int v; int w; this(int) immutable { v = 1; v = 2; // multiple initialization if (true) w = 1; w = 2; // multiple initialization } } /***************************************************/ // in __traits(compiles) struct S4 { immutable int v; this(int) { static assert(__traits(compiles, v = 1)); v = 1; static assert(__traits(compiles, v = 1)); // multiple initialization } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9665b.d ================================================ /***************************************************/ // with disable this() struct struct X { @disable this(); this(int) {} } /+ TEST_OUTPUT: --- fail_compilation/fail9665b.d(32): Error: one path skips field `x2` fail_compilation/fail9665b.d(33): Error: one path skips field `x3` fail_compilation/fail9665b.d(35): Error: one path skips field `x5` fail_compilation/fail9665b.d(36): Error: one path skips field `x6` fail_compilation/fail9665b.d(30): Error: field `x1` must be initialized in constructor fail_compilation/fail9665b.d(30): Error: field `x4` must be initialized in constructor --- +/ struct S1 { X x1; X x2; X x3; X[2] x4; X[2] x5; X[2] x6; this(int) { if (true) x2 = X(1); auto n = true ? (x3 = X(1)) : X.init; if (true) x5 = X(1); auto m = true ? (x6 = X(1)) : typeof(x6).init; } } /***************************************************/ // with nested struct /+ TEST_OUTPUT: --- fail_compilation/fail9665b.d(65): Error: one path skips field `x2` fail_compilation/fail9665b.d(66): Error: one path skips field `x3` fail_compilation/fail9665b.d(68): Error: one path skips field `x5` fail_compilation/fail9665b.d(69): Error: one path skips field `x6` fail_compilation/fail9665b.d(63): Error: field `x1` must be initialized in constructor, because it is nested struct fail_compilation/fail9665b.d(63): Error: field `x4` must be initialized in constructor, because it is nested struct fail_compilation/fail9665b.d(76): Error: template instance `fail9665b.S2!(X)` error instantiating --- +/ struct S2(X) { X x1; X x2; X x3; X[2] x4; X[2] x5; X[2] x6; this(X x) { if (true) x2 = x; auto a = true ? (x3 = x) : X.init; if (true) x5 = x; auto b = true ? (x6 = x) : typeof(x6).init; } } void test2() { struct X { this(int) {} } static assert(X.tupleof.length == 1); S2!(X) s = X(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail97.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail97.d(11): Error: pragma `lib` is missing a terminating `;` --- */ // https://issues.dlang.org/show_bug.cgi?id=151 import std.stdio; pragma(lib,"ws2_32.lib")//; class bla{} void main(){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9710.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9710.d(9): Error: static variable `e` cannot be read at compile time --- */ int* e; enum v = e[1]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9735.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/fail9735.d(10): Deprecation: casting from void delegate() to void* is deprecated --- */ void* dg2ptr(void delegate() dg) { return cast(void*) dg; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9766.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9766.d(14): Error: cannot interpret `Foo!int` at compile time fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not -1 fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0 fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 3 fail_compilation/fail9766.d(26): Error: alignment must be an integer positive power of 2, not 2147483649u --- */ template Foo(T) {} align(Foo!int) struct S9766a {} align(-1) struct S9766b {} align(0) struct S9766c {} align(3) struct S9766d {} align((1u << 31) + 1) struct S9766e {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9773.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9773.d(7): Error: `""` is not an lvalue and cannot be modified --- */ void f(ref string a = "") { a = "crash and burn"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9790.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9790.d(13): Error: undefined identifier `_Unused_` fail_compilation/fail9790.d(20): Error: template instance `fail9790.foo!()` error instantiating fail_compilation/fail9790.d(18): Error: undefined identifier `_Unused_` fail_compilation/fail9790.d(21): Error: template instance `fail9790.bar!()` error instantiating --- */ template foo() { enum bool _foo = _Unused_._unused_; enum bool foo = _foo; } template bar() { enum bool bar = _Unused_._unused_; } alias Foo = foo!(); alias Bar = bar!(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail98.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail98.d(17): Error: cannot implicitly convert expression `256` of type `int` to `E` --- */ // https://issues.dlang.org/show_bug.cgi?id=139 E foo(int index) { return index + 256; } enum : E { D3DTS_WORLD = 256, D3DTS_WORLD1, D3DTS_WORLD2, D3DTS_WORLD3 } enum E { D3DTS_VIEW = 2, D3DTS_PROJECTION, D3DTS_TEXTURE0 = 16, D3DTS_TEXTURE1, D3DTS_TEXTURE2, D3DTS_TEXTURE3, D3DTS_TEXTURE4, D3DTS_TEXTURE5, D3DTS_TEXTURE6, D3DTS_TEXTURE7, // = 23 D3DTS_FORCE_DWORD = 0xffffffff } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9891.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9891.d(13): Error: `cast(int)i` is not an lvalue and cannot be modified fail_compilation/fail9891.d(18): Error: `cast(int)i` is not an lvalue and cannot be modified fail_compilation/fail9891.d(23): Error: `prop()` is not an lvalue and cannot be modified --- */ immutable int i; int prop() { return 0; } void f1(ref int n = i) { ++n; } void f2(out int n = i) { ++n; } void f3(ref int n = prop) { ++n; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9892.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=9892 /* TEST_OUTPUT: --- fail_compilation/fail9892.d(11): Error: enum member `fail9892.a` circular reference to `enum` member --- */ enum { a = b, //Segfault! b } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail99.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail99.d(12): Error: delegate `dg(int)` is not callable using argument types `()` --- */ //import std.stdio; void foo(void delegate(int) dg) { dg(); //writefln("%s", dg(3)); } void main() { foo(delegate(int i) { //writefln("i = %d\n", i); } ); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail9936.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail9936.d(25): Error: `S().opBinary` isn't a template fail_compilation/fail9936.d(26): Error: `S().opBinaryRight` isn't a template fail_compilation/fail9936.d(27): Error: `S().opOpAssign` isn't a template fail_compilation/fail9936.d(29): Error: `S().opIndexUnary` isn't a template fail_compilation/fail9936.d(30): Error: `S().opUnary` isn't a template --- */ struct S { auto opBinary(S s) { return 1; } auto opBinaryRight(int n) { return 1; } auto opOpAssign(S s) { return 1; } auto opIndexUnary(S s) { return 1; } auto opUnary(S s) { return 1; } } void main() { static assert(!is(typeof( S() + S() ))); static assert(!is(typeof( 100 + S() ))); static assert(!is(typeof( S() += S() ))); S() + S(); 100 + S(); S() += S(); +S()[0]; +S(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(11): Error: invalid array operation `a + a` (possible missing []) --- */ void test2199(int[] a) // https://issues.dlang.org/show_bug.cgi?id=2199 - Segfault using array operation in function call (from fail266.d) { test2199(a + a); } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(29): Error: invalid array operation `-a` (possible missing []) --- */ void fail323() // from fail323.d, maybe was a part of https://issues.dlang.org/show_bug.cgi?id=3471 fix? { void foo(double[]) {} auto a = new double[10], b = a.dup, c = a.dup, d = a.dup; foo(-a); // a[] = -(b[] * (c[] + 4)) + 5 * d[]; // / 3; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(54): Error: invalid array operation `-a` (possible missing []) fail_compilation/fail_arrayop1.d(55): Error: invalid array operation `~a` (possible missing []) fail_compilation/fail_arrayop1.d(56): Error: invalid array operation `a + a` (possible missing []) fail_compilation/fail_arrayop1.d(57): Error: invalid array operation `a - a` (possible missing []) fail_compilation/fail_arrayop1.d(58): Error: invalid array operation `a * a` (possible missing []) fail_compilation/fail_arrayop1.d(59): Error: invalid array operation `a / a` (possible missing []) fail_compilation/fail_arrayop1.d(60): Error: invalid array operation `a % a` (possible missing []) fail_compilation/fail_arrayop1.d(61): Error: invalid array operation `a ^^ a` (possible missing []) fail_compilation/fail_arrayop1.d(62): Error: invalid array operation `a & a` (possible missing []) fail_compilation/fail_arrayop1.d(63): Error: invalid array operation `a | a` (possible missing []) fail_compilation/fail_arrayop1.d(64): Error: invalid array operation `a ^ a` (possible missing []) --- */ void test3903() { int[] a = [1, 2]; int[] r; r = -a; r = ~a; r = a + a; r = a - a; r = a * a; r = a / a; r = a % a; r = a ^^ a; r = a & a; r = a | a; r = a ^ a; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(85): Error: invalid array operation `a += a[]` (possible missing []) fail_compilation/fail_arrayop1.d(86): Error: invalid array operation `a -= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(87): Error: invalid array operation `a *= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(88): Error: invalid array operation `a /= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(89): Error: invalid array operation `a %= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(90): Error: invalid array operation `a ^= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(91): Error: invalid array operation `a &= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(92): Error: invalid array operation `a |= a[]` (possible missing []) fail_compilation/fail_arrayop1.d(93): Error: invalid array operation `a ^^= a[]` (possible missing []) --- */ void test9459() { int[] a = [1, 2, 3]; a += a[]; a -= a[]; a *= a[]; a /= a[]; a %= a[]; a ^= a[]; a &= a[]; a |= a[]; a ^^= a[]; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(105): Error: invalid array operation `a[] <<= 1` (possible missing []) --- */ void test11566() { int[] a; a[] <<= 1; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop1.d(121): Error: invalid array operation `a + b` (possible missing []) fail_compilation/fail_arrayop1.d(122): Error: invalid array operation `x + y` (possible missing []) fail_compilation/fail_arrayop1.d(123): Error: invalid array operation `"hel" + "lo."` (possible missing []) --- */ void test14649() { char[] a, b, r; string x, y; r[] = a + b; r[] = x + y; r[] = "hel" + "lo."; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(13): Error: array operation `[1, 2, 3] - [1, 2, 3]` without destination memory not allowed fail_compilation/fail_arrayop2.d(16): Error: invalid array operation `"a" - "b"` (possible missing []) --- */ void test2603() // https://issues.dlang.org/show_bug.cgi?id=2603 - ICE(cgcs.c) on subtracting string literals { auto c1 = [1,2,3] - [1,2,3]; // this variation is wrong code on D2, ICE ..\ztc\cgcs.c 358 on D1. string c2 = "a" - "b"; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(38): Error: array operation `-a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(39): Error: array operation `~a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(41): Error: array operation `a[] + a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(42): Error: array operation `a[] - a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(43): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(44): Error: array operation `a[] / a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(45): Error: array operation `a[] % a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(46): Error: array operation `a[] ^ a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(47): Error: array operation `a[] & a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(48): Error: array operation `a[] | a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(49): Error: array operation `a[] ^^ a[]` without destination memory not allowed (possible missing []) --- */ void test9459() { int[] a = [1, 2, 3]; a = -a[]; a = ~a[]; a = a[] + a[]; a = a[] - a[]; a = a[] * a[]; a = a[] / a[]; a = a[] % a[]; a = a[] ^ a[]; a = a[] & a[]; a = a[] | a[]; a = a[] ^^ a[]; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(75): Error: array operation `a[] + a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(76): Error: array operation `a[] - a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(77): Error: array operation `a[] * a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(78): Error: array operation `a[] / a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(79): Error: array operation `a[] % a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(80): Error: array operation `a[] ^ a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(81): Error: array operation `a[] & a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(82): Error: array operation `a[] | a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(83): Error: array operation `a[] ^^ 10` without destination memory not allowed fail_compilation/fail_arrayop2.d(84): Error: array operation `-a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(85): Error: array operation `~a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(90): Error: array operation `[1] + a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(91): Error: array operation `[1] + a[]` without destination memory not allowed --- */ void test12179() { void foo(int[]) {} int[1] a; foo(a[] + a[]); foo(a[] - a[]); foo(a[] * a[]); foo(a[] / a[]); foo(a[] % a[]); foo(a[] ^ a[]); foo(a[] & a[]); foo(a[] | a[]); foo(a[] ^^ 10); foo(-a[]); foo(~a[]); // from https://issues.dlang.org/show_bug.cgi?id=11992 int[] arr1; int[][] arr2; arr1 ~= [1] + a[]; // NG arr2 ~= [1] + a[]; // NG } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(105): Error: array operation `h * y[]` without destination memory not allowed --- */ void test12381() { double[2] y; double h; double[2] temp1 = cast(double[2])(h * y[]); } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(118): Error: array operation `-a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(120): Error: array operation `(-a[])[0..4]` without destination memory not allowed --- */ float[] test12769(float[] a) { if (a.length < 4) return -a[]; else return (-a[])[0..4]; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(137): Error: array operation `a[] - a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(139): Error: array operation `a[] - a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(140): Error: array operation `a[] - a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(143): Error: array operation `a[] - a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(145): Error: array operation `a[] - a[]` without destination memory not allowed --- */ void test13208() { int[] a; auto arr = [a[] - a[]][0]; auto aa1 = [1 : a[] - a[]]; auto aa2 = [a[] - a[] : 1]; struct S { int[] a; } auto s = S(a[] - a[]); auto n = int(a[] - a[]); } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(160): Error: array operation `a[] * a[]` without destination memory not allowed fail_compilation/fail_arrayop2.d(161): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed fail_compilation/fail_arrayop2.d(164): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing []) fail_compilation/fail_arrayop2.d(165): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed (possible missing []) --- */ void test13497() { int[1] a; auto b1 = (a[] * a[])[]; auto b2 = (a[] * a[])[0..1]; int[] c; c = (a[] * a[])[]; c = (a[] * a[])[0..1]; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(181): Error: array operation `data[segmentId][28..29] & cast(ubyte)(1 << 0)` without destination memory not allowed --- */ void test13910() { ubyte[][] data; size_t segmentId; bool isGroup() { return !!((data[segmentId][28..29]) & (1 << 0)); } } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(195): Error: array operation `a[] + 1` without destination memory not allowed fail_compilation/fail_arrayop2.d(195): Error: array operation `a[] * 2` without destination memory not allowed --- */ void test14895() { int[] a; int[] b = (a[] + 1) ~ a[] * 2; } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(247): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(248): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(249): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(253): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(256): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(265): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(268): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]` fail_compilation/fail_arrayop2.d(281): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/fail_arrayop2.d(281): Error: `[1] * 6` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(291): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(294): Error: `[1] * 6` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(295): Error: `([1] * 6)[]` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(298): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(299): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(300): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(303): Error: `[1] * 6` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(304): Error: `[1] * 6` is not an lvalue and cannot be modified fail_compilation/fail_arrayop2.d(307): Error: `[1] * 6` is not of integral type, it is a `int[]` fail_compilation/fail_arrayop2.d(308): Error: `[1] * 6` is not of integral type, it is a `int[]` fail_compilation/fail_arrayop2.d(309): Error: `[1] * 6` is not of integral type, it is a `int[]` fail_compilation/fail_arrayop2.d(312): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(313): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(316): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(317): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(318): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed --- */ // Test all expressions, which can take arrays as their operands but cannot be a part of array operation. void test15407exp() { struct S { int[] a; } void f(int[] a) {} int[] da; int[6] sa; { auto r = [[1] * 6]; } // ArrayLiteralExp { auto r = [[1] * 6 : [1] * 6]; } // AssocArrayLiteralExp //TupleExp // StructLiteralExp.elements <- preFunctionParameters in CallExp { auto r = S([1] * 6); } // NewExp.newargs/arguments <- preFunctionParameters { auto r = new S([1] * 6); } // TODO: TypeidExp //auto ti = typeid([1] * 6); //auto foo(T)(T t) {} //foo(typeid([1] * 6)); //auto a = [typeid([1] * 6)]; // CommaExp.e1 { auto r = ([1] * 6, 1); } // AssertExp assert([1] * 6, cast(char)1 + "abc"[]); // CallExp.arguments <- preFunctionParameters f([1] * 6); // AddrExp, if a CT-known length slice can become an TypeSarray lvalue in the future. { auto r = &(([1] * 6)[0..2]); } // PtrExp, *([1] * 6).ptr is also invalid -> show better diagnostic { auto r = *([1] * 6); } // DeleteExp - e1 delete ([1] * 6); // TypeDArray.dotExp, cannot check in ArrayLengthExp.semantic() { auto r = (6 * da[]).length; } // IndexExp - e1 { auto x1 = (da[] * 6)[1]; } // Pre, PostExp - e1 ([1] * 6)++; --([1] * 6); // AssignExp e1 ([1] * 6) = 10; ([1] * 6)[] = 10; // BinAssignExp e1 ([1] * 6) += 1; ([1] * 6)[] *= 2; ([1] * 6)[] ^^= 3; // CatExp e1 ([1] * 6) ~= 1; ([1] * 6)[] ~= 2; // Shl, Shr, UshrExp - e1, e2 --> checkIntegralBin { auto r = ([1] * 6) << 1; } { auto r = ([1] * 6) >> 1; } { auto r = ([1] * 6) >>> 1; } // AndAnd, OrOrExp - e1, e2 { auto r = sa[0..5] && [1] * 6; } { auto r = sa[0..5] || [1] * 6; } // Cmp, Equal, IdentityExp - e1, e2 { auto r = sa[0..5] <= [1] * 6; } { auto r = sa[0..5] == [1] * 6; } { auto r = sa[0..5] is [1] * 6; } // CondExp - econd, e1, e2 { auto r = [1] * 6 ? [1] * 6 : [1] * 6; } } /* TEST_OUTPUT: --- fail_compilation/fail_arrayop2.d(342): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(345): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(348): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(349): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(350): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(353): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(356): Error: array operation `[1] * 6` without destination memory not allowed fail_compilation/fail_arrayop2.d(359): Error: array operation `"str"[] + cast(immutable(char))1` without destination memory not allowed fail_compilation/fail_arrayop2.d(367): Error: CTFE internal error: non-constant value `"uvt"[]` --- */ // Test all statements, which can take arrays as their operands. void test15407stmt() { // ExpStatement - exp [1] * 6; // DoStatement - condition do {} while ([1] * 6); // ForStatement - condition, increment for ([1] * 6; // init == ExpStatement [1] * 6; [1] * 6) {} // ForeachStatement - aggr -> lowered to ForStatement foreach (e; [1] * 6) {} // IfStatement condition if ([1] * 6) {} // SwitchStatement - condition switch ("str"[] + 1) { case "tus": break; default: break; } // CaseStatement - exp switch ("tus") { case "uvt"[] - 1: break; default: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3a.d ================================================ // REQUIRED_ARGS: -o- /* example output from druntime ---- ../../druntime/import/core/internal/arrayop.d(160): Error: static assert "Binary op `*` not supported for element type X." ../../druntime/import/core/internal/arrayop.d(145): instantiated from here: `opsSupported!(true, X, "*")` ../../druntime/import/core/internal/arrayop.d(20): instantiated from here: `opsSupported!(true, X, "*", "=")` ../../druntime/import/object.d(3640): instantiated from here: `arrayOp!(X[], X[], X[], "*", "=")` fail_compilation/fail_arrayop3a.d(28): instantiated from here: `_arrayOp!(X[], X[], X[], "*", "=")` ../../druntime/import/core/internal/arrayop.d(160): Error: static assert "Binary op `+=` not supported for element type string." ../../druntime/import/core/internal/arrayop.d(20): instantiated from here: `opsSupported!(true, string, "+=")` ../../druntime/import/object.d(3640): instantiated from here: `arrayOp!(string[], string[], "+=")` fail_compilation/fail_arrayop3a.d(32): instantiated from here: `_arrayOp!(string[], string[], "+=")` ../../druntime/import/core/internal/arrayop.d(160): Error: static assert "Binary op `*=` not supported for element type int*." ../../druntime/import/core/internal/arrayop.d(20): instantiated from here: `opsSupported!(true, int*, "*=")` ../../druntime/import/object.d(3640): instantiated from here: `arrayOp!(int*[], int*[], "*=")` fail_compilation/fail_arrayop3a.d(36): instantiated from here: `_arrayOp!(int*[], int*[], "*=")` ---- */ void test11376() { struct X { } auto x1 = [X()]; auto x2 = [X()]; auto x3 = [X()]; x1[] = x2[] * x3[]; string[] s1; string[] s2; s2[] += s1[]; int*[] pa1; int*[] pa2; pa1[] *= pa2[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3b.d ================================================ // REQUIRED_ARGS: -o- /* example output from druntime ---- ../../druntime/import/core/internal/arrayop.d(160): Error: static assert "Binary op `+=` not supported for element type string." ../../druntime/import/core/internal/arrayop.d(20): instantiated from here: `opsSupported!(true, string, "+=")` ../../druntime/import/object.d(3640): instantiated from here: `arrayOp!(string[], string[], "+=")` fail_compilation/fail_arrayop3b.d(16): instantiated from here: `_arrayOp!(string[], string[], "+=")` --- */ void test11376() { string[] s1; string[] s2; s2[] += s1[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3c.d ================================================ // REQUIRED_ARGS: -o- /* example output from druntime ---- ../../druntime/import/core/internal/arrayop.d(160): Error: static assert "Binary op `*=` not supported for element type int*." ../../druntime/import/core/internal/arrayop.d(20): instantiated from here: `opsSupported!(true, int*, "*=")`` ../../druntime/import/object.d(3640): instantiated from here: `arrayOp!(int*[], int*[], "*=")` fail_compilation/fail_arrayop3c.d(16): instantiated from here: `_arrayOp!(int*[], int*[], "*=")` ---- */ void test11376() { int*[] pa1; int*[] pa2; pa1[] *= pa2[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_casting.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(12): Error: cannot cast expression `x` of type `short[2]` to `int[2]` because of different sizes --- */ void test3133() { short[2] x = [1, 2]; auto y = cast(int[2])x; // error } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(28): Error: cannot cast expression `null` of type `typeof(null)` to `S1` fail_compilation/fail_casting.d(29): Error: cannot cast expression `null` of type `typeof(null)` to `S2` fail_compilation/fail_casting.d(30): Error: cannot cast expression `s1` of type `S1` to `typeof(null)` fail_compilation/fail_casting.d(31): Error: cannot cast expression `s2` of type `S2` to `typeof(null)` --- */ void test9904() { static struct S1 { size_t m; } static struct S2 { size_t m; byte b; } { auto x = cast(S1)null; } { auto x = cast(S2)null; } { S1 s1; auto x = cast(typeof(null))s1; } { S2 s2; auto x = cast(typeof(null))s2; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(46): Error: cannot cast expression `x` of type `Object[]` to `object.Object` fail_compilation/fail_casting.d(47): Error: cannot cast expression `x` of type `Object[2]` to `object.Object` fail_compilation/fail_casting.d(49): Error: cannot cast expression `x` of type `object.Object` to `Object[]` fail_compilation/fail_casting.d(50): Error: cannot cast expression `x` of type `object.Object` to `Object[2]` --- */ void test10646() { // T[] or T[n] --> Tclass { Object[] x; auto y = cast(Object)x; } { Object[2] x; auto y = cast(Object)x; } // T[] or T[n] <-- Tclass { Object x; auto y = cast(Object[] )x; } { Object x; auto y = cast(Object[2])x; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(69): Error: cannot cast expression `x` of type `int[1]` to `int` fail_compilation/fail_casting.d(70): Error: cannot cast expression `x` of type `int` to `int[1]` fail_compilation/fail_casting.d(71): Error: cannot cast expression `x` of type `float[1]` to `int` fail_compilation/fail_casting.d(72): Error: cannot cast expression `x` of type `int` to `float[1]` fail_compilation/fail_casting.d(75): Error: cannot cast expression `x` of type `int[]` to `int` fail_compilation/fail_casting.d(76): Error: cannot cast expression `x` of type `int` to `int[]` fail_compilation/fail_casting.d(77): Error: cannot cast expression `x` of type `float[]` to `int` fail_compilation/fail_casting.d(78): Error: cannot cast expression `x` of type `int` to `float[]` --- */ void test11484() { // Tsarray <--> integer { int[1] x; auto y = cast(int ) x; } { int x; auto y = cast(int[1] ) x; } { float[1] x; auto y = cast(int ) x; } { int x; auto y = cast(float[1]) x; } // Tarray <--> integer { int[] x; auto y = cast(int ) x; } { int x; auto y = cast(int[] ) x; } { float[] x; auto y = cast(int ) x; } { int x; auto y = cast(float[]) x; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(97): Error: cannot cast expression `x` of type `int` to `fail_casting.test11485.C` fail_compilation/fail_casting.d(98): Error: cannot cast expression `x` of type `int` to `fail_casting.test11485.I` fail_compilation/fail_casting.d(101): Error: cannot cast expression `x` of type `fail_casting.test11485.C` to `int` fail_compilation/fail_casting.d(102): Error: cannot cast expression `x` of type `fail_casting.test11485.I` to `int` --- */ void test11485() { class C {} interface I {} // https://issues.dlang.org/show_bug.cgi?id=11485 TypeBasic --> Tclass { int x; auto y = cast(C)x; } { int x; auto y = cast(I)x; } // https://issues.dlang.org/show_bug.cgi?id=7472 TypeBasic <-- Tclass { C x; auto y = cast(int)x; } { I x; auto y = cast(int)x; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(114): Error: cannot cast expression `x` of type `typeof(null)` to `int[2]` fail_compilation/fail_casting.d(115): Error: cannot cast expression `x` of type `int[2]` to `typeof(null)` --- */ void test8179() { { typeof(null) x; auto y = cast(int[2])x; } { int[2] x; auto y = cast(typeof(null))x; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(128): Error: cannot cast expression `x` of type `S` to `int*` fail_compilation/fail_casting.d(130): Error: cannot cast expression `x` of type `void*` to `S` --- */ void test13959() { struct S { int* p; } { S x; auto y = cast(int*)x; } { int* x; auto y = cast(S)x; } // no error so it's rewritten as: S(x) { void* x; auto y = cast(S)x; } } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(144): Error: cannot cast expression `mi.x` of type `int` to `MyUbyte14154` --- */ struct MyUbyte14154 { ubyte x; alias x this; } struct MyInt14154 { int x; alias x this; } void test14154() { MyInt14154 mi; ubyte t = cast(MyUbyte14154)mi; } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_0` of type `int` to `object.Object` fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_1` of type `int` to `object.Object` --- */ alias TypeTuple14093(T...) = T; struct Tuple14093(T...) { static if (T.length == 4) { alias Types = TypeTuple14093!(T[0], T[2]); Types expand; @property ref inout(Tuple14093!Types) _Tuple_super() inout @trusted { return *cast(typeof(return)*) &(expand[0]); } alias _Tuple_super this; } else { alias Types = T; Types expand; alias expand this; } } void test14093() { Tuple14093!(int, "x", int, "y") point; auto newPoint = cast(Object)(point); } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(192): Error: cannot cast expression `p` of type `void*` to `char[]` fail_compilation/fail_casting.d(193): Error: cannot cast expression `p` of type `void*` to `char[2]` --- */ void test14596() { void* p = null; auto arr = cast(char[])p; char[2] sarr = cast(char[2])p; } /* TEST_OUTPUT: --- fail_compilation/fail_casting.d(217): Error: cannot cast expression `c` of type `fail_casting.test14629.C` to `typeof(null)` fail_compilation/fail_casting.d(218): Error: cannot cast expression `p` of type `int*` to `typeof(null)` fail_compilation/fail_casting.d(219): Error: cannot cast expression `da` of type `int[]` to `typeof(null)` fail_compilation/fail_casting.d(220): Error: cannot cast expression `aa` of type `int[int]` to `typeof(null)` fail_compilation/fail_casting.d(221): Error: cannot cast expression `fp` of type `int function()` to `typeof(null)` fail_compilation/fail_casting.d(222): Error: cannot cast expression `dg` of type `int delegate()` to `typeof(null)` --- */ void test14629() { alias P = int*; P p; alias DA = int[]; DA da; alias AA = int[int]; AA aa; alias FP = int function(); FP fp; alias DG = int delegate(); DG dg; class C {} C c; alias N = typeof(null); { auto x = cast(N)c; } { auto x = cast(N)p; } { auto x = cast(N)da; } { auto x = cast(N)aa; } { auto x = cast(N)fp; } { auto x = cast(N)dg; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_casting1.d ================================================ // REQUIRED_SRGS: -o- // references alias P = int*; P p; alias FP = int function(); FP fp; alias DG = int delegate(); DG dg; alias DA = int[]; DA da; alias AA = int[int]; AA aa; class C {} C c; alias N = typeof(null); N n; // values alias SA = int[1]; SA sa; struct S {} S s; int i; double f; /* TEST_OUTPUT: --- fail_compilation/fail_casting1.d(39): Error: cannot cast expression `p` of type `int*` to `int[1]` fail_compilation/fail_casting1.d(40): Error: cannot cast expression `fp` of type `int function()` to `int[1]` fail_compilation/fail_casting1.d(41): Error: cannot cast expression `dg` of type `int delegate()` to `int[1]` fail_compilation/fail_casting1.d(42): Error: cannot cast expression `da` of type `int[]` to `int[1]` fail_compilation/fail_casting1.d(43): Error: cannot cast expression `aa` of type `int[int]` to `int[1]` fail_compilation/fail_casting1.d(44): Error: cannot cast expression `c` of type `fail_casting1.C` to `int[1]` fail_compilation/fail_casting1.d(45): Error: cannot cast expression `n` of type `typeof(null)` to `int[1]` fail_compilation/fail_casting1.d(49): Error: cannot cast expression `sa` of type `int[1]` to `int delegate()` fail_compilation/fail_casting1.d(51): Error: cannot cast expression `sa` of type `int[1]` to `double[]` since sizes don't line up fail_compilation/fail_casting1.d(52): Error: cannot cast expression `sa` of type `int[1]` to `int[int]` fail_compilation/fail_casting1.d(53): Error: cannot cast expression `sa` of type `int[1]` to `fail_casting1.C` fail_compilation/fail_casting1.d(54): Error: cannot cast expression `sa` of type `int[1]` to `typeof(null)` --- */ void test1() { { auto x = cast(SA) p; } // Reject (Bugzilla 14596) { auto x = cast(SA)fp; } // Reject (Bugzilla 14596) (FP is Tpointer) { auto x = cast(SA)dg; } // Reject (from e2ir) { auto x = cast(SA)da; } // Reject (from e2ir) { auto x = cast(SA)aa; } // Reject (from e2ir) { auto x = cast(SA) c; } // Reject (Bugzilla 10646) { auto x = cast(SA) n; } // Reject (Bugzilla 8179) { auto x = cast( P)sa; } // Accept (equivalent with: cast(int*)sa.ptr;) { auto x = cast(double*)sa; } // Accept (equivalent with: cast(double*)sa.ptr;) { auto x = cast(FP)sa; } // Accept (equivalent with: cast(FP)sa.ptr;) { auto x = cast(DG)sa; } // Reject (from e2ir) { auto x = cast(DA)sa; } // Accept (equivalent with: cast(int[])sa[];) { auto x = cast(double[])sa; } // Reject (from e2ir) { auto x = cast(AA)sa; } // Reject (from e2ir) { auto x = cast( C)sa; } // Reject (Bugzilla 10646) { auto x = cast( N)sa; } // Reject (Bugzilla 8179) } /* TEST_OUTPUT: --- fail_compilation/fail_casting1.d(78): Error: cannot cast expression `p` of type `int*` to `S` fail_compilation/fail_casting1.d(79): Error: cannot cast expression `fp` of type `int function()` to `S` fail_compilation/fail_casting1.d(80): Error: cannot cast expression `dg` of type `int delegate()` to `S` fail_compilation/fail_casting1.d(81): Error: cannot cast expression `da` of type `int[]` to `S` fail_compilation/fail_casting1.d(82): Error: cannot cast expression `aa` of type `int[int]` to `S` fail_compilation/fail_casting1.d(83): Error: cannot cast expression `c` of type `fail_casting1.C` to `S` fail_compilation/fail_casting1.d(84): Error: cannot cast expression `n` of type `typeof(null)` to `S` fail_compilation/fail_casting1.d(85): Error: cannot cast expression `s` of type `S` to `int*` fail_compilation/fail_casting1.d(86): Error: cannot cast expression `s` of type `S` to `int function()` fail_compilation/fail_casting1.d(87): Error: cannot cast expression `s` of type `S` to `int delegate()` fail_compilation/fail_casting1.d(88): Error: cannot cast expression `s` of type `S` to `int[]` fail_compilation/fail_casting1.d(89): Error: cannot cast expression `s` of type `S` to `int[int]` fail_compilation/fail_casting1.d(90): Error: cannot cast expression `s` of type `S` to `fail_casting1.C` fail_compilation/fail_casting1.d(91): Error: cannot cast expression `s` of type `S` to `typeof(null)` --- */ void test2() { { auto x = cast( S) p; } // Reject (Bugzilla 13959) { auto x = cast( S)fp; } // Reject (Bugzilla 13959) (FP is Tpointer) { auto x = cast( S)dg; } // Reject (from e2ir) { auto x = cast( S)da; } // Reject (from e2ir) { auto x = cast( S)aa; } // Reject (from e2ir) { auto x = cast( S) c; } // Reject (from e2ir) { auto x = cast( S) n; } // Reject (Bugzilla 9904) { auto x = cast( P) s; } // Reject (Bugzilla 13959) { auto x = cast(FP) s; } // Reject (Bugzilla 13959) (FP is Tpointer) { auto x = cast(DG) s; } // Reject (from e2ir) { auto x = cast(DA) s; } // Reject (from e2ir) { auto x = cast(AA) s; } // Reject (from e2ir) { auto x = cast( C) s; } // Reject (from e2ir) { auto x = cast( N) s; } // Reject (Bugzilla 9904) } /* TEST_OUTPUT: --- fail_compilation/fail_casting1.d(125): Error: cannot cast expression `p` of type `int*` to `int delegate()` fail_compilation/fail_casting1.d(126): Error: cannot cast expression `p` of type `int*` to `int[]` fail_compilation/fail_casting1.d(129): Error: cannot cast expression `p` of type `int*` to `typeof(null)` fail_compilation/fail_casting1.d(133): Error: cannot cast expression `fp` of type `int function()` to `int delegate()` fail_compilation/fail_casting1.d(134): Error: cannot cast expression `fp` of type `int function()` to `int[]` fail_compilation/fail_casting1.d(137): Error: cannot cast expression `fp` of type `int function()` to `typeof(null)` fail_compilation/fail_casting1.d(139): Deprecation: casting from int delegate() to int* is deprecated fail_compilation/fail_casting1.d(140): Deprecation: casting from int delegate() to int function() is deprecated fail_compilation/fail_casting1.d(142): Error: cannot cast expression `dg` of type `int delegate()` to `int[]` fail_compilation/fail_casting1.d(143): Error: cannot cast expression `dg` of type `int delegate()` to `int[int]` fail_compilation/fail_casting1.d(144): Error: cannot cast expression `dg` of type `int delegate()` to `fail_casting1.C` fail_compilation/fail_casting1.d(145): Error: cannot cast expression `dg` of type `int delegate()` to `typeof(null)` fail_compilation/fail_casting1.d(157): Error: cannot cast expression `da` of type `int[]` to `int delegate()` fail_compilation/fail_casting1.d(159): Error: cannot cast expression `da` of type `int[]` to `int[int]` fail_compilation/fail_casting1.d(160): Error: cannot cast expression `da` of type `int[]` to `fail_casting1.C` fail_compilation/fail_casting1.d(161): Error: cannot cast expression `da` of type `int[]` to `typeof(null)` fail_compilation/fail_casting1.d(165): Error: cannot cast expression `aa` of type `int[int]` to `int delegate()` fail_compilation/fail_casting1.d(166): Error: cannot cast expression `aa` of type `int[int]` to `int[]` fail_compilation/fail_casting1.d(169): Error: cannot cast expression `aa` of type `int[int]` to `typeof(null)` fail_compilation/fail_casting1.d(173): Error: cannot cast expression `c` of type `fail_casting1.C` to `int delegate()` fail_compilation/fail_casting1.d(174): Error: cannot cast expression `c` of type `fail_casting1.C` to `int[]` fail_compilation/fail_casting1.d(177): Error: cannot cast expression `c` of type `fail_casting1.C` to `typeof(null)` --- */ void test3() // between reference types { { auto x = cast( P) p; } // Accept { auto x = cast(FP) p; } // Accept (FP is Tpointer) { auto x = cast(DG) p; } // Reject (from e2ir) { auto x = cast(DA) p; } // Reject (Bugzilla 14596) { auto x = cast(AA) p; } // Accept (because of size match) { auto x = cast( C) p; } // Accept (because of size match) { auto x = cast( N) p; } // Reject (Bugzilla 14629) { auto x = cast( P)fp; } // Accept (FP is Tpointer) { auto x = cast(FP)fp; } // Accept { auto x = cast(DG)fp; } // Reject (from e2ir) { auto x = cast(DA)fp; } // Reject (Bugzilla 14596) { auto x = cast(AA)fp; } // Accept (because of size match) { auto x = cast( C)fp; } // Accept (because of size match) { auto x = cast( N)fp; } // Reject (Bugzilla 14629) { auto x = cast( P)dg; } // Deprecated (equivalent with: cast( P)dg.ptr;) { auto x = cast(FP)dg; } // Deprecated (equivalent with: cast(FP)dg.ptr;) { auto x = cast(DG)dg; } // Accept { auto x = cast(DA)dg; } // Reject (from e2ir) { auto x = cast(AA)dg; } // Reject (from e2ir) { auto x = cast( C)dg; } // Reject (from e2ir) { auto x = cast( N)dg; } // Reject (Bugzilla 14629) { auto x = cast( P) n; } // Accept { auto x = cast(FP) n; } // Accept { auto x = cast(DG) n; } // Accept { auto x = cast(DA) n; } // Accept { auto x = cast(AA) n; } // Accept { auto x = cast( C) n; } // Accept { auto x = cast( N) n; } // Accept { auto x = cast( P)da; } // Accept (equivalent with: cast(P)da.ptr;) { auto x = cast(FP)da; } // Accept (FP is Tpointer) { auto x = cast(DG)da; } // Reject (from e2ir) { auto x = cast(DA)da; } // Accept { auto x = cast(AA)da; } // Reject (from e2ir) { auto x = cast( C)da; } // Reject (Bugzilla 10646) { auto x = cast( N)da; } // Reject (Bugzilla 14629) { auto x = cast( P)aa; } // Accept (because of size match) { auto x = cast(FP)aa; } // Accept (FP is Tpointer) { auto x = cast(DG)aa; } // Reject (from e2ir) { auto x = cast(DA)aa; } // Reject (from e2ir) { auto x = cast(AA)aa; } // Accept { auto x = cast( C)aa; } // Accept (because of size match) { auto x = cast( N)aa; } // Reject (Bugzilla 14629) { auto x = cast( P) c; } // Accept { auto x = cast(FP) c; } // Accept (FP is Tpointer) { auto x = cast(DG) c; } // Reject (from e2ir) { auto x = cast(DA) c; } // Reject (Bugzilla 10646) { auto x = cast(AA) c; } // Accept (because of size match) { auto x = cast( C) c; } // Accept { auto x = cast( N) c; } // Reject (Bugzilla 14629) } /* TEST_OUTPUT: --- fail_compilation/fail_casting1.d(206): Error: cannot cast expression `0` of type `int` to `int delegate()` fail_compilation/fail_casting1.d(207): Error: cannot cast expression `0` of type `int` to `int[]` fail_compilation/fail_casting1.d(208): Error: cannot cast expression `0` of type `int` to `int[1]` fail_compilation/fail_casting1.d(209): Error: cannot cast expression `0` of type `int` to `int[int]` fail_compilation/fail_casting1.d(210): Error: cannot cast expression `0` of type `int` to `fail_casting1.C` fail_compilation/fail_casting1.d(211): Error: cannot cast expression `0` of type `int` to `typeof(null)` fail_compilation/fail_casting1.d(215): Error: cannot cast expression `i` of type `int` to `int delegate()` fail_compilation/fail_casting1.d(216): Error: cannot cast expression `i` of type `int` to `int[]` fail_compilation/fail_casting1.d(217): Error: cannot cast expression `i` of type `int` to `int[1]` fail_compilation/fail_casting1.d(218): Error: cannot cast expression `i` of type `int` to `int[int]` fail_compilation/fail_casting1.d(219): Error: cannot cast expression `i` of type `int` to `fail_casting1.C` fail_compilation/fail_casting1.d(220): Error: cannot cast expression `i` of type `int` to `typeof(null)` fail_compilation/fail_casting1.d(224): Error: cannot cast expression `dg` of type `int delegate()` to `int` fail_compilation/fail_casting1.d(225): Error: cannot cast expression `da` of type `int[]` to `int` fail_compilation/fail_casting1.d(226): Error: cannot cast expression `sa` of type `int[1]` to `int` fail_compilation/fail_casting1.d(227): Error: cannot cast expression `aa` of type `int[int]` to `int` fail_compilation/fail_casting1.d(228): Error: cannot cast expression `c` of type `fail_casting1.C` to `int` --- */ void test4() { { auto x = cast( P) 0; } // Accept { auto x = cast(FP) 0; } // Accept { auto x = cast(DG) 0; } // Reject (from constfold) { auto x = cast(DA) 0; } // Reject (Bugzilla 11484) { auto x = cast(SA) 0; } // Reject (Bugzilla 11484) { auto x = cast(AA) 0; } // Reject (from constfold) { auto x = cast( C) 0; } // Reject (Bugzilla 11485) { auto x = cast( N) 0; } // Reject (from constfold) { auto x = cast( P) i; } // Accept { auto x = cast(FP) i; } // Accept { auto x = cast(DG) i; } // Reject (from e2ir) { auto x = cast(DA) i; } // Reject (Bugzilla 11484) { auto x = cast(SA) i; } // Reject (Bugzilla 11484) { auto x = cast(AA) i; } // Reject (from e2ir) { auto x = cast( C) i; } // Reject (Bugzilla 11485) { auto x = cast( N) i; } // Reject (from e2ir) { auto x = cast(int) p; } // Accept { auto x = cast(int)fp; } // Accept { auto x = cast(int)dg; } // Reject (from e2ir) { auto x = cast(int)da; } // Reject (Bugzilla 11484) { auto x = cast(int)sa; } // Reject (Bugzilla 11484) { auto x = cast(int)aa; } // Reject (from e2ir) { auto x = cast(int) c; } // Reject (Bugzilla 7472) { auto x = cast(int) n; } // Accept } /* TEST_OUTPUT: --- fail_compilation/fail_casting1.d(249): Error: cannot cast expression `0` of type `int` to `int[1]` fail_compilation/fail_casting1.d(250): Error: cannot cast expression `0` of type `int` to `S` fail_compilation/fail_casting1.d(251): Error: cannot cast expression `i` of type `int` to `int[1]` fail_compilation/fail_casting1.d(252): Error: cannot cast expression `i` of type `int` to `S` fail_compilation/fail_casting1.d(253): Error: cannot cast expression `f` of type `double` to `int[1]` fail_compilation/fail_casting1.d(254): Error: cannot cast expression `f` of type `double` to `S` fail_compilation/fail_casting1.d(255): Error: cannot cast expression `sa` of type `int[1]` to `int` fail_compilation/fail_casting1.d(256): Error: cannot cast expression `s` of type `S` to `int` fail_compilation/fail_casting1.d(257): Error: cannot cast expression `sa` of type `int[1]` to `double` fail_compilation/fail_casting1.d(258): Error: cannot cast expression `s` of type `S` to `double` --- */ void test5() { { auto x = cast(SA) 0; } // Reject (Bugzilla 14154) { auto x = cast( S) 0; } // Reject (Bugzilla 14154) { auto x = cast(SA) i; } // Reject (Bugzilla 14154) { auto x = cast( S) i; } // Reject (Bugzilla 14154) { auto x = cast(SA) f; } // Reject (Bugzilla 14154) { auto x = cast( S) f; } // Reject (Bugzilla 14154) { auto x = cast(int)sa; } // Reject (Bugzilla 14154) { auto x = cast(int) s; } // Reject (Bugzilla 14154) { auto x = cast(double)sa; } // Reject (Bugzilla 14154) { auto x = cast(double) s; } // Reject (Bugzilla 14154) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail_casting2.d(15): Error: type `int` is not an expression fail_compilation/fail_casting2.d(17): Error: template lambda has no type fail_compilation/fail_casting2.d(20): Error: template `Templ()` has no type --- */ void test15214() { alias Type = int; cast(void)(Type); cast(void)(x => mixin(x)("mixin(x);")); template Templ() {} cast(void)(Templ); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_circular.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_circular.d(16): Error: circular reference to variable `fail_circular.a1` fail_compilation/fail_circular.d(17): Error: circular reference to variable `fail_circular.a2` fail_compilation/fail_circular.d(19): Error: circular reference to variable `fail_circular.b1` fail_compilation/fail_circular.d(20): Error: circular reference to variable `fail_circular.b2` fail_compilation/fail_circular.d(22): Error: circular reference to variable `fail_circular.c1` fail_compilation/fail_circular.d(23): Error: circular reference to variable `fail_circular.c2` fail_compilation/fail_circular.d(25): Error: circular initialization of variable `fail_circular.d1` fail_compilation/fail_circular.d(26): Error: circular initialization of variable `fail_circular.d2` fail_compilation/fail_circular.d(28): Error: circular initialization of variable `fail_circular.e1` fail_compilation/fail_circular.d(29): Error: circular initialization of variable `fail_circular.e2` --- */ auto a1 = a1; // semantic error (cannot determine expression type) auto a2 = .a2; // semantic error const b1 = b1; // semantic error const b2 = .b2; // semantic error enum c1 = c1; // semantic error enum c2 = .c2; // semantic error const int d1 = d1; // CTFE error (expression type is determined to int) const int d2 = .d2; // CTFE error enum int e1 = e1; // CTFE error enum int e2 = .e2; // CTFE error /* TEST_OUTPUT: --- fail_compilation/fail_circular.d(47): Error: circular reference to variable `fail_circular.a1a` fail_compilation/fail_circular.d(49): Error: circular reference to variable `fail_circular.a2a` fail_compilation/fail_circular.d(52): Error: circular reference to variable `fail_circular.b1a` fail_compilation/fail_circular.d(54): Error: circular reference to variable `fail_circular.b2a` fail_compilation/fail_circular.d(57): Error: circular reference to variable `fail_circular.c1a` fail_compilation/fail_circular.d(59): Error: circular reference to variable `fail_circular.c2a` fail_compilation/fail_circular.d(62): Error: circular initialization of variable `fail_circular.d1a` fail_compilation/fail_circular.d(64): Error: circular initialization of variable `fail_circular.d2a` fail_compilation/fail_circular.d(67): Error: circular initialization of variable `fail_circular.e1a` fail_compilation/fail_circular.d(69): Error: circular initialization of variable `fail_circular.e2a` --- */ auto a1a = a1b; auto a1b = a1a; // semantic error auto a2a = a2b; auto a2b = .a2a; // semantic error const b1a = b1b; const b1b = b1a; // semantic error const b2a = b2b; const b2b = .b2a; // semantic error enum c1a = c1b; enum c1b = c1a; // semantic error enum c2a = c2b; enum c2b = .c2a; // semantic error const int d1a = d1b; const int d1b = d1a; // CTFE error const int d2a = d2b; const int d2b = .d2a; // CTFE error enum int e1a = e1b; enum int e1b = e1a; // CTFE error enum int e2a = e2b; enum int e2b = .e2a; // CTFE error /* TEST_OUTPUT: --- fail_compilation/fail_circular.d(84): Error: circular reference to variable `fail_circular.S1.a1` fail_compilation/fail_circular.d(88): Error: circular reference to variable `fail_circular.S2.b1` fail_compilation/fail_circular.d(92): Error: circular reference to variable `fail_circular.S3.c1` fail_compilation/fail_circular.d(97): Error: circular reference to variable `fail_circular.S4.a1a` fail_compilation/fail_circular.d(102): Error: circular reference to variable `fail_circular.S5.b1a` fail_compilation/fail_circular.d(107): Error: circular reference to variable `fail_circular.S6.c1a` --- */ struct S1 { static a1 = S1.a1; // semantic error } struct S2 { static const b1 = S2.b1; // semantic error } struct S3 { enum c1 = S3.c1; // semantic error } struct S4 { static a1a = S4.a1b; static a1b = S4.a1a; // semantic error } struct S5 { static const b1a = S5.b1b; static const b1b = S5.b1a; // semantic error } struct S6 { enum c1a = S6.c1b; enum c1b = S6.c1a; // semantic error } /* TEST_OUTPUT: --- fail_compilation/fail_circular.d(123): Error: circular reference to variable `fail_circular.C.a1` fail_compilation/fail_circular.d(125): Error: circular reference to variable `fail_circular.C.b1` fail_compilation/fail_circular.d(127): Error: circular reference to variable `fail_circular.C.c1` fail_compilation/fail_circular.d(130): Error: circular reference to variable `fail_circular.C.a1a` fail_compilation/fail_circular.d(133): Error: circular reference to variable `fail_circular.C.b1a` fail_compilation/fail_circular.d(136): Error: circular reference to variable `fail_circular.C.c1a` --- */ class C { static a1 = C.a1; // semantic error static const b1 = C.b1; // semantic error enum c1 = C.c1; // semantic error static a1a = C.a1b; static a1b = C.a1a; // semantic error static const b1a = C.b1b; static const b1b = C.b1a; // semantic error enum c1a = C.c1b; enum c1b = C.c1a; // semantic error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_circular2.d(10): Error: circular initialization of variable `fail_circular2.S.d1` fail_compilation/fail_circular2.d(12): Error: circular initialization of variable `fail_circular2.S.e1` --- */ struct S { static const int d1 = S.d1; // CTFE error (expression type is determined to int) enum int e1 = S.e1; // CTFE error } /* TEST_OUTPUT: --- fail_compilation/fail_circular2.d(24): Error: circular initialization of variable `fail_circular2.C.d1` fail_compilation/fail_circular2.d(26): Error: circular initialization of variable `fail_circular2.C.e1` --- */ class C { static const int d1 = C.d1; // CTFE error enum int e1 = C.e1; // CTFE error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_contracts1.d(8): Error: `(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `)` --- */ void foo() out()){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_contracts2.d(8): Error: missing `do { ... }` after `in` or `out` --- */ void foo()in{}{} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_contracts3.d(13): Error: function `fail_contracts3.D.foo` cannot have an in contract when overridden function `fail_contracts3.C.foo` does not have an in contract --- */ class C { void foo(){} } class D : C { override void foo()in{}do{} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_contracts4.d(8): Error: missing `do { ... }` for function literal --- */ enum x = delegate int()in(true) out(;true) out(r; true) in{} out(r){}; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_isZeroInit.d ================================================ /* TEST_OUTPUT: --- fail_compilation/fail_isZeroInit.d(11): Error: type expected as second argument of __traits `isZeroInit` instead of `a` --- */ void test() { int a = 3; // Providing a specific variable rather than a type isn't allowed. enum bool az = __traits(isZeroInit, a); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_opover.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/fail_opover.d(13): Error: no `[]` operator overload for type `object.Object` fail_compilation/fail_opover.d(17): Error: no `[]` operator overload for type `TestS` --- */ void test1() { Object m; m[] = error; struct TestS {} TestS s; s[] = error; } /* TEST_OUTPUT: --- fail_compilation/fail_opover.d(46): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(47): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(48): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(49): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(50): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(51): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(52): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(53): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(54): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(55): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(56): Error: no `[]` operator overload for type `S` fail_compilation/fail_opover.d(57): Error: no `[]` operator overload for type `S` --- */ void test2() { struct S { void func(int) {} alias func this; } S s; // The errors failing aliasthis access need to be gagged for better error messages. s[]; // in ArrayExp::op_overload() s[1]; // ditto s[1..2]; // ditto +s[]; // in UnaExp::op_overload() +s[1]; // ditto +s[1..2]; // ditto s[] = 3; // in AssignExp::semantic() s[1] = 3; // ditto s[1..2] = 3; // ditto s[] += 3; // in BinAssignExp::op_overload() s[1] += 3; // ditto s[1..2] += 3; // ditto } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fail_scope.d ================================================ /* PERMUTE_ARGS: REQUIRED_ARGS: -dip25 TEST_OUTPUT: --- fail_compilation/fail_scope.d(45): Error: returning `cast(char[])string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(63): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a` fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a` fail_compilation/fail_scope.d(108): Error: escaping reference to outer local variable `x` fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- //fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned //fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned //fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned //fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned //fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned //fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned //fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned */ alias int delegate() dg_t; int[] checkEscapeScope1(scope int[] da) { return da; } int[3] checkEscapeScope2(scope int[3] sa) { return sa; } Object checkEscapeScope3(scope Object o) { return o; } dg_t checkEscapeScope4(scope dg_t dg) { return dg; } int[] checkEscapeScope1() { scope int[] da = []; return da; } int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; } Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; } int* test(scope int* p) @safe { return p; } char[] foo140() { char[4] string = "abcd"; return string; } /************/ struct S { int x; ref int bar() return { return x; } } ref int test() { S s; return s.bar(); } /************/ ref int foo8(ref int x); ref int foo8(return ref int x); void testover() { int x; foo8(x); } /************/ char* fail141() { char[4] string = "abcd"; return string.ptr; } /************/ int[] test1313b() out{} body { int[2] a; return a; } int[] test1313a() //out{} body { int[2] a; return a; } /******************/ // https://issues.dlang.org/show_bug.cgi?id=15192 ref int fun15192(ref int x) @safe { ref int bar(){ return x; } return bar(); } ref int fun15192_2(return ref int x) @safe { ref int bar(){ return x; } return bar(); } /**************************/ // https://issues.dlang.org/show_bug.cgi?id=15193 ref int foo15193()@safe{ struct S{ int x; ref int bar() { return x; } } S s; return s.bar(); } /*****************************/ // https://issues.dlang.org/show_bug.cgi?id=16226 ref int test16226() @safe { int i; return foo16226(i); } ref foo16226(ref int bar) @safe { return bar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failattr.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/failattr.d(16): Error: variable `failattr.C2901.v1` cannot be `synchronized` fail_compilation/failattr.d(17): Error: variable `failattr.C2901.v2` cannot be `override` fail_compilation/failattr.d(18): Error: variable `failattr.C2901.v3` cannot be `abstract` fail_compilation/failattr.d(19): Error: variable `failattr.C2901.v4` cannot be `final`, perhaps you meant `const`? fail_compilation/failattr.d(31): Error: variable `failattr.C2901.v13` cannot be `final abstract synchronized override` fail_compilation/failattr.d(33): Error: variable `failattr.C2901.v14` cannot be `final`, perhaps you meant `const`? --- */ class C2901 { synchronized int v1; // error override int v2; // error abstract int v3; // error final int v4; // error synchronized { int v5; } // no error override { int v6; } // no error abstract { int v7; } // no error final { int v8; } // no error synchronized: int v9; // no error override: int v10; // no error abstract: int v11; // no error final: int v12; // no error synchronized override abstract final int v13; // one line error static final int v14; // error, even if static is applied at the same time } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failcontracts.d ================================================ /* TEST_OUTPUT: --- fail_compilation/failcontracts.d(18): Error: missing `{ ... }` for function literal fail_compilation/failcontracts.d(18): Error: semicolon expected following auto declaration, not `bode` fail_compilation/failcontracts.d(19): Error: function declaration without return type. (Note that constructors are always named `this`) fail_compilation/failcontracts.d(19): Error: no identifier for declarator `test1()` fail_compilation/failcontracts.d(19): Error: semicolon expected following function declaration fail_compilation/failcontracts.d(20): Error: semicolon expected following function declaration fail_compilation/failcontracts.d(22): Error: unexpected `(` in declarator fail_compilation/failcontracts.d(22): Error: found `T` when expecting `)` fail_compilation/failcontracts.d(22): Error: enum declaration is invalid fail_compilation/failcontracts.d(22): Error: found `)` instead of statement --- */ void test() { auto f1 = function() bode; auto test1() bode; auto test2()() bode; enum : int (int function() bode T); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d ================================================ /* TEST_OUTPUT: --- fail_compilation/faildeleteaa.d(12): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/faildeleteaa.d(12): Error: cannot delete type `int` --- */ void main() { int[int] aa = [1 : 2]; delete aa[1]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d ================================================ /* TEST_OUTPUT: --- fail_compilation/faildottypeinfo.d(11): Error: no property `typeinfo` for type `int` fail_compilation/faildottypeinfo.d(12): Error: no property `typeinfo` for type `object.Object` --- */ void main() { auto x = 0.typeinfo; auto y = Object.typeinfo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failescape.d ================================================ /* TEST_OUTPUT: --- fail_compilation/failescape.d(8): Error: character '\' is not a valid token --- */ string x = \n; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failinout1.d ================================================ inout(int) foo(inout(int) x) { x = 5; // cannot modify inout return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failinout2.d ================================================ inout int x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d ================================================ struct S3748 { inout(int) err8; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d ================================================ void main() { inout(int)* err11; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d ================================================ /* TEST_OUTPUT: --- fail_compilation/failmemalloc.d(11): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class fail_compilation/failmemalloc.d(14): Error: member allocators not supported by CTFE --- */ struct S { new(size_t sz) { return null; } } S* s = new S(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failoffset.d ================================================ /* TEST_OUTPUT: --- fail_compilation/failoffset.d(12): Error: no property `offset` for type `int` fail_compilation/failoffset.d(12): while evaluating: `static assert(b.offset == 4)` --- */ void main() { struct S { int a, b; } static assert(S.b.offset == 4); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failsafea.d ================================================ void systemfunc() @system {} @safe void callingsystem() { systemfunc(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failsafeb.d ================================================ void function() @system sysfuncptr; @safe void callingsystem() { sysfuncptr(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/failsafec.d ================================================ void delegate() @system sysdelegate; @safe void callingsystem() { sysdelegate(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix17635.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/fix17635.d(22): Error: cannot implicitly convert expression `f(& p)` of type `immutable(int)**` to `immutable(int**)` --- */ // https://issues.dlang.org/show_bug.cgi?id=17635 // https://issues.dlang.org/show_bug.cgi?id=15660 alias T = immutable int; T** f(const T** input) pure { T** output; return output; } void main() { T i; T* p = &i; immutable T** r = f(&p); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix17751.d ================================================ /* REQUIRED_ARGS: -m64 * TEST_OUTPUT: --- fail_compilation/fix17751.d(15): Error: last parameter to `__simd()` must be a constant --- */ // https://issues.dlang.org/show_bug.cgi?id=17751 import core.simd; pure @safe V1 simd(XMM opcode, V1, V2)(V1 op1, V2 op2, ubyte imm8) if (is(V1 == __vector) && is(V2 == __vector)) { return cast(V1)__simd(opcode, op1, op2, imm8); } void main() { float4 a, b; a = simd!(XMM.CMPPD)(a, b, 0x7A); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix18575.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to parameter `t`, perhaps annotate with `return` --- */ // https://issues.dlang.org/show_bug.cgi?id=18575 @safe: struct S { @safe: int x; void bar() { } auto foo() { return &this.bar; } auto def() { return &bar; } auto abc() { return &x; } auto ghi(ref S s) { return &s.bar; } } auto f(S s) { return s.foo(); } auto g(S s) { return s.foo(); } auto h(S s) { return s.abc(); } auto j(S s, S t) { return s.ghi(t); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix19018.d ================================================ /* REQUIRED_ARGS: -de * PERMUTE_ARGS: * TEST_OUTPUT: --- fail_compilation/fix19018.d(17): Deprecation: `0b` isn't a valid integer literal, use `0b0` instead fail_compilation/fix19018.d(18): Deprecation: `0B` isn't a valid integer literal, use `0B0` instead fail_compilation/fix19018.d(19): Deprecation: `0x` isn't a valid integer literal, use `0x0` instead fail_compilation/fix19018.d(20): Deprecation: `0X` isn't a valid integer literal, use `0X0` instead fail_compilation/fix19018.d(21): Deprecation: `0x_` isn't a valid integer literal, use `0x0` instead --- */ // https://issues.dlang.org/show_bug.cgi?id=19018 void foo() { auto a = 0b; auto b = 0B; auto c = 0x; auto d = 0X; auto e = 0x_; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix19059.d ================================================ /* REQUIRED_ARGS: * PERMUTE_ARGS: * TEST_OUTPUT: --- fail_compilation/fix19059.d(17): Error: octal digit expected, not `8` fail_compilation/fix19059.d(17): Error: octal literals larger than 7 are no longer supported fail_compilation/fix19059.d(18): Error: octal digit expected, not `9` fail_compilation/fix19059.d(18): Error: octal literals larger than 7 are no longer supported fail_compilation/fix19059.d(19): Error: octal literals `010` are no longer supported, use `std.conv.octal!10` instead --- */ // https://issues.dlang.org/show_bug.cgi?id=19059 void foo() { auto a = 08; auto b = 09; auto c = 010; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix350a.d ================================================ struct S1 { int a, b, c; static immutable S1 C1 = { 1 2 3 }; // no commas here, compiles static immutable S1 C2 = { 1, 2, 3 }; // compiles as well } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix350b.d ================================================ int foo() { return 3; } struct S2 { int a, b, c; static immutable S2 C1 = { foo() 2 3 }; // compiles (and works) static immutable S2 C2 = { foo() 2, 3 }; // compiles (and works) //static immutable S2 C3 = { 2 foo() 3 }; // does not compile: comma expected separating field initializers } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/fix5212.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/fix5212.d(14): Error: scope variable `args_` assigned to non-scope `this.args` --- */ // https://issues.dlang.org/show_bug.cgi?id=5212 class Foo { int[] args; @safe this(int[] args_...) { args = args_; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269a.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269a.d(12): Error: undefined identifier `B` --- */ static if(is(typeof(A4269.sizeof))) {} class A4269 { void foo(B b); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269b.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269b.d(10): Error: undefined identifier `Y` --- */ static if(is(typeof(X2.init))) {} struct X2 { Y y; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269c.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269c.d(10): Error: undefined identifier `T3`, did you mean function `X3`? --- */ static if(is(typeof(X3.init))) {} void X3(T3) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269d.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269d.d(10): Error: undefined identifier `Y4`, did you mean function `X4`? --- */ static if(is(typeof(X4.init))) {} Y4 X4() { return typeof(return).init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269e.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269e.d(10): Error: undefined identifier `Y8`, did you mean class `X8`? --- */ static if(is(typeof(X8.init))) {} class X8 : Y8 {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269f.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269f.d(11): Error: undefined identifier `Y9`, did you mean interface `X9`? fail_compilation/gag4269f.d(11): Error: variable `gag4269f.X9.y` field not allowed in interface --- */ static if(is(typeof(X9.init))) {} interface X9 { Y9 y; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/gag4269g.d ================================================ // REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- fail_compilation/gag4269g.d(10): Error: undefined identifier `Y13`, did you mean template `X13(Y13 y)`? --- */ static if(is(typeof(X13!(0).init))) {} template X13(Y13 y) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10016.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10016.d(33): Error: undefined identifier `unknownIdentifier` fail_compilation/ice10016.d(47): Error: template instance `ice10016.RefCounted!(S)` error instantiating --- */ struct RefCounted(T) { struct RefCountedStore { struct Impl { T _payload; } Impl* _store; } RefCountedStore _refCounted; void opAssign(typeof(this)) { } void opAssign(T) { } @property refCountedPayload() { return _refCounted._store._payload; } alias refCountedPayload this; } struct S { int i = unknownIdentifier; } class C {} class N { this(C) {} C c() { return null; } } class D : N { this() { super(c); } RefCounted!S _s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10076.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10076.d(18): Error: template instance `getMembersAndAttributesWhere!()` template `getMembersAndAttributesWhere` is not defined fail_compilation/ice10076.d(23): Error: template instance `ice10076.getValidaterAttrs!string` error instantiating fail_compilation/ice10076.d(13): instantiated from here: `validate!string` --- */ void main() { string s; validate(s); } template getValidaterAttrs(T) { alias getMembersAndAttributesWhere!().Elements getValidaterAttrs; } void validate(T)(T) { alias getValidaterAttrs!T memberAttrs; auto x = memberAttrs.length; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10212.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10212.d(12): Error: mismatched function return type inference of `int function() pure nothrow @nogc @safe` and `int` --- */ int delegate() foo() { // returns "int function() pure nothrow @safe function() pure nothrow @safe" // and it mismatches to "int delegate()" return () => { return 1; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10259.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10259.d(11): Error: circular reference to `ice10259.D.d` fail_compilation/ice10259.d(11): called from here: `(*function () => x)()` --- */ class D { int x; D d = { auto x = new D(); return x; }(); } enum x = new D; /* TEST_OUTPUT: --- fail_compilation/ice10259.d(25): Error: circular reference to `ice10259.D2.d` fail_compilation/ice10259.d(25): called from here: `(*function () => x)()` --- */ class D2 { int x; D2 d = function { auto x = new D2(); return x; }(); } enum x2 = new D2; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10273.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=10273 // ICE in CTFE struct Bug10273 { int val = 3.45; } int bug10273() { Bug10273 p; return 1; } static assert(bug10273()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10283.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=10283 S10283 blah(S10283 xxx) { return xxx; } S10283 repy = blah(S10283()); struct S10283 { string source = 7; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10341.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10341.d(10): Error: case range not in `switch` statement --- */ void main() { case 1: .. case 2: } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10382.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10382.d(14): Error: can only catch class objects, not `int` --- */ void main () { try { int b = 3; } catch (int a) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10419.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10419.d(12): Error: `arr().length` is not an lvalue and cannot be modified --- */ int[] arr() { return []; } void main() { arr().length = 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10599.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=10599 // ICE(interpret.c) struct Bug { int val = 3.45; } int bug10599() { Bug p = Bug(); return 1; } static assert(bug10599()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10600.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10600.d(30): Error: template instance `to!(int, double)` does not match template declaration `to(T)` --- */ import imports.ice10600a; import imports.ice10600b; template Tuple(Specs...) { struct Tuple { string toString() { Appender!string w; // issue! return ""; } } } Tuple!T tuple(T...)(T args) { return typeof(return)(); } void main() { auto a = to!int(""); auto b = to!(int, double)(""); tuple(1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10616.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10616.d(8): Error: class `ice10616.A` is forward referenced when looking for `B` --- */ class A : A.B { interface B {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10624.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10624.d(38): Error: need member function `opCmp()` for struct `Tuple!(Msg)` to compare fail_compilation/ice10624.d(48): Error: template instance `ice10624.Variant.handler!(Tuple!(Msg))` error instantiating fail_compilation/ice10624.d(21): instantiated from here: `opAssign!(Tuple!(Msg))` --- */ struct Msg {} struct Tuple(Specs...) { Specs expand; alias expand this; } void main() { Variant data; data = Tuple!Msg(); } struct Variant { ptrdiff_t function() fptr = &handler!(void); static ptrdiff_t handler(A : void)() { return 0; } static ptrdiff_t handler(A)() { A* zis; A* rhsPA; { return *zis < *rhsPA ? -1 : 1; // Tuple!(Msg) < Tuple!(Msg) // Tuple!(Msg).expand < Tuple!(Msg).expand // -> should be error } return 0; } Variant opAssign(T)(T rhs) { fptr = &handler!(T); return this; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10651.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10651.d(11): Error: can only throw class objects derived from `Throwable`, not type `int*` --- */ void main() { alias T = int; throw new T(); // ICE } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10713.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10713.d(10): Error: no property `nonExistingField` for type `S` --- */ struct S { void f(typeof(this.nonExistingField) a) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10727a.d ================================================ // REQUIRED_ARGS: -c /* TEST_OUTPUT: --- fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop` --- */ import imports.foo10727a; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10727b.d ================================================ // REQUIRED_ARGS: -c /* TEST_OUTPUT: --- fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop` --- */ import imports.foo10727b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10770.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10770.d(13): Error: enum `ice10770.E2` is forward referenced looking for base type fail_compilation/ice10770.d(13): while evaluating: `static assert(is(E2 e == enum))` --- */ enum E1 : int; static assert(is(E1 e == enum) && is(e == int)); enum E2; static assert(is(E2 e == enum)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10922.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10922.d(9): Error: function `ice10922.__lambda4(const(uint) n)` is not callable using argument types `()` --- */ auto fib = (in uint n) pure nothrow { enum self = __traits(parent, {}); return (n < 2) ? n : self(n - 1) + self(n - 2); }; void main() { auto n = fib(39); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10938.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10938.d(12): Error: no property `opts` for type `ice10938.C` --- */ class C { this() { this.opts["opts"] = 1; } auto opDispatch(string field : "opts")() { return this.opts; // ICE -> compile time error } } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice10949.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice10949.d(12): Error: Using the result of a comma expression is not allowed fail_compilation/ice10949.d(12): Error: array index 3 is out of bounds `[5, 5][0 .. 2]` fail_compilation/ice10949.d(12): Error: array index 17 is out of bounds `[2, 3][0 .. 2]` fail_compilation/ice10949.d(12): while evaluating: `static assert((((([5, 5][3] + global - global) * global / global % global >> global & global | global) ^ global) == 9 , [2, 3][17]) || [3, 3, 3][9] is 4 && [[1, 2, 3]][4].length)` --- */ int global; static assert((((((([5,5][3] + global - global)*global/global%global)>>global) &global|global)^global) == 9, [2,3][17]) || ([3,3,3][9] is 4) && ([[1,2,3]][4]).length); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11086.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11086.d(10): Error: template instance `foo!A` template `foo` is not defined --- */ struct A { foo!(A) l1,l2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11136.d ================================================ // EXTRA_SOURCES: imports/bar11136.d /* TEST_OUTPUT: --- fail_compilation/imports/bar11136.d(1): Error: package name 'ice11136' conflicts with usage as a module name in file fail_compilation/ice11136.d --- */ module ice11136; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11153.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11153.d(11): Error: function declaration without return type. (Note that constructors are always named `this`) fail_compilation/ice11153.d(11): Error: no identifier for declarator `foo()` --- */ struct S { foo(T)() {} // Parser creates a TemplateDeclaration object with ident == NULL } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11404.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11404.d(10): Error: cannot have associative array of `(int, int)` --- */ template TypeTuple(TL...) { alias TL TypeTuple; } void main() { TypeTuple!(int, int)[string] my_map; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice1144.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice1144.d(14): Error: undefined identifier `a` fail_compilation/ice1144.d(23): Error: template instance `ice1144.testHelper!("hello", "world")` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=1144 // ICE(template.c) template mixin causes DMD crash char[] testHelper(A ...)() { char[] result; foreach (t; a) { result ~= "int " ~ t ~ ";\n"; } return result; } void main() { mixin(testHelper!("hello", "world")()); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11472.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11472.d(13): Error: template instance `fun2!fun` `fun2` is not a template declaration, it is a function fail_compilation/ice11472.d(18): Error: template instance `ice11472.fun1!(fun3)` error instantiating --- */ void fun3() {} void fun2(string a) {} void fun1(alias fun=fun3)() { "a".fun2!fun; } void main() { fun1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11513a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/ice11513x.d(1): Error: package name 'ice11513a' conflicts with usage as a module name in file fail_compilation/ice11513a.d --- */ module ice11513a; import imports.ice11513x; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11513b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/ice11513y.d(1): Error: package name 'ice11513b' conflicts with usage as a module name in file fail_compilation/ice11513b.d --- */ module ice11513b; import imports.ice11513y; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11518.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11518.d(17): Error: class `ice11518.B` matches more than one template declaration: fail_compilation/ice11518.d(12): `B(T : A!T)` and fail_compilation/ice11518.d(13): `B(T : A!T)` --- */ class A(T) {} class B(T : A!T) {} class B(T : A!T) {} void main() { new B!(A!void); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11552.d ================================================ /* REQUIRED_ARGS: -o- PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/ice11552.d(14): Error: label `label` is undefined fail_compilation/ice11552.d(17): called from here: `test11552()` fail_compilation/ice11552.d(17): while evaluating: `static assert(test11552())` --- */ int test11552() { goto label; return 1; } static assert(test11552()); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11553.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11553.d(22): Error: recursive template expansion while looking for `A!().A()` --- */ template A(alias T) { template A() { alias A = T!(); } } template B() { alias B = A!(.B); } static if (A!B) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11626.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11626.d(8): Error: undefined identifier `Bar` --- */ void foo(in ref Bar) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11726.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11726.d(16): Error: undefined identifier `x` --- */ struct S { auto opDispatch(string fn, Args...)(Args args) { } } void main() { S().reserve(x.foo()); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11790.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11790.d(8): Error: cannot pass type `string` as a function argument --- */ string[string] crash = new string[string]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11793.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11793.d(11): Error: circular reference to `ice11793.Outer.outer` --- */ class Outer { int foo; Outer outer = new Outer(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11822.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/ice11822.d(32): Deprecation: function `ice11822.d` is deprecated fail_compilation/ice11822.d(21): instantiated from here: `S!(__lambda1)` fail_compilation/ice11822.d(32): instantiated from here: `g!((n) => d(i))` --- */ struct S(alias pred) { this(int) { pred(1); } void f() { pred(2); } } auto g(alias pred)() { return S!pred(3); } deprecated bool d(int) { return true; } auto h() { int i; return g!(n => d(i))(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11849b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11849b.d(11): Error: circular reference to enum base type `DWORD1` fail_compilation/ice11849b.d(11): Error: `DWORD1` is used as a type fail_compilation/ice11849b.d(16): Error: circular reference to enum base type `typeof(DWORD2)` --- */ enum REG_DWORD = 1; enum : DWORD1 { DWORD1 = REG_DWORD } enum : typeof(DWORD2) { DWORD2 = REG_DWORD } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11850.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11850.d(14): Error: incompatible types for `(a) < ([0])`: `uint[]` and `int[]` fail_compilation/imports/a11850.d(9): instantiated from here: `FilterResult!(__lambda1, uint[][])` fail_compilation/ice11850.d(14): instantiated from here: `filter!(uint[][])` --- */ import imports.a11850 : filter; void main() { filter!(a => a < [0])([[0u]]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11919.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11919.d(17): Error: cannot interpret `foo` at compile time fail_compilation/imports/a11919.d(4): Error: template instance `a11919.doBar!(Foo).doBar.zoo!(t)` error instantiating fail_compilation/imports/a11919.d(11): instantiated from here: `doBar!(Foo)` fail_compilation/ice11919.d(25): instantiated from here: `doBar!(Bar)` --- */ import imports.a11919; enum foo; class Foo { @foo bool _foo; } class Bar : Foo {} void main() { auto bar = new Bar(); bar.doBar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11922.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11922.d(11): Error: undefined identifier `a` fail_compilation/ice11922.d(17): Error: template instance `ice11922.S.f!int` error instantiating --- */ struct S { auto f(B)(B) { return a; } } void main() { S s; s.f(5); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11926.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11926.d(11): Error: no identifier for declarator `const(a)` fail_compilation/ice11926.d(12): Error: no identifier for declarator `const(b)` --- */ enum { const a = 1, const b = 2 } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11944.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11944.d(12): Error: template instance `doCommand!(func)` does not match template declaration `doCommand(f, T)(f, T arg)` --- */ void func(int var) {} void doCommand(f, T)(f, T arg) {} auto var = &doCommand!func; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11963.d ================================================ A("")= ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11965.d ================================================ u[{b*A, ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11967.d ================================================ [F(%g{@ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11968.d ================================================ void main() { delete __FILE__ ; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11969.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice11969.d(9): Error: undefined identifier `index` fail_compilation/ice11969.d(10): Error: undefined identifier `cond` fail_compilation/ice11969.d(11): Error: undefined identifier `msg` --- */ void test1() { mixin ([index]); } void test2() { mixin (assert(cond)); } void test3() { mixin (assert(0, msg)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11974.d ================================================ void main() { 0 = __LINE__ ^^ [ 0 ] ; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice11982.d ================================================ void main() { new scope ( funk ) function } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12040.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12040.d(8): Error: circular reference to `ice12040.lol` --- */ bool[lol.length] lol; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12158.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12158.d(7): Error: module `object` import `nonexisting` not found --- */ import object : nonexisting; auto x = nonexisting.init; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12174.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12174.d(12): Error: no property `sum` for type `int[]` fail_compilation/ice12174.d(20): Error: CTFE failed because of previous errors in `this` fail_compilation/ice12174.d(13): called from here: `filter([1, 2, 3])` --- */ void main() { enum foo3 = (int n) => [1,2,3].sum; enum bar3 = [1,2,3].filter!(n => n % foo3(n) == 0); } template filter(alias pred) { auto filter(Range)(Range rs) { return FilterResult!(pred, Range)(rs); } } private struct FilterResult(alias pred, R) { R _input; this(R r) { _input = r; while (_input.length && !pred(_input[0])) { _input = _input[1..$]; } } @property bool empty() { return _input.length == 0; } @property auto ref front() { return _input[0]; } void popFront() { do { _input = _input[1..$]; } while (_input.length && !pred(_input[0])); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12235.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function `__lambda1` fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function `__lambda1` fail_compilation/ice12235.d(15): while evaluating `pragma(msg, __lambda1.mangleof)` --- */ void main() { (){ int x; enum s = __traits(parent, x).mangleof; pragma(msg, __traits(parent, x).mangleof); }(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12350.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12350.d(15): Error: type `MyUDC` has no value fail_compilation/ice12350.d(30): Error: template instance `ice12350.testAttrs!(MyStruct)` error instantiating --- */ enum MyUDC; struct MyStruct { int a; @MyUDC int b; } void testAttrs(T)(const ref T t) if (is(T == struct)) { foreach (name; __traits(allMembers, T)) { auto tr = __traits(getAttributes, __traits(getMember, t, name)); } } void main() { MyStruct s; testAttrs(s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12362.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12362.d(12): Error: cannot interpret `foo` at compile time --- */ enum foo; void main() { enum bar = foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12397.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12397.d(12): Error: undefined identifier `tokenLookup` --- */ struct DSplitter { enum Token : int { max = tokenLookup.length } immutable string[Token.max] tokenText; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12501.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12501.d(29): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` fail_compilation/ice12501.d(29): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` fail_compilation/ice12501.d(43): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating --- */ struct Tuple(T...) { alias Types = T; T field; alias field this; } Tuple!A tuple(A...)(A args) { return typeof(return)(args); } template reduce(fun...) { auto reduce(Args...)(Args args) { alias seed = args[0]; alias r = args[1]; Args[0] result = seed; for (; r.length != 0; r = r[1..$]) { foreach (i, Unused; Args[0].Types) { result[i] = fun[i](result[i], r[0]); } } return result; } } int foo(int value) { return value; } void main() { reduce!(foo, foo)(tuple(0, 0), [ 1 ]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12534.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12534.d(14): Error: static assert: `is(exprs[0 .. 0])` is false --- */ alias TypeTuple(T...) = T; void main() { int x, y; alias exprs = TypeTuple!(x, y); static assert(is(exprs[0..0])); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12539.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12539.d(15): Error: array index `[0]` is outside array bounds `[0 .. 0]` --- */ alias TypeTuple(E...) = E; void main () { int[string] map; alias Foo = TypeTuple!(); auto a = map[Foo[0]]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12574.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12574.d(40): Error: tuple index `2` exceeds length 2 fail_compilation/ice12574.d(53): Error: template instance `ice12574.reduce!("a", "a").reduce!(Tuple!(int, int, int))` error instantiating --- */ struct Tuple(T...) { alias Types = T; T field; alias field this; } Tuple!A tuple(A...)(A args) { return typeof(return)(args); } template binaryFun(alias fun) { static if (is(typeof(fun) : string)) { auto binaryFun(ElementType1, ElementType2)(auto ref ElementType1 __a, auto ref ElementType2 __b) { mixin("alias "~"a"~" = __a ;"); mixin("alias "~"b"~" = __b ;"); return mixin(fun); } } else { alias binaryFun = fun; } } template reduce(fun...) { auto reduce(Seed)(Seed result) { foreach (i, Unused; Seed.Types) { result[i] = binaryFun!(fun[i])(1, 1); // here } return result; } } int foo(int value) { return value; } void main() { reduce!("a", "a")(tuple(1, 1, 1)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12581.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12581.d(21): Error: undefined identifier `undef` --- */ struct S { int[3] a; alias a this; } struct T { S s; alias s this; } void main() { T x; x[] = (undef = 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12673.d ================================================ void main() { static assert(__traits(compiles, { abcd(); })); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12727.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/ice12727.d(16): Error: alias `ice12727.IndexTuple!(1, 0).IndexTuple` recursive alias declaration fail_compilation/ice12727.d(23): Error: template instance `ice12727.IndexTuple!(1, 0)` error instantiating fail_compilation/ice12727.d(27): instantiated from here: `Matrix!(float, 3)` fail_compilation/ice12727.d(28): instantiated from here: `Vector!(float, 3)` ---- */ template IndexTuple(int e, int s = 0, T...) { static if (s == e) alias IndexTuple = T; else alias IndexTuple = IndexTuple!(e); } struct Matrix(T, int N = M) { pure decomposeLUP() { foreach (j; IndexTuple!(1)) {} } } alias Vector(T, int M) = Matrix!(T, M); alias Vector3 = Vector!(float, 3); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12827.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12827.d(10): Error: circular initialization of variable `ice12827.Test.i` --- */ struct Test { immutable int i = i; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12836.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12836.d(9): Error: undefined identifier `C` fail_compilation/ice12836.d(9): Error: undefined identifier `K` --- */ immutable C L = 1 << K; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12838.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12838.d(27): Error: cannot implicitly convert expression `1` of type `int` to `string` --- */ struct Tuple(T...) { T field; alias field this; } struct Data { string a; } template toTuple(T) { mixin(`alias toTuple = Tuple!(string);`); } void main() { toTuple!Data a; a[0] = 1; // ICE! } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12841.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12841.d(23): Error: `taskPool().amap(Args...)(Args args)` is not an lvalue and cannot be modified fail_compilation/ice12841.d(24): Error: `amap(Args...)(Args args)` is not an lvalue and cannot be modified --- */ @property TaskPool taskPool() @trusted { return new TaskPool; } final class TaskPool { template amap(functions...) { auto amap(Args...)(Args args) { } } } void main() { auto dg = &(taskPool.amap!"a.result()"); auto fp = &(TaskPool.amap!"a.result()"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12850.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12850.d(12): Error: cannot implicitly convert expression `0` of type `int` to `string` --- */ alias TypeTuple(TL...) = TL; void main() { int[string] arr; alias staticZip = TypeTuple!(arr[0]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12902.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void` fail_compilation/ice12902.d(20): Error: expression `s.opDollar()` is `void` and has no value --- */ struct S { void opDollar() { } void opIndex() { } void opIndexAssign() { } void opSliceAssign() { } } void main() { S s; s[] = s[$]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice12907.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice12907.d(10): Error: template lambda has no type --- */ auto f(void function() g) { return x => (*g)(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13024.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13024.d(15): Error: cannot implicitly convert expression `t.x` of type `A` to `B` --- */ enum A { a } enum B { b } struct T { A x; B y; } void main() { T t; auto r1 = [cast(int)(t.x), cast(int)(t.y)]; // OK auto r3 = [t.x, t.y]; // crash } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13027.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13027.d(9): Error: template instance `b!"c"` template `b` is not defined --- */ void main() { scope a = b!"c"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13081.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13081.d(17): Error: undefined identifier `node` fail_compilation/ice13081.d(17): Error: undefined identifier `data` fail_compilation/ice13081.d(17): Error: undefined identifier `node` fail_compilation/ice13081.d(28): Error: template instance `ice13081.Cube!(SparseDataStore)` error instantiating --- */ struct Cube(StorageT) { StorageT datastore; alias datastore this; auto seed() { this[] = node.data ? data : node.data; } } class SparseDataStore { auto opSlice() {} } void main() { Cube!SparseDataStore c; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13131.d ================================================ // EXTRA_SOURCES: imports/a13131parameters.d imports/a13131elec.d /* TEST_OUTPUT: --- +A +B fail_compilation/imports/a13131elec.d(10): Error: template instance `elecConnOf!gconn` template `elecConnOf` is not defined -B -A --- */ void main() { struct Connectivity {} auto L = Connectivity(); import imports.a13131elec; // [1] import L.initElec; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13220.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13220.d(22): Error: template instance `test!0` does not match template declaration `test(T)()` --- */ struct Tuple(T...) { T field; alias field this; } template test(T) { bool test() { return false; }; } void main() { Tuple!bool t; t[0] = test!0(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13221.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13221.d(20): Error: variable `r` cannot be read at compile time --- */ struct Tuple(T...) { T field; alias field this; } template test(T) {} void main() { foreach (r; 0 .. 0) { enum i = r; test!(Tuple!bool[i]); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13225.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S _param_0) => 0)` does not match template declaration `M(T)` fail_compilation/ice13225.d(16): Error: undefined identifier `undefined` --- */ mixin template M(T) {} struct S { mixin M!((typeof(this)) => 0); } struct T { mixin M!(() => undefined); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13311.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/a13311.d(8): Error: undefined identifier `PieceTree` --- */ module ice13311; struct TextPiece { import imports.a13311; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13356.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13356.d(32): Error: template instance `Algebraic!(Tuple!(List))` recursive template expansion fail_compilation/ice13356.d(15): Error: template instance `ice13356.isPrintable!(List)` error instantiating fail_compilation/ice13356.d(33): instantiated from here: `Tuple!(List)` --- */ struct Tuple(Types...) { Types expand; alias expand this; static if (isPrintable!(Types[0])) { } } // T == Tuple!List, and accessing its .init will cause unresolved forward reference enum bool isPrintable(T) = is(typeof({ T t; })); struct Algebraic(AllowedTypesX...) { alias AllowedTypes = AllowedTypesX; double x; // dummy for the syntax Payload(d) } struct List { alias Payload = Algebraic!( Tuple!(List) ); Payload payload; this(double d) { payload = Payload(d); } } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13382.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13382.d(18): Error: incompatible types for `(a) == (0)`: `int[]` and `int` fail_compilation/ice13382.d(19): Error: incompatible types for `(a) >= (0)`: `int[]` and `int` fail_compilation/ice13382.d(20): Error: incompatible types for `(0) == (a)`: `int` and `int[]` fail_compilation/ice13382.d(21): Error: incompatible types for `(0) >= (a)`: `int` and `int[]` fail_compilation/ice13382.d(22): Error: incompatible types for `(a) is (0)`: `int[]` and `int` fail_compilation/ice13382.d(23): Error: incompatible types for `(a) !is (0)`: `int[]` and `int` fail_compilation/ice13382.d(24): Error: incompatible types for `(0) is (a)`: `int` and `int[]` fail_compilation/ice13382.d(25): Error: incompatible types for `(0) !is (a)`: `int` and `int[]` --- */ void main () { int[] a; if (a == 0) {} if (a >= 0) {} if (0 == a) {} if (0 >= a) {} if (a is 0) {} if (a !is 0) {} if (0 is a) {} if (0 !is a) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13385.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13385.d(9): Error: protection attribute `package(a)` does not bind to one of ancestor packages of module `ice13385` --- */ module ice13385; package(a) void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13459.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13459.d(12): Error: undefined identifier `B` fail_compilation/ice13459.d(18): Error: none of the overloads of `opSlice` are callable using argument types `(int, int)`, candidates are: fail_compilation/ice13459.d(11): `ice13459.A.opSlice()` --- */ struct A { auto opSlice() const {} auto opSlice() { return B; } } void main() { auto df = A(); foreach (fi; df[0..0]) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13465a.d ================================================ // REQUIRED_ARGS: -o- // EXTRA_SOURCES: imports/a13465.d /* TEST_OUTPUT: --- fail_compilation/imports/a13465.d(10): Error: cannot infer type from template instance `isMaskField!()` fail_compilation/ice13465a.d(17): Error: template instance `imports.a13465.isMatchingMaskField!()` error instantiating --- */ module ice13465a; import imports.a13465; auto createCheckpointMixins() { enum b = isMatchingMaskField!(); } immutable checkpointMixins = createCheckpointMixins; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13465b.d ================================================ // REQUIRED_ARGS: -o- // EXTRA_SOURCES: imports/b13465.d /* TEST_OUTPUT: --- fail_compilation/imports/b13465.d(10): Error: cannot infer type from template instance `isMaskField!()` fail_compilation/ice13465b.d(17): Error: template instance `imports.b13465.isMatchingMaskField!()` error instantiating --- */ module ice13465b; import imports.b13465; auto createCheckpointMixins() { enum b = isMatchingMaskField!(); } immutable checkpointMixins = createCheckpointMixins; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13563.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13563.d(23): Error: undefined identifier `z` in module `ice13563` --- */ struct Payload { void opIndex(K)(K i) {} void opIndexAssign(T, N)(T value, N i) {} } struct Value { Payload payload; alias payload this; } void main() { Value v; v["name"] = .z(); // ICE //v["name"] = z(); // OK //v.opIndex("name") = .z(); // OK //v.payload["name"] = .z(); // OK } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice1358.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice1358.d(29): Error: invalid UTF character \U80000000 --- */ // https://issues.dlang.org/show_bug.cgi?id=1358 // ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF /* 1358. Assertion failure: '0' on line 1548 in file '..\root\root.c' This one is trivial. PATCH(lexer.c, Lexer::escapeSequence()). --- lexer.c (revision 24) +++ lexer.c (working copy) @@ -1281,8 +1281,10 @@ break; } } - if (ndigits != 2 && !utf_isValidDchar(v)) + if (ndigits != 2 && !utf_isValidDchar(v)) { error("invalid UTF character \\U%08x", v); + v = 0; // prevent ICE + } c = v; } else */ auto bla = "\U80000000"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13644.d ================================================ struct Tuple(T...) { T field; alias field this; } Tuple!(string, string)[] foo() { Tuple!(string, string)[] res; return res; } void main() { foreach (string k2, string v2; foo()) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13788.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13788.d(11): Error: pragma `mangle` string expected for mangled name fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int` fail_compilation/ice13788.d(13): Error: pragma `mangle` zero-length string not allowed for mangled name fail_compilation/ice13788.d(14): Error: pragma `mangle` mangled name characters can only be of type `char` --- */ pragma(mangle) void f1(); pragma(mangle, 1) void f2(); pragma(mangle, "") void f3(); pragma(mangle, "a"w) void f4(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13816.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13816.d(15): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration fail_compilation/ice13816.d(20): Error: template instance `ice13816.ItemProperty!()` error instantiating --- */ alias TypeTuple(T...) = T; template ItemProperty() { static if (true) { alias ItemProperty = TypeTuple!(ItemProperty!()); } } void main() { alias items = ItemProperty!(); enum num = items.length; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13835.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13835.d(15): Error: value of `this` is not known at compile time fail_compilation/ice13835.d(21): Error: template instance `ice13835.Foo!int` error instantiating --- */ class Foo(T) { private T* _data; final private void siftUp(int position) nothrow { static T crash = *(this._data + position); } } void main() { auto heap = new Foo!(int); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13921.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13921.d(13): Error: undefined identifier `undefined_identifier` fail_compilation/ice13921.d(25): Error: template instance `ice13921.S!string` error instantiating --- */ struct S(N) { void fun() { undefined_identifier; // or anything that makes the instantiation fail } } void test(T)(S!T) { } void main() { S!string g; test(g); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice13987.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice13987.d(9): Error: cannot use array to initialize `S` --- */ struct S {} S s = [{}]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14055.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14055.d(16): Error: uninitialized variable `foo` cannot be returned from CTFE --- */ struct S { static returnsFoo() { uint[1] foo = void; return foo; } static enum fooEnum = returnsFoo(); static uint[1] fooArray = fooEnum[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14096.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14096.d(29): Error: cannot access frame pointer of `ice14096.main.Baz!((i) => i).Baz` fail_compilation/ice14096.d(23): Error: template instance `ice14096.foo!(Tuple!(Baz!((i) => i))).foo.bar!(t)` error instantiating fail_compilation/ice14096.d(40): instantiated from here: `foo!(Tuple!(Baz!((i) => i)))` --- */ struct Tuple(Types...) { Types expand; alias expand this; alias field = expand; } Tuple!T tuple(T...)(T args) { return typeof(return)(args); } auto foo(T)(T t) { bar!t(); } auto bar(alias s)() { // default construction is not possible for: Tuple!(Baz!(i => i)) typeof(s) p; } struct Baz(alias f) { void g() {} } void main() { auto t = tuple(Baz!(i => i)()); foo(t); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14116.d ================================================ // EXTRA_SOURCES: imports/a14116.d /* TEST_OUTPUT: --- fail_compilation/imports/a14116.d(3): Error: module `ice14116.ice14116` from file fail_compilation/ice14116.d must be imported with 'import ice14116.ice14116;' --- */ module ice14116.ice14116; void foo() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14130.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` fail_compilation/ice14130.d(14): Error: template `ice14130.foo` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/ice14130.d(10): `ice14130.foo(R, F = Undef)(R r, F s = 0)` --- */ F foo(R, F = Undef)(R r, F s = 0) {} void main() { 0.foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14146.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14146.d(15): Error: constructor `ice14146.Array.this` default constructor for structs only allowed with `@disable`, no body, and no parameters --- */ struct RangeT(A) { A[1] XXXouter; } struct Array { this() { } alias Range = RangeT!Array; bool opEquals(Array) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14177.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/ice14177.d(8): Error: alias `ice14177.Primitive` recursive alias declaration ---- */ alias Primitive = Atom*; alias Atom = Primitive; void main() { Atom atom; atom; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14185.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14185.d(12): Error: cannot implicitly convert expression `this` of type `Mutexed` to `Mutexed*` --- */ struct Mutexed { auto acquire () { return Lock (this); } alias acquire this; struct Lock { Mutexed* source; } } void main () { Mutexed x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14272.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14272.d(11): Error: circular initialization of variable `ice14272.A14272!1.A14272.tag` fail_compilation/ice14272.d(14): Error: template instance `ice14272.A14272!1` error instantiating --- */ struct A14272(int tag) { enum int tag = tag; } alias a14272 = A14272!1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14424.d ================================================ // REQUIRED_ARGS: -o- -unittest /* TEST_OUTPUT: --- fail_compilation/ice14424.d(12): Error: `tuple(__unittest_L3_C1)` has no effect --- */ void main() { import imports.a14424; __traits(getUnitTests, imports.a14424); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14446.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: // EXTRA_SOURCES: extra-files/a14446.d /* TEST_OUTPUT: --- fail_compilation/extra-files/a14446.d(5): Error: module `x14446` from file fail_compilation/ice14446.d must be imported with 'import x14446;' --- */ module x14446; struct CDB {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14621.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14621.d(22): Error: static assert: `false` is false fail_compilation/ice14621.d(28): instantiated from here: `erroneousTemplateInstantiation!()` --- */ void main() { S s; s.foo(); } struct S { float[] array; alias array this; template erroneousTemplateInstantiation() { static assert(false); } void foo() { S ret; ret[] = erroneousTemplateInstantiation!(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14642.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14642.d(47): Error: undefined identifier `errorValue` fail_compilation/ice14642.d(23): Error: template instance `ice14642.X.NA!()` error instantiating --- */ alias TypeTuple(T...) = T; struct X { static struct NA() { X x; void check() { x.func(); } } alias na = NA!(); auto func() { Y* p; p.func(); } } struct Y { mixin Mix; } template Mix() { void func() { auto z = Z(null); } } struct Type(size_t v) {} enum errVal = errorValue; struct Z { Type!errVal v; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14844.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14844.d(20): Error: template `opDispatch(string name)` has no members --- */ struct Typedef { template opDispatch(string name) { static if (true) { } } } void runUnitTestsImpl() { foreach (x; __traits(allMembers, Typedef.opDispatch)) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14907.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14907.d(14): Error: struct `ice14907.S(int v = S)` recursive template expansion fail_compilation/ice14907.d(19): while looking for match for `S!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(21): Error: template `ice14907.f` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/ice14907.d(15): `ice14907.f(int v = f)()` --- */ struct S(int v = S) {} void f(int v = f)() {} void main() { S!() s; // OK <- ICE f!()(); // OK <- ICE f(); // OK <- ICE } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14923.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` fail_compilation/ice14923.d(22): instantiated from here: `bar!((b) => parse(b))` --- */ auto bar(alias fun)() { size_t counter; scope(exit) counter++; Object a2; if (auto ai = cast(A)a2) return fun(ai); if (auto ai = cast(B)a2) return fun(ai); } void parse(C a) { bar!(b => parse(b))(); } class A {} class C {} class B : C {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice14929.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice14929.d(45): Error: `cast(Node)(*this.current).items[this.index]` is not an lvalue and cannot be modified fail_compilation/ice14929.d(88): Error: template instance `ice14929.HashMap!(ulong, int).HashMap.opBinaryRight!"in"` error instantiating fail_compilation/ice14929.d(92): instantiated from here: `HashmapComponentStorage!int` fail_compilation/ice14929.d(92): Error: template instance `ice14929.isComponentStorage!(HashmapComponentStorage!int, int)` error instantiating fail_compilation/ice14929.d(92): while evaluating: `static assert(isComponentStorage!(HashmapComponentStorage!int, int))` --- */ struct HashMap(K, V) { V* opBinaryRight(string op)(K key) const if (op == "in") { size_t index; foreach (ref node; buckets[index].range) { return &(node.value); } return null; } struct Node { K key; V value; } alias Bucket = UnrolledList!(Node); Bucket[] buckets; } struct UnrolledList(T) { Range range() const pure { return Range(_front); } static struct Range { ref T front() const @property { return cast(T) current.items[index]; } void popFront() pure { } bool empty() const pure @property { return true; } const(Node)* current; size_t index; } Node* _front; static struct Node { ContainerStorageType!T[10] items; } } template ContainerStorageType(T) { alias ContainerStorageType = T; } template isComponentStorage(CS, C) { enum bool isComponentStorage = is(typeof( (inout int = 0) { CS cs = CS.init; ulong eid; cs.add(eid, C.init); })); } struct HashmapComponentStorage(ComponentType) { private HashMap!(ulong, ComponentType) components; void add(ulong eid, ComponentType component) { assert(eid !in components); } } static assert(isComponentStorage!(HashmapComponentStorage!int, int)); void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15002.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15002.d(10): Error: array index 5 is out of bounds `x[0 .. 3]` fail_compilation/ice15002.d(10): Error: array index 5 is out of bounds `x[0 .. 3]` --- */ int[][3] x = []; int* p = &x[5][0]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15092.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15092.d(13): Error: struct `ice15092.A.S` conflicts with struct `ice15092.A.S` at fail_compilation/ice15092.d(12) fail_compilation/ice15092.d(16): Error: class `ice15092.A.C` conflicts with class `ice15092.A.C` at fail_compilation/ice15092.d(15) fail_compilation/ice15092.d(19): Error: interface `ice15092.A.I` conflicts with interface `ice15092.A.I` at fail_compilation/ice15092.d(18) --- */ class A { struct S {} struct S {} class C {} class C {} interface I {} interface I {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15127.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15127.d(17): Error: basic type expected, not `struct` fail_compilation/ice15127.d(17): Error: identifier expected for template value parameter fail_compilation/ice15127.d(17): Error: found `struct` when expecting `)` fail_compilation/ice15127.d(17): Error: found `ExampleStruct` when expecting `=` fail_compilation/ice15127.d(17): Error: semicolon expected following auto declaration, not `)` fail_compilation/ice15127.d(17): Error: declaration expected, not `)` --- */ struct ExampleStruct(S) { } template ExampleTemplate(K) { enum ExampleTemplate(struct ExampleStruct(K)) = K; } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15172.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15172.d(14): Error: constructor `ice15172.ThreadError.this` no match for implicit `super()` call in constructor --- */ // 1. ClassDeclaration.semantic class ThreadError : Error { // 2. FuncDeclaration.semantic // 4. FuncDeclaration.semantic3 // --> error happens this(string) { } } // 3. FuncDeclaration.semantic // 5. FuncDeclaration.semantic3 void onThreadError() { // 6. NewExp.semantic // --> cd.members.errors == false, cd.members.semantic3Errors == true // BUT, The ThreadError class constructor is not a template function, so // the errors inside its function body won't be associated with the validness of this NewExp. // Therefore, converting the semantic3Error to ErrorExp is not correct. // 7. ctfeInterpret // Finally, FuncDeclaration::interpret may encounter a function which is semantic3Errors == true. So // 7a. functionSemantic3() should return false if semantic3Errors is true. // 7b. the function body errors may not happen during ctfeInterpret call and global.errors could be unincremented. __gshared auto ThreadError = new ThreadError(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15239.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15239.d(21): Error: cannot interpret `opDispatch!"foo"` at compile time fail_compilation/ice15239.d(21): Error: bad type/size of operands `__error` --- */ struct T { template opDispatch(string Name, P...) { static void opDispatch(P) {} } } void main() { version(GNU) { asm { "" : : "r" T.foo; } } else { asm { call T.foo; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15317.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/ice15317.d(11): Error: undefined identifier `fun` --- */ void main() { alias f = fun; auto x1 = &f; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15332.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15332.d(16): Error: need `this` for `fun` of type `int()` fail_compilation/ice15332.d(17): Error: need `this` for `var` of type `int` --- */ class C { int fun() { return 5; } int var; void test() { int a1 = function() { return fun; }(); int a2 = function() { return var; }(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15441.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15441.d(24): Error: variable `ice15441.main.__front3` type `void` is inferred from initializer `__r2.front()`, and variables cannot be of type `void` fail_compilation/ice15441.d(24): Error: expression `__r2.front()` is `void` and has no value fail_compilation/ice15441.d(24): Error: `s1.front` is `void` and has no value fail_compilation/ice15441.d(27): Error: cannot infer argument types, expected 1 argument, not 2 --- */ struct S1 { auto front()() {} } struct S2 { auto front()() { return 1; } } void main() { S1 s1; foreach (p, e; s1) {} S2 s2; foreach (p, e; s2) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15688.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: --- fail_compilation/ice15688.d(12): Error: undefined identifier `mappings` fail_compilation/ice15688.d(12): Error: function expected before `()`, not `0` of type `int` --- */ void main() { (mappings, 0)(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15788.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15788.d(17): Error: none of the overloads of `iota` are callable using argument types `!()(S, S)` --- */ import imports.range15788 : iota; void iota() {} struct S {} void main() { S s; iota(s, s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15816.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/a15816.d(3): Error: anonymous classes not allowed --- */ class A { import imports.a15816; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15855.d ================================================ // REQUIRED_ARGS: -o- a[{for ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice15922.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice15922.d(23): Error: function `ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false.correctedInsert` has no `return` statement, but is expected to return a value of type `int` fail_compilation/ice15922.d(21): Error: template instance `ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false` error instantiating fail_compilation/ice15922.d(26): instantiated from here: `ValidSparseDataStore!int` fail_compilation/ice15922.d(14): Error: need `this` for `insert` of type `pure nothrow @nogc @safe int()` fail_compilation/ice15922.d(26): Error: template instance `ice15922.StorageAttributes!(ValidSparseDataStore!int)` error instantiating --- */ template StorageAttributes(Store) { enum hasInsertMethod = Store.insert; enum hasFullSlice = Store.init[]; } struct ValidSparseDataStore(DataT) { DataT insert() { correctedInsert!(false); } DataT correctedInsert(bool CorrectParents)() {} auto opSlice() inout {} } alias BasicCubeT = StorageAttributes!(ValidSparseDataStore!int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice16035.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice16035.d(18): Error: forward reference to inferred return type of function call `this.a[0].toString()` fail_compilation/ice16035.d(13): Error: template instance `ice16035.Value.get!string` error instantiating --- */ struct Value { auto toString() inout { get!string; } T get(T)() { a[0].toString(); } const(Value)* a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice17074.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice17074.d(9): Error: identifier expected for C++ namespace fail_compilation/ice17074.d(9): Error: found `cast` when expecting `)` fail_compilation/ice17074.d(9): Error: declaration expected, not `)` --- */ extern(C++, cast) void ice_keyword(); /* TEST_OUTPUT: --- fail_compilation/ice17074.d(19): Error: identifier expected for C++ namespace fail_compilation/ice17074.d(19): Error: found `__overloadset` when expecting `)` fail_compilation/ice17074.d(19): Error: declaration expected, not `)` --- */ extern(C++, std.__overloadset) void ice_std_keyword(); /* TEST_OUTPUT: --- fail_compilation/ice17074.d(29): Error: identifier expected for C++ namespace fail_compilation/ice17074.d(29): Error: found `...` when expecting `)` fail_compilation/ice17074.d(29): Error: declaration expected, not `)` --- */ extern(C++, ...) void ice_token(); /* TEST_OUTPUT: --- fail_compilation/ice17074.d(39): Error: identifier expected for C++ namespace fail_compilation/ice17074.d(39): Error: found `*` when expecting `)` fail_compilation/ice17074.d(39): Error: declaration expected, not `)` --- */ extern(C++, std.*) void ice_std_token(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice17690.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice17690.d(9): Error: undefined identifier `x` --- */ void main(){ scope(exit) int x=3; assert(x==3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice17831.d ================================================ // REQUIRED_ARGS: -d /* TEST_OUTPUT: --- fail_compilation/ice17831.d(19): Error: `case` variable `i` declared at fail_compilation/ice17831.d(17) cannot be declared in `switch` body fail_compilation/ice17831.d(33): Error: `case` variable `i` declared at fail_compilation/ice17831.d(31) cannot be declared in `switch` body fail_compilation/ice17831.d(48): Error: `case` variable `i` declared at fail_compilation/ice17831.d(45) cannot be declared in `switch` body fail_compilation/ice17831.d(61): Error: `case` variable `i` declared at fail_compilation/ice17831.d(60) cannot be declared in `switch` body fail_compilation/ice17831.d(73): Error: `case` variable `i` declared at fail_compilation/ice17831.d(72) cannot be declared in `switch` body --- */ void test17831a() { switch (0) { foreach (i; 0 .. 5) { case i: break; } default: break; } } void test17831b() { switch (0) { for (int i = 0; i < 5; i++) { case i: break; } default: break; } } void test17831c() { switch (0) { int i = 0; while (i++ < 5) { case i: break; } default: break; } } void test17831d() { switch (0) { int i = 0; case i: break; default: break; } } void test17831e() { switch (0) { static int i = 0; case i: break; default: break; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice18469.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice18469.d(10): Error: no property `opCall` for type `void` --- */ class Bar { ~this(){} this(){alias T = typeof(Bar.__dtor.opCall);} } void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice18753.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void` fail_compilation/ice18753.d(23): Error: template instance `ice18753.isInputRange!(Group)` error instantiating fail_compilation/ice18753.d(18): instantiated from here: `isForwardRange!(Group)` fail_compilation/ice18753.d(18): while evaluating: `static assert(isForwardRange!(Group))` --- */ // https://issues.dlang.org/show_bug.cgi?id=18753 struct ChunkByImpl { struct Group { } static assert(isForwardRange!Group); } enum isInputRange(R) = ReturnType; enum isForwardRange(R) = isInputRange!R is ReturnType!(() => r); template ReturnType(func...) { static if (is(FunctionTypeOf!func R == return)) ReturnType R; } template FunctionTypeOf(func...) { static if (is(typeof(func[0]) T)) static if (is(T Fptr ) ) alias FunctionTypeOf = Fptr; } template Select() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice18803a.d ================================================ void main() { import ice18803b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice18803b.d ================================================ static if ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice2843.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice2843.d(22): Error: incompatible types for `(1) is (typeid(int))`: `int` and `object.TypeInfo` --- */ // https://issues.dlang.org/show_bug.cgi?id=2843 // ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid expression /* 2843 Assertion failure: '0' on line 863 in file 'constfold.c' PATCH: constfold.c, line 861: OLD: }else assert(0); NEW: }else if (e1->isConst() && e2->isConst()) { // Comparing a SymExp with a literal, eg typeid(int) is 7.1; cmp=0; // An error has already occurred. Prevent an ICE. }else assert(0); */ bool b = 1 is typeid(int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice4094.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice4094.d(11): Error: circular reference to variable `ice4094.Zug!0.Zug.bahn` fail_compilation/ice4094.d(19): Error: template instance `ice4094.Zug!0` error instantiating --- */ // REQUIRED_ARGS: -d struct Zug(int Z) { const bahn = Bug4094!(0).hof.bahn; } struct Bug4094(int Q) { Zug!(0) hof; } const a = Zug!(0).bahn; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice4983.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice4983.d(14): Error: circular reference to `ice4983.Foo.dg` --- */ struct Foo { void bar() { } void delegate() dg = &Foo.init.bar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice5996.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice5996.d(8): Error: undefined identifier `anyOldGarbage` --- */ auto bug5996() { if (anyOldGarbage) {} return 2; } enum uint h5996 = bug5996(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice6538.d ================================================ /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=9361 /* TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: expression `super` is not a valid template value argument fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` cannot deduce function from argument types `!()()`, candidates are: fail_compilation/ice6538.d(23): `ice6538.D.foo()() if (Sym!(super))` --- */ template Sym(alias A) { enum Sym = true; } class C {} class D : C { void foo()() if (Sym!(super)) {} } void test9361b() { auto d = new D(); d.foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice7645.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice7645.d(28): Error: need `this` for `t` of type `char` fail_compilation/ice7645.d(31): Error: need `this` for `fn` of type `pure nothrow @nogc @safe void()` --- */ class C { class C2() { char t; } } struct S { struct S2(T) { void fn() {} } } void main() { C c; auto v = c.C2!().t; S s; s.S2!int.fn(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice7782.d ================================================ import imports.ice7782algorithm; import imports.ice7782range. imports.ice7782math; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8100.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8100.d(10): Error: no property `Q` for type `ice8100.Bar!bool` fail_compilation/ice8100.d(11): Error: template instance `ice8100.Foo!(Bar!bool)` error instantiating fail_compilation/ice8100.d(12): instantiated from here: `Bar!bool` --- */ class Foo(T1) { T1.Q r; } class Bar(T2) : Foo!(Bar!T2) {} Bar!bool b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8255.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8255.d(11): Error: function `ice8255.F!(G).F.f(ref G _param_0)` is not callable using argument types `(G)` fail_compilation/ice8255.d(11): cannot pass rvalue argument `G()` of type `G` to parameter `ref G _param_0` fail_compilation/ice8255.d(11): while evaluating `pragma(msg, F().f(G()))` --- */ struct G {} struct F(T) { void f(ref T) {} } pragma(msg, F!G().f(G.init)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8309.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8309.d(10): Error: incompatible types for `(__lambda1) : (__lambda2)`: `double function() pure nothrow @nogc @safe` and `int function() pure nothrow @nogc @safe` --- */ void main() { auto x = [()=>1.0, ()=>1]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8499.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8499.d(18): Error: undefined identifier `i` --- */ struct Variant { @property T get(T)() { struct X {} // necessary } } void main() { (Variant()).get!(typeof(() => i)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8511.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8511.d(11): Error: enum `ice8511.hypot.SQRTMAX` is forward referenced looking for base type fail_compilation/ice8511.d(12): Error: incompatible types for `(SQRTMAX) / (2)`: cannot use `/` with types --- */ real hypot() { enum SQRTMAX; SQRTMAX/2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8604.d ================================================ struct StructFoo { static if(i) { } else enum z = ""; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8630.d ================================================ auto map(alias func, R)(R r) { return r; } typeof(v) foo(R)(R v) { return map!(p=>p)(v); } void main() { foo([1]); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8711.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8711.d(8): Error: cannot use array to initialize `int function(int)` --- */ int function(int) foos = [x => 0]; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8742.d ================================================ // PERMUTE_ARGS: class C { class D { } } void main ( ) { auto c = new C; auto d = c.new class C.D { }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8795.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `(` fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `End of File` fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `)` fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` instead of statement fail_compilation/ice8795.d-mixin-15(15): Error: { } expected following `interface` declaration fail_compilation/ice8795.d-mixin-15(15): Error: anonymous interfaces not allowed --- */ void main() { mixin("switch"); mixin("interface;"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice8795b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice8795b.d-mixin-8(8): Error: { } expected following `interface` declaration fail_compilation/ice8795b.d-mixin-8(8): Error: anonymous interfaces not allowed --- */ mixin("interface;"); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9013.d ================================================ void main() { foreach (i; 0 .. missing) int[] foo = cast(int[])[i]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9254a.d ================================================ void main() { foreach (divisor; !(2, 3, 4, 8, 7, 9)) { // ice in ForeachRangeStatement::blockExit() foreach (v; 0..uint.max) {} // ice in WhileStatement::blockExit() while (1) {} } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9254b.d ================================================ class C { synchronized void foo() { foreach(divisor; !(2, 3, 4, 8, 7, 9)) { // ice in ForeachRangeStatement::usesEH() foreach (v; 0..uint.max) {} // ice in WhileStatement::usesEH() while (1) {} } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9254c.d ================================================ void main() { foreach(divisor; !(2, 3, 4, 8, 7, 9)) { assert(0); // ice in ForeachRangeStatement::comeFrom() foreach (v; 0..uint.max) {} // ice in WhileStatement::comeFrom() while (1) {} } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9273a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9273a.d(19): Error: constructor `ice9273a.C.__ctor!().this` no match for implicit `super()` call in constructor fail_compilation/ice9273a.d(23): Error: template instance `ice9273a.C.__ctor!()` error instantiating --- */ template CtorMixin() { this(T)() {} } class B { mixin CtorMixin!(); } class C : B { this()() {} } void main() { auto c = new C(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9273b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9273b.d(14): Error: constructor `ice9273b.B.this` no match for implicit `super()` call in constructor --- */ class A { this(T)() {} } class B : A { this() {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9284.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` cannot deduce function from argument types `!()(int)`, candidates are: fail_compilation/ice9284.d(12): `ice9284.C.__ctor()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- */ class C { this()(string) { this(10); // delegating to a constructor which not exists. } } void main() { new C("hello"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9291.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9291.d(10): Error: undefined identifier `F` --- */ void main() nothrow { throw new F(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9338.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9338.d(13): Error: value of `this` is not known at compile time fail_compilation/ice9338.d(14): Error: value of `this` is not known at compile time --- */ class Foo { void test() { enum members1 = makeArray(); enum members2 = this.makeArray(); } string[] makeArray() { return ["a"]; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9406.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9406.d(21): Error: expression has no value --- */ mixin template Mixin() { } struct S { template t1() { mixin Mixin t1; } } void main() { S s1; s1.t1!(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9439.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9439.d(12): Error: `this` for `foo` needs to be type `Derived` not type `ice9439.Base` fail_compilation/ice9439.d(12): while evaluating: `static assert((__error).foo())` fail_compilation/ice9439.d(19): Error: template instance `ice9439.Base.boo!(foo)` error instantiating --- */ class Base { void boo(alias F)() { static assert(F()); } } class Derived : Base { int foo() { return 1; } void bug() { boo!(foo)(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9494.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9494.d(10): Error: circular reference to variable `ice9494.test` fail_compilation/ice9494.d(14): Error: circular reference to variable `ice9494.Foo.test` fail_compilation/ice9494.d(19): Error: circular reference to variable `ice9494.Bar.test` --- */ int[test] test; // stack overflow class Foo { int[this.test] test; // stack overflow } struct Bar { int[this.test] test; // stack overflow } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9540.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9540.d(34): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int _param_0)` is not callable using argument types `()` fail_compilation/ice9540.d(25): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating --- */ template Tuple(E...) { alias E Tuple; } alias Tuple!(int) Args; void main() { (new A).test (); } void test1 (int delegate (int) f) { f (-2); } class A { int f (int a) { return a; } void test () { test1 (&AddFront!(this, f)); } } template AddFront (alias ctx, alias fun) { auto AddFront(Args args) { auto dg (Args dgArgs) { return fun (dgArgs); } dg.ptr = ctx; return dg(args); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9545.d ================================================ // REQUIRED_ARGS: -o- /* TEST_OUTPUT: ---- fail_compilation/ice9545.d(13): Error: type `int` has no value ---- */ struct S { template T(X) { alias T = X; } } void main() { auto x1 = S.init.T!int; // ICE } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9759.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9759.d(25): Error: mutable method `ice9759.Json.opAssign` is not callable using a `const` object fail_compilation/ice9759.d(25): Consider adding `const` or `inout` to ice9759.Json.opAssign --- */ struct Json { union { Json[] m_array; Json[string] m_object; } void opAssign(Json v) { } } void bug() { const(Json) r; r = r.init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9806.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9806.d(12): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(17): Error: template instance `ice9806.S1!()` error instantiating fail_compilation/ice9806.d(13): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(19): Error: template instance `ice9806.C1!()` error instantiating fail_compilation/ice9806.d(14): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(21): Error: template instance `ice9806.I1!()` error instantiating --- */ struct S1() { enum x = undefined_expr; } class C1() { enum x = undefined_expr; } class I1() { enum x = undefined_expr; } void test1() { static assert(!is(typeof(S1!().x))); auto sx = S1!().x; static assert(!is(typeof(C1!().x))); auto cx = C1!().x; static assert(!is(typeof(I1!().x))); auto ix = I1!().x; } // -------- /* TEST_OUTPUT: --- fail_compilation/ice9806.d(36): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(44): Error: template instance `ice9806.S2!()` error instantiating fail_compilation/ice9806.d(37): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(46): Error: template instance `ice9806.C2!()` error instantiating fail_compilation/ice9806.d(38): Error: undefined identifier `undefined_expr` fail_compilation/ice9806.d(48): Error: template instance `ice9806.I2!()` error instantiating --- */ int foo2()() { return undefined_expr; } int bar2()() { return undefined_expr; } int baz2()() { return undefined_expr; } struct S2() { enum x = foo2(); } class C2() { enum x = bar2(); } class I2() { enum x = baz2(); } void test2() { static assert(!is(typeof(S2!().x))); auto sx = S2!().x; static assert(!is(typeof(C2!().x))); auto cx = C2!().x; static assert(!is(typeof(I2!().x))); auto ix = I2!().x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/ice9865.d ================================================ /* TEST_OUTPUT: --- fail_compilation/ice9865.d(8): Error: alias `ice9865.Baz` recursive alias declaration --- */ public import imports.ice9865b : Baz; struct Foo { Baz f; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/impconv.d ================================================ /* FIXME: DMD host compilers < 2.073 with faulty optimization lead to unfortunate test failures, see https://github.com/dlang/dmd/pull/6831#issuecomment-304495842. DISABLED: win32 win64 linux osx freebsd */ /* TEST_OUTPUT: --- fail_compilation/impconv.d(30): Error: function `impconv.foo_float(float)` is not callable using argument types `(int)` fail_compilation/impconv.d(30): cannot pass argument `-2147483647` of type `int` to parameter `float` fail_compilation/impconv.d(31): Error: function `impconv.foo_float(float)` is not callable using argument types `(uint)` fail_compilation/impconv.d(31): cannot pass argument `4294967295u` of type `uint` to parameter `float` fail_compilation/impconv.d(34): Error: function `impconv.foo_double(double)` is not callable using argument types `(long)` fail_compilation/impconv.d(34): cannot pass argument `-9223372036854775807L` of type `long` to parameter `double` fail_compilation/impconv.d(35): Error: function `impconv.foo_double(double)` is not callable using argument types `(ulong)` fail_compilation/impconv.d(35): cannot pass argument `18446744073709551615LU` of type `ulong` to parameter `double` --- */ void foo_float(float); void foo_double(double); void foo_real(real); void main() { foo_float(1); // implicitly convertible to float foo_float(-int.max); // -(2^31 - 1) foo_float(uint.max); // 2^32 - 1 foo_double(int.max); // implicitly convertible to double foo_double(-long.max); // -(2^63 - 1) foo_double(ulong.max); // 2^64 - 1 foo_real(0xffff_ffff_ffffL); // 2^48 - 1, implicitly convertible to real static assert(__traits(compiles, foo_real(-long.max)) == (real.mant_dig >= 63)); static assert(__traits(compiles, foo_real(ulong.max)) == (real.mant_dig >= 64)); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imphint.d ================================================ /* PERMUTE_ARGS: --- fail_compilation/imphint.d(14): Error: 'printf' is not defined, perhaps you need to import core.stdc.stdio; ? fail_compilation/imphint.d(15): Error: 'writeln' is not defined, perhaps you need to import std.stdio; ? fail_compilation/imphint.d(16): Error: 'sin' is not defined, perhaps you need to import std.math; ? fail_compilation/imphint.d(17): Error: 'cos' is not defined, perhaps you need to import std.math; ? fail_compilation/imphint.d(18): Error: 'sqrt' is not defined, perhaps you need to import std.math; ? fail_compilation/imphint.d(19): Error: 'fabs' is not defined, perhaps you need to import std.math; ? --- */ void foo() { printf("hello world\n"); writeln("hello world\n"); sin(3.6); cos(1.2); sqrt(2.0); fabs(-3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a10169.d ================================================ module imports.a10169; struct B { private int x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d ================================================ private enum string a = "asdfgh"; private enum { b = "asdfgh" } struct S { private enum string c = "qwerty"; } class C { private enum string d = "qwerty"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d ================================================ //import std.array, std.range; module imports.a11850; template filter(alias pred) { auto filter(Range)(Range rs) { return FilterResult!(pred, Range)(rs); } } private struct FilterResult(alias pred, Range) { alias Range R; R _input; this(R r) { _input = r; while (_input.length != 0 && !pred(_input[0])) { _input = _input[1..$]; } } auto opSlice() { return this; } @property bool empty() { return _input.length == 0; } void popFront() { do { _input = _input[1..$]; } while (_input.length != 0 && !pred(_input[0])); } @property auto ref front() { return _input[0]; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a11919.d ================================================ void doBar(T)(T t) { static if (t.tupleof.length) if (zoo!t.length == 0) {} static if (is(T B == super) && is(B[0] == class) && is(B[]) ) { B[0] b = t; doBar(b); } } template zoo(alias t) { enum zoo = __traits(getAttributes, t.tupleof); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a13131checkpoint.d ================================================ module imports.a13131checkpoint; mixin(createGlobalsMixins); // [3] mixin auto createGlobalsMixins() // [4] semantic3 { pragma(msg, "+A"); enum fullModuleName = "imports.a13131parameters"; // necessary mixin("import "~fullModuleName~";"); foreach (e ; __traits(derivedMembers, mixin(fullModuleName))) { // [5] see imports.parameters (it's listed in command line) static if ( __traits(compiles, mixin(`__traits(getAttributes, `~fullModuleName~`.`~e~`)`))) {} } pragma(msg, "-A"); return ""; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a13131elec.d ================================================ module imports.a13131elec; import imports.a13131checkpoint; // [2] import void initElec(T)(T L) { immutable cv = econn.velocities; // econn is invalid so generates ErrorExp } alias econn = elecConnOf!gconn; // invalid declaration ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a13131parameters.d ================================================ module imports.a13131parameters; auto createParameterMixins() // auto is necessary to invoke semantic3 to calculate full signature { pragma(msg, "+B"); enum fullModuleName = "imports.a13131elec"; // necessary mixin("import "~fullModuleName~";"); foreach (e ; __traits(derivedMembers, mixin(fullModuleName))) { // will access yet-not semantic analyzed invalid symbol 'econn' in imports.elec static if ( __traits(compiles, mixin(`__traits(getAttributes, `~fullModuleName~`.`~e~`)`))) {} } pragma(msg, "-B"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a13311.d ================================================ module imports.a13311; import ice13311; class Z { TextPiece piece; this(PieceTree owner) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a13465.d ================================================ module imports.a13465; template isMaskField() { import imports.a13465; } template isMatchingMaskField() { enum isMatchingMaskField = isMaskField!(); /* Semantic analysis journey came from isMatchingMaskField!() * * TemplateInstance('isMaskField!T')->semantic() * TemplateInstance('isMaskField!T')->semantic2() <--- * TemplateInstance::semantic() will run its semantic2() always. * Import('import imports.ice1365a;')->semantic2() * Module('imports.ice1365a')->semantic2() * VarDeclaration('imports.ice1365a.isMatchingMaskField!().isMatchingMaskField')->semantic2() <--- * The type field is yet NULL during type inference, then ICE happens. */ } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a14116.d ================================================ module ice14116.a14116; import ice14116; void main() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d ================================================ module imports.a14235; struct SomeThing(T...) { } class SomeClass {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d ================================================ module imports.a14407; deprecated class C { private deprecated new (size_t, string) { return null; } private this(int) {} } deprecated struct S { private deprecated new (size_t, string) { return null; } private this(int) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a14424.d ================================================ module imports.a14424; unittest { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a15667.d ================================================ module imports.a15667; template staticIndexOf(T) { enum staticIndexOf = genericIndexOf!T; } template genericIndexOf(args...) { alias e = args; alias tuple = args; alias tail = tuple; enum next = genericIndexOf!(e, tail); } alias X = ; static if (staticIndexOf!X) ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a15816.d ================================================ module imports.a15816; class { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a17625.d ================================================ module a17625; private int boo() { return 69; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a17630.d ================================================ module a17630; import b17630; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a18219.d ================================================ module a18219; struct AST { import b18219; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a18243.d ================================================ module a18243; import std.math : isNaN; public bool isNaN() { return false; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a313.d ================================================ module imports.a313; private import imports.b313; private static import imports.b313; private static import b313 = imports.b313; private import imports.pkg313; private import core.stdc.stdio; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/a314.d ================================================ module imports.a314; static import imports.c314; import renamed = imports.c314; import imports.c314 : bug; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b13465.d ================================================ module imports.b13465; template isMaskField() { import imports.b13465; } template isMatchingMaskField() { enum isMatchingMaskField = { enum n = isMaskField!(); return n; }(); /* Semantic analysis journey came from isMatchingMaskField!() * * TemplateInstance('isMaskField!T')->semantic() * TemplateInstance('isMaskField!T')->semantic2() <--- * TemplateInstance::semantic() should run its semantic2() in function body. * Import('import imports.ice1365a;')->semantic2() * Module('imports.ice1365a')->semantic2() * VarDeclaration('imports.ice1365a.isMatchingMaskField!().isMatchingMaskField')->semantic2() <--- * Cannot avoid this visiting, so we need to add a fix in VarDeclaration::semantic2(). */ } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b17625.d ================================================ module b17625; private int boo() { return 45; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b17630.d ================================================ module b17630; int Erase; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b17918a.d ================================================ module imports.b17918a; class Base { auto byNode() { return _listMap; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b18219.d ================================================ module b18219; class Foobar { int a; this(int a) { this.a = a; } static int smeth() { return 1; } } void fun() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b313.d ================================================ module imports.b313; void bug() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/b314.d ================================================ module imports.b314; package import renamedpkg = imports.c314; package import imports.c314 : bugpkg=bug; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/bar11136.d ================================================ module ice11136.bar11136; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/c314.d ================================================ module imports.c314; void bug(string s) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag10089a.d ================================================ module imports.diag10089a; struct chunks { this(size_t size) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag10089b.d ================================================ module imports.diag10089b; void chunks(Source)(Source source, size_t chunkSize) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag10141a.d ================================================ module imports.diag10141a; import imports.diag10141b; string format() { auto w = Appender!string(); char[] digits = ['0']; put(w, digits); return null; } template Tuple(Specs...) { struct Tuple { Specs expand; enum x = format(); // in injectNameFields() } } private template Identity(alias T) { alias T Identity; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d ================================================ module imports.diag10141b; template isSomeChar(T) { enum isSomeChar = is(immutable T == immutable char) || is(immutable T == immutable wchar) || is(immutable T == immutable dchar); } struct Appender(A : T[], T) { private template canPutItem(U) { enum bool canPutItem = //isImplicitlyConvertible!(U, T) || isSomeChar!T && isSomeChar!U; } private template canPutRange(Range) { enum bool canPutRange = //isInputRange!Range && is(typeof(Appender.init.put("a"d[0]))); } /** * Appends one item to the managed array. */ void put(U)(U item) if (canPutItem!U) { char[T.sizeof == 1 ? 4 : 2] encoded; auto len = 1; put(encoded[0 .. len]); // ! } /** * Appends an entire range to the managed array. */ void put(Range)(Range items) if (canPutRange!Range) { } } void put(R, E)(ref R r, E e) { static if (is(typeof(r.put(e)))) { r.put(e); } else { static assert(false, "Cannot put a "~E.stringof~" into a "~R.stringof); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag12598a.d ================================================ module imports.diag12598a; struct lines { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag9210b.d ================================================ module imports.diag9210b; import imports.diag9210c; import imports.diag9210stdcomplex; interface B : A {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag9210c.d ================================================ module imports.diag9210c; import diag9210a; interface C : A {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d ================================================ module imports.diag9210stdcomplex; import imports.diag9210stdtraits; struct Complex(T) if (isFloatingPoint!T) { T re; T im; } // https://issues.dlang.org/show_bug.cgi?id=9210: Complex!real instantiation is incomplete in here, // because its completion is deferred by an "undefined identifier" error in imports.diag9210b. Complex!real expi(real y) { return Complex!real(0, 0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdtraits.d ================================================ module imports.diag9210stdtraits; template FloatingPointTypeOf(T)// if (!is(T == enum)) { inout( float) idx( inout( float) ); inout(double) idx( inout(double) ); inout( real) idx( inout( real) ); shared(inout float) idx( shared(inout float) ); shared(inout double) idx( shared(inout double) ); shared(inout real) idx( shared(inout real) ); immutable( float) idy( immutable( float) ); immutable(double) idy( immutable(double) ); immutable( real) idy( immutable( real) ); static if (is(typeof(idx(T.init)) X)) { alias X FloatingPointTypeOf; } else static if (is(typeof(idy(T.init)) X)) { alias X FloatingPointTypeOf; } else { static assert(0, T.stringof~" is not a floating point type"); } } template isFloatingPoint(T) { enum bool isFloatingPoint = is(FloatingPointTypeOf!T); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/dip22a.d ================================================ module imports.dip22a; class Klass { private void bar() {} } struct Struct { private void bar() {} } private void bar() {} template Template(T) { private void bar() {} } private void bar(int) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/dip22b.d ================================================ module imports.dip22b; // this public import only exports symbols that are visible within this module public import imports.dip22c; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/dip22c.d ================================================ module pkg.dip22c; package(pkg) struct Foo {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/dip22d.d ================================================ module imports.dip22d; private struct Foo {} private void foo() {} private void bar() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/dip22e.d ================================================ module imports.dip22e; public struct Foo {} public void bar(int) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail10277.d ================================================ module imports.fail10277; class TypeInfo { } class TypeInfo_Class { } class TypeInfo_Interface { } class TypeInfo_Struct { } class TypeInfo_Typedef { } class TypeInfo_Pointer { } class TypeInfo_Array { } class TypeInfo_AssociativeArray { } class TypeInfo_Enum { } class TypeInfo_Function { } class TypeInfo_Delegate { } class TypeInfo_Tuple { } class TypeInfo_Const { } class TypeInfo_Invariant { } class TypeInfo_Shared { } class TypeInfo_Inout { } class TypeInfo_Vector { } class Object { } class Throwable { } class Exception { } class Error { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail17646.d ================================================ module imports.fail17646; struct TestData { } const(TestData)[] allTestData(MOD_STRINGS...)() { foreach (i; MOD_STRINGS) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail1900a.d ================================================ module imports.fail1900a; template Bar(int n) { enum Bar = n; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail1900b.d ================================================ module imports.fail1900b; template Bar(short n) { enum Bar = n; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail2962a.d ================================================ import fail2962; // comment 4 int foo4() { return bar4(0); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail320a.d ================================================ void foo(int) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail320b.d ================================================ void foo(T)(){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail347a.d ================================================ module imports.fail347a; pure size_t strlen(in char* s); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail355.d ================================================ module imports.fail355; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail356.d ================================================ module imports.fail356; int bar; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail4479.d ================================================ module imports.fail4479mod; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/fail5385.d ================================================ module imports.fail5385; class C { static private int privX; static package int packX; __gshared private int privX2; __gshared package int packX2; } struct S { static private int privX; static package int packX; __gshared private int privX2; __gshared package int packX2; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/foo10727a.d ================================================ struct CirBuff(T) { import imports.stdtraits10727 : isArray; CirBuff!T opAssign(R)(R) if (isArray!R) {} struct Range(U, S) { Range!(U, S) save() { return U; } } T[] toArray() { T[] ret = new T[this.length]; return ret; } alias toArray this; Range!(T, T) range() {} } class Bar(T = int) { CirBuff!T _bar; } class Once { Bar!Foo _foobar; } class Foo : Frop {} // Frop is not defined ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/foo10727b.d ================================================ struct CirBuff(T) { import imports.stdtraits10727 : isArray; CirBuff!T opAssign(R)(R) if (isArray!R) {} T[] toArray() { T[] ret = new T[this.length]; return ret; } alias toArray this; } class Bar(T = int) { CirBuff!T _bar; } class Once { Bar!Foo _foobar; } class Foo : Frop {} // Frop is not defined ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice10600a.d ================================================ module imports.ice10600a; struct Appender(A : T[], T) { this(T[]) {} } Appender!(E[]) appender(A : E[], E)() { return Appender!(E[])(null); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice10600b.d ================================================ module imports.ice10600b; import imports.ice10600a; template to(T) { T to(A...)(A args) { return toImpl!T(args); } } T toImpl(T, S)(S value) if (is(S : T)) { return value; } T toImpl(T, S)(S value) if (!is(S : T) && is(T == string)) { auto w = appender!T(); //Appender!T w; return null; } T toImpl(T, S)(S value) if ( is(S == string) && !is(T == string) && is(typeof(to!string(value[0]))) ) { return T.init; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice11513x.d ================================================ module ice11513a.imports; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice11513y.d ================================================ module ice11513b.imports.ice11513y; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice7782algorithm.d ================================================ module imports.ice7782algorithm; import imports.ice7782range; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice7782range.d ================================================ module imports.ice7782range; import imports.ice7782algorithm; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/ice9865b.d ================================================ public import ice9865; class Bar { Foo foo; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/imp1.d ================================================ module imports.imp1; enum X = 1; enum Y = 1; enum Z = 1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/imp15896.d ================================================ module imports.imp15896; private int thebar=4; package int packagebar=3; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/imp17602.d ================================================ module imports.imp17602; enum Status { on } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/imp18554.d ================================================ struct S { private int i; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/imp2.d ================================================ module imports.imp2; enum X = 2; enum Y = 2; enum Z = 2; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/pkg313/package.d ================================================ module imports.pkg313; void bug() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/range15788.d ================================================ module imports.range15788; auto iota(B, E, S)(B, E, S) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/spell9644a.d ================================================ module imports.spell9644a; public import imports.spell9644b; int cora; int pub; private int priv; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/spell9644b.d ================================================ module imports.spell9644b; private int prib; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/stdtraits10727.d ================================================ template StaticArrayTypeOf(T) { inout(U[n]) idx(U, size_t n)( inout(U[n]) ); /+static if (is(T == enum)) alias .StaticArrayTypeOf!(OriginalType!T) StaticArrayTypeOf; else +/static if (is(typeof(idx(T.init/+defaultInit!T+/)) X)) alias X StaticArrayTypeOf; else static assert(0, T.stringof~" is not a static array type"); } template DynamicArrayTypeOf(T) { inout(U[]) idx(U)( inout(U[]) ); /+static if (is(T == enum)) alias .DynamicArrayTypeOf!(OriginalType!T) DynamicArrayTypeOf; else +/static if (!is(StaticArrayTypeOf!T) && is(typeof(idx(T.init/+defaultInit!T+/)) X)) { alias typeof(T.init[0]/+defaultInit!T[0]+/) E; E[] idy( E[] ); const(E[]) idy( const(E[]) ); inout(E[]) idy( inout(E[]) ); shared( E[]) idy( shared( E[]) ); shared(const E[]) idy( shared(const E[]) ); shared(inout E[]) idy( shared(inout E[]) ); immutable(E[]) idy( immutable(E[]) ); alias typeof(idy(T.init/+defaultInit!T+/)) DynamicArrayTypeOf; } else static assert(0, T.stringof~" is not a dynamic array"); } template isDynamicArray(T) { enum isDynamicArray = is(DynamicArrayTypeOf!T)/+ && !isAggregateType!T+/; } template isArray(T) { enum bool isArray = /+isStaticArray!T || +/isDynamicArray!T; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test10327/empty.d ================================================ module empty; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152a.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152b.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152c.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152d.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152e.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152f.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152g.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152h.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152i.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152j.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152k.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152l.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152m.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152n.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152o.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152p.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152q.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152r.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152s.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152t.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152u.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152v.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152w.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152x.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152y.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test13152z.d ================================================ public import imports.test13152a; public import imports.test13152b; public import imports.test13152c; public import imports.test13152d; public import imports.test13152e; public import imports.test13152f; public import imports.test13152g; public import imports.test13152h; public import imports.test13152i; public import imports.test13152j; public import imports.test13152k; public import imports.test13152l; public import imports.test13152m; public import imports.test13152n; public import imports.test13152o; public import imports.test13152p; public import imports.test13152q; public import imports.test13152r; public import imports.test13152s; public import imports.test13152t; public import imports.test13152u; public import imports.test13152v; public import imports.test13152w; public import imports.test13152x; public import imports.test13152y; public import imports.test13152z; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test143.d ================================================ module imports.test143; package int x = 5; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test15785.d ================================================ module imports.test15785; class Base { private void foo() {} private void bar() {} private alias T = int; } interface IBase2 { private alias T = int; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test15897.d ================================================ module imports.test15897; import test15897; class Cat : Animal { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test18480b.d ================================================ template TestTemplate() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test5412a.d ================================================ module imports.test5412a; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test5412b.d ================================================ module imports.test5412b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d ================================================ module imports; const char[] file1 = "File1"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/isreturnonstack.d ================================================ /* TEST_OUTPUT: --- fail_compilation/isreturnonstack.d(11): Error: argument to `__traits(isReturnOnStack, int)` is not a function fail_compilation/isreturnonstack.d(12): Error: expected 1 arguments for `isReturnOnStack` but had 2 --- */ int test() { return 0; } enum b = __traits(isReturnOnStack, int); enum c = __traits(isReturnOnStack, test, int); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/issue3827.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/issue3827.d(12): Error: Implicit string concatenation is deprecated, use "Hello" ~ "World" instead fail_compilation/issue3827.d(13): Error: Implicit string concatenation is deprecated, use "A" ~ "B" instead --- */ void main () { string[] arr = [ "Hello" "World" ]; auto foo = "A" "B"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/lexer1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/lexer1.d(30): Deprecation: Built-in hex string literals are deprecated, use `std.conv.hexString` instead. fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w` fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U` fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1` fail_compilation/lexer1.d(33): Error: declaration expected, not `0.1f` fail_compilation/lexer1.d(34): Error: declaration expected, not `0.1L` fail_compilation/lexer1.d(35): Error: declaration expected, not `0.1i` fail_compilation/lexer1.d(36): Error: declaration expected, not `0.1fi` fail_compilation/lexer1.d(37): Error: declaration expected, not `0.1Li` fail_compilation/lexer1.d(38): Error: declaration expected, not `32U` fail_compilation/lexer1.d(39): Error: declaration expected, not `55295U` fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U` fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a"d` fail_compilation/lexer1.d(43): Error: declaration expected, not `module` fail_compilation/lexer1.d(45): Error: escape hex sequence has 1 hex digits instead of 2 fail_compilation/lexer1.d(46): Error: undefined escape hex sequence \xG fail_compilation/lexer1.d(47): Error: unnamed character entity &unnamedentity; fail_compilation/lexer1.d(48): Error: unterminated named entity &1; fail_compilation/lexer1.d(49): Error: unterminated named entity &*; fail_compilation/lexer1.d(50): Error: unterminated named entity &s1"; fail_compilation/lexer1.d(51): Error: unterminated named entity &2; fail_compilation/lexer1.d(52): Error: escape octal sequence \400 is larger than \377 --- */ // https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html x"01 02 03"w; 0x80000001; 0.1; 0.1f; 0.1L; 0.1i; 0.1fi; 0.1Li; ' '; '\uD7FF'; '\U00010000'; "ab\\c\"\u1234a\U00011100a\000ab"d; module x; static s1 = "\x1G"; static s2 = "\xGG"; static s3 = "\&unnamedentity;"; static s4 = "\&1"; static s5 = "\&*"; static s6 = "\&s1"; static s7 = "\&2;"; static s7 = "\400;"; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/lexer2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/lexer2.d(16): Error: odd number (3) of hex characters in hex string fail_compilation/lexer2.d(16): Deprecation: Built-in hex string literals are deprecated, use `std.conv.hexString` instead. fail_compilation/lexer2.d(17): Error: non-hex character 'G' in hex string fail_compilation/lexer2.d(17): Deprecation: Built-in hex string literals are deprecated, use `std.conv.hexString` instead. fail_compilation/lexer2.d(18): Error: heredoc rest of line should be blank fail_compilation/lexer2.d(20): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(20) fail_compilation/lexer2.d(22): Error: semicolon expected following auto declaration, not `End of File` --- */ // https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html static s1 = x"123"; static s2 = x"123G"; static s4 = q"here notblank here"; static s5 = q"here "; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/lexer3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/lexer3.d(9): Error: unterminated token string constant starting at fail_compilation/lexer3.d(9) fail_compilation/lexer3.d(10): Error: semicolon expected following auto declaration, not `End of File` --- */ static s1 = q{ asef; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/lexer4.d ================================================ /* TEST_OUTPUT: --- fail_compilation/lexer4.d(22): Error: unterminated character constant fail_compilation/lexer4.d(24): Error: unterminated character constant fail_compilation/lexer4.d(25): Error: unterminated character constant fail_compilation/lexer4.d(26): Error: binary digit expected, not `2` fail_compilation/lexer4.d(27): Error: octal digit expected, not `8` fail_compilation/lexer4.d(27): Error: octal literals larger than 7 are no longer supported fail_compilation/lexer4.d(28): Error: decimal digit expected, not `a` fail_compilation/lexer4.d(29): Error: unrecognized token fail_compilation/lexer4.d(30): Error: exponent required for hex float fail_compilation/lexer4.d(31): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead fail_compilation/lexer4.d(32): Error: use 'i' suffix instead of 'I' fail_compilation/lexer4.d(34): Error: line number `1234567891234567879` out of range fail_compilation/lexer4.d(36): Error: #line integer ["filespec"]\n expected fail_compilation/lexer4.d(19): Error: #line integer ["filespec"]\n expected fail_compilation/lexer4.d(19): Error: declaration expected, not `"file"` --- */ static c1 = ' ; static c2 = ''; static c3 = 'a; int i = 0b12; int j = 0128; int k = 12a; int l = 12UU; int f = 0x1234.0; int m = 12l; static n = 12.1I; #line 1234567891234567879 #line whatever #line 18 __FILE__ #line 20 "file" "file" /** asdf *//** asdf2 */ int o; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/lookup.d ================================================ /* TEST_OUTPUT: --- fail_compilation/lookup.d(23): Error: no property `X` for type `lookup.B` fail_compilation/lookup.d(23): while evaluating: `static assert((B).X == 0)` fail_compilation/lookup.d(24): Error: no property `Y` for type `lookup.B` fail_compilation/lookup.d(24): while evaluating: `static assert((B).Y == 2)` --- */ import imports.imp1; enum X = 0; class B { import imports.imp2; static assert(X == 0); static assert(Y == 2); } class C : B { static assert(B.X == 0); static assert(B.Y == 2); static assert(X == 0); static assert(Y == 1); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/mangle1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/mangle1.d(8): Error: pragma `mangle` can only apply to a single declaration --- */ pragma(mangle, "_stuff_") __gshared { int x, y; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/mangle2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/mangle2.d(20): Error: pragma `mangle` char 0x20 not allowed in mangled name fail_compilation/mangle2.d(21): Error: pragma `mangle` char 0x20 not allowed in mangled name fail_compilation/mangle2.d(24): Error: pragma `mangle` char 0x0a not allowed in mangled name fail_compilation/mangle2.d(25): Error: pragma `mangle` char 0x0a not allowed in mangled name fail_compilation/mangle2.d(28): Error: pragma `mangle` char 0x07 not allowed in mangled name fail_compilation/mangle2.d(29): Error: pragma `mangle` char 0x07 not allowed in mangled name fail_compilation/mangle2.d(32): Error: pragma `mangle` char 0x01 not allowed in mangled name fail_compilation/mangle2.d(33): Error: pragma `mangle` char 0x01 not allowed in mangled name fail_compilation/mangle2.d(36): Error: pragma `mangle` char 0x00 not allowed in mangled name fail_compilation/mangle2.d(37): Error: pragma `mangle` char 0x00 not allowed in mangled name fail_compilation/mangle2.d(40): Error: pragma `mangle` Outside Unicode code space fail_compilation/mangle2.d(41): Error: pragma `mangle` Outside Unicode code space --- */ //spaces __gshared pragma(mangle, "test 9") ubyte test9_1; __gshared extern pragma(mangle, "test 9") ubyte test9_1_e; //\n chars __gshared pragma(mangle, "test\n9") ubyte test9_2; __gshared extern pragma(mangle, "test\n9") ubyte test9_2_e; //\a chars __gshared pragma(mangle, "test\a9") ubyte test9_3; __gshared extern pragma(mangle, "test\a9") ubyte test9_3_e; //\x01 chars __gshared pragma(mangle, "test\x019") ubyte test9_4; __gshared extern pragma(mangle, "test\x019") ubyte test9_4_e; //\0 chars __gshared pragma(mangle, "test\09") ubyte test9_5; __gshared extern pragma(mangle, "test\09") ubyte test9_5_e; //\xff chars __gshared pragma(mangle, "test\xff9") ubyte test9_6; __gshared extern pragma(mangle, "test\xff9") ubyte test9_6_e; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/moduleundefuda.d ================================================ /* TEST_OUTPUT: --- fail_compilation/moduleundefuda.d(7): Error: undefined identifier `undef` --- */ @undef module moduleundefuda; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d ================================================ /* DFLAGS: REQUIRED_ARGS: -c EXTRA_SOURCES: extra-files/no_Throwable/object.d TEST_OUTPUT: --- fail_compilation/no_Throwable.d(13): Error: Cannot use `throw` statements because `object.Throwable` was not declared fail_compilation/no_Throwable.d(18): Error: Cannot use try-catch statements because `object.Throwable` was not declared --- */ void test() { throw new Exception("msg"); } void test2() { try { test(); } catch (Exception e) { } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d ================================================ /* DFLAGS: REQUIRED_ARGS: -c EXTRA_SOURCES: extra-files/no_TypeInfo/object.d TEST_OUTPUT: --- fail_compilation/no_TypeInfo.d(13): Error: `object.TypeInfo` could not be found, but is implicitly used --- */ void test() { int i; auto ti = typeid(i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/nogc1.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /***************** NewExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc1.d(17): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class fail_compilation/nogc1.d(18): Deprecation: class allocators have been deprecated, consider moving the allocation strategy outside of the class --- */ struct S1 { } struct S2 { this(int); } struct S3 { this(int) @nogc; } struct S4 { new(size_t); } struct S5 { @nogc new(size_t); } /* TEST_OUTPUT: --- fail_compilation/nogc1.d(35): Error: cannot use `new` in `@nogc` function `nogc1.testNew` fail_compilation/nogc1.d(37): Error: cannot use `new` in `@nogc` function `nogc1.testNew` fail_compilation/nogc1.d(38): Error: cannot use `new` in `@nogc` function `nogc1.testNew` fail_compilation/nogc1.d(40): Error: cannot use `new` in `@nogc` function `nogc1.testNew` fail_compilation/nogc1.d(41): Error: `@nogc` function `nogc1.testNew` cannot call non-@nogc constructor `nogc1.S2.this` fail_compilation/nogc1.d(42): Error: cannot use `new` in `@nogc` function `nogc1.testNew` fail_compilation/nogc1.d(43): Error: `@nogc` function `nogc1.testNew` cannot call non-@nogc allocator `nogc1.S4.new` fail_compilation/nogc1.d(46): Error: cannot use `new` in `@nogc` function `nogc1.testNew` --- */ @nogc void testNew() { int* p1 = new int; int[] a1 = new int[3]; int[][] a2 = new int[][](2, 3); S1* ps1 = new S1(); S2* ps2 = new S2(1); S3* ps3 = new S3(1); S4* ps4 = new S4; S5* ps5 = new S5; // no error Object o1 = new Object(); } /* TEST_OUTPUT: --- fail_compilation/nogc1.d(63): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope` fail_compilation/nogc1.d(65): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope` fail_compilation/nogc1.d(66): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope` fail_compilation/nogc1.d(68): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope` fail_compilation/nogc1.d(69): Error: `@nogc` function `nogc1.testNewScope` cannot call non-@nogc constructor `nogc1.S2.this` fail_compilation/nogc1.d(70): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope` fail_compilation/nogc1.d(71): Error: `@nogc` function `nogc1.testNewScope` cannot call non-@nogc allocator `nogc1.S4.new` --- */ @nogc void testNewScope() { scope int* p1 = new int; scope int[] a1 = new int[3]; scope int[][] a2 = new int[][](2, 3); scope S1* ps1 = new S1(); scope S2* ps2 = new S2(1); scope S3* ps3 = new S3(1); scope S4* ps4 = new S4; scope S5* ps5 = new S5; // no error scope Object o1 = new Object(); // no error scope o2 = new Object(); // no error } /***************** DeleteExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc1.d(93): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/nogc1.d(93): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` fail_compilation/nogc1.d(94): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/nogc1.d(94): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` fail_compilation/nogc1.d(95): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/nogc1.d(95): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete` --- */ @nogc void testDelete(int* p, Object o, S1* s) { delete p; delete o; delete s; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/nogc2.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /***************** CatExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc2.d(21): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(22): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(23): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(25): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(26): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(27): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(28): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` fail_compilation/nogc2.d(29): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat` --- */ @nogc void testCat(int[] a, string s) { int[] a1 = a ~ a; int[] a2 = a ~ 1; int[] a3 = 1 ~ a; string s1 = s ~ s; string s2 = s ~ "a"; string s3 = "a" ~ s; string s4 = s ~ 'c'; string s5 = 'c' ~ s; string s6 = "a" ~ "b"; // no error string s7 = "a" ~ 'c'; // no error string s8 = 'c' ~ "b"; // no error } /***************** CatAssignExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc2.d(48): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign` fail_compilation/nogc2.d(50): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign` fail_compilation/nogc2.d(51): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign` --- */ @nogc void testCatAssign(int[] a, string s) { a ~= 1; s ~= "a"; s ~= 'c'; } /***************** ArrayLiteralExp *******************/ @nogc int* barA(); /* TEST_OUTPUT: --- fail_compilation/nogc2.d(70): Error: array literal in `@nogc` function `nogc2.testArray` may cause a GC allocation fail_compilation/nogc2.d(71): Error: array literal in `@nogc` function `nogc2.testArray` may cause a GC allocation --- */ @nogc void testArray() { enum arrLiteral = [null, null]; int* p; auto a = [p, p, barA()]; a = arrLiteral; } /***************** AssocArrayLiteralExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc2.d(87): Error: associative array literal in `@nogc` function `nogc2.testAssocArray` may cause a GC allocation fail_compilation/nogc2.d(88): Error: associative array literal in `@nogc` function `nogc2.testAssocArray` may cause a GC allocation --- */ @nogc void testAssocArray() { enum aaLiteral = [10: 100]; auto aa = [1:1, 2:3, 4:5]; aa = aaLiteral; } /***************** IndexExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc2.d(102): Error: indexing an associative array in `@nogc` function `nogc2.testIndex` may cause a GC allocation fail_compilation/nogc2.d(103): Error: indexing an associative array in `@nogc` function `nogc2.testIndex` may cause a GC allocation --- */ @nogc void testIndex(int[int] aa) { aa[1] = 0; int n = aa[1]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/nogc3.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /***************** AssignExp *******************/ /* TEST_OUTPUT: --- fail_compilation/nogc3.d(16): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation fail_compilation/nogc3.d(17): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation fail_compilation/nogc3.d(18): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation --- */ @nogc void testArrayLength(int[] a) { a.length = 3; a.length += 1; a.length -= 1; } /***************** CallExp *******************/ void barCall(); /* TEST_OUTPUT: --- fail_compilation/nogc3.d(35): Error: `@nogc` function `nogc3.testCall` cannot call non-@nogc function pointer `fp` fail_compilation/nogc3.d(36): Error: `@nogc` function `nogc3.testCall` cannot call non-@nogc function `nogc3.barCall` --- */ @nogc void testCall() { auto fp = &barCall; (*fp)(); barCall(); } /****************** Closure ***********************/ @nogc void takeDelegate2(scope int delegate() dg) {} @nogc void takeDelegate3( int delegate() dg) {} /* TEST_OUTPUT: --- fail_compilation/nogc3.d(53): Error: function `nogc3.testClosure1` is `@nogc` yet allocates closures with the GC fail_compilation/nogc3.d(56): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(55) fail_compilation/nogc3.d(65): Error: function `nogc3.testClosure3` is `@nogc` yet allocates closures with the GC fail_compilation/nogc3.d(68): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(67) --- */ @nogc auto testClosure1() { int x; int bar() { return x; } return &bar; } @nogc void testClosure2() { int x; int bar() { return x; } takeDelegate2(&bar); // no error } @nogc void testClosure3() { int x; int bar() { return x; } takeDelegate3(&bar); } /****************** ErrorExp ***********************/ /* TEST_OUTPUT: --- fail_compilation/nogc3.d(86): Error: array literal in `@nogc` function `nogc3.foo13702` may cause a GC allocation fail_compilation/nogc3.d(87): Error: array literal in `@nogc` function `nogc3.foo13702` may cause a GC allocation fail_compilation/nogc3.d(93): Error: array literal in `@nogc` function `nogc3.bar13702` may cause a GC allocation fail_compilation/nogc3.d(92): Error: array literal in `@nogc` function `nogc3.bar13702` may cause a GC allocation --- */ int[] foo13702(bool b) @nogc { if (b) return [1]; // error return 1 ~ [2]; // error } int[] bar13702(bool b) @nogc { if (b) return [1]; // error <- no error report auto aux = 1 ~ [2]; // error return aux; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/notype.d ================================================ struct S(int var = 3) { int a; } S s; alias A() = int; A a; enum e() = 5; e val; interface I() { } I i; template t() { } t tv; /* TEST_OUTPUT: --- fail_compilation/notype.d(4): Error: template struct `notype.S(int var = 3)` is used as a type without instantiation; to instantiate it use `S!(arguments)` fail_compilation/notype.d(7): Error: template `notype.A()` is used as a type fail_compilation/notype.d(10): Error: template `notype.e()` is used as a type fail_compilation/notype.d(15): Error: template interface `notype.I()` is used as a type without instantiation; to instantiate it use `I!(arguments)` fail_compilation/notype.d(20): Error: template `notype.t()` is used as a type --- */ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/objc_non_objc_base.d ================================================ // EXTRA_OBJC_SOURCES /* TEST_OUTPUT: --- fail_compilation/objc_non_objc_base.d(12): Error: interface `objc_non_objc_base.A` base interface for an Objective-C interface must be `extern (Objective-C)` --- */ interface Base {} extern (Objective-C) interface A : Base {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse12924.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse12924.d(14): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(15): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(16): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(17): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(18): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(19): Error: declaration expected following attribute, not `;` fail_compilation/parse12924.d(20): Error: declaration expected following attribute, not `;` --- */ static; void f1() {} deprecated; void f2() {} deprecated(""); void f3() {} extern(C); void f4() {} public; void f5() {} align(1); void f6() {} @(1); void f7() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse12967a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse12967a.d(14): Error: function `parse12967a.pre_i1` without `this` cannot be `immutable` fail_compilation/parse12967a.d(15): Error: function `parse12967a.pre_i2` without `this` cannot be `immutable` fail_compilation/parse12967a.d(16): Error: function `parse12967a.pre_c1` without `this` cannot be `const` fail_compilation/parse12967a.d(17): Error: function `parse12967a.pre_c2` without `this` cannot be `const` fail_compilation/parse12967a.d(18): Error: function `parse12967a.pre_w1` without `this` cannot be `inout` fail_compilation/parse12967a.d(19): Error: function `parse12967a.pre_w2` without `this` cannot be `inout` fail_compilation/parse12967a.d(20): Error: function `parse12967a.pre_s1` without `this` cannot be `shared` fail_compilation/parse12967a.d(21): Error: function `parse12967a.pre_s2` without `this` cannot be `shared` --- */ immutable pre_i1() {} immutable void pre_i2() {} const pre_c1() {} const void pre_c2() {} inout pre_w1() {} inout void pre_w2() {} shared pre_s1() {} shared void pre_s2() {} /* TEST_OUTPUT: --- fail_compilation/parse12967a.d(36): Error: function `parse12967a.post_i1` without `this` cannot be `immutable` fail_compilation/parse12967a.d(37): Error: function `parse12967a.post_i2` without `this` cannot be `immutable` fail_compilation/parse12967a.d(38): Error: function `parse12967a.post_c1` without `this` cannot be `const` fail_compilation/parse12967a.d(39): Error: function `parse12967a.post_c2` without `this` cannot be `const` fail_compilation/parse12967a.d(40): Error: function `parse12967a.post_w1` without `this` cannot be `inout` fail_compilation/parse12967a.d(41): Error: function `parse12967a.post_w2` without `this` cannot be `inout` fail_compilation/parse12967a.d(42): Error: function `parse12967a.post_s1` without `this` cannot be `shared` fail_compilation/parse12967a.d(43): Error: function `parse12967a.post_s2` without `this` cannot be `shared` --- */ auto post_i1() immutable {} void post_i2() immutable {} auto post_c1() const {} void post_c2() const {} auto post_w1() inout {} void post_w2() inout {} auto post_s1() shared {} void post_s2() shared {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse12967b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse12967b.d(24): Error: function `parse12967b.C.pre_c` without `this` cannot be `const` fail_compilation/parse12967b.d(25): Error: function `parse12967b.C.pre_i` without `this` cannot be `immutable` fail_compilation/parse12967b.d(26): Error: function `parse12967b.C.pre_w` without `this` cannot be `inout` fail_compilation/parse12967b.d(27): Error: function `parse12967b.C.pre_s` without `this` cannot be `shared` fail_compilation/parse12967b.d(29): Error: function `parse12967b.C.post_c` without `this` cannot be `const` fail_compilation/parse12967b.d(30): Error: function `parse12967b.C.post_i` without `this` cannot be `immutable` fail_compilation/parse12967b.d(31): Error: function `parse12967b.C.post_w` without `this` cannot be `inout` fail_compilation/parse12967b.d(32): Error: function `parse12967b.C.post_s` without `this` cannot be `shared` fail_compilation/parse12967b.d(37): Error: function `parse12967b.D.pre_c` without `this` cannot be `const` fail_compilation/parse12967b.d(38): Error: function `parse12967b.D.pre_i` without `this` cannot be `immutable` fail_compilation/parse12967b.d(39): Error: function `parse12967b.D.pre_w` without `this` cannot be `inout` fail_compilation/parse12967b.d(40): Error: function `parse12967b.D.pre_s` without `this` cannot be `shared` fail_compilation/parse12967b.d(41): Error: function `parse12967b.D.post_c` without `this` cannot be `const` fail_compilation/parse12967b.d(42): Error: function `parse12967b.D.post_i` without `this` cannot be `immutable` fail_compilation/parse12967b.d(43): Error: function `parse12967b.D.post_w` without `this` cannot be `inout` fail_compilation/parse12967b.d(44): Error: function `parse12967b.D.post_s` without `this` cannot be `shared` --- */ class C { const static pre_c() {} immutable static pre_i() {} inout static pre_w() {} shared static pre_s() {} static post_c() const {} static post_i() immutable {} static post_w() inout {} static post_s() shared {} } class D { const static void pre_c() {} immutable static void pre_i() {} inout static void pre_w() {} shared static void pre_s() {} static void post_c() const {} static void post_i() immutable {} static void post_w() inout {} static void post_s() shared {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse13361.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse13361.d(11): Error: empty attribute list is not allowed fail_compilation/parse13361.d(14): Error: empty attribute list is not allowed fail_compilation/parse13361.d(14): Error: use `@(attributes)` instead of `[attributes]` --- */ struct A { @() int b; [] // deprecated style int c; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse14285.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse14285.d(10): Error: no identifier for declarator `this` --- */ struct S { alias this; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parse14745.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parse14745.d(11): Error: function literal cannot be `immutable` fail_compilation/parse14745.d(12): Error: function literal cannot be `const` --- */ void test14745() { auto fp1 = function () pure immutable { return 0; }; auto fp2 = function () pure const { return 0; }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parseStc.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parseStc.d(11): Error: found `;` when expecting `)` fail_compilation/parseStc.d(11): Error: found `)` when expecting `;` following statement fail_compilation/parseStc.d(12): Error: redundant attribute `const` --- */ void test1() { if (x; 1) {} if (const const auto x = 1) {} } /* TEST_OUTPUT: --- fail_compilation/parseStc.d(25): Error: redundant attribute `const` fail_compilation/parseStc.d(26): Error: redundant attribute `const` fail_compilation/parseStc.d(27): Error: conflicting attribute `immutable` --- */ void test2() { const const x = 1; foreach (const const x; [1,2,3]) {} foreach (const immutable x; [1,2,3]) {} } /* TEST_OUTPUT: --- fail_compilation/parseStc.d(37): Error: redundant attribute `const` fail_compilation/parseStc.d(38): Error: redundant attribute `const` --- */ struct S3 { const const test3() {} } void test4(const const int x) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parseStc2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(11): Error: conflicting attribute `const` fail_compilation/parseStc2.d(12): Error: conflicting attribute `@system` fail_compilation/parseStc2.d(13): Error: conflicting attribute `@safe` fail_compilation/parseStc2.d(14): Error: conflicting attribute `@trusted` fail_compilation/parseStc2.d(15): Error: conflicting attribute `__gshared` --- */ immutable const void f4() {} @safe @system void f4() {} @trusted @safe void f4() {} @system @trusted void f4() {} shared __gshared f4() {} /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(26): Error: redundant attribute `static` fail_compilation/parseStc2.d(27): Error: redundant attribute `pure` fail_compilation/parseStc2.d(28): Error: redundant attribute `@property` fail_compilation/parseStc2.d(29): Error: redundant attribute `@safe` --- */ static static void f1() {} pure nothrow pure void f2() {} @property extern(C) @property void f3() {} deprecated("") @safe @safe void f4() {} @(1) @(1) void f5() {} // OK /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(39): Error: redundant linkage `extern (C)` fail_compilation/parseStc2.d(40): Error: conflicting linkage `extern (C)` and `extern (C++)` --- */ extern(C) extern(C) void f6() {} extern(C) extern(C++) void f7() {} extern(C++, foo) extern(C++, bar) void f8() {} // OK /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(50): Error: redundant protection attribute `public` fail_compilation/parseStc2.d(51): Error: conflicting protection attribute `public` and `private` --- */ public public void f9() {} public private void f10() {} /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align` fail_compilation/parseStc2.d(64): Error: redundant alignment attribute `align(1)` fail_compilation/parseStc2.d(65): Error: redundant alignment attribute `align(1)` fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align` fail_compilation/parseStc2.d(67): Error: redundant alignment attribute `align(2)` --- */ align align void f11() {} align(1) align(1) void f12() {} align align(1) void f13() {} align(1) align void f14() {} align(1) align(2) void f15() {} /* TEST_OUTPUT: --- fail_compilation/parseStc2.d(76): Error: redundant linkage `extern (System)` fail_compilation/parseStc2.d(77): Error: conflicting linkage `extern (System)` and `extern (C++)` --- */ extern(System) extern(System) void f16() {} extern(System) extern(C++) void f17() {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parseStc3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parseStc3.d(10): Error: redundant attribute `pure` fail_compilation/parseStc3.d(11): Error: redundant attribute `nothrow` fail_compilation/parseStc3.d(12): Error: redundant attribute `@nogc` fail_compilation/parseStc3.d(13): Error: redundant attribute `@property` --- */ pure void f1() pure {} nothrow void f2() nothrow {} @nogc void f3() @nogc {} @property void f4() @property {} //ref int f5() ref { static int g; return g; } /* TEST_OUTPUT: --- fail_compilation/parseStc3.d(24): Error: redundant attribute `@safe` fail_compilation/parseStc3.d(25): Error: redundant attribute `@system` fail_compilation/parseStc3.d(26): Error: redundant attribute `@trusted` --- */ @safe void f6() @safe {} @system void f7() @system {} @trusted void f8() @trusted {} /* TEST_OUTPUT: --- fail_compilation/parseStc3.d(39): Error: conflicting attribute `@system` fail_compilation/parseStc3.d(40): Error: conflicting attribute `@trusted` fail_compilation/parseStc3.d(41): Error: conflicting attribute `@safe` fail_compilation/parseStc3.d(42): Error: conflicting attribute `@trusted` fail_compilation/parseStc3.d(43): Error: conflicting attribute `@safe` fail_compilation/parseStc3.d(44): Error: conflicting attribute `@system` --- */ @safe void f9() @system {} @safe void f10() @trusted {} @system void f11() @safe {} @system void f12() @trusted {} @trusted void f13() @safe {} @trusted void f14() @system {} /* TEST_OUTPUT: --- fail_compilation/parseStc3.d(59): Error: conflicting attribute `@system` fail_compilation/parseStc3.d(59): Error: conflicting attribute `@trusted` fail_compilation/parseStc3.d(60): Error: conflicting attribute `@system` fail_compilation/parseStc3.d(60): Error: redundant attribute `@system` fail_compilation/parseStc3.d(61): Error: conflicting attribute `@safe` fail_compilation/parseStc3.d(61): Error: redundant attribute `@system` fail_compilation/parseStc3.d(62): Error: conflicting attribute `@safe` fail_compilation/parseStc3.d(62): Error: redundant attribute `@trusted` --- */ @safe @system void f15() @trusted {} @safe @system void f16() @system {} @system @safe void f17() @system {} @trusted @safe void f18() @trusted {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parseStc4.d ================================================ /* TEST_OUTPUT: --- fail_compilation/parseStc4.d(14): Error: redundant attribute `pure` fail_compilation/parseStc4.d(14): Error: redundant attribute `nothrow` fail_compilation/parseStc4.d(14): Error: conflicting attribute `@system` fail_compilation/parseStc4.d(14): Error: redundant attribute `@nogc` fail_compilation/parseStc4.d(14): Error: redundant attribute `@property` --- */ pure nothrow @safe @nogc @property int foo() pure nothrow @system @nogc @property { return 0; } /* TEST_OUTPUT: --- fail_compilation/parseStc4.d(35): Error: redundant attribute `const` fail_compilation/parseStc4.d(36): Error: redundant attribute `const` fail_compilation/parseStc4.d(36): Deprecation: `const` postblit is deprecated. Please use an unqualified postblit. fail_compilation/parseStc4.d(37): Error: redundant attribute `const` fail_compilation/parseStc4.d(39): Error: redundant attribute `pure` fail_compilation/parseStc4.d(40): Error: redundant attribute `@safe` fail_compilation/parseStc4.d(41): Error: redundant attribute `nothrow` fail_compilation/parseStc4.d(42): Error: conflicting attribute `@trusted` --- */ struct S { const this(int) const {} const this(this) const {} const ~this() const {} pure static this() pure {} @safe static ~this() @safe {} nothrow shared static this() nothrow {} @system shared static ~this() @trusted {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/parseStc5.d ================================================ // REQUIRED_ARGS: /* TEST_OUTPUT: --- fail_compilation/parseStc5.d(11): Error: constructor cannot be static fail_compilation/parseStc5.d(12): Error: postblit cannot be `static` --- */ class C1 { static pure this(int) {} // `static pure` + `this(int)` static pure this(this) {} // `static pure` + `this(this)` } /* TEST_OUTPUT: --- fail_compilation/parseStc5.d(28): Error: use `shared static this()` to declare a shared static constructor fail_compilation/parseStc5.d(29): Error: use `shared static this()` to declare a shared static constructor fail_compilation/parseStc5.d(31): Error: use `shared static this()` to declare a shared static constructor fail_compilation/parseStc5.d(33): Error: use `shared static ~this()` to declare a shared static destructor fail_compilation/parseStc5.d(34): Error: use `shared static ~this()` to declare a shared static destructor fail_compilation/parseStc5.d(36): Error: use `shared static ~this()` to declare a shared static destructor --- */ class C2 // wrong combinations of `shared`, `static`, and `~?this()` { shared pure static this() {} // `shared pure` + `static this()` shared static pure this() {} // `shared static pure` + `this()` static this() shared {} // `shared pure` + `static this()` shared pure static ~this() {} // `shared pure` + `static ~this()` shared static pure ~this() {} // `shared static pure` + `~this()` static ~this() shared {} // `shared` + `static ~this()` } /* TEST_OUTPUT: --- fail_compilation/parseStc5.d(48): Error: use `static this()` to declare a static constructor fail_compilation/parseStc5.d(49): Error: use `static ~this()` to declare a static destructor --- */ class C3 // wrong combinations of `static` and `~?this()` { static pure this() {} // `static pure` + `this()` static pure ~this() {} // `static pure` + `~this()` } /* TEST_OUTPUT: --- fail_compilation/parseStc5.d(64): Error: redundant attribute `shared` fail_compilation/parseStc5.d(65): Error: redundant attribute `shared` fail_compilation/parseStc5.d(67): Error: redundant attribute `static` fail_compilation/parseStc5.d(69): Error: redundant attribute `static shared` fail_compilation/parseStc5.d(70): Error: redundant attribute `static shared` --- */ class C4 // redundancy of `shared` and/or `static` { shared shared static this() {} // `shared` + `shared static this()` shared static this() shared {} // `shared` + `shared static this()` static static this() {} // `static` + `shared static this()` shared static shared static this() {} // shared static + `shared static this()` shared static shared static this() shared {} // shared shared static + `shared static this()` } /* TEST_OUTPUT: --- fail_compilation/parseStc5.d(84): Error: static constructor cannot be `const` fail_compilation/parseStc5.d(85): Error: static destructor cannot be `const` fail_compilation/parseStc5.d(86): Error: shared static constructor cannot be `const` fail_compilation/parseStc5.d(87): Error: shared static destructor cannot be `const` --- */ class C5 // wrong MemberFunctionAttributes on `shared? static (con|de)structor` { static this() const {} static ~this() const {} shared static this() const {} shared static ~this() const {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/pragmainline.d ================================================ /* TEST_OUTPUT: --- fail_compilation/pragmainline.d(9): Error: pragma `inline` one boolean expression expected for `pragma(inline)`, not 3 fail_compilation/pragmainline.d(10): Error: pragma `inline` pragma(`inline`, `true` or `false`) expected, not `"string"` --- */ pragma(inline, 1,2,3) void bar(); pragma(inline, "string") void baz(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/pragmas.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: */ /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/pragmas.d(103): Error: boolean expression expected for `pragma(inline)` fail_compilation/pragmas.d(108): Error: boolean expression expected for `pragma(inline)` fail_compilation/pragmas.d(113): Error: pragma(inline, true or false) expected, not `"string"` fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)` --- */ #line 100 void test1() { pragma(inline); pragma(inline, true, false); } void test2() { pragma(inline, true, false); } void test3() { pragma(inline, "string"); } void test4() { pragma(unrecognized, "string"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protattr1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/protection/subpkg/test1.d(3): Error: protection attribute `package(undefined)` does not bind to one of ancestor packages of module `protection.subpkg.test1` --- */ import protection.subpkg.test1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protattr2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/protection/subpkg/test2.d(3): Error: protection attribute `package(protection.subpkg2)` does not bind to one of ancestor packages of module `protection.subpkg.test2` --- */ import protection.subpkg.test2; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protattr3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/protection/subpkg/test3.d(3): Error: `protection package` expected as dot-separated identifiers, got `123` --- */ import protection.subpkg.test3; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test1.d ================================================ module protection.subpkg.test1; package(undefined) void foo1(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test2.d ================================================ module protection.subpkg.test2; package(protection.subpkg2) void foo2(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test3.d ================================================ module protection.subpkg.test3; package(123) void foo3(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/reserved_version.d ================================================ // REQUIRED_ARGS: -verrors=0 /* TEST_OUTPUT: --- fail_compilation/reserved_version.d(105): Error: version identifier `MSP430` is reserved and cannot be set fail_compilation/reserved_version.d(106): Error: version identifier `D_P16` is reserved and cannot be set fail_compilation/reserved_version.d(107): Error: version identifier `DigitalMars` is reserved and cannot be set fail_compilation/reserved_version.d(108): Error: version identifier `GNU` is reserved and cannot be set fail_compilation/reserved_version.d(109): Error: version identifier `LDC` is reserved and cannot be set fail_compilation/reserved_version.d(110): Error: version identifier `SDC` is reserved and cannot be set fail_compilation/reserved_version.d(111): Error: version identifier `Windows` is reserved and cannot be set fail_compilation/reserved_version.d(112): Error: version identifier `Win32` is reserved and cannot be set fail_compilation/reserved_version.d(113): Error: version identifier `Win64` is reserved and cannot be set fail_compilation/reserved_version.d(114): Error: version identifier `linux` is reserved and cannot be set fail_compilation/reserved_version.d(115): Error: version identifier `OSX` is reserved and cannot be set fail_compilation/reserved_version.d(116): Error: version identifier `FreeBSD` is reserved and cannot be set fail_compilation/reserved_version.d(117): Error: version identifier `OpenBSD` is reserved and cannot be set fail_compilation/reserved_version.d(118): Error: version identifier `NetBSD` is reserved and cannot be set fail_compilation/reserved_version.d(119): Error: version identifier `DragonFlyBSD` is reserved and cannot be set fail_compilation/reserved_version.d(120): Error: version identifier `BSD` is reserved and cannot be set fail_compilation/reserved_version.d(121): Error: version identifier `Solaris` is reserved and cannot be set fail_compilation/reserved_version.d(122): Error: version identifier `Posix` is reserved and cannot be set fail_compilation/reserved_version.d(123): Error: version identifier `AIX` is reserved and cannot be set fail_compilation/reserved_version.d(124): Error: version identifier `Haiku` is reserved and cannot be set fail_compilation/reserved_version.d(125): Error: version identifier `SkyOS` is reserved and cannot be set fail_compilation/reserved_version.d(126): Error: version identifier `SysV3` is reserved and cannot be set fail_compilation/reserved_version.d(127): Error: version identifier `SysV4` is reserved and cannot be set fail_compilation/reserved_version.d(128): Error: version identifier `Hurd` is reserved and cannot be set fail_compilation/reserved_version.d(129): Error: version identifier `Android` is reserved and cannot be set fail_compilation/reserved_version.d(130): Error: version identifier `PlayStation` is reserved and cannot be set fail_compilation/reserved_version.d(131): Error: version identifier `PlayStation4` is reserved and cannot be set fail_compilation/reserved_version.d(132): Error: version identifier `Cygwin` is reserved and cannot be set fail_compilation/reserved_version.d(133): Error: version identifier `MinGW` is reserved and cannot be set fail_compilation/reserved_version.d(134): Error: version identifier `FreeStanding` is reserved and cannot be set fail_compilation/reserved_version.d(135): Error: version identifier `X86` is reserved and cannot be set fail_compilation/reserved_version.d(136): Error: version identifier `X86_64` is reserved and cannot be set fail_compilation/reserved_version.d(137): Error: version identifier `ARM` is reserved and cannot be set fail_compilation/reserved_version.d(138): Error: version identifier `ARM_Thumb` is reserved and cannot be set fail_compilation/reserved_version.d(139): Error: version identifier `ARM_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(140): Error: version identifier `ARM_SoftFP` is reserved and cannot be set fail_compilation/reserved_version.d(141): Error: version identifier `ARM_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(142): Error: version identifier `AArch64` is reserved and cannot be set fail_compilation/reserved_version.d(143): Error: version identifier `Epiphany` is reserved and cannot be set fail_compilation/reserved_version.d(144): Error: version identifier `PPC` is reserved and cannot be set fail_compilation/reserved_version.d(145): Error: version identifier `PPC_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(146): Error: version identifier `PPC_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(147): Error: version identifier `PPC64` is reserved and cannot be set fail_compilation/reserved_version.d(148): Error: version identifier `IA64` is reserved and cannot be set fail_compilation/reserved_version.d(149): Error: version identifier `MIPS32` is reserved and cannot be set fail_compilation/reserved_version.d(150): Error: version identifier `MIPS64` is reserved and cannot be set fail_compilation/reserved_version.d(151): Error: version identifier `MIPS_O32` is reserved and cannot be set fail_compilation/reserved_version.d(152): Error: version identifier `MIPS_N32` is reserved and cannot be set fail_compilation/reserved_version.d(153): Error: version identifier `MIPS_O64` is reserved and cannot be set fail_compilation/reserved_version.d(154): Error: version identifier `MIPS_N64` is reserved and cannot be set fail_compilation/reserved_version.d(155): Error: version identifier `MIPS_EABI` is reserved and cannot be set fail_compilation/reserved_version.d(156): Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(157): Error: version identifier `MIPS_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(158): Error: version identifier `NVPTX` is reserved and cannot be set fail_compilation/reserved_version.d(159): Error: version identifier `NVPTX64` is reserved and cannot be set fail_compilation/reserved_version.d(160): Error: version identifier `RISCV32` is reserved and cannot be set fail_compilation/reserved_version.d(161): Error: version identifier `RISCV64` is reserved and cannot be set fail_compilation/reserved_version.d(162): Error: version identifier `SPARC` is reserved and cannot be set fail_compilation/reserved_version.d(163): Error: version identifier `SPARC_V8Plus` is reserved and cannot be set fail_compilation/reserved_version.d(164): Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(165): Error: version identifier `SPARC_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(166): Error: version identifier `SPARC64` is reserved and cannot be set fail_compilation/reserved_version.d(167): Error: version identifier `S390` is reserved and cannot be set fail_compilation/reserved_version.d(168): Error: version identifier `S390X` is reserved and cannot be set fail_compilation/reserved_version.d(169): Error: version identifier `SystemZ` is reserved and cannot be set fail_compilation/reserved_version.d(170): Error: version identifier `HPPA` is reserved and cannot be set fail_compilation/reserved_version.d(171): Error: version identifier `HPPA64` is reserved and cannot be set fail_compilation/reserved_version.d(172): Error: version identifier `SH` is reserved and cannot be set fail_compilation/reserved_version.d(173): Error: version identifier `Alpha` is reserved and cannot be set fail_compilation/reserved_version.d(174): Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(175): Error: version identifier `Alpha_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(176): Error: version identifier `LittleEndian` is reserved and cannot be set fail_compilation/reserved_version.d(177): Error: version identifier `BigEndian` is reserved and cannot be set fail_compilation/reserved_version.d(178): Error: version identifier `ELFv1` is reserved and cannot be set fail_compilation/reserved_version.d(179): Error: version identifier `ELFv2` is reserved and cannot be set fail_compilation/reserved_version.d(180): Error: version identifier `CRuntime_Bionic` is reserved and cannot be set fail_compilation/reserved_version.d(181): Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set fail_compilation/reserved_version.d(182): Error: version identifier `CRuntime_Glibc` is reserved and cannot be set fail_compilation/reserved_version.d(183): Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set fail_compilation/reserved_version.d(184): Error: version identifier `CRuntime_Musl` is reserved and cannot be set fail_compilation/reserved_version.d(185): Error: version identifier `CRuntime_UClibc` is reserved and cannot be set fail_compilation/reserved_version.d(186): Error: version identifier `D_Coverage` is reserved and cannot be set fail_compilation/reserved_version.d(187): Error: version identifier `D_Ddoc` is reserved and cannot be set fail_compilation/reserved_version.d(188): Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set fail_compilation/reserved_version.d(189): Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set fail_compilation/reserved_version.d(190): Error: version identifier `D_LP64` is reserved and cannot be set fail_compilation/reserved_version.d(191): Error: version identifier `D_X32` is reserved and cannot be set fail_compilation/reserved_version.d(192): Error: version identifier `D_HardFloat` is reserved and cannot be set fail_compilation/reserved_version.d(193): Error: version identifier `D_SoftFloat` is reserved and cannot be set fail_compilation/reserved_version.d(194): Error: version identifier `D_PIC` is reserved and cannot be set fail_compilation/reserved_version.d(195): Error: version identifier `D_SIMD` is reserved and cannot be set fail_compilation/reserved_version.d(196): Error: version identifier `D_Version2` is reserved and cannot be set fail_compilation/reserved_version.d(197): Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set fail_compilation/reserved_version.d(200): Error: version identifier `all` is reserved and cannot be set fail_compilation/reserved_version.d(201): Error: version identifier `none` is reserved and cannot be set fail_compilation/reserved_version.d(202): Error: version identifier `AsmJS` is reserved and cannot be set fail_compilation/reserved_version.d(203): Error: version identifier `Emscripten` is reserved and cannot be set fail_compilation/reserved_version.d(204): Error: version identifier `WebAssembly` is reserved and cannot be set fail_compilation/reserved_version.d(205): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set fail_compilation/reserved_version.d(206): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set fail_compilation/reserved_version.d(207): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set fail_compilation/reserved_version.d(208): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set fail_compilation/reserved_version.d(209): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set --- */ // Some extra empty lines to help fixup the manual line numbering after adding new version identifiers #line 105 version = MSP430; version = D_P16; version = DigitalMars; version = GNU; version = LDC; version = SDC; version = Windows; version = Win32; version = Win64; version = linux; version = OSX; version = FreeBSD; version = OpenBSD; version = NetBSD; version = DragonFlyBSD; version = BSD; version = Solaris; version = Posix; version = AIX; version = Haiku; version = SkyOS; version = SysV3; version = SysV4; version = Hurd; version = Android; version = PlayStation; version = PlayStation4; version = Cygwin; version = MinGW; version = FreeStanding; version = X86; version = X86_64; version = ARM; version = ARM_Thumb; version = ARM_SoftFloat; version = ARM_SoftFP; version = ARM_HardFloat; version = AArch64; version = Epiphany; version = PPC; version = PPC_SoftFloat; version = PPC_HardFloat; version = PPC64; version = IA64; version = MIPS32; version = MIPS64; version = MIPS_O32; version = MIPS_N32; version = MIPS_O64; version = MIPS_N64; version = MIPS_EABI; version = MIPS_SoftFloat; version = MIPS_HardFloat; version = NVPTX; version = NVPTX64; version = RISCV32; version = RISCV64; version = SPARC; version = SPARC_V8Plus; version = SPARC_SoftFloat; version = SPARC_HardFloat; version = SPARC64; version = S390; version = S390X; version = SystemZ; version = HPPA; version = HPPA64; version = SH; version = Alpha; version = Alpha_SoftFloat; version = Alpha_HardFloat; version = LittleEndian; version = BigEndian; version = ELFv1; version = ELFv2; version = CRuntime_Bionic; version = CRuntime_DigitalMars; version = CRuntime_Glibc; version = CRuntime_Microsoft; version = CRuntime_Musl; version = CRuntime_UClibc; version = D_Coverage; version = D_Ddoc; version = D_InlineAsm_X86; version = D_InlineAsm_X86_64; version = D_LP64; version = D_X32; version = D_HardFloat; version = D_SoftFloat; version = D_PIC; version = D_SIMD; version = D_Version2; version = D_NoBoundsChecks; //version = unittest; //version = assert; version = all; version = none; version = AsmJS; version = Emscripten; version = WebAssembly; version = CppRuntime_Clang; version = CppRuntime_DigitalMars; version = CppRuntime_Gcc; version = CppRuntime_Microsoft; version = CppRuntime_Sun; // This should work though debug = DigitalMars; debug = GNU; debug = LDC; debug = SDC; debug = Windows; debug = Win32; debug = Win64; debug = linux; debug = OSX; debug = FreeBSD; debug = OpenBSD; debug = NetBSD; debug = DragonFlyBSD; debug = BSD; debug = Solaris; debug = Posix; debug = AIX; debug = Haiku; debug = SkyOS; debug = SysV3; debug = SysV4; debug = Hurd; debug = Android; debug = Cygwin; debug = MinGW; debug = FreeStanding; debug = X86; debug = X86_64; debug = ARM; debug = ARM_Thumb; debug = ARM_SoftFloat; debug = ARM_SoftFP; debug = ARM_HardFloat; debug = AArch64; debug = Epiphany; debug = PPC; debug = PPC_SoftFloat; debug = PPC_HardFloat; debug = PPC64; debug = IA64; debug = MIPS32; debug = MIPS64; debug = MIPS_O32; debug = MIPS_N32; debug = MIPS_O64; debug = MIPS_N64; debug = MIPS_EABI; debug = MIPS_SoftFloat; debug = MIPS_HardFloat; debug = NVPTX; debug = NVPTX64; debug = RISCV32; debug = RISCV64; debug = SPARC; debug = SPARC_V8Plus; debug = SPARC_SoftFloat; debug = SPARC_HardFloat; debug = SPARC64; debug = S390; debug = S390X; debug = SystemZ; debug = HPPA; debug = HPPA64; debug = SH; debug = Alpha; debug = Alpha_SoftFloat; debug = Alpha_HardFloat; debug = LittleEndian; debug = BigEndian; debug = ELFv1; debug = ELFv2; debug = CRuntime_Bionic; debug = CRuntime_DigitalMars; debug = CRuntime_Glibc; debug = CRuntime_Microsoft; debug = CRuntime_Musl; debug = CRuntime_UClibc; debug = CppRuntime_Clang; debug = CppRuntime_DigitalMars; debug = CppRuntime_Gcc; debug = CppRuntime_Microsoft; debug = CppRuntime_Sun; debug = D_Coverage; debug = D_Ddoc; debug = D_InlineAsm_X86; debug = D_InlineAsm_X86_64; debug = D_LP64; debug = D_X32; debug = D_HardFloat; debug = D_SoftFloat; debug = D_PIC; debug = D_SIMD; debug = D_Version2; debug = D_NoBoundsChecks; //debug = unittest; //debug = assert; debug = all; debug = none; debug = D_P16; debug = MSP430; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d ================================================ // REQUIRED_ARGS: -verrors=0 // REQUIRED_ARGS: -version=DigitalMars // REQUIRED_ARGS: -version=GNU // REQUIRED_ARGS: -version=LDC // REQUIRED_ARGS: -version=SDC // REQUIRED_ARGS: -version=Windows // REQUIRED_ARGS: -version=Win32 // REQUIRED_ARGS: -version=Win64 // REQUIRED_ARGS: -version=linux // REQUIRED_ARGS: -version=OSX // REQUIRED_ARGS: -version=FreeBSD // REQUIRED_ARGS: -version=OpenBSD // REQUIRED_ARGS: -version=NetBSD // REQUIRED_ARGS: -version=DragonFlyBSD // REQUIRED_ARGS: -version=BSD // REQUIRED_ARGS: -version=Solaris // REQUIRED_ARGS: -version=Posix // REQUIRED_ARGS: -version=AIX // REQUIRED_ARGS: -version=Haiku // REQUIRED_ARGS: -version=SkyOS // REQUIRED_ARGS: -version=SysV3 // REQUIRED_ARGS: -version=SysV4 // REQUIRED_ARGS: -version=Hurd // REQUIRED_ARGS: -version=Android // REQUIRED_ARGS: -version=Cygwin // REQUIRED_ARGS: -version=MinGW // REQUIRED_ARGS: -version=FreeStanding // REQUIRED_ARGS: -version=X86 // REQUIRED_ARGS: -version=X86_64 // REQUIRED_ARGS: -version=ARM // REQUIRED_ARGS: -version=ARM_Thumb // REQUIRED_ARGS: -version=ARM_SoftFloat // REQUIRED_ARGS: -version=ARM_SoftFP // REQUIRED_ARGS: -version=ARM_HardFloat // REQUIRED_ARGS: -version=AArch64 // REQUIRED_ARGS: -version=Epiphany // REQUIRED_ARGS: -version=PPC // REQUIRED_ARGS: -version=PPC_SoftFloat // REQUIRED_ARGS: -version=PPC_HardFloat // REQUIRED_ARGS: -version=PPC64 // REQUIRED_ARGS: -version=IA64 // REQUIRED_ARGS: -version=MIPS32 // REQUIRED_ARGS: -version=MIPS64 // REQUIRED_ARGS: -version=MIPS_O32 // REQUIRED_ARGS: -version=MIPS_N32 // REQUIRED_ARGS: -version=MIPS_O64 // REQUIRED_ARGS: -version=MIPS_N64 // REQUIRED_ARGS: -version=MIPS_EABI // REQUIRED_ARGS: -version=MIPS_SoftFloat // REQUIRED_ARGS: -version=MIPS_HardFloat // REQUIRED_ARGS: -version=NVPTX // REQUIRED_ARGS: -version=NVPTX64 // REQUIRED_ARGS: -version=RISCV32 // REQUIRED_ARGS: -version=RISCV64 // REQUIRED_ARGS: -version=SPARC // REQUIRED_ARGS: -version=SPARC_V8Plus // REQUIRED_ARGS: -version=SPARC_SoftFloat // REQUIRED_ARGS: -version=SPARC_HardFloat // REQUIRED_ARGS: -version=SPARC64 // REQUIRED_ARGS: -version=S390 // REQUIRED_ARGS: -version=S390X // REQUIRED_ARGS: -version=SystemZ // REQUIRED_ARGS: -version=HPPA // REQUIRED_ARGS: -version=HPPA64 // REQUIRED_ARGS: -version=SH // REQUIRED_ARGS: -version=Alpha // REQUIRED_ARGS: -version=Alpha_SoftFloat // REQUIRED_ARGS: -version=Alpha_HardFloat // REQUIRED_ARGS: -version=LittleEndian // REQUIRED_ARGS: -version=BigEndian // REQUIRED_ARGS: -version=ELFv1 // REQUIRED_ARGS: -version=ELFv2 // REQUIRED_ARGS: -version=CRuntime_Bionic // REQUIRED_ARGS: -version=CRuntime_DigitalMars // REQUIRED_ARGS: -version=CRuntime_Glibc // REQUIRED_ARGS: -version=CRuntime_Microsoft // REQUIRED_ARGS: -version=CRuntime_Musl // REQUIRED_ARGS: -version=CRuntime_UClibc // REQUIRED_ARGS: -version=CppRuntime_Clang // REQUIRED_ARGS: -version=CppRuntime_DigitalMars // REQUIRED_ARGS: -version=CppRuntime_Gcc // REQUIRED_ARGS: -version=CppRuntime_Microsoft // REQUIRED_ARGS: -version=CppRuntime_Sun // REQUIRED_ARGS: -version=D_Coverage // REQUIRED_ARGS: -version=D_Ddoc // REQUIRED_ARGS: -version=D_InlineAsm_X86 // REQUIRED_ARGS: -version=D_InlineAsm_X86_64 // REQUIRED_ARGS: -version=D_LP64 // REQUIRED_ARGS: -version=D_X32 // REQUIRED_ARGS: -version=D_HardFloat // REQUIRED_ARGS: -version=D_SoftFloat // REQUIRED_ARGS: -version=D_PIC // REQUIRED_ARGS: -version=D_SIMD // REQUIRED_ARGS: -version=D_Version2 // REQUIRED_ARGS: -version=D_NoBoundsChecks // REQUIRED_ARGS: -version=unittest // REQUIRED_ARGS: -version=assert // REQUIRED_ARGS: -version=all // REQUIRED_ARGS: -version=none // REQUIRED_ARGS: -debug=DigitalMars // REQUIRED_ARGS: -debug=GNU // REQUIRED_ARGS: -debug=LDC // REQUIRED_ARGS: -debug=SDC // REQUIRED_ARGS: -debug=Windows // REQUIRED_ARGS: -debug=Win32 // REQUIRED_ARGS: -debug=Win64 // REQUIRED_ARGS: -debug=linux // REQUIRED_ARGS: -debug=OSX // REQUIRED_ARGS: -debug=FreeBSD // REQUIRED_ARGS: -debug=OpenBSD // REQUIRED_ARGS: -debug=NetBSD // REQUIRED_ARGS: -debug=DragonFlyBSD // REQUIRED_ARGS: -debug=BSD // REQUIRED_ARGS: -debug=Solaris // REQUIRED_ARGS: -debug=Posix // REQUIRED_ARGS: -debug=AIX // REQUIRED_ARGS: -debug=Haiku // REQUIRED_ARGS: -debug=SkyOS // REQUIRED_ARGS: -debug=SysV3 // REQUIRED_ARGS: -debug=SysV4 // REQUIRED_ARGS: -debug=Hurd // REQUIRED_ARGS: -debug=Android // REQUIRED_ARGS: -debug=Cygwin // REQUIRED_ARGS: -debug=MinGW // REQUIRED_ARGS: -debug=FreeStanding // REQUIRED_ARGS: -debug=X86 // REQUIRED_ARGS: -debug=X86_64 // REQUIRED_ARGS: -debug=ARM // REQUIRED_ARGS: -debug=ARM_Thumb // REQUIRED_ARGS: -debug=ARM_SoftFloat // REQUIRED_ARGS: -debug=ARM_SoftFP // REQUIRED_ARGS: -debug=ARM_HardFloat // REQUIRED_ARGS: -debug=AArch64 // REQUIRED_ARGS: -debug=Epiphany // REQUIRED_ARGS: -debug=PPC // REQUIRED_ARGS: -debug=PPC_SoftFloat // REQUIRED_ARGS: -debug=PPC_HardFloat // REQUIRED_ARGS: -debug=PPC64 // REQUIRED_ARGS: -debug=IA64 // REQUIRED_ARGS: -debug=MIPS32 // REQUIRED_ARGS: -debug=MIPS64 // REQUIRED_ARGS: -debug=MIPS_O32 // REQUIRED_ARGS: -debug=MIPS_N32 // REQUIRED_ARGS: -debug=MIPS_O64 // REQUIRED_ARGS: -debug=MIPS_N64 // REQUIRED_ARGS: -debug=MIPS_EABI // REQUIRED_ARGS: -debug=MIPS_SoftFloat // REQUIRED_ARGS: -debug=MIPS_HardFloat // REQUIRED_ARGS: -debug=NVPTX // REQUIRED_ARGS: -debug=NVPTX64 // REQUIRED_ARGS: -debug=SPARC // REQUIRED_ARGS: -debug=SPARC_V8Plus // REQUIRED_ARGS: -debug=SPARC_SoftFloat // REQUIRED_ARGS: -debug=SPARC_HardFloat // REQUIRED_ARGS: -debug=SPARC64 // REQUIRED_ARGS: -debug=S390 // REQUIRED_ARGS: -debug=S390X // REQUIRED_ARGS: -debug=SystemZ // REQUIRED_ARGS: -debug=HPPA // REQUIRED_ARGS: -debug=HPPA64 // REQUIRED_ARGS: -debug=SH // REQUIRED_ARGS: -debug=Alpha // REQUIRED_ARGS: -debug=Alpha_SoftFloat // REQUIRED_ARGS: -debug=Alpha_HardFloat // REQUIRED_ARGS: -debug=LittleEndian // REQUIRED_ARGS: -debug=BigEndian // REQUIRED_ARGS: -debug=ELFv1 // REQUIRED_ARGS: -debug=ELFv2 // REQUIRED_ARGS: -debug=CRuntime_Bionic // REQUIRED_ARGS: -debug=CRuntime_DigitalMars // REQUIRED_ARGS: -debug=CRuntime_Glibc // REQUIRED_ARGS: -debug=CRuntime_Microsoft // REQUIRED_ARGS: -debug=CRuntime_Musl // REQUIRED_ARGS: -debug=CRuntime_UClibc // REQUIRED_ARGS: -debug=CppRuntime_Clang // REQUIRED_ARGS: -debug=CppRuntime_DigitalMars // REQUIRED_ARGS: -debug=CppRuntime_Gcc // REQUIRED_ARGS: -debug=CppRuntime_Microsoft // REQUIRED_ARGS: -debug=CppRuntime_Sun // REQUIRED_ARGS: -debug=D_Coverage // REQUIRED_ARGS: -debug=D_Ddoc // REQUIRED_ARGS: -debug=D_InlineAsm_X86 // REQUIRED_ARGS: -debug=D_InlineAsm_X86_64 // REQUIRED_ARGS: -debug=D_LP64 // REQUIRED_ARGS: -debug=D_X32 // REQUIRED_ARGS: -debug=D_HardFloat // REQUIRED_ARGS: -debug=D_SoftFloat // REQUIRED_ARGS: -debug=D_PIC // REQUIRED_ARGS: -debug=D_SIMD // REQUIRED_ARGS: -debug=D_Version2 // REQUIRED_ARGS: -debug=D_NoBoundsChecks // REQUIRED_ARGS: -debug=unittest // REQUIRED_ARGS: -debug=assert // REQUIRED_ARGS: -debug=all // REQUIRED_ARGS: -debug=none /* TEST_OUTPUT: --- Error: version identifier `DigitalMars` is reserved and cannot be set Error: version identifier `GNU` is reserved and cannot be set Error: version identifier `LDC` is reserved and cannot be set Error: version identifier `SDC` is reserved and cannot be set Error: version identifier `Windows` is reserved and cannot be set Error: version identifier `Win32` is reserved and cannot be set Error: version identifier `Win64` is reserved and cannot be set Error: version identifier `linux` is reserved and cannot be set Error: version identifier `OSX` is reserved and cannot be set Error: version identifier `FreeBSD` is reserved and cannot be set Error: version identifier `OpenBSD` is reserved and cannot be set Error: version identifier `NetBSD` is reserved and cannot be set Error: version identifier `DragonFlyBSD` is reserved and cannot be set Error: version identifier `BSD` is reserved and cannot be set Error: version identifier `Solaris` is reserved and cannot be set Error: version identifier `Posix` is reserved and cannot be set Error: version identifier `AIX` is reserved and cannot be set Error: version identifier `Haiku` is reserved and cannot be set Error: version identifier `SkyOS` is reserved and cannot be set Error: version identifier `SysV3` is reserved and cannot be set Error: version identifier `SysV4` is reserved and cannot be set Error: version identifier `Hurd` is reserved and cannot be set Error: version identifier `Android` is reserved and cannot be set Error: version identifier `Cygwin` is reserved and cannot be set Error: version identifier `MinGW` is reserved and cannot be set Error: version identifier `FreeStanding` is reserved and cannot be set Error: version identifier `X86` is reserved and cannot be set Error: version identifier `X86_64` is reserved and cannot be set Error: version identifier `ARM` is reserved and cannot be set Error: version identifier `ARM_Thumb` is reserved and cannot be set Error: version identifier `ARM_SoftFloat` is reserved and cannot be set Error: version identifier `ARM_SoftFP` is reserved and cannot be set Error: version identifier `ARM_HardFloat` is reserved and cannot be set Error: version identifier `AArch64` is reserved and cannot be set Error: version identifier `Epiphany` is reserved and cannot be set Error: version identifier `PPC` is reserved and cannot be set Error: version identifier `PPC_SoftFloat` is reserved and cannot be set Error: version identifier `PPC_HardFloat` is reserved and cannot be set Error: version identifier `PPC64` is reserved and cannot be set Error: version identifier `IA64` is reserved and cannot be set Error: version identifier `MIPS32` is reserved and cannot be set Error: version identifier `MIPS64` is reserved and cannot be set Error: version identifier `MIPS_O32` is reserved and cannot be set Error: version identifier `MIPS_N32` is reserved and cannot be set Error: version identifier `MIPS_O64` is reserved and cannot be set Error: version identifier `MIPS_N64` is reserved and cannot be set Error: version identifier `MIPS_EABI` is reserved and cannot be set Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set Error: version identifier `MIPS_HardFloat` is reserved and cannot be set Error: version identifier `NVPTX` is reserved and cannot be set Error: version identifier `NVPTX64` is reserved and cannot be set Error: version identifier `RISCV32` is reserved and cannot be set Error: version identifier `RISCV64` is reserved and cannot be set Error: version identifier `SPARC` is reserved and cannot be set Error: version identifier `SPARC_V8Plus` is reserved and cannot be set Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set Error: version identifier `SPARC_HardFloat` is reserved and cannot be set Error: version identifier `SPARC64` is reserved and cannot be set Error: version identifier `S390` is reserved and cannot be set Error: version identifier `S390X` is reserved and cannot be set Error: version identifier `SystemZ` is reserved and cannot be set Error: version identifier `HPPA` is reserved and cannot be set Error: version identifier `HPPA64` is reserved and cannot be set Error: version identifier `SH` is reserved and cannot be set Error: version identifier `Alpha` is reserved and cannot be set Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set Error: version identifier `Alpha_HardFloat` is reserved and cannot be set Error: version identifier `LittleEndian` is reserved and cannot be set Error: version identifier `BigEndian` is reserved and cannot be set Error: version identifier `ELFv1` is reserved and cannot be set Error: version identifier `ELFv2` is reserved and cannot be set Error: version identifier `CRuntime_Bionic` is reserved and cannot be set Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set Error: version identifier `CRuntime_Glibc` is reserved and cannot be set Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set Error: version identifier `CRuntime_Musl` is reserved and cannot be set Error: version identifier `CRuntime_UClibc` is reserved and cannot be set Error: version identifier `CppRuntime_Clang` is reserved and cannot be set Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set Error: version identifier `CppRuntime_Sun` is reserved and cannot be set Error: version identifier `D_Coverage` is reserved and cannot be set Error: version identifier `D_Ddoc` is reserved and cannot be set Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set Error: version identifier `D_LP64` is reserved and cannot be set Error: version identifier `D_X32` is reserved and cannot be set Error: version identifier `D_HardFloat` is reserved and cannot be set Error: version identifier `D_SoftFloat` is reserved and cannot be set Error: version identifier `D_PIC` is reserved and cannot be set Error: version identifier `D_SIMD` is reserved and cannot be set Error: version identifier `D_Version2` is reserved and cannot be set Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set Error: version identifier `unittest` is reserved and cannot be set Error: version identifier `assert` is reserved and cannot be set Error: version identifier `all` is reserved and cannot be set Error: version identifier `none` is reserved and cannot be set --- */ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retref2.d ================================================ // REQUIRED_ARGS: -dip25 /* TEST_OUTPUT: --- fail_compilation/retref2.d(21): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`? fail_compilation/retref2.d(22): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`? --- */ class C { ref int foo(ref int); ref int bar(); } class D : C { override ref int foo(return ref int); override ref int bar() return; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/retscope.d(23): Error: scope variable `p` may not be returned fail_compilation/retscope.d(33): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j` fail_compilation/retscope.d(46): Error: scope variable `p` assigned to non-scope `q` fail_compilation/retscope.d(48): Error: address of variable `i` assigned to `q` with longer lifetime fail_compilation/retscope.d(49): Error: scope variable `a` assigned to non-scope `b` fail_compilation/retscope.d(50): Error: reference to stack allocated value returned by `(*fp2)()` assigned to non-scope `q` --- */ int* foo1(return scope int* p) { return p; } // ok int* foo2()(scope int* p) { return p; } // ok, 'return' is inferred alias foo2a = foo2!(); int* foo3(scope int* p) { return p; } // error int* foo4(bool b) { int i; int j; int* nested1(scope int* p) { return null; } int* nested2(return scope int* p) { return p; } return b ? nested1(&i) : nested2(&j); } /************************************************/ struct S2 { int a,b,c,d; } @safe S2 function() fp2; void test2(scope int* p, int[] a ...) @safe { static int* q; static int[] b; q = p; int i; q = &i; b = a; q = &fp2().d; } /**************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(76): Error: function `retscope.HTTP.Impl.onReceive` is `@nogc` yet allocates closures with the GC fail_compilation/retscope.d(78): retscope.HTTP.Impl.onReceive.__lambda1 closes over variable this at fail_compilation/retscope.d(76) --- */ struct Curl { int delegate() dg; } struct HTTP { struct Impl { Curl curl; int x; @nogc void onReceive() { auto dg = ( ) { return x; }; curl.dg = dg; } } } /***********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(97): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling retscope.bar8 --- */ // https://issues.dlang.org/show_bug.cgi?id=8838 int[] foo8() @safe { int[5] sa; return bar8(sa); } int[] bar8(int[] a) @safe { return a; } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(124): Error: returning `foo9(cast(char[])tmp)` escapes a reference to local variable `tmp` --- */ char[] foo9(return char[] a) @safe pure nothrow @nogc { return a; } char[] bar9() @safe { char[20] tmp; foo9(tmp); // ok return foo9(tmp); // error } /*************************************************/ /* // // //fail_compilation/retscope.d(143): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` // */ struct S10 { static int opApply(int delegate(S10*) dg); } S10* test10() { foreach (S10* m; S10) return m; return null; } /************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(159): Error: scope variable `this` may not be returned --- */ class C11 { @safe C11 foo() scope { return this; } } /****************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(178): Error: address of variable `i` assigned to `p` with longer lifetime --- */ void foo11() @safe { int[] p; int[3] i; p = i[]; } /************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(198): Error: scope variable `e` may not be returned --- */ struct Escaper { void* DG; } void* escapeDg1(scope void* d) @safe { Escaper e; e.DG = d; return e.DG; } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(213): Error: scope variable `p` assigned to non-scope `e.e` --- */ struct Escaper3 { void* e; } void* escape3 (scope void* p) @safe { Escaper3 e; scope dg = () { return e.e; }; e.e = p; return dg(); } /**************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(230): Error: scope variable `ptr` may not be returned --- */ alias dg_t = void* delegate () return scope @safe; void* funretscope(scope dg_t ptr) @safe { return ptr(); } /*****************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` --- */ void escape4() @safe { alias FunDG = void* delegate () @safe; int x = 42; scope FunDG f = () return { return &x; }; scope FunDG g = () { return &x; }; } /**************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(267): Error: cannot take address of `scope` local `p` in `@safe` function `escape5` --- */ void escape5() @safe { int* q; scope int* p; scope int** pp = &q; // ok pp = &p; // error } /***********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(287): Error: returning `foo6(& b)` escapes a reference to local variable `b` --- */ @safe int* foo6()(int* arg) { return arg; } int* escape6() @safe { int b; return foo6(&b); } /***************************************************/ struct S7 { int[10] a; int[3] abc(int i) @safe { return a[0 .. 3]; // should not error } } /***************************************************/ int[3] escape8(scope int[] p) @safe { return p[0 .. 3]; } // should not error char*[3] escape9(scope char*[] p) @safe { return p[0 .. 3]; } /***************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(320): Error: reference to local variable `i` assigned to non-scope `f` --- */ int* escape10() @safe { int i; int* f; scope int** x = &f; f = &i; return bar10(x); } int* bar10( scope int** ptr ) @safe { return *ptr; } /******************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(343): Error: cannot take address of `scope` local `aa` in `@safe` function `escape11` --- */ int* escape11() @safe { int i; int*[3] aa = [ &i, null, null ]; return bar11(&aa[0]); } int* bar11(scope int** x) @safe { return foo11(*x); } int* foo11(int* x) @safe { return x; } /******************************************/ void escape15() @safe { int arg; const(void)*[1] argsAddresses; argsAddresses[0] = // MUST be an array assignment (ref arg)@trusted{ return cast(const void*) &arg; }(arg); } /******************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1003): Error: returning `f.foo()` escapes a reference to local variable `f` --- */ #line 1000 int* escape12() @safe { Foo12 f; return f.foo; } struct Foo12 { int* foo() return @safe; } /******************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1103): Error: scope variable `f` may not be returned --- */ #line 1100 int* escape13() @safe { scope Foo13 f; return f.foo; } class Foo13 { int* foo() return @safe; } /******************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1205): Error: scope variable `f14` assigned to non-scope parameter `this` calling retscope.Foo14.foo --- */ #line 1200 int* escape14() @safe { int i; Foo14 f14; f14.v = &i; return f14.foo; } struct Foo14 { int* v; int* foo () @safe { return this.v; } } /******************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1311): Error: scope variable `u2` assigned to `ek` with longer lifetime --- */ #line 1300 @safe struct U13 { int* k; int* get() return scope { return k; } static int* sget(return scope ref U13 u) { return u.k; } } @safe void foo13() { int* ek; int i; auto u2 = U13(&i); ek = U13.sget(u2); // Error: scope variable u2 assigned to ek with longer lifetime auto u1 = U13(new int); ek = u1.get(); // ok ek = U13.sget(u1); // ok } /************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `unnamed` calling retscope.myprintf --- */ #line 1400 @trusted extern(C) int myprintf(const(char)*, ...); @safe void foo14() { char[4] buf = [ 'h', 'i', '\n', 0 ]; myprintf(&buf[0]); } /************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1509): Error: reference to stack allocated value returned by `(*fp15)()` assigned to non-scope parameter `unnamed` --- */ #line 1500 @safe void bar15(int*); struct S15 { int a,b,c,d; } @safe S15 function() fp15; void test15() @safe { bar15(&fp15().d); } /*************************************************/ void foo16() @nogc nothrow { alias dg_t = string delegate(string) @nogc nothrow; dg_t dg = (string s) => s; } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1701): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(scope int* p)` fail_compilation/retscope.d(1702): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)` fail_compilation/retscope.d(1703): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)` fail_compilation/retscope.d(1711): Error: cannot implicitly convert expression `& funcr` of type `int* function(return scope int* p)` to `int* function(scope int* p)` fail_compilation/retscope.d(1716): Error: cannot implicitly convert expression `& funcrs` of type `int* function(return scope int* p)` to `int* function(scope int* p)` --- */ int* func(int* p); int* funcs(scope int* p); int* funcr(return int* p); int* funcrs(return scope int* p); void foo17() { #line 1700 typeof(func) *fp1 = &func; typeof(funcs) *fp2 = &func; // error typeof(funcr) *fp3 = &func; // error typeof(funcrs) *fp4 = &func; // error typeof(func) *fq1 = &funcs; typeof(funcs) *fq2 = &funcs; typeof(funcr) *fq3 = &funcs; typeof(funcrs) *fq4 = &funcs; typeof(func) *fr1 = &funcr; typeof(funcs) *fr2 = &funcr; // error typeof(funcr) *fr3 = &funcr; typeof(funcrs) *fr4 = &funcr; typeof(func) *fs1 = &funcrs; typeof(funcs) *fs2 = &funcrs; // error typeof(funcr) *fs3 = &funcrs; typeof(funcrs) *fs4 = &funcrs; } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope.d(1801): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() scope` fail_compilation/retscope.d(1802): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() return scope` fail_compilation/retscope.d(1803): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() return scope` fail_compilation/retscope.d(1811): Error: cannot implicitly convert expression `&c.funcr` of type `int* delegate() return scope` to `int* delegate() scope` fail_compilation/retscope.d(1816): Error: cannot implicitly convert expression `&c.funcrs` of type `int* delegate() return scope` to `int* delegate() scope` --- */ class C18 { int* func(); int* funcs() scope; int* funcr() return; int* funcrs() return scope; } void foo18() { C18 c; #line 1800 typeof(&c.func) fp1 = &c.func; typeof(&c.funcs) fp2 = &c.func; // error typeof(&c.funcr) fp3 = &c.func; // error typeof(&c.funcrs) fp4 = &c.func; // error typeof(&c.func) fq1 = &c.funcs; typeof(&c.funcs) fq2 = &c.funcs; typeof(&c.funcr) fq3 = &c.funcs; typeof(&c.funcrs) fq4 = &c.funcs; typeof(&c.func) fr1 = &c.funcr; typeof(&c.funcs) fr2 = &c.funcr; // error typeof(&c.funcr) fr3 = &c.funcr; typeof(&c.funcrs) fr4 = &c.funcr; typeof(&c.func) fs1 = &c.funcrs; typeof(&c.funcs) fs2 = &c.funcrs; // error typeof(&c.funcr) fs3 = &c.funcrs; typeof(&c.funcrs) fs4 = &c.funcrs; } /*********************************************/ @safe void foo19(C)(ref C[] str) // infer 'scope' for 'str' { str = str; str = str[1 .. str.length]; } @safe void test19() { char[10] s; char[] t = s[]; foo19(t); } /********************************************/ bool foo20(const string a) @safe pure nothrow @nogc { return !a.length; } struct Result(R) { R source; bool empty() // infer 'scope' for 'this' { return foo20(source); } } @safe void test20() { scope n = Result!string("abc"); n.empty(); } /************************************************/ // https://issues.dlang.org/show_bug.cgi?id=17117 ref int foo21(return ref int s) { return s; } int fail21() { int s; return foo21(s); // Error: escaping reference to local variable s } int test21() { int s; s = foo21(s); return s; } /**********************************************/ @safe void foo22()(ref char[] s) { char[] a = s; } @safe void test22(scope char[] s) { foo22(s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope2.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `p` with longer lifetime fail_compilation/retscope2.d(107): Error: address of variable `s` assigned to `p` with longer lifetime --- */ #line 100 @safe foo1(ref char[] p, scope char[] s) { p = s; } @safe bar1(ref char* p, char s) { p = &s; } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=17123 void test200() { char[256] buffer; char[] delegate() read = () { return buffer[]; }; } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(302): Error: scope variable `a` assigned to return scope `b` --- */ #line 300 @safe int* test300(scope int* a, return scope int* b) { b = a; return b; } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(403): Error: scope variable `a` assigned to return scope `c` --- */ #line 400 @safe int* test400(scope int* a, return scope int* b) { auto c = b; // infers 'return scope' for 'c' c = a; return c; } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned --- */ #line 500 @safe int* test500(scope int* a, return scope int* b) { scope c = b; // does not infer 'return' for 'c' c = a; return c; } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `unnamed` calling retscope2.foo600 fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `unnamed` calling retscope2.foo600 fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating --- */ #line 600 @safe test600(A...)(scope A args) { foreach (i, Arg; A) { foo600(args[i]); } } @safe void foo600(int*); @safe bar600() { scope int* p; scope int* q; test600(p, q); } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(719): Error: returning `get2(s)` escapes a reference to local variable `s` fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a reference to local variable `s` --- */ #line 700 // https://issues.dlang.org/show_bug.cgi?id=17049 @safe S700* get2(return ref scope S700 _this) { return &_this; } struct S700 { @safe S700* get1() return scope { return &this; } } S700* escape700(int i) @safe { S700 s; if (i) return s.get2(); // 719 else return s.get1(); // 721 } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(804): Error: scope variable `e` may not be thrown --- */ #line 800 void foo800() { scope Exception e; throw e; } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(907): Error: address of variable `this` assigned to `p17568` with longer lifetime --- */ #line 900 int* p17568; struct T17568 { int a; void escape() @safe scope { p17568 = &a; } } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(1005): Error: scope variable `p` assigned to non-scope `this._p` fail_compilation/retscope2.d(1021): Error: scope variable `p` assigned to non-scope `c._p` fail_compilation/retscope2.d(1024): Error: scope variable `p` assigned to non-scope `d._p` --- */ #line 1000 class C17428 { void set(scope int* p) @safe { _p = p; } int* _p; } class C17428b { int* _p; } void test17428() @safe { int x; int* p = &x; scope C17428b c; c._p = p; // bad C17428b d; d._p = p; // bad } /*************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(1107): Error: scope variable `dg` may not be returned --- */ #line 1100 struct S17430 { void foo() {} } void delegate() test17430() @safe { S17430 s; auto dg = &s.foo; // infer dg as scope return dg; } /****************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(1216): Error: returning `s.foo()` escapes a reference to local variable `s` fail_compilation/retscope2.d(1233): Error: returning `t.foo()` escapes a reference to local variable `t` --- */ #line 1200 // https://issues.dlang.org/show_bug.cgi?id=17388 struct S17388 { //int* auto foo() return @safe { return &x; } int x; } @safe int* f17388() { S17388 s; return s.foo(); } struct T17388 { //int[] auto foo() return @safe { return x[]; } int[4] x; } @safe int[] g17388() { T17388 t; return t.foo(); } /****************************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope2.d(1306): Error: copying `& i` into allocated memory escapes a reference to local variable `i` --- */ #line 1300 // https://issues.dlang.org/show_bug.cgi?id=17370 void test1300() @safe { int i; auto p = new S1300(&i).oops; } struct S1300 { int* oops; // this(int* p) @safe { oops = p; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope3.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: */ /* TEST_OUTPUT: --- fail_compilation/retscope3.d(2008): Error: copying `& i` into allocated memory escapes a reference to local variable `i` fail_compilation/retscope3.d(2017): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i` --- */ #line 2000 // https://issues.dlang.org/show_bug.cgi?id=17790 @safe: int* bar1() { int i; int*[] arr = [ &i ]; return arr[0]; } struct S2000 { int* p; } S2000 bar2() { int i; S2000[] arr = [ S2000(&i) ]; return arr[0]; } void bar3(string[] u...) @safe pure nothrow @nogc { foreach (str; u) { } } void bar4() { static struct S { int* p; } S[2][10] pairs; foreach (ref pair; pairs) { } } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope3.d(3027): Error: scope variable `l` assigned to `elem` with longer lifetime --- */ #line 3000 struct List { Elem front() @safe return scope; ~this() @trusted scope; @disable this(this); void* data; } struct Elem { void* data; } List list() @trusted { return List(); } void test3000() @safe { Elem elem; { auto l = list(); // inferred as scope elem = l.front; // escapes, b/c l isn't scoped } } /**********************************************/ /* TEST_OUTPUT: --- fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to variadic parameter `u` fail_compilation/retscope3.d(4016): Error: storing reference to outer local variable `i` into allocated memory causes it to escape fail_compilation/retscope3.d(4025): Error: storing reference to stack allocated value returned by `makeSA()` into allocated memory causes it to escape --- */ #line 4000 void bar4000(int[1] u...) @safe { int[][] n = [u[]]; } void bar4001() @safe { static int i; int*[] n = [&i]; } ref int bar4002(return ref int i) @safe { void nested() { int*[] n = [&i]; } return i; } int[3] makeSA() @safe; void bar4003() @safe { int[][] a = [makeSA()[]]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope4.d ================================================ /* REQUIRED_ARGS: -de PERMUTE_ARGS: */ /* TEST_OUTPUT: --- fail_compilation/retscope4.d(3007): Deprecation: slice of static array temporary returned by `func()` assigned to longer lived variable `a` --- */ #line 3000 // https://issues.dlang.org/show_bug.cgi?id=12625 int[16] func(); void foo() { int[] a = func(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope5.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: */ /* TEST_OUTPUT: --- fail_compilation/retscope5.d(5010): Error: reference `t` assigned to `p` with longer lifetime --- */ #line 5000 // https://issues.dlang.org/show_bug.cgi?id=17725 void test() @safe { int* p; struct T { int a; } void escape(ref T t) @safe { p = &t.a; // should not compile } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/retscope6.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: */ /* TEST_OUTPUT: --- fail_compilation/retscope6.d(6007): Error: copying `& i` into allocated memory escapes a reference to local variable `i` --- */ #line 6000 // https://issues.dlang.org/show_bug.cgi?id=17795 int* test() @safe { int i; int*[][] arr = new int*[][](1); arr[0] ~= &i; return arr[0][0]; } /* TEST_OUTPUT: --- fail_compilation/retscope6.d(7034): Error: reference to local variable `i` assigned to non-scope parameter `_param_1` calling retscope6.S.emplace!(int*).emplace fail_compilation/retscope6.d(7035): Error: reference to local variable `i` assigned to non-scope parameter `_param_0` calling retscope6.S.emplace2!(int*).emplace2 fail_compilation/retscope6.d(7024): Error: scope variable `_param_2` assigned to `s` with longer lifetime fail_compilation/retscope6.d(7025): Error: scope variable `_param_2` assigned to `t` with longer lifetime fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating --- */ #line 7000 alias T = int*; struct S { T payload; static void emplace(Args...)(ref S s, Args args) @safe { s.payload = args[0]; } void emplace2(Args...)(Args args) @safe { payload = args[0]; } static void emplace3(Args...)(S s, Args args) @safe { s.payload = args[0]; } static void emplace4(Args...)(scope ref S s, scope out S t, scope Args args) @safe { s.payload = args[0]; t.payload = args[0]; } } void foo() @safe { S s; int i; s.emplace(s, &i); s.emplace2(&i); s.emplace3(s, &i); s.emplace4(s, s, &i); } /* TEST_OUTPUT: --- fail_compilation/retscope6.d(8016): Error: reference to local variable `i` assigned to non-scope parameter `s` calling retscope6.frank!().frank fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling retscope6.betty!().betty fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.betty!().betty fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.archie!().archie --- */ // https://issues.dlang.org/show_bug.cgi?id=19035 #line 8000 @safe { void escape(int*); /**********************/ void frank()(ref scope int* p, int* s) { p = s; // should error here } void testfrankly() { int* p; int i; frank(p, &i); } /**********************/ void betty()(int* p, int* q) { p = q; escape(p); } void testbetty() { int i; int j; betty(&i, &j); // should error on i and j } /**********************/ void archie()(int* p, int* q, int* r) { p = q; r = p; escape(q); } void testarchie() { int i; int j; int k; archie(&i, &j, &k); // should error on j } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/scope_class.d ================================================ /* TEST_OUTPUT: --- fail_compilation/scope_class.d(10): Error: functions cannot return `scope scope_class.C` --- */ scope class C { int i; } // Notice the use of `scope` here C increment(C c) { c.i++; return c; } void main() { scope C c = new C(); c.increment(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/skip.d ================================================ /* * REQUIRED_ARGS: -de * TEST_OUTPUT: --- fail_compilation/skip.d(21): Error: `switch` skips declaration of `with` temporary at fail_compilation/skip.d(26) fail_compilation/skip.d(43): Error: `switch` skips declaration of variable `skip.test14532.n` at fail_compilation/skip.d(45) --- */ // https://issues.dlang.org/show_bug.cgi?id=10524 struct S { int field; } void test10524() { int a = 1; S struct_with_long_name; switch( a ) { case 0: struct_with_long_name.field = 444; // ok break; with( struct_with_long_name ) { case 1: field = 555; // segfault break; } default: break; } } // https://issues.dlang.org/show_bug.cgi?id=14532 void test14532() { char ch = '!'; switch (ch) { int n = 42; case '!': assert(n == 42); break; default: } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/spell9644.d ================================================ // REQUIRED_ARGS: -o- // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/spell9644.d(27): Error: undefined identifier `b` fail_compilation/spell9644.d(28): Error: undefined identifier `xx` fail_compilation/spell9644.d(29): Error: undefined identifier `cb`, did you mean variable `ab`? fail_compilation/spell9644.d(30): Error: undefined identifier `bc`, did you mean variable `abc`? fail_compilation/spell9644.d(31): Error: undefined identifier `ccc` fail_compilation/spell9644.d(33): Error: undefined identifier `cor2`, did you mean variable `cor1`? fail_compilation/spell9644.d(34): Error: undefined identifier `pua`, did you mean variable `pub`? fail_compilation/spell9644.d(35): Error: undefined identifier `priw` --- */ import imports.spell9644a; int a; int ab; int abc; int cor1; int main() { cast(void)b; // max distance 0, no match cast(void)xx; // max distance 1, no match cast(void)cb; // max distance 1, match cast(void)bc; // max distance 1, match cast(void)ccc; // max distance 2, match cast(void)cor2; // max distance 1, match "cor1", but not cora from import (bug 13736) cast(void)pua; // max distance 1, match "pub" from import cast(void)priw; // max distance 1, match "priv" from import, but do not report (bug 5839) } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d ================================================ /* REQUIRED_ARGS: -m64 PERMUTE_ARGS: --- fail_compilation/staticarrayoverflow.d(21): Error: static array S[1879048192] size overflowed to 7516192768000 fail_compilation/staticarrayoverflow.d(21): Error: variable staticarrayoverflow.y size overflow fail_compilation/staticarrayoverflow.d(22): Error: variable staticarrayoverflow.z size of x1000ae0 exceeds max allowed size 0x100_0000 fail_compilation/staticarrayoverflow.d(23): Error: static array S[8070450532247928832] size overflowed to 0 fail_compilation/staticarrayoverflow.d(23): Error: variable staticarrayoverflow.a size overflow --- */ struct S { int[1000] x; } S[0x7000_0000] y; S[0x100_0000/(4*1000 - 1)] z; S[0x7000_0000_0000_0000] a; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/staticforeach1.d ================================================ /* TEST_OUTPUT: --- fail_compilation/staticforeach1.d(10): Error: must use labeled `break` within `static foreach` --- */ void main(){ for(;;){ static foreach(i;0..1){ break; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/staticforeach2.d ================================================ /* TEST_OUTPUT: --- fail_compilation/staticforeach2.d(10): Error: must use labeled `continue` within `static foreach` --- */ void main(){ for(;;){ static foreach(i;0..1){ continue; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/staticforeach3.d ================================================ /* TEST_OUTPUT: --- fail_compilation/staticforeach3.d(7): Error: variable `staticforeach3.__anonymous.i` conflicts with variable `staticforeach3.__anonymous.i` at fail_compilation/staticforeach3.d(7) --- */ static foreach(i,i;[0]){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/switches.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: */ /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/switches.d(105): Error: `case 2` not found --- */ #line 100 void test1(int i) { switch (i) { case 1: goto case 2; defaut: break; } } /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/switches.d(205): Error: no `case` statement following `goto case;` --- */ #line 200 void test2(int i) { switch (i) { case 1: goto case; defaut: break; } } /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/switches.d(302): Error: `switch` skips declaration of variable `switches.test3.j` at fail_compilation/switches.d(306) --- */ #line 300 void test3(int i) { switch (i) { case 1: { int j; case 2: ++j; break; } default: break; } } /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/switches.d(404): Error: `switch` skips declaration of variable `switches.test.z` at fail_compilation/switches.d(406) --- */ #line 400 // https://issues.dlang.org/show_bug.cgi?id=18858 int test(int n) { final switch(n) { int z = 5; enum e = 6; case 1: int y = 2; return y; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test1.d ================================================ fail ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test10.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test10.d(10): Error: found `else` without a corresponding `if`, `version` or `debug` statement --- */ void test(int i) { ++i; else ++i; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test11006.d ================================================ /* REQUIRED_ARGS: -main -de * TEST_OUTPUT: --- fail_compilation/test11006.d(10): Deprecation: cannot subtract pointers to different types: `void*` and `int*`. fail_compilation/test11006.d(10): while evaluating: `static assert(2L == 2L)` fail_compilation/test11006.d(11): Deprecation: cannot subtract pointers to different types: `int*` and `void*`. fail_compilation/test11006.d(11): while evaluating: `static assert(8L == 8L)` --- */ static assert(cast(void*)8 - cast(int*) 0 == 2L); static assert(cast(int*) 8 - cast(void*)0 == 8L); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test11047.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test11047.d(11): Error: value of `x` is not known at compile time fail_compilation/test11047.d(11): Error: value of `x` is not known at compile time --- */ // https://issues.dlang.org/show_bug.cgi?id=11047 int x; @(++x, ++x) void foo(){} @safe pure void test() { __traits(getAttributes, foo); __traits(getAttributes, foo)[0]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test11176.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test11176.d(12): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead --- */ // https://issues.dlang.org/show_bug.cgi?id=11176 @safe ubyte oops(ubyte[] b) { return *b.ptr; } @safe ubyte oops(ubyte[3] b) { return *b.ptr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test12228.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/test12228.d(14): Deprecation: Using `this` as a type is deprecated. Use `typeof(this)` instead fail_compilation/test12228.d(19): Error: no property `x` for type `object.Object` fail_compilation/test12228.d(20): Deprecation: Using `super` as a type is deprecated. Use `typeof(super)` instead fail_compilation/test12228.d(21): Deprecation: Using `super` as a type is deprecated. Use `typeof(super)` instead --- */ class C { shared(this) x; } class D : C { alias x = typeof(super).x; shared(super) a; super b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test12385.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test12385.d(29): Error: cannot modify `immutable` expression `BundledState("bla", 3).x` --- */ // https://issues.dlang.org/show_bug.cgi?id=12385 class BundledState { string m_State; int x = 3; this(string state) immutable { m_State = state; } } enum States : immutable(BundledState) { unbundled = new immutable BundledState("bla"), } void main() { States.unbundled.x = 6; // Modifies x. } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test12558.d ================================================ // REQUIRED_ARGS: /* TEST_OUTPUT: --- fail_compilation/test12558.d(18): Error: `catch` statement without an exception specification is deprecated fail_compilation/test12558.d(18): use `catch(Throwable)` for old behavior fail_compilation/test12558.d(23): Error: `catch` statement without an exception specification is deprecated fail_compilation/test12558.d(23): use `catch(Throwable)` for old behavior --- */ void main() { auto handler = () { }; try { assert(0); } catch handler(); try { assert(0); } catch { handler(); } // ensure diagnostics are not emitted for verioned-out blocks version (none) { try { assert(0); } catch // should not emit diagnostics handler(); try { assert(0); } catch { // ditto handler(); } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test12822.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test12822.d(13): Error: cannot modify delegate pointer in `@safe` code `dg.ptr` fail_compilation/test12822.d(14): Error: `dg.funcptr` cannot be used in `@safe` code --- */ // https://issues.dlang.org/show_bug.cgi?id=12822 void test2(int delegate() dg) @safe { static int i; dg.ptr = &i; dg.funcptr = &func; } int func(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test12979.d ================================================ // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/test12979.d(13): Error: `const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks --- */ void foo() { version(GNU) { asm const shared { ""; } } else { asm const shared { ret; } } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test13152.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test13152.d(11): Error: undefined identifier `x` --- */ import imports.test13152a; void main() { auto y = x; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test13536.d ================================================ /* PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test13536.d(24): Error: field `U.sysDg` cannot access pointers in `@safe` code that overlap other fields fail_compilation/test13536.d(24): Error: address of variable `s` assigned to `u` with longer lifetime fail_compilation/test13536.d(25): Error: field `U.safeDg` cannot access pointers in `@safe` code that overlap other fields --- */ // https://issues.dlang.org/show_bug.cgi?id=13536 struct S { void sysMethod() @system {} } void fun() @safe { union U { void delegate() @system sysDg; void delegate() @safe safeDg; } U u; S s; u.sysDg = &s.sysMethod; u.safeDg(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test13537.d ================================================ /* PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test13537.d(32): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes fail_compilation/test13537.d(33): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes fail_compilation/test13537.d(34): Error: field `U.z` cannot access pointers in `@safe` code that overlap other fields fail_compilation/test13537.d(35): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes --- */ // https://issues.dlang.org/show_bug.cgi?id=13537 union U { immutable int x; int y; int* z; } union V { immutable int x; const int y; } void fun() @safe { U u; // errors u.y = 1; int* p = &u.y; int** q = &u.z; abc(u.y); // read access is allowed int a = u.x; a = u.y; def(u.y); // Overlapping const/immutable is allowed auto v = V(1); assert(v.y == 1); } void gun() @system { U u; // allowed because system code u.y = 1; int* p = &u.y; int** q = &u.z; abc(u.y); } @safe: void abc(ref int x) { } void def(const ref int x) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test13786.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test13786.d(14): Error: debug `123` level declaration must be at module level fail_compilation/test13786.d(15): Error: debug `abc` declaration must be at module level fail_compilation/test13786.d(16): Error: version `123` level declaration must be at module level fail_compilation/test13786.d(17): Error: version `abc` declaration must be at module level fail_compilation/test13786.d(20): Error: template instance `test13786.T!()` error instantiating --- */ template T() { debug = 123; debug = abc; version = 123; version = abc; } alias X = T!(); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test13867.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test13867.d(12): Error: function `void test13867.X.blah()` does not override any function, did you mean to override `extern (C++) void test13867.Base.blah()`? fail_compilation/test13867.d(19): Error: function `void test13867.Z.blah()` does not override any function, did you mean to override `extern (C++) void test13867.Base.blah()`? --- */ extern (C++) class Base { void blah() {} } class X : Base { override void blah();//Error } extern (C++) class Y : Base { override void blah(){} } class Z : Base { alias blah = typeof(super).blah; override void blah(){}//Error } class O : Base { extern (C++) override void blah(){} } extern (C++) class OK : Base { alias blah = typeof(super).blah; override void blah(){} } void main() { scope b = new Base(); b.blah(); scope x = new X(); x.blah(); scope y = new Y(); y.blah(); scope o = new O(); o.blah(); scope z = new Z(); z.blah(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test14238.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test14238.d(21): Error: scope variable `fn` may not be returned fail_compilation/test14238.d(29): Error: escaping reference to stack allocated value returned by `&baz` --- */ // https://issues.dlang.org/show_bug.cgi?id=14238 @safe: alias Fn = ref int delegate() return; ref int foo(return scope Fn fn) { return fn(); // Ok } ref int foo2(scope Fn fn) { return fn(); // Error } ref int bar() { int x; ref int baz() { return x; } return foo(&baz); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test143.d ================================================ // REQUIRED_ARGS: -de module test143; // https://issues.dlang.org/show_bug.cgi?id=143 import imports.test143; void bar(int) { } void foo() { bar(x); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test14496.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test14496.d(21): Error: variable `test14496.foo.f` `void` initializers for pointers not allowed in safe functions fail_compilation/test14496.d(24): Error: variable `test14496.foo.Bar.foo` `void` initializers for pointers not allowed in safe functions fail_compilation/test14496.d(28): Error: variable `test14496.foo.Baz.x` `void` initializers for pointers not allowed in safe functions fail_compilation/test14496.d(48): Error: variable `test14496.sinister.bar` `void` initializers for pointers not allowed in safe functions fail_compilation/test14496.d(49): Error: variable `test14496.sinister.baz` `void` initializers for pointers not allowed in safe functions --- */ // https://issues.dlang.org/show_bug.cgi?id=14496 @safe void foo() { struct Foo { int* indirection1; Object indirection2; string[] indirection3; } Foo f = void; struct Bar { Foo foo = void; } struct Baz { int* x = void; } } struct Foo { int* indirection1; Object indirection2; string[] indirection3; } struct Bar { Foo foo = void; } struct Baz { int* x = void; } @safe void sinister() { Bar bar; Baz baz; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test14538.d ================================================ // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/test14538.d(19): Error: cannot implicitly convert expression `x ? cast(uint)this.fCells[x].code : 32u` of type `uint` to `Cell` --- */ struct Cell { dchar code; alias code this; } struct Row { Cell[] fCells; Cell opIndex(size_t x) { return x ? fCells[x] : ' '; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15191.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test15191.d(17): Error: cannot take address of `ref return` of `foo()` in `@safe` function `bar` --- */ // https://issues.dlang.org/show_bug.cgi?id=15191 ref int foo(return ref int s)@safe { return s; } int* bar(return ref int s) @safe { return &foo(s); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15306.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test15306.d(17): Error: `immutable` delegate `test15306.main.__dgliteral1` cannot access mutable data `i` fail_compilation/test15306.d(21): Error: `shared` delegate `test15306.main.__dgliteral2` cannot access non-shared data `p` --- */ // https://issues.dlang.org/show_bug.cgi?id=15306 void main() { // immutable cannot access mutable int i = 42; auto dg1 = delegate void() immutable { auto inner = i; }; // shared cannot access unshared int* p = &i; auto dg2 = delegate int() shared { return *p; }; assert(dg2() == i); // unshared can access shared shared j = 43; shared int* q = &j; auto dg3 = delegate int() { return *q; }; assert(dg2() == j); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15373.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test15373.d(21): Error: Runtime type information is not supported for `extern(C++)` classes --- */ // https://issues.dlang.org/show_bug.cgi?id=15373 // Using `typeid` on an `extern(C++) class` type is ok as it is evaluated at compile-time // See test/runnable/test15373.d // Using `typeid` on an `extern(C++) class` instance is not ok because `extern(C++) class` // instances are not rooted in `Object` extern(C++) class C { } void foo() { C c = new C(); auto ti = typeid(c); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15399.d ================================================ /* https://issues.dlang.org/show_bug.cgi?id=15399 --- fail_compilation/test15399.d(31): Error: writing to misaligned pointer in field S1.ptr is not @safe fail_compilation/test15399.d(32): Error: writing to misaligned pointer in field S2.ptr is not @safe fail_compilation/test15399.d(33): Error: taking address of misaligned pointer in field S1.ptr is not @safe fail_compilation/test15399.d(34): Error: taking address of misaligned pointer in field S2.ptr is not @safe fail_compilation/test15399.d(35): Error: 'ref' of misaligned pointer in field S1.ptr is not @safe fail_compilation/test15399.d(36): Error: 'ref' of misaligned pointer in field S2.ptr is not @safe fail_compilation/test15399.d(37): Error: 'out' of misaligned pointer in field S1.ptr is not @safe fail_compilation/test15399.d(38): Error: 'out' of misaligned pointer in field S2.ptr is not @safe --- */ struct S1 { char c; align (1) int* ptr; } align (1) struct S2 { int* ptr; } @safe void test(S1* s1, S2* s2) { int* p = s1.ptr; p = s2.ptr; s1.ptr = null; s2.ptr = null; int** pp = &s1.ptr; pp = &s2.ptr; bar(s1.ptr); bar(s2.ptr); sinister(s1.ptr); sinister(s2.ptr); cbar(s1.ptr); cbar(s2.ptr); } @safe void bar(ref int*); @safe void cbar(ref const int*); @safe void sinister(out int*); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15544.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test15544.d(21): Error: reference to local `this` assigned to non-scope `_del` in @safe code fail_compilation/test15544.d(23): Error: reference to local `this` assigned to non-scope `_del` in @safe code --- */ // https://issues.dlang.org/show_bug.cgi?id=15544 void delegate() @safe _del; struct S { int x = 42; @safe void test() { void foo() { assert(x == 42); } _del = &foo; _del = { assert(x == 42); }; } } /* TEST_OUTPUT: --- fail_compilation/test15544.d(47): Error: reference to local `y` assigned to non-scope `dg` in @safe code --- */ int delegate() dg; void testClosure1() { int* x; int bar() { return *x; } dg = &bar; } @safe void testClosure2() { scope int* y; int bar() { return *y; } dg = &bar; // Error auto dg2 = &bar; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15660.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])` --- */ // https://issues.dlang.org/show_bug.cgi?id=15660 int[] f(ref void[] m) pure { auto result = new int[5]; m = result; return result; } void main() { void[] v; immutable x = f(v); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15672.d ================================================ /* * TEST_OUTPUT: --- fail_compilation/test15672.d(15): Error: cast from `void[]` to `byte[]` not allowed in safe code fail_compilation/test15672.d(25): Error: cast from `void*` to `byte*` not allowed in safe code --- */ // https://issues.dlang.org/show_bug.cgi?id=15672 alias byte T; alias const(byte) CT; @safe T[] test1(void[] a) { return cast(T[])a; } @safe CT[] test2(void[] a) { return cast(CT[])a; } @safe T* test3(void* a) { return cast(T*)a; } @safe CT* test4(void* a) { return cast(CT*)a; } @safe T[] test5() { return cast(T[])[]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15703.d ================================================ /* REQUIRED_ARGS: -m32 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test15703.d(17): Error: cast from `Object[]` to `uint[]` not allowed in safe code fail_compilation/test15703.d(19): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code fail_compilation/test15703.d(22): Error: cast from `uint[]` to `Object[]` not allowed in safe code --- */ // https://issues.dlang.org/show_bug.cgi?id=15703 void test() @safe { auto objs = [ new Object() ]; auto longs = cast(size_t[]) objs; // error auto longc = cast(const(size_t)[]) objs; // ok auto longp = cast(const(size_t)*) objs[0]; // error size_t[] al; objs = cast(Object[]) al; // error auto am = cast(int[])[]; } void test2() @safe { const(ubyte)[] a; auto b = cast(const(uint[])) a; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15704.d ================================================ /* * TEST_OUTPUT: --- fail_compilation/test15704.d(15): Error: cannot copy `void[]` to `void[]` in `@safe` code --- */ // https://issues.dlang.org/show_bug.cgi?id=15704 void main() @safe { Object[] objs = [ new Object() ]; void[] arr1 = objs; void[] arr2 = [ 123, 345, 567 ]; arr1[] = arr2[]; // overwrites pointers with arbitrary ints } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15785.d ================================================ // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/test15785.d(17): Deprecation: `imports.test15785.Base.foo` is not visible from module `test15785` fail_compilation/test15785.d(17): Error: class `test15785.Derived` member `foo` is not accessible fail_compilation/test15785.d(18): Deprecation: `imports.test15785.Base.bar` is not visible from module `test15785` fail_compilation/test15785.d(18): Error: class `test15785.Derived` member `bar` is not accessible --- */ import imports.test15785; class Derived : Base { void test() { super.foo(); bar(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15785b.d ================================================ // REQUIRED_ARGS: -de // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/test15785b.d(15): Deprecation: `imports.test15785.Base.T` is not visible from module `test15785b` fail_compilation/test15785b.d(16): Deprecation: `imports.test15785.Base.T` is not visible from module `test15785b` fail_compilation/test15785b.d(17): Deprecation: `imports.test15785.IBase2.T` is not visible from module `test15785b` --- */ import imports.test15785; class Derived : Base, IBase2 { typeof(super).T t; Base.T t2; IBase2.T t3; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15897.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/test15897.d(18): Deprecation: `test15897.Animal.create` is not visible from class `Cat` --- */ module test15897; import imports.test15897; class Animal { private void create() {} } void foo(Cat cat) { cat.create(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test15989.d ================================================ /* PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test15989.d(40): Error: variable `test15989.main.ctRegex` : Unable to initialize enum with class or pointer to struct. Use static const variable instead. fail_compilation/test15989.d(49): Error: variable `test15989.test.c` : Unable to initialize enum with class or pointer to struct. Use static const variable instead. fail_compilation/test15989.d(50): Error: cannot use non-constant CTFE pointer in an initializer `&[3][0]` --- */ // https://issues.dlang.org/show_bug.cgi?id=15989 import core.stdc.stdio; interface Kickstart{ bool foo( int ); } class ShiftOr : Kickstart { bool foo( int i ) { printf("i = %d\n", i); return false; } } struct Regex { Kickstart kickstart; } Regex regex() { return Regex(new ShiftOr()); } void main() { enum ctRegex = regex(); Regex r = ctRegex; r.kickstart.foo(7); } class C { } void test() { enum c = new C(); enum pi = new int(3); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16095.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test16095.d(20): Error: `shared` method `test16095.C.ping` is not callable using a non-shared `a` fail_compilation/test16095.d(30): Error: `shared` method `test16095.S.ping` is not callable using a non-shared `*a` fail_compilation/test16095.d(43): Error: mutable method `test16095.Foo.flip` is not callable using a `immutable` `foo` --- */ // https://issues.dlang.org/show_bug.cgi?id=16095 class C { void ping() shared; } void test1(C a) { (&a.ping)(); // error } struct S { void ping() shared; } void test2(S* a) { (&a.ping)(); // error } struct Foo { bool flag; void flip() { flag = true; } } void test3() { immutable Foo foo; (&foo.flip)(); // error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16116.d ================================================ /* REQUIRED_ARGS: -m64 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test16116.d(15): Error: incompatible types for `(v) * (i)`: `__vector(short[8])` and `int` --- */ // https://issues.dlang.org/show_bug.cgi?id=16116 void foo() { __vector(short[8]) v; int i; v = v * i; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16188.d ================================================ /* PERMUTE_ARGS: */ // https://issues.dlang.org/show_bug.cgi?id=16188 /* This produces the message: * Error: no property 'name' for type 'Where' * when the actual error is 'getMember is undefined'. * This happens because errors are gagged when opDispatch() is compiled, * I don't understand why. */ void where() { Where().name; } struct Where { void opDispatch(string name)() { alias FieldType = typeof(getMember); WhereField!FieldType; } } struct WhereField(FieldType) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16193.d ================================================ /* REQUIRED_ARGS: -dip1000 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test16193.d(39): Error: function `test16193.abc` is `@nogc` yet allocates closures with the GC fail_compilation/test16193.d(41): test16193.abc.__foreachbody1 closes over variable x at fail_compilation/test16193.d(40) --- */ //fail_compilation/test16193.d(22): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` //fail_compilation/test16193.d(34): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` //fail_compilation/test16193.d(41): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` // https://issues.dlang.org/show_bug.cgi?id=16193 struct S { int opApply(int delegate(int) dg) @nogc; } void foo() { int x = 0; foreach(i; S.init) { x++; } } struct T { int opApply(scope int delegate(int) dg) @nogc; } void bar() @nogc { int x = 0; foreach(i; T.init) { x++; } } void abc() @nogc { int x = 0; foreach(i; S.init) { x++; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16195.d ================================================ /* * TEST_OUTPUT: --- fail_compilation/test16195.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead. fail_compilation/test16195.d(14): Error: `delete p` is not `@safe` but is used in `@safe` function `test` --- */ // https://issues.dlang.org/show_bug.cgi?id=16195 @safe pure nothrow @nogc void test(int* p) { delete p; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16228.d ================================================ /* REQUIRED_ARGS: -dip25 TEST_OUTPUT: --- fail_compilation/test16228.d(23): Error: function `test16228.S.bar` `static` member has no `this` to which `return` can apply --- */ // https://issues.dlang.org/show_bug.cgi?id=16228 int* wrap ( return ref int input ) { return &input; } struct S { int x; int foo() return { return 3; } static ref int bar() return { return x; } } // https://issues.dlang.org/show_bug.cgi?id=18963 T Identity(T)(return T t) { return t; } void bar(int i, void* p) { Identity(p); Identity(i); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16365.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test16365.d(22): Error: `this` reference necessary to take address of member `f1` in `@safe` function `main` fail_compilation/test16365.d(24): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe` fail_compilation/test16365.d(28): Error: address of variable `s` assigned to `dg` with longer lifetime fail_compilation/test16365.d(29): Error: `dg.funcptr` cannot be used in `@safe` code --- */ // https://issues.dlang.org/show_bug.cgi?id=16365 struct S { void f1() @safe { } } void main() @safe { void function() @safe f; f = &S.f1; void f2() @safe { } f = &f2; void delegate() @safe dg; S s; dg = &s.f1; f = dg.funcptr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16381.d ================================================ /* REQUIRED_ARGS: -m64 PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/test16381.d(16): Error: `foo()` is not an lvalue and cannot be modified --- */ // https://issues.dlang.org/show_bug.cgi?id=16381 __vector(float[4]) foo(); void bar() { float g = foo().ptr[0]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16523.d ================================================ // REQUIRED_ARGS: -de /* TEST_OUTPUT: --- fail_compilation/test16523.d(13): Deprecation: `case` variables have to be `const` or `immutable` --- */ void test(int a, int b) { switch (a) { case b: return; default: assert(0); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16589.d ================================================ /* PERMUTE_ARGS: REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`, perhaps annotate with `return` fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`, perhaps annotate with `return` fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to parameter `s`, perhaps annotate with `return` --- */ // https://issues.dlang.org/show_bug.cgi?id=16589 struct S { int data; @safe int* access1() { return &data; } @safe S* access2() { return &this; } } @safe int* access3(ref S s) { return &s.data; } @safe S* access4(ref S s) { return &s; } @safe int* access5(S s) { return &s.data; } @safe S* access6(S s) { return &s; } class C { int data; @safe int* access7() { return &data; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test16694.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test16694.d(8): Error: cannot take address of imported symbol `bar` at compile time --- */ export void bar(); auto barptr = &bar; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17096.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17096.d(28): Error: expected 1 arguments for `isPOD` but had 2 fail_compilation/test17096.d(29): Error: expected 1 arguments for `isNested` but had 2 fail_compilation/test17096.d(30): Error: expected 1 arguments for `isVirtualFunction` but had 2 fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualMethod` but had 2 fail_compilation/test17096.d(32): Error: expected 1 arguments for `isAbstractFunction` but had 2 fail_compilation/test17096.d(33): Error: expected 1 arguments for `isFinalFunction` but had 2 fail_compilation/test17096.d(34): Error: expected 1 arguments for `isOverrideFunction` but had 2 fail_compilation/test17096.d(35): Error: expected 1 arguments for `isStaticFunction` but had 2 fail_compilation/test17096.d(36): Error: expected 1 arguments for `isRef` but had 2 fail_compilation/test17096.d(37): Error: expected 1 arguments for `isOut` but had 2 fail_compilation/test17096.d(38): Error: expected 1 arguments for `isLazy` but had 2 fail_compilation/test17096.d(39): Error: expected 1 arguments for `identifier` but had 2 fail_compilation/test17096.d(40): Error: expected 1 arguments for `getProtection` but had 2 fail_compilation/test17096.d(41): Error: expected 1 arguments for `parent` but had 2 fail_compilation/test17096.d(42): Error: expected 1 arguments for `classInstanceSize` but had 2 fail_compilation/test17096.d(43): Error: expected 1 arguments for `allMembers` but had 2 fail_compilation/test17096.d(44): Error: expected 1 arguments for `derivedMembers` but had 2 fail_compilation/test17096.d(45): Error: expected 1 arguments for `getAliasThis` but had 2 fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAttributes` but had 2 fail_compilation/test17096.d(47): Error: expected 1 arguments for `getFunctionAttributes` but had 2 fail_compilation/test17096.d(48): Error: expected 1 arguments for `getUnitTests` but had 2 fail_compilation/test17096.d(49): Error: expected 1 arguments for `getVirtualIndex` but had 2 fail_compilation/test17096.d(50): Error: a single type expected for trait pointerBitmap --- */ enum b03 = __traits(isPOD, 1, 2); enum b04 = __traits(isNested, 1, 2); enum b05 = __traits(isVirtualFunction, 1, 2); enum b06 = __traits(isVirtualMethod, 1, 2); enum b07 = __traits(isAbstractFunction, 1, 2); enum b08 = __traits(isFinalFunction, 1, 2); enum b09 = __traits(isOverrideFunction, 1, 2); enum b10 = __traits(isStaticFunction, 1, 2); enum b11 = __traits(isRef, 1, 2); enum b12 = __traits(isOut, 1, 2); enum b13 = __traits(isLazy, 1, 2); enum b14 = __traits(identifier, 1, 2); enum b15 = __traits(getProtection, 1, 2); enum b16 = __traits(parent, 1, 2); enum b17 = __traits(classInstanceSize, 1, 2); enum b18 = __traits(allMembers, 1, 2); enum b19 = __traits(derivedMembers, 1, 2); enum b20 = __traits(getAliasThis, 1, 2); enum b21 = __traits(getAttributes, 1, 2); enum b22 = __traits(getFunctionAttributes, 1, 2); enum b23 = __traits(getUnitTests, 1, 2); enum b24 = __traits(getVirtualIndex, 1, 2); enum b25 = __traits(getPointerBitmap, 1, 2); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17284.d ================================================ /* REQUIRED_ARGS: TEST_OUTPUT: --- fail_compilation/test17284.d(16): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields pure nothrow @safe void(U t) --- */ // https://issues.dlang.org/show_bug.cgi?id=17284 class C { } union U { C c; int i; } @safe void func(T)(T t) { t.c = new C; } pragma(msg, typeof(func!U)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17307.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17307.d(9): Error: anonymous struct can only be a part of an aggregate, not module `test17307` --- * https://issues.dlang.org/show_bug.cgi?id=17307 */ struct { enum bitsPerWord = size_t; } void main() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17380.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17380.d(12): Error: undefined identifier `ThisTypeDoesNotExistsAndCrahesTheCompiler` --- * https://issues.dlang.org/show_bug.cgi?id=17380 */ struct Int128 { Uint128 opCast() { return ThisTypeDoesNotExistsAndCrahesTheCompiler; } alias opCast this; } struct Uint128 { Int128 opCast() { return Int128.init; } alias opCast this; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17380spec.d ================================================ /* REQUIRED_ARGS: -verrors=spec TEST_OUTPUT: --- (spec:1) fail_compilation/test17380spec.d(14): Error: cannot resolve identifier `ThisTypeDoesNotExistAndCrashesTheCompiler` (spec:1) fail_compilation/test17380spec.d(14): Error: no property `ThisTypeDoesNotExistAndCrashesTheCompiler` for type `Uint128` fail_compilation/test17380spec.d(14): Error: undefined identifier `ThisTypeDoesNotExistAndCrashesTheCompiler` --- */ struct Int128 { Uint128 opCast() { return ThisTypeDoesNotExistAndCrashesTheCompiler; } alias opCast this; } struct Uint128 { Int128 opCast() { return Int128.init; } alias opCast this; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17422.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned --- */ struct RC { Object get() return scope @trusted { return cast(Object) &store[0]; } private: ubyte[__traits(classInstanceSize, Object)] store; } Object test() @safe { RC rc; auto p = rc.get; // p must be inferred as scope variable, works for int* return p; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17423.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` calling test17423.Bar.opApply --- */ // https://issues.dlang.org/show_bug.cgi?id=17423 struct Bar { int delegate(int) @safe myDlg; auto opApply(int delegate(int) @safe dlg) @safe { myDlg = dlg; return 0; } } struct Foo { Bar o; int i = 3; this(int x) @safe { foreach(_; o) { i = 0; } i = x; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17425.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17425.d(24): Error: parameter index must be in range 0..4 not 4 fail_compilation/test17425.d(27): Error: first argument to `__traits(getParameterStorageClasses, i, 4)` is not a function fail_compilation/test17425.d(29): Error: expression expected as second argument of `__traits(getParameterStorageClasses, foo, int)` fail_compilation/test17425.d(31): Error: expected 2 arguments for `getParameterStorageClasses` but had 3 --- */ // https://issues.dlang.org/show_bug.cgi?id=17425 ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); //pragma(msg, __traits(getParameterStorageClasses, foo, 0)); static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); //pragma(msg, __traits(getParameterStorageClasses, foo, 1)); static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); enum a1 = __traits(getParameterStorageClasses, foo, 4); int i; enum a2 = __traits(getParameterStorageClasses, i, 4); enum a3 = __traits(getParameterStorageClasses, foo, int); enum a4 = __traits(getParameterStorageClasses, foo, 0, 1); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17450.d ================================================ /* REQUIRED_ARGS: -dip1000 -dip25 TEST_OUTPUT: --- fail_compilation/test17450.d(15): Error: returning `&s.bar` escapes a reference to parameter `s`, perhaps annotate with `return` fail_compilation/test17450.d(18): Error: returning `&this.bar` escapes a reference to parameter `this`, perhaps annotate with `return` --- */ // https://issues.dlang.org/show_bug.cgi?id=17450 alias dg_t = void delegate(); struct S { @safe dg_t foo1(ref S s) { return &s.bar; } @safe dg_t foo2() { return &bar; } @safe dg_t foo3(return ref S s) { return &s.bar; } @safe dg_t foo4() return { return &bar; } @safe void bar(); } /* TEST_OUTPUT: --- fail_compilation/test17450.d(103): Error: scope variable `c` may not be returned fail_compilation/test17450.d(106): Error: scope variable `this` may not be returned --- */ // https://issues.dlang.org/show_bug.cgi?id=17450 #line 100 class C { @safe dg_t foo1(scope C c) { return &c.bar; } @safe dg_t foo2() scope { return &bar; } @safe dg_t foo3(return scope C c) { return &c.bar; } @safe dg_t foo4() return scope { return &bar; } @safe void bar(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17451.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17451.d(22): Error: undefined identifier `allocator` fail_compilation/test17451.d(23): Error: `false` has no effect fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` size of type `ThreadSlot` is invalid fail_compilation/test17451.d(44): Error: template instance `test17451.HashMap!(ThreadSlot)` error instantiating --- */ // https://issues.dlang.org/show_bug.cgi?id=17451 interface ManualEvent {} interface EventDriver { ManualEvent createManualEvent() ; } struct ArraySet(Key) { ~this() { try allocator; catch false; // should never happen } } struct HashMap(TValue) { alias Value = TValue; static if ({ Value v; }) {} } struct Task {} class Libevent2Driver : EventDriver { Libevent2ManualEvent createManualEvent() {} } struct ThreadSlot { ArraySet!Task tasks; } class Libevent2ManualEvent { HashMap!ThreadSlot m_waiters; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17586.d ================================================ /* REQUIRED_ARGS: -o- -de TEST_OUTPUT: --- fail_compilation/test17586.d(13): Deprecation: `test17586.D.foo` is overriding the deprecated method `test17586.C.foo` --- */ class C{ deprecated void foo(){} } class D : C{ override void foo(){} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17868.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/test17868.d(10): Error: pragma `crt_constructor` takes no argument fail_compilation/test17868.d(11): Error: pragma `crt_constructor` takes no argument fail_compilation/test17868.d(12): Error: pragma `crt_constructor` takes no argument fail_compilation/test17868.d(13): Error: pragma `crt_constructor` takes no argument ---- */ pragma(crt_constructor, ctfe()) pragma(crt_constructor, 1.5f) pragma(crt_constructor, "foobar") pragma(crt_constructor, S()) void foo() { } int ctfe() { __gshared int val; return val; } struct S {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17868b.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/test17868b.d(10): Error: function `test17868b.foo` must be `extern(C)` for `pragma(crt_constructor)` fail_compilation/test17868b.d(14): Error: function `test17868b.bar` must be `extern(C)` for `pragma(crt_constructor)` fail_compilation/test17868b.d(9): Error: pragma `crt_constructor` can only apply to a single declaration ---- */ pragma(crt_constructor): void foo() { } void bar() { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17892.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test17892.d(27): Error: returning `s.pointer1()` escapes a reference to local variable `s` fail_compilation/test17892.d(29): Error: returning `s.pointer2()` escapes a reference to local variable `s` fail_compilation/test17892.d(31): Error: returning `s.pointer3()` escapes a reference to local variable `s` --- */ // https://issues.dlang.org/show_bug.cgi?id=17892 struct S { @safe: int x; int[1] y; auto pointer1() return { return &x; } auto pointer2() return { return &y[0]; } auto pointer3() return { return &y[0..1][0]; } } @safe int* testPointer(int b) { S s; if (b == 1) return s.pointer1(); else if (b == 2) return s.pointer2(); else return s.pointer3(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17908a.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17908a.d(10): Error: function `test17908a.foo` cannot be used because it is annotated with `@disable` --- */ @disable void foo(); @disable void foo(int) {} alias g = foo; void main() { g(10); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17908b.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test17908b.d(13): Error: function `test17908b.foobar` cannot be used because it is annotated with `@disable` --- */ void foobar() {} @disable void foobar(int) {} alias i = foobar; void main() { i(10); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test17959.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test17959.d(18): Error: scope variable `this` assigned to non-scope `this.escape` fail_compilation/test17959.d(19): Error: scope variable `this` assigned to non-scope `this.f` --- */ // https://issues.dlang.org/show_bug.cgi?id=17959 class Foo { void delegate () @safe escape; Foo f; void escfoo() @safe scope { this.escape = &this.escfoo; f = this; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18130.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test18130.d(8): Error: variable `test18130.foo.v` Zero-length `out` parameters are not allowed. --- */ // https://issues.dlang.org/show_bug.cgi?id=18130 void foo(out byte[0] v) { } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18282.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test18282.d(25): Error: scope variable `aa` may not be returned fail_compilation/test18282.d(34): Error: copying `& i` into allocated memory escapes a reference to local variable `i` fail_compilation/test18282.d(35): Error: copying `& i` into allocated memory escapes a reference to local variable `i` fail_compilation/test18282.d(36): Error: scope variable `staa` may not be returned fail_compilation/test18282.d(44): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i` fail_compilation/test18282.d(53): Error: copying `& i` into allocated memory escapes a reference to local variable `i` fail_compilation/test18282.d(53): Error: copying `& c` into allocated memory escapes a reference to local variable `c` --- */ // https://issues.dlang.org/show_bug.cgi?id=18282 string* f() @safe { scope string*[] ls; return ls[0]; } int* g() @safe { scope int*[3] aa; return aa[0]; } @safe: auto bar1() { int i = void; int*[1] staa = [ &i ]; auto dyna = [ &i ]; int*[ ] dynb = [ &i ]; return staa[0]; } struct S2000 { int* p; } S2000 bar2() { int i; S2000[] arr = [ S2000(&i) ]; return arr[0]; } void bar2() { int i; char c; char*[int*] aa = [ &i : &c ]; } /****************************** TEST_OUTPUT: --- fail_compilation/test18282.d(1007): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` fail_compilation/test18282.d(1008): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` fail_compilation/test18282.d(1009): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` fail_compilation/test18282.d(1016): Error: copying `&this` into allocated memory escapes a reference to parameter variable `this` --- */ #line 1000 // https://issues.dlang.org/show_bug.cgi?id=18282 void test18282() @safe { string foo = "foo"; scope string*[] ls; ls = ls ~ &foo; ls = &foo ~ ls; ls ~= &foo; } struct S { auto fun() { arr ~= &this; } S*[] arr; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18312.d ================================================ /* REQUIRED_ARGS: -betterC TEST_OUTPUT: --- fail_compilation/test18312.d(14): Error: array concatenation of expression `"[" ~ s ~ "]"` requires the GC which is not available with -betterC --- */ // https://issues.dlang.org/show_bug.cgi?id=18312 extern (C) void main() { scope string s; s = "[" ~ s ~ "]"; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18484.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test18484.d(19): Error: returning `x.bar()` escapes a reference to local variable `x` fail_compilation/test18484.d(24): Error: escaping reference to stack allocated value returned by `S(0)` --- */ // https://issues.dlang.org/show_bug.cgi?id=18484 struct S { int* bar() return; int i; } int* test1() { auto x = S(); return x.bar(); // error } int* test2() { return S().bar(); // error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18554.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test18554.d(15): Error: struct `imp18554.S` member `i` is not accessible from `@safe` code --- */ // https://issues.dlang.org/show_bug.cgi?id=18554 import imports.imp18554; void test1() @safe { S s; s.tupleof[0] = 1; } void test2() { S s; s.tupleof[0] = 1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18597.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test18597.d(24): Error: field `Unaligned.p` cannot modify misaligned pointers in `@safe` code fail_compilation/test18597.d(25): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code fail_compilation/test18597.d(26): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code --- */ // https://issues.dlang.org/show_bug.cgi?id=18597 @safe: align(1) struct Unaligned { align(1): ubyte filler; int* p; } void test() { Unaligned u; u.p = new int; Unaligned v = Unaligned(0, new int); Unaligned w = { p : new int }; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18607.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test18607.d(10): Error: function `test18607.test!int.test` no `return exp;` or `assert(0);` at end of function & test --- */ // https://issues.dlang.org/show_bug.cgi?id=18607 int* test(T...)() pure @safe { L:foreach(_; T) { continue L; return null; } } pragma(msg, &test!(int)); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18644.d ================================================ /* REQUIRED_ARGS: -dip1000 TEST_OUTPUT: --- fail_compilation/test18644.d(15): Error: storing reference to stack allocated value returned by `foo()` into allocated memory causes it to escape fail_compilation/test18644.d(16): Error: escaping reference to stack allocated value returned by `foo()` fail_compilation/test18644.d(22): Error: escaping reference to stack allocated value returned by `foo()` --- */ // https://issues.dlang.org/show_bug.cgi?id=18644 @safe int* test1() { int i; int* foo() { return &i; } int*[] b = [foo()]; return foo(); } @safe ref int test2() { int i; ref int foo() { return i; } return foo(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18708.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test18708.d(24): Error: one path skips field `s` fail_compilation/test18708.d(29): Error: one path skips field `s` fail_compilation/test18708.d(34): Error: one path skips field `s` fail_compilation/test18708.d(39): Error: one path skips field `s` --- */ // https://issues.dlang.org/show_bug.cgi?id=18708 struct S { int y; @disable this(); } class C { S s; this(S t) { if (bar(s = t)) foo(); // OK } this(S t, int i) { i || bar(s = t); } this(S t, int i, int j) { i && bar(s = t); } this(S t, int i, long j) { i ? bar(s = t) : i; } this(S t, int i, byte j) { i ? i : bar(s = t); } } int bar(S s); int foo(); /***********************************/ class E : Exception { this(string msg, int line = 0, int pos = 0) pure nothrow @safe { if (line) super("hello"); else super(msg); } this(string msg, string file, size_t line) pure nothrow @safe { super(msg, file, line); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test18736.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test18736.d(21): Error: constructor calls not allowed in loops or after labels --- */ // https://issues.dlang.org/show_bug.cgi?id=18736 class A { this(char c) { } this(int i) { switch (i) { case 1: break; case 2: .. case 4: break; default: break; } this('c'); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test19112.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test19112.d(13): Error: cannot implicitly convert expression `[123, 456]` of type `int[]` to `int[1]` fail_compilation/test19112.d(15): Error: cannot implicitly convert expression `a` of type `int[]` to `int[1]` --- */ // https://issues.dlang.org/show_bug.cgi?id=19112 void main() { int[int[1]] aa; int* p = [123, 456] in aa; int[] a; p = a in aa; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test19176.d ================================================ /* REQUIRED_ARGS: -unittest TEST_OUTPUT: --- fail_compilation/test19176.d(19): Error: `static if` conditional cannot be at global scope fail_compilation/test19176.d(14): Error: `tuple()` has no effect --- */ // https://issues.dlang.org/show_bug.cgi?id=19176 void main() { __traits(getUnitTests, foo); } template foo() { static if(true) { enum bar; } else { enum bar; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test19193.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT --- fail_compilation/test19193.d(13): Deprecation: enum member `test19193.T19193!int.A.b` is deprecated --- */ // https://issues.dlang.org/show_bug.cgi?id=19193 void main () { cast(void)T19193!int.A.b; } template T19193(T) { enum A { deprecated b } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test314.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/test314.d(19): Deprecation: `imports.a314.renamed` is not visible from module `test314` fail_compilation/test314.d(20): Deprecation: `imports.a314.bug` is not visible from module `test314` fail_compilation/test314.d(22): Deprecation: `imports.b314.renamedpkg` is not visible from module `test314` fail_compilation/test314.d(23): Deprecation: `imports.b314.bugpkg` is not visible from module `test314` --- */ module test314; import imports.a314; import imports.b314; void main() { renamed.bug("This should not work.\n"); bug("This should not work.\n"); renamedpkg.bug("This should not work.\n"); bugpkg("This should not work.\n"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test4682.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/test4682.d(10): Error: integer overflow: `int.min / -1` fail_compilation/test4682.d(11): Error: integer overflow: `long.min / -1L` fail_compilation/test4682.d(12): Error: integer overflow: `int.min % -1` fail_compilation/test4682.d(13): Error: integer overflow: `long.min % -1L` ---- */ auto a = int.min / -1; auto b = long.min / -1; auto c = int.min % -1; auto d = long.min % -1; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test4682a.d ================================================ /* TEST_OUTPUT: ---- fail_compilation/test4682a.d(10): Error: divide by 0 fail_compilation/test4682a.d(11): Error: divide by 0 fail_compilation/test4682a.d(12): Error: divide by 0 fail_compilation/test4682a.d(13): Error: divide by 0 ---- */ auto a = int.min / 0; auto b = long.min / 0; auto c = int.min % 0; auto d = long.min % 0; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test4838.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test4838.d(13): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions fail_compilation/test4838.d(14): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions fail_compilation/test4838.d(15): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions fail_compilation/test4838.d(16): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions fail_compilation/test4838.d(17): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions fail_compilation/test4838.d(18): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions --- */ void function() const fpc; void function() immutable fpi; void function() shared fps; void function() shared const fpsc; void function() inout fpw; void function() shared inout fpsw; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test4946.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test4946.d(13): Error: 'pure' cannot be placed after a template constraint fail_compilation/test4946.d(14): Error: 'const' cannot be placed after a template constraint fail_compilation/test4946.d(15): Error: 'immutable' cannot be placed after a template constraint fail_compilation/test4946.d(16): Error: 'inout' cannot be placed after a template constraint fail_compilation/test4946.d(17): Error: 'shared' cannot be placed after a template constraint fail_compilation/test4946.d(18): Error: 'nothrow' cannot be placed after a template constraint fail_compilation/test4946.d(19): Error: attributes cannot be placed after a template constraint --- */ void bar1(int x)() if (x > 0) pure { int a;} void bar2(int x)() if (x > 0) const { int a;} void bar3(int x)() if (x > 0) immutable { int a;} void bar4(int x)() if (x > 0) inout { int a;} void bar5(int x)() if (x > 0) shared { int a;} void bar6(int x)() if (x > 0) nothrow { int a;} void bar7(int x)() if (x > 0) @safe { int a;} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test5412a.d ================================================ module test5412a; import A = imports.test5412a; import A = imports.test5412b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test5412b.d ================================================ module test5412b; import A = imports.test5412a; static import A = imports.test5412b; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test5412c.d ================================================ module test5412c; import test5412c2 = imports.test5412a; import test5412c2; ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test64.d ================================================ /* TEST_OUTPUT: --- fail_compilation/imports/test64a.d(1): Error: module `imports` from file fail_compilation/imports/test64a.d conflicts with package name imports --- */ // PERMUTE_ARGS: //import std.stdio; import imports.test64a; int main(string[] args) { //writefln(file1); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test6883.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test6883.d(15): Error: array index 5 is out of bounds `x[0 .. 5]` fail_compilation/test6883.d(17): Error: array index 7 is out of bounds `x[0 .. 5]` fail_compilation/test6883.d(21): Error: array index 5 is out of bounds `x[0 .. 5]` fail_compilation/test6883.d(23): Error: array index 7 is out of bounds `x[0 .. 5]` --- */ void main() { { int[5] x; x[x.length] = 1; enum size_t n = 2; x[x.length + n] = 2; } { int[5] x; x[$] = 1; enum size_t n = 2; x[$ + n] = 2; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test8509.d ================================================ module test8509; enum E : string { a = "hello", b = "world" } void main() { E e1 = E.a ~ " world"; E e2 = "hello " ~ E.b; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test8556.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test8556.d(21): Error: template instance `test8556.Grab!(Circle!(uint[]))` does not match template declaration `Grab(Range) if (!isSliceable!Range)` fail_compilation/test8556.d(52): Error: template instance `test8556.grab!(Circle!(uint[]))` error instantiating --- */ extern(C) int printf(const char*, ...); template isSliceable(R) { enum bool isSliceable = is(typeof( R.init[1 .. 2] )); } struct Grab(Range) if (!isSliceable!Range) { public Range source; } Grab!R grab(R)(R input) { return Grab!R(input); } // 3. evaluate isSliceable in template constraint auto grabExactly(R)(R range) if (!isSliceable!R) { return 0; } auto grabExactly(R)(R range) if ( isSliceable!R) { return 0; } struct Circle(Range) { // 2. auto return opSlice auto opSlice(size_t i, size_t j) { //pragma(msg, typeof(opSlice)); // prints "fwdref err" with B, but doesn't with A printf("%d %d\n", i, j); assert(j >= i); // 1. grabExactly curcular refers this opSlice. return grabExactly(typeof(this)()); // broken execution with A } } Circle!R circle(R)() { return Circle!R(); } void main() { auto t = grab(circle!(uint[])()); auto cx = circle!(uint[])(); auto slice = cx[23 .. 33]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test8751.d ================================================ Bar foo3(ref const int x) pure { return y => x > y; // error } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test9150.d ================================================ // https://issues.dlang.org/show_bug.cgi?id=9150 // Mismatching static array length should be detected in foreach /* TEST_OUTPUT: --- fail_compilation/test9150.d(14): Error: mismatched array lengths, 5 and 3 --- */ void main() { int[3][2] matrix = [ [1,11,111], [2,22,222] ]; foreach (int[5] row; matrix) //if int[3], there is no error. { foreach (x; row) {}//write(x, " "); //writeln(); } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test9176.d ================================================ /* TEST_OUTPUT: --- fail_compilation/test9176.d(14): Error: forward reference to inferred return type of function call `get()` fail_compilation/test9176.d(10): while evaluating: `static assert(!false)` --- */ void foo(int x) {} static assert(!is(typeof(foo(S())))); struct S { auto get() { return get(); } alias get this; } void main(){} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test9701.d ================================================ /* TEST_OUTPUT --- fail_compilation/test9701.d(38): Error: `@safe` is not a valid attribute for enum members fail_compilation/test9701.d(39): Error: `@system` is not a valid attribute for enum members fail_compilation/test9701.d(40): Error: `@trusted` is not a valid attribute for enum members fail_compilation/test9701.d(41): Error: `@nogc` is not a valid attribute for enum members fail_compilation/test9701.d(42): Error: `pure` is not a valid attribute for enum members fail_compilation/test9701.d(43): Error: `shared` is not a valid attribute for enum members fail_compilation/test9701.d(44): Error: `inout` is not a valid attribute for enum members fail_compilation/test9701.d(45): Error: `immutable` is not a valid attribute for enum members fail_compilation/test9701.d(46): Error: `const` is not a valid attribute for enum members fail_compilation/test9701.d(47): Error: `synchronized` is not a valid attribute for enum members fail_compilation/test9701.d(48): Error: `scope` is not a valid attribute for enum members fail_compilation/test9701.d(49): Error: `auto` is not a valid attribute for enum members fail_compilation/test9701.d(50): Error: `ref` is not a valid attribute for enum members fail_compilation/test9701.d(51): Error: `__gshared` is not a valid attribute for enum members fail_compilation/test9701.d(52): Error: `final` is not a valid attribute for enum members fail_compilation/test9701.d(53): Error: `extern` is not a valid attribute for enum members fail_compilation/test9701.d(54): Error: `export` is not a valid attribute for enum members fail_compilation/test9701.d(55): Error: `nothrow` is not a valid attribute for enum members fail_compilation/test9701.d(56): Error: `public` is not a valid attribute for enum members fail_compilation/test9701.d(57): Error: `private` is not a valid attribute for enum members fail_compilation/test9701.d(58): Error: `package` is not a valid attribute for enum members fail_compilation/test9701.d(59): Error: `static` is not a valid attribute for enum members fail_compilation/test9701.d(60): Error: `static` is not a valid attribute for enum members fail_compilation/test9701.d(61): Error: `static` is not a valid attribute for enum members fail_compilation/test9701.d(62): Error: `static` is not a valid attribute for enum members --- */ // This test exists to verify that parsing of enum member attributes rejects invalid attributes // https://issues.dlang.org/show_bug.cgi?id=9701 enum Enum { @safe safe, @system system, @trusted trusted, @nogc nogc, pure pure_, shared shared_, inout inout_, immutable immutable_, const const_, synchronized synchronized_, scope scope_, auto auto_, ref ref_, __gshared __gshared_, final final_, extern extern_, export export_, nothrow nothrow_, public public_, private private_, package package_, static static1, @("a") static static2, static @("a") static3, @("a") static @("b") static3, } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/test9701b.d ================================================ /* REQUIRED_ARGS: -de TEST_OUTPUT --- fail_compilation/test9701b.d(20): Deprecation: enum member `test9701b.Enum.e0` is deprecated fail_compilation/test9701b.d(21): Deprecation: enum member `test9701b.Enum.e1` is deprecated - message --- */ // https://issues.dlang.org/show_bug.cgi?id=9701 enum Enum { deprecated e0, deprecated("message") e1, } void main() { auto value = Enum.e0; auto value2 = Enum.e1; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/testCols.d ================================================ // REQUIRED_ARGS: -vcolumns // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/testCols.d(13,5): Error: undefined identifier `nonexistent` --- */ void test() { nonexistent(); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/testInference.d ================================================ /* TEST_OUTPUT: --- fail_compilation/testInference.d(24): Error: cannot implicitly convert expression `this.a` of type `inout(A8998)` to `immutable(A8998)` --- */ class A8998 { int i; } class C8998 { A8998 a; this() { a = new A8998(); } // WRONG: Returns immutable(A8998) immutable(A8998) get() inout pure { return a; // should be error } } /* TEST_OUTPUT: --- fail_compilation/testInference.d(39): Error: cannot implicitly convert expression `s` of type `const(char[])` to `string` fail_compilation/testInference.d(44): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` fail_compilation/testInference.d(49): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` fail_compilation/testInference.d(54): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` --- */ string foo(in char[] s) pure { return s; // } immutable(int[]) x1() /*pure*/ { int[] a = new int[](10); return a; // } immutable(int[]) x2(int len) /*pure*/ { int[] a = new int[](len); return a; } immutable(int[]) x3(immutable(int[]) org) /*pure*/ { int[] a = new int[](org.length); return a; // } /* TEST_OUTPUT: --- fail_compilation/testInference.d(94): Error: cannot implicitly convert expression `c` of type `testInference.C1` to `immutable(C1)` fail_compilation/testInference.d(95): Error: cannot implicitly convert expression `c` of type `testInference.C1` to `immutable(C1)` fail_compilation/testInference.d(96): Error: cannot implicitly convert expression `c` of type `testInference.C3` to `immutable(C3)` fail_compilation/testInference.d(97): Error: cannot implicitly convert expression `c` of type `testInference.C3` to `immutable(C3)` fail_compilation/testInference.d(100): Error: undefined identifier `X1`, did you mean function `x1`? fail_compilation/testInference.d(106): Error: cannot implicitly convert expression `s` of type `S1` to `immutable(S1)` fail_compilation/testInference.d(109): Error: cannot implicitly convert expression `a` of type `int*[]` to `immutable(int*[])` fail_compilation/testInference.d(110): Error: cannot implicitly convert expression `a` of type `const(int)*[]` to `immutable(int*[])` fail_compilation/testInference.d(114): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` fail_compilation/testInference.d(115): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` fail_compilation/testInference.d(116): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` fail_compilation/testInference.d(118): Error: cannot implicitly convert expression `a` of type `const(int)*[]` to `immutable(int*[])` --- */ immutable(Object) get(inout int*) pure { auto o = new Object; return o; // should be ok } immutable(Object) get(immutable Object) pure { auto o = new Object; return o; // should be ok } inout(Object) get(inout Object) pure { auto o = new Object; return o; // should be ok (, but cannot in current conservative rule) } class C1 { C2 c2; } class C2 { C3 c3; } class C3 { C1 c1; } immutable(C1) recursive1(C3 pc) pure { auto c = new C1(); return c; } // should be error, because pc.c1 == C1 immutable(C1) recursive2(C2 pc) pure { auto c = new C1(); return c; } // should be error, because pc.c3.c1 == C1 immutable(C3) recursive3(C1 pc) pure { auto c = new C3(); return c; } // should be error, c.c1 may be pc immutable(C3) recursive4(C2 pc) pure { auto c = new C3(); return c; } // should be error, c.c1.c2 may be pc immutable(C1) recursive5(shared C2 pc) pure { auto c = new C1(); return c; } immutable(C1) recursive6(immutable C2 pc) pure { auto c = new C1(); return c; } immutable(C1) recursiveE(immutable C2 pc) pure { auto c = new X1(); return c; } class C4 { C4[] arr; } immutable(C4)[] recursive7(int[] arr) pure { auto a = new C4[](1); return a; } struct S1 { int* ptr; } immutable(S1) foo1a( int*[] prm) pure { S1 s; return s; } // NG immutable(S1) foo1b( const int*[] prm) pure { S1 s; return s; } // OK immutable(S1) foo1c(immutable int*[] prm) pure { S1 s; return s; } // OK immutable(int*[]) bar1a( S1 prm) pure { int *[] a; return a; } // NG immutable(int*[]) bar1b( S1 prm) pure { const(int)*[] a; return a; } // NG immutable(int*[]) bar1c( S1 prm) pure { immutable(int)*[] a; return a; } // OK struct S2 { const(int)* ptr; } immutable(S2) foo2a( int*[] prm) pure { S2 s; return s; } // OK immutable(S2) foo2b( const int*[] prm) pure { S2 s; return s; } // NG immutable(S2) foo2c(immutable int*[] prm) pure { S2 s; return s; } // NG immutable(int*[]) bar2a( S2 prm) pure { int *[] a; return a; } // OK immutable(int*[]) bar2b( S2 prm) pure { const(int)*[] a; return a; } // NG immutable(int*[]) bar2c( S2 prm) pure { immutable(int)*[] a; return a; } // OK /* TEST_OUTPUT: --- fail_compilation/testInference.d(134): Error: cannot implicitly convert expression `f10063(cast(inout(void*))p)` of type `inout(void)*` to `immutable(void)*` --- */ inout(void)* f10063(inout void* p) pure { return p; } immutable(void)* g10063(inout int* p) pure { return f10063(p); } /* TEST_OUTPUT: --- fail_compilation/testInference.d(154): Error: `pure` function `testInference.bar14049` cannot call impure function `testInference.foo14049!int.foo14049` --- */ auto impure14049() { static int i = 1; return i; } void foo14049(T)(T val) { auto n = () @trusted { return impure14049(); }(); } void bar14049() pure { foo14049(1); } /* TEST_OUTPUT: --- fail_compilation/testInference.d(166): Error: `pure` function `testInference.f14160` cannot access mutable static data `g14160` --- */ int g14160; int* f14160() pure { return &g14160; // should be rejected } /* TEST_OUTPUT: --- fail_compilation/testInference.d(180): Error: `pure` function `testInference.test12422` cannot call impure function `testInference.test12422.bar12422!().bar12422` --- */ int g12422; void foo12422() { ++g12422; } void test12422() pure { void bar12422()() { foo12422(); } bar12422(); } /* TEST_OUTPUT: --- fail_compilation/testInference.d(196): Error: `pure` function `testInference.test13729a` cannot access mutable static data `g13729` fail_compilation/testInference.d(206): Error: `pure` function `testInference.test13729b` cannot call impure function `testInference.test13729b.foo!().foo` --- */ int g13729; void test13729a() pure { static void foo() // typed as impure { g13729++; // disallowed } foo(); } void test13729b() pure { static void foo()() // inferred to impure { g13729++; } foo(); // cannot call impure function } /* TEST_OUTPUT: --- fail_compilation/testInference.d(225): Error: `testInference.test17086` called with argument types `(bool)` matches both: fail_compilation/testInference.d(219): `testInference.test17086!(bool, false).test17086(bool x)` and: fail_compilation/testInference.d(220): `testInference.test17086!(bool, false).test17086(bool y)` --- */ void test17086 (T, T V = T.init) (T x) { assert(x.foo); } void test17086 (T, T V = T.init) (T y) { assert(y.bar); } void test17086_call () { bool f; test17086(f); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/testpull1810.d ================================================ // REQUIRED_ARGS: -c -w /* TEST_OUTPUT: --- fail_compilation/testpull1810.d(19): Warning: statement is not reachable --- */ uint foo(uint i) { try { ++i; return 3; } catch (Exception e) { } return 4; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d ================================================ /* TEST_OUTPUT: --- fail_compilation/testscopestatic.d(15): Error: variable `testscopestatic.foo.p` cannot be `scope` and `static` fail_compilation/testscopestatic.d(16): Error: variable `testscopestatic.foo.b` cannot be `scope` and `extern` fail_compilation/testscopestatic.d(17): Error: variable `testscopestatic.foo.c` cannot be `scope` and `__gshared` fail_compilation/testscopestatic.d(21): Error: variable `testscopestatic.foo.S.x` field cannot be `scope` --- */ void foo() { scope int a; static scope int* p; extern scope int b; scope __gshared int c; struct S { scope int x; } } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/traits.d ================================================ /* REQUIRED_ARGS: PERMUTE_ARGS: */ /************************************************************/ /* TEST_OUTPUT: --- fail_compilation/traits.d(100): Error: `getTargetInfo` key `"not_a_target_info"` not supported by this implementation fail_compilation/traits.d(101): Error: string expected as argument of __traits `getTargetInfo` instead of `100` fail_compilation/traits.d(102): Error: expected 1 arguments for `getTargetInfo` but had 2 fail_compilation/traits.d(103): Error: expected 1 arguments for `getTargetInfo` but had 0 --- */ #line 100 enum A = __traits(getTargetInfo, "not_a_target_info"); enum B = __traits(getTargetInfo, 100); enum C = __traits(getTargetInfo, "cppRuntimeLibrary", "bits"); enum D = __traits(getTargetInfo); ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/typeerrors.d ================================================ /* PERMUTE_ARGS: TEST_OUTPUT: --- fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4 fail_compilation/typeerrors.d(38): Error: variable `x` cannot be read at compile time fail_compilation/typeerrors.d(39): Error: cannot have array of `void()` fail_compilation/typeerrors.d(40): Error: cannot have array of scope `typeerrors.C` fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C` fail_compilation/typeerrors.d(44): Error: `int[5]` is not an expression fail_compilation/typeerrors.d(46): Error: `x` is used as a type fail_compilation/typeerrors.d(47): Error: cannot have associative array key of `void()` fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void` fail_compilation/typeerrors.d(49): Error: cannot have array of scope `typeerrors.C` fail_compilation/typeerrors.d(50): Error: cannot have associative array of `void` fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void()` fail_compilation/typeerrors.d(53): Error: cannot have parameter of type `void` fail_compilation/typeerrors.d(55): Error: slice `[1..5]` is out of range of [0..4] fail_compilation/typeerrors.d(56): Error: slice `[2..1]` is out of range of [0..4] --- */ template tuple(T...) { alias T tuple; } void bar(); scope class C { } void foo() { alias T = tuple!(1,2,int,7); T[4] a; int x; T[x] b; typeof(bar)[5] c; C[6] d; C[] e; alias int[5] AI; auto f = AI.ptr; int[x*] g; int[typeof(bar)] h; int[void] i; C[int] j; void[int] k; typeof(bar)[int] l; void abc(void) { } alias T2 = T[1 .. 5]; alias T3 = T[2 .. 1]; } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/udaparams.d ================================================ /* TEST_OUTPUT: --- fail_compilation/udaparams.d(31): Error: variadic parameter cannot have user-defined attributes fail_compilation/udaparams.d(32): Error: variadic parameter cannot have user-defined attributes fail_compilation/udaparams.d(34): Error: user-defined attributes cannot appear as postfixes fail_compilation/udaparams.d(35): Error: user-defined attributes cannot appear as postfixes fail_compilation/udaparams.d(36): Error: user-defined attributes cannot appear as postfixes fail_compilation/udaparams.d(38): Error: `@safe` attribute for function parameter is not supported fail_compilation/udaparams.d(39): Error: `@safe` attribute for function parameter is not supported fail_compilation/udaparams.d(40): Error: `@safe` attribute for function parameter is not supported fail_compilation/udaparams.d(43): Error: `@system` attribute for function parameter is not supported fail_compilation/udaparams.d(44): Error: `@trusted` attribute for function parameter is not supported fail_compilation/udaparams.d(45): Error: `@nogc` attribute for function parameter is not supported fail_compilation/udaparams.d(51): Error: Cannot put a storage-class in an alias declaration. fail_compilation/udaparams.d(52): Error: Cannot put a storage-class in an alias declaration. fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration fail_compilation/udaparams.d(53): Error: declaration expected, not `=>` fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration fail_compilation/udaparams.d(54): Error: declaration expected, not `=>` fail_compilation/udaparams.d(57): Error: basic type expected, not `@` fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter fail_compilation/udaparams.d(57): Error: found `@` when expecting `)` fail_compilation/udaparams.d(57): Error: basic type expected, not `3` fail_compilation/udaparams.d(57): Error: found `3` when expecting `)` fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration fail_compilation/udaparams.d(57): Error: declaration expected, not `)` --- */ void vararg1(int a, @(10) ...); extern(C) void vararg2(int a, @(10) ...); void rhsuda(int a @(10)); void rhsuda2(int @(10)); void rhsuda3(int[] arr @(10) ...); void wrongAttr1(@safe int); void wrongAttr2(@safe void function()); void wrongAttr3(@safe void delegate()); void test16(A)(A a @system); void test16(A)(A a @trusted); void test16(A)(A a @nogc); // lambdas without parentheses alias test19a = @safe b => 1 + 2; alias test19b = @system b => 1 + 2; alias test19c = @nogc b => 1 + 2; alias test19d = @(2) @system b => 1 + 2; alias test19e = @safe @(2) b => 1 + 2; alias test19f = extern(C++) b => 1 + 2; alias test19g = align(2) b => 1 + 2; // UDAs on Template parameter aren't supported void test21(@(3) T)(T t) {} ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/verrors0.d ================================================ // REQUIRED_ARGS: -verrors=0 void main() { { T a; } // 1 { T a; } // 2 { T a; } // 3 { T a; } // 4 { T a; } // 5 { T a; } // 6 { T a; } // 7 { T a; } // 8 { T a; } // 9 { T a; } // 10 { T a; } // 11 { T a; } // 12 { T a; } // 13 { T a; } // 14 { T a; } // 15 { T a; } // 16 { T a; } // 17 { T a; } // 18 { T a; } // 19 { T a; } // 20 (default limit) { T a; } // 21 { T a; } // 22 { T a; } // 23 { T a; } // 24 { T a; } // 25 } /* TEST_OUTPUT: --- fail_compilation/verrors0.d(5): Error: undefined identifier `T` fail_compilation/verrors0.d(6): Error: undefined identifier `T` fail_compilation/verrors0.d(7): Error: undefined identifier `T` fail_compilation/verrors0.d(8): Error: undefined identifier `T` fail_compilation/verrors0.d(9): Error: undefined identifier `T` fail_compilation/verrors0.d(10): Error: undefined identifier `T` fail_compilation/verrors0.d(11): Error: undefined identifier `T` fail_compilation/verrors0.d(12): Error: undefined identifier `T` fail_compilation/verrors0.d(13): Error: undefined identifier `T` fail_compilation/verrors0.d(14): Error: undefined identifier `T` fail_compilation/verrors0.d(15): Error: undefined identifier `T` fail_compilation/verrors0.d(16): Error: undefined identifier `T` fail_compilation/verrors0.d(17): Error: undefined identifier `T` fail_compilation/verrors0.d(18): Error: undefined identifier `T` fail_compilation/verrors0.d(19): Error: undefined identifier `T` fail_compilation/verrors0.d(20): Error: undefined identifier `T` fail_compilation/verrors0.d(21): Error: undefined identifier `T` fail_compilation/verrors0.d(22): Error: undefined identifier `T` fail_compilation/verrors0.d(23): Error: undefined identifier `T` fail_compilation/verrors0.d(24): Error: undefined identifier `T` fail_compilation/verrors0.d(25): Error: undefined identifier `T` fail_compilation/verrors0.d(26): Error: undefined identifier `T` fail_compilation/verrors0.d(27): Error: undefined identifier `T` fail_compilation/verrors0.d(28): Error: undefined identifier `T` fail_compilation/verrors0.d(29): Error: undefined identifier `T` --- */ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/verrors5.d ================================================ // REQUIRED_ARGS: -verrors=5 void main() { { T a; } // 1 { T a; } // 2 { T a; } // 3 { T a; } // 4 { T a; } // 5 { T a; } // 6 { T a; } // 7 { T a; } // 8 { T a; } // 9 { T a; } // 10 { T a; } // 11 { T a; } // 12 { T a; } // 13 { T a; } // 14 { T a; } // 15 { T a; } // 16 { T a; } // 17 { T a; } // 18 { T a; } // 19 { T a; } // 20 (default limit) { T a; } // 21 { T a; } // 22 { T a; } // 23 { T a; } // 24 { T a; } // 25 } /* TEST_OUTPUT: --- fail_compilation/verrors5.d(5): Error: undefined identifier `T` fail_compilation/verrors5.d(6): Error: undefined identifier `T` fail_compilation/verrors5.d(7): Error: undefined identifier `T` fail_compilation/verrors5.d(8): Error: undefined identifier `T` fail_compilation/verrors5.d(9): Error: undefined identifier `T` --- */ ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/warn12809.d ================================================ // REQUIRED_ARGS: -o- -w /* TEST_OUTPUT: --- fail_compilation/warn12809.d(25): Warning: statement is not reachable fail_compilation/warn12809.d(33): Warning: statement is not reachable --- */ //void test_unrachable1() //{ // try assert(0); // finally // { // int x = 1; // unreachable // } //} void test_unrachable2() { try assert(0); finally {} int x = 1; // unreachable } void test_unrachable3() { try {} finally assert(0); int x = 1; // unreachable } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/warn13679.d ================================================ // REQUIRED_ARGS: -w // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/warn13679.d(14): Warning: cannot use `foreach_reverse` with an associative array --- */ void main() { int[int] aa; foreach_reverse(k, v; aa) {} } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/warn7444.d ================================================ // REQUIRED_ARGS: -w // PERMUTE_ARGS: /* TEST_OUTPUT: --- fail_compilation/warn7444.d(23): Error: cannot implicitly convert expression `e` of type `int` to `int[]` --- */ void test7444() { int[2] sa; int[] da; int e; { // X: Changed accepts-invalid to rejects-invalid by this issue // a: slice assignment // b: element-wise assignment sa = e; // X sa[] = e; // b da = e; da[] = e; // b // lhs is static array sa = sa; // b == identity assign sa = sa[]; // X sa[] = sa; // X sa[] = sa[]; // b sa = da; // X sa = da[]; // X sa[] = da; // X sa[] = da[]; // b // lhs is dynamic array da = sa; // X da = sa[]; // a da[] = sa; // X da[] = sa[]; // b da = da; // a == identity assign da = da[]; // a da[] = da; // X da[] = da[]; // b } } /* TEST_OUTPUT: --- No warning --- */ void test10214() { bool[1] arr; arr = 0; pragma(msg, "No warning"); } /* TEST_OUTPUT: --- No warning --- */ struct S11228 { int[2] ii; alias ii this; } void test11228() { S11228 s; int[2] ii; ii = s.ii; // OK ii = s; // OK <- Warning pragma(msg, "No warning"); } ================================================ FILE: gcc/testsuite/gdc.test/fail_compilation/widechars.d ================================================ /* DISABLED: win32 win64 TEST_OUTPUT: --- fail_compilation/widechars.d(10): Error: undefined identifier `wchar_t`, did you mean `dchar`? --- */ wchar_t x; ================================================ FILE: gcc/testsuite/gdc.test/runnable/A16.d ================================================ // EXTRA_SOURCES: imports/A16a.d import std.stdio; class AA16 { protected: this() { printf("class AA16\n"); } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/Same.d ================================================ // EXTRA_SOURCES: imports/Other.d // PERMUTE_ARGS: module Same; // makes no difference if removed import core.stdc.stdio; class Same { this() { printf("Same\n"); } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/a17.d ================================================ // EXTRA_SOURCES: imports/a17a.d module a17; import std.stdio; private import imports.a17a; class barx { this() { printf("barx\n"); } } int main() { foo2x f = new foo2x(); // f = new foo2x(); // f.x++; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/a18.d ================================================ // COMPILE_SEPARATELY // EXTRA_SOURCES: imports/a18a.d // PERMUTE_ARGS: import imports.a18a; extern(C) int printf(const char*, ...); alias IContainer!(int) icontainer_t; int main() { printf("Test enumerator\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/a19.d ================================================ // COMPILE_SEPARATELY // EXTRA_SOURCES: imports/a19a.d // PERMUTE_ARGS: import imports.a19a; int main(char[][] args) { TemplatedStruct!(Dummy) e; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/a21.d ================================================ // EXTRA_SOURCES: imports/a21a.d // PERMUTE_ARGS: import std.stdio; import imports.a21a; template BadMixin() { int badFunc() { printf("badFunc\n"); return 2; } } int main() { int i; auto x = new SomeClass; i = x.goodFunc(); assert(i == 1); i = x.badFunc(); assert(i == 2); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/aliasthis.d ================================================ extern (C) int printf(const(char*) fmt, ...); import core.vararg; struct Tup(T...) { T field; alias field this; bool opEquals(const Tup rhs) const { foreach (i, _; T) if (field[i] != rhs.field[i]) return false; return true; } } Tup!T tup(T...)(T fields) { return typeof(return)(fields); } template Seq(T...) { alias T Seq; } /**********************************************/ struct S { int x; alias x this; } int foo(int i) { return i * 2; } void test1() { S s; s.x = 7; int i = -s; assert(i == -7); i = s + 8; assert(i == 15); i = s + s; assert(i == 14); i = 9 + s; assert(i == 16); i = foo(s); assert(i == 14); } /**********************************************/ class C { int x; alias x this; } void test2() { C s = new C(); s.x = 7; int i = -s; assert(i == -7); i = s + 8; assert(i == 15); i = s + s; assert(i == 14); i = 9 + s; assert(i == 16); i = foo(s); assert(i == 14); } /**********************************************/ void test3() { Tup!(int, double) t; t[0] = 1; t[1] = 1.1; assert(t[0] == 1); assert(t[1] == 1.1); printf("%d %g\n", t[0], t[1]); } /**********************************************/ struct Iter { bool empty() { return true; } void popFront() { } ref Tup!(int, int) front() { return *new Tup!(int, int); } ref Iter opSlice() { return this; } } void test4() { foreach (a; Iter()) { } } /**********************************************/ void test5() { static struct Double1 { double val = 1; alias val this; } static Double1 x() { return Double1(); } x()++; } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=4617 struct S4617 { struct F { int square(int n) { return n*n; } real square(real n) { return n*n; } } F forward; alias forward this; alias forward.square sqr; // okay int field; void mfunc(); template Templ(){} void tfunc()(){} } template Id4617(alias k) { alias k Id4617; } void test4617a() { alias Id4617!(S4617.square) test1; //NG alias Id4617!(S4617.forward.square) test2; //OK alias Id4617!(S4617.sqr) test3; //okay static assert(__traits(isSame, S4617.square, S4617.forward.square)); } void test4617b() { static struct Sub(T) { T value; @property ref inout(T) payload() inout { return value; } alias payload this; } alias Id4617!(S4617.field) S_field; alias Id4617!(S4617.mfunc) S_mfunc; alias Id4617!(S4617.Templ) S_Templ; alias Id4617!(S4617.tfunc) S_tfunc; alias Sub!S4617 T4617; alias Id4617!(T4617.field) R_field; alias Id4617!(T4617.mfunc) R_mfunc; alias Id4617!(T4617.Templ) R_Templ; alias Id4617!(T4617.tfunc) R_tfunc; static assert(__traits(isSame, R_field, S_field)); static assert(__traits(isSame, R_mfunc, S_mfunc)); static assert(__traits(isSame, R_Templ, S_Templ)); static assert(__traits(isSame, R_tfunc, S_tfunc)); alias Id4617!(T4617.square) R_sqr; static assert(__traits(isSame, R_sqr, S4617.forward.square)); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=4773 void test4773() { struct Rebindable { Object obj; @property const(Object) get(){ return obj; } alias get this; } Rebindable r; if (r) assert(0); r.obj = new Object; if (!r) assert(0); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=5188 void test5188() { struct S { int v = 10; alias v this; } S s; assert(s <= 20); assert(s != 14); } /***********************************************/ struct Foo { void opIndexAssign(int x, size_t i) { val = x; } void opSliceAssign(int x, size_t a, size_t b) { val = x; } int val; } struct Bar { Foo foo; alias foo this; } void test6() { Bar b; b[0] = 1; assert(b.val == 1); b[0 .. 1] = 2; assert(b.val == 2); } /**********************************************/ // recursive alias this detection class C0 {} class C1 { C2 c; alias c this; } class C2 { C1 c; alias c this; } class C3 { C2 c; alias c this; } struct S0 {} struct S1 { S2* ps; @property ref get(){return *ps;} alias get this; } struct S2 { S1* ps; @property ref get(){return *ps;} alias get this; } struct S3 { S2* ps; @property ref get(){return *ps;} alias get this; } struct S4 { S5* ps; @property ref get(){return *ps;} alias get this; } struct S5 { S4* ps; @property ref get(){return *ps;} alias get this; } struct S6 { S5* ps; @property ref get(){return *ps;} alias get this; } void test7() { // Able to check a type is implicitly convertible within a finite time. static assert(!is(C1 : C0)); static assert( is(C2 : C1)); static assert( is(C1 : C2)); static assert(!is(C3 : C0)); static assert( is(C3 : C1)); static assert( is(C3 : C2)); static assert(!is(S1 : S0)); static assert( is(S2 : S1)); static assert( is(S1 : S2)); static assert(!is(S3 : S0)); static assert( is(S3 : S1)); static assert( is(S3 : S2)); C0 c0; C1 c1; C3 c3; S0 s0; S1 s1; S3 s3; S4 s4; S6 s6; // Allow merging types that contains alias this recursion. static assert( __traits(compiles, c0 is c1)); // typeMerge(c || c) e2->implicitConvTo(t1); static assert( __traits(compiles, c0 is c3)); // typeMerge(c || c) e2->implicitConvTo(t1); static assert( __traits(compiles, c1 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); static assert( __traits(compiles, c3 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); static assert(!__traits(compiles, s1 is c0)); // typeMerge(c || c) e1 static assert(!__traits(compiles, s3 is c0)); // typeMerge(c || c) e1 static assert(!__traits(compiles, c0 is s1)); // typeMerge(c || c) e2 static assert(!__traits(compiles, c0 is s3)); // typeMerge(c || c) e2 static assert(!__traits(compiles, s1 is s0)); // typeMerge(s && s) e1 static assert(!__traits(compiles, s3 is s0)); // typeMerge(s && s) e1 static assert(!__traits(compiles, s0 is s1)); // typeMerge(s && s) e2 static assert(!__traits(compiles, s0 is s3)); // typeMerge(s && s) e2 static assert(!__traits(compiles, s1 is s4)); // typeMerge(s && s) e1 + e2 static assert(!__traits(compiles, s3 is s6)); // typeMerge(s && s) e1 + e2 static assert(!__traits(compiles, s1 is 10)); // typeMerge(s || s) e1 static assert(!__traits(compiles, s3 is 10)); // typeMerge(s || s) e1 static assert(!__traits(compiles, 10 is s1)); // typeMerge(s || s) e2 static assert(!__traits(compiles, 10 is s3)); // typeMerge(s || s) e2 // SliceExp::semantic static assert(!__traits(compiles, c1[])); static assert(!__traits(compiles, c3[])); static assert(!__traits(compiles, s1[])); static assert(!__traits(compiles, s3[])); // CallExp::semantic // static assert(!__traits(compiles, c1())); // static assert(!__traits(compiles, c3())); static assert(!__traits(compiles, s1())); static assert(!__traits(compiles, s3())); // AssignExp::semantic static assert(!__traits(compiles, { c1[1] = 0; })); static assert(!__traits(compiles, { c3[1] = 0; })); static assert(!__traits(compiles, { s1[1] = 0; })); static assert(!__traits(compiles, { s3[1] = 0; })); static assert(!__traits(compiles, { c1[ ] = 0; })); static assert(!__traits(compiles, { c3[ ] = 0; })); static assert(!__traits(compiles, { s1[ ] = 0; })); static assert(!__traits(compiles, { s3[ ] = 0; })); // UnaExp::op_overload static assert(!__traits(compiles, +c1[1])); static assert(!__traits(compiles, +c3[1])); static assert(!__traits(compiles, +s1[1])); static assert(!__traits(compiles, +s3[1])); static assert(!__traits(compiles, +c1[ ])); static assert(!__traits(compiles, +c3[ ])); static assert(!__traits(compiles, +s1[ ])); static assert(!__traits(compiles, +s3[ ])); static assert(!__traits(compiles, +c1)); static assert(!__traits(compiles, +c3)); static assert(!__traits(compiles, +s1)); static assert(!__traits(compiles, +s3)); // ArrayExp::op_overload static assert(!__traits(compiles, c1[1])); static assert(!__traits(compiles, c3[1])); static assert(!__traits(compiles, s1[1])); static assert(!__traits(compiles, s3[1])); // BinExp::op_overload static assert(!__traits(compiles, c1 + 10)); // e1 static assert(!__traits(compiles, c3 + 10)); // e1 static assert(!__traits(compiles, 10 + c1)); // e2 static assert(!__traits(compiles, 10 + c3)); // e2 static assert(!__traits(compiles, s1 + 10)); // e1 static assert(!__traits(compiles, s3 + 10)); // e1 static assert(!__traits(compiles, 10 + s1)); // e2 static assert(!__traits(compiles, 10 + s3)); // e2 // BinExp::compare_overload static assert(!__traits(compiles, c1 < 10)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, c3 < 10)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, 10 < c1)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, 10 < c3)); // (Object.opCmp(int) is invalid) static assert(!__traits(compiles, s1 < 10)); // e1 static assert(!__traits(compiles, s3 < 10)); // e1 static assert(!__traits(compiles, 10 < s1)); // e2 static assert(!__traits(compiles, 10 < s3)); // e2 // BinAssignExp::op_overload static assert(!__traits(compiles, c1[1] += 1)); static assert(!__traits(compiles, c3[1] += 1)); static assert(!__traits(compiles, s1[1] += 1)); static assert(!__traits(compiles, s3[1] += 1)); static assert(!__traits(compiles, c1[ ] += 1)); static assert(!__traits(compiles, c3[ ] += 1)); static assert(!__traits(compiles, s1[ ] += 1)); static assert(!__traits(compiles, s3[ ] += 1)); static assert(!__traits(compiles, c1 += c0)); // e1 static assert(!__traits(compiles, c3 += c0)); // e1 static assert(!__traits(compiles, s1 += s0)); // e1 static assert(!__traits(compiles, s3 += s0)); // e1 static assert(!__traits(compiles, c0 += c1)); // e2 static assert(!__traits(compiles, c0 += c3)); // e2 static assert(!__traits(compiles, s0 += s1)); // e2 static assert(!__traits(compiles, s0 += s3)); // e2 static assert(!__traits(compiles, c1 += s1)); // e1 + e2 static assert(!__traits(compiles, c3 += s3)); // e1 + e2 // ForeachStatement::inferAggregate static assert(!__traits(compiles, { foreach (e; s1){} })); static assert(!__traits(compiles, { foreach (e; s3){} })); static assert(!__traits(compiles, { foreach (e; c1){} })); static assert(!__traits(compiles, { foreach (e; c3){} })); // Expression::checkToBoolean static assert(!__traits(compiles, { if (s1){} })); static assert(!__traits(compiles, { if (s3){} })); // SwitchStatement::semantic static assert(!__traits(compiles, { switch (c0) { default: } })); static assert(!__traits(compiles, { switch (c1) { default: } })); static assert(!__traits(compiles, { switch (c3) { default: } })); // https://issues.dlang.org/show_bug.cgi?id=12537: function arguments with IFTI void eq12537()(Object lhs) {} const C0 cc0; const C1 cc1; const C3 cc3; static assert(!__traits(compiles, eq12537(cc0))); static assert(!__traits(compiles, eq12537(cc1))); static assert(!__traits(compiles, eq12537(cc3))); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11875 // endless recursion in Type::deduceType struct T11875x(C) { C c; } class D11875a { D11875b c; alias c this; } class D11875b { D11875a c; alias c this; } static assert(!is(D11875a == D11875b)); static assert( is(T11875x!D11875a == T11875x!D, D) && is(D == D11875a)); static assert(!is(D11875a == T11875x!D, D)); // this used to freeze dmd // test that types in recursion are still detected struct T11875y(C) { C c; alias c this; } class D11875c { T11875y!D11875b c; alias c this; } static assert(is(D11875c : T11875y!D, D) && is(D == D11875b)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11930 class BarObj11930 {} struct Bar11930 { BarObj11930 _obj; alias _obj this; } BarObj11930 getBarObj11930(T)(T t) { static if (is(T unused : BarObj11930)) return t; else static assert(false, "Can not get BarObj from " ~ T.stringof); } void test11930() { Bar11930 b; getBarObj11930(b); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=2781 struct Tuple2781a(T...) { T data; alias data this; } struct Tuple2781b(T) { T data; alias data this; } void test2781() { Tuple2781a!(uint, float) foo; foreach(elem; foo) {} { Tuple2781b!(int[]) bar1; foreach(elem; bar1) {} Tuple2781b!(int[int]) bar2; foreach(key, elem; bar2) {} Tuple2781b!(string) bar3; foreach(dchar elem; bar3) {} } { Tuple2781b!(int[]) bar1; foreach(elem; bar1) goto L1; L1: ; Tuple2781b!(int[int]) bar2; foreach(key, elem; bar2) goto L2; L2: ; Tuple2781b!(string) bar3; foreach(dchar elem; bar3) goto L3; L3: ; } int eval; auto t1 = tup(10, "str"); auto i1 = 0; foreach (e; t1) { pragma(msg, "[] = ", typeof(e)); static if (is(typeof(e) == int )) assert(i1 == 0 && e == 10); static if (is(typeof(e) == string)) assert(i1 == 1 && e == "str"); ++i1; } auto t2 = tup(10, "str"); foreach (i2, e; t2) { pragma(msg, "[", cast(int)i2, "] = ", typeof(e)); static if (is(typeof(e) == int )) { static assert(i2 == 0); assert(e == 10); } static if (is(typeof(e) == string)) { static assert(i2 == 1); assert(e == "str"); } } auto t3 = tup(10, "str"); auto i3 = 2; foreach_reverse (e; t3) { --i3; pragma(msg, "[] = ", typeof(e)); static if (is(typeof(e) == int )) assert(i3 == 0 && e == 10); static if (is(typeof(e) == string)) assert(i3 == 1 && e == "str"); } auto t4 = tup(10, "str"); foreach_reverse (i4, e; t4) { pragma(msg, "[", cast(int)i4, "] = ", typeof(e)); static if (is(typeof(e) == int )) { static assert(i4 == 0); assert(e == 10); } static if (is(typeof(e) == string)) { static assert(i4 == 1); assert(e == "str"); } } eval = 0; foreach (i, e; tup(tup((){eval++; return 10;}(), 3.14), tup("str", [1,2]))) { static if (i == 0) assert(e == tup(10, 3.14)); static if (i == 1) assert(e == tup("str", [1,2])); } assert(eval == 1); eval = 0; foreach (i, e; tup((){eval++; return 10;}(), tup(3.14, tup("str", tup([1,2]))))) { static if (i == 0) assert(e == 10); static if (i == 1) assert(e == tup(3.14, tup("str", tup([1,2])))); } assert(eval == 1); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6546 void test6546() { class C {} class D : C {} struct S { C c; alias c this; } // S : C struct T { S s; alias s this; } // T : S struct U { T t; alias t this; } // U : T C c; D d; S s; T t; U u; assert(c is c); // OK assert(c is d); // OK assert(c is s); // OK assert(c is t); // OK assert(c is u); // OK assert(d is c); // OK assert(d is d); // OK assert(d is s); // doesn't work assert(d is t); // doesn't work assert(d is u); // doesn't work assert(s is c); // OK assert(s is d); // doesn't work assert(s is s); // OK assert(s is t); // doesn't work assert(s is u); // doesn't work assert(t is c); // OK assert(t is d); // doesn't work assert(t is s); // doesn't work assert(t is t); // OK assert(t is u); // doesn't work assert(u is c); // OK assert(u is d); // doesn't work assert(u is s); // doesn't work assert(u is t); // doesn't work assert(u is u); // OK } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6736 void test6736() { static struct S1 { struct S2 // must be 8 bytes in size { uint a, b; } S2 s2; alias s2 this; } S1 c; static assert(!is(typeof(c + c))); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=2777 struct ArrayWrapper(T) { T[] array; alias array this; } // alias array this void test2777a() { ArrayWrapper!(uint) foo; foo.length = 5; // Works foo[0] = 1; // Works auto e0 = foo[0]; // Works auto e4 = foo[$ - 1]; // Error: undefined identifier __dollar auto s01 = foo[0..2]; // Error: ArrayWrapper!(uint) cannot be sliced with[] } // alias tuple this void test2777b() { auto t = tup(10, 3.14, "str", [1,2]); assert(t[$ - 1] == [1,2]); auto f1 = t[]; assert(f1[0] == 10); assert(f1[1] == 3.14); assert(f1[2] == "str"); assert(f1[3] == [1,2]); auto f2 = t[1..3]; assert(f2[0] == 3.14); assert(f2[1] == "str"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=2787 struct Base2787 { int x; void foo() { auto _ = x; } } struct Derived2787 { Base2787 _base; alias _base this; int y; void bar() { auto _ = x; } } /***********************************/ // https://issues.dlang.org/show_bug.cgi?id=5679 void test5679() { class Foo {} class Base { @property Foo getFoo() { return null; } } class Derived : Base { alias getFoo this; } Derived[] dl; Derived d = new Derived(); dl ~= d; // Error: cannot append type alias_test.Base to type Derived[] } /***********************************/ // https://issues.dlang.org/show_bug.cgi?id=6508 void test6508() { int x, y; Seq!(x, y) = tup(10, 20); assert(x == 10); assert(y == 20); } void test6508x() { static int ctor, cpctor, dtor; static struct Tuple(T...) { T field; alias field this; this(int) { ++ctor; printf("ctor\n"); } this(this) { ++cpctor; printf("cpctor\n"); } ~this() { ++dtor; printf("dtor\n"); } } { alias Tup = Tuple!(int, string); auto tup = Tup(1); assert(ctor==1 && cpctor==0 && dtor==0); auto getVal() { return tup; } ref getRef(ref Tup s = tup) { return s; } { auto n1 = tup[0]; assert(ctor==1 && cpctor==0 && dtor==0); auto n2 = getRef()[0]; assert(ctor==1 && cpctor==0 && dtor==0); auto n3 = getVal()[0]; assert(ctor==1 && cpctor==1 && dtor==1); } // bug in DotVarExp::semantic { typeof(tup.field) vars; vars = getVal(); assert(ctor==1 && cpctor==2 && dtor==2); } } assert(ctor==1 && cpctor==2 && dtor==3); assert(ctor + cpctor == dtor); } /***********************************/ // https://issues.dlang.org/show_bug.cgi?id=6369 void test6369a() { alias Seq!(int, string) Field; auto t1 = Tup!(int, string)(10, "str"); Field field1 = t1; // NG -> OK assert(field1[0] == 10); assert(field1[1] == "str"); auto t2 = Tup!(int, string)(10, "str"); Field field2 = t2.field; // NG -> OK assert(field2[0] == 10); assert(field2[1] == "str"); auto t3 = Tup!(int, string)(10, "str"); Field field3; field3 = t3.field; assert(field3[0] == 10); assert(field3[1] == "str"); } void test6369b() { auto t = Tup!(Tup!(int, double), string)(tup(10, 3.14), "str"); Seq!(int, double, string) fs1 = t; assert(fs1[0] == 10); assert(fs1[1] == 3.14); assert(fs1[2] == "str"); Seq!(Tup!(int, double), string) fs2 = t; assert(fs2[0][0] == 10); assert(fs2[0][1] == 3.14); assert(fs2[0] == tup(10, 3.14)); assert(fs2[1] == "str"); Tup!(Tup!(int, double), string) fs3 = t; assert(fs3[0][0] == 10); assert(fs3[0][1] == 3.14); assert(fs3[0] == tup(10, 3.14)); assert(fs3[1] == "str"); } void test6369c() { auto t = Tup!(Tup!(int, double), Tup!(string, int[]))(tup(10, 3.14), tup("str", [1,2])); Seq!(int, double, string, int[]) fs1 = t; assert(fs1[0] == 10); assert(fs1[1] == 3.14); assert(fs1[2] == "str"); assert(fs1[3] == [1,2]); Seq!(int, double, Tup!(string, int[])) fs2 = t; assert(fs2[0] == 10); assert(fs2[1] == 3.14); assert(fs2[2] == tup("str", [1,2])); Seq!(Tup!(int, double), string, int[]) fs3 = t; assert(fs3[0] == tup(10, 3.14)); assert(fs3[0][0] == 10); assert(fs3[0][1] == 3.14); assert(fs3[1] == "str"); assert(fs3[2] == [1,2]); } void test6369d() { int eval = 0; Seq!(int, string) t = tup((){++eval; return 10;}(), "str"); assert(eval == 1); assert(t[0] == 10); assert(t[1] == "str"); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6434 struct Variant6434{} struct A6434 { Variant6434 i; alias i this; void opDispatch(string name)() { } } void test6434() { A6434 a; a.weird; // no property 'weird' for type 'VariantN!(maxSize)' } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=6366 void test6366() { struct Zip { string str; size_t i; this(string s) { str = s; } @property const bool empty() { return i == str.length; } @property Tup!(size_t, char) front() { return typeof(return)(i, str[i]); } void popFront() { ++i; } } foreach (i, c; Zip("hello")) { switch (i) { case 0: assert(c == 'h'); break; case 1: assert(c == 'e'); break; case 2: assert(c == 'l'); break; case 3: assert(c == 'l'); break; case 4: assert(c == 'o'); break; default:assert(0); } } auto range(F...)(F field) { static struct Range { F field; bool empty = false; Tup!F front() { return typeof(return)(field); } void popFront(){ empty = true; } } return Range(field); } foreach (i, t; range(10, tup("str", [1,2]))){ static assert(is(typeof(i) == int)); static assert(is(typeof(t) == Tup!(string, int[]))); assert(i == 10); assert(t == tup("str", [1,2])); } auto r1 = range(10, "str", [1,2]); auto r2 = range(tup(10, "str"), [1,2]); auto r3 = range(10, tup("str", [1,2])); auto r4 = range(tup(10, "str", [1,2])); alias Seq!(r1, r2, r3, r4) ranges; foreach (n, _; ranges) { foreach (i, s, a; ranges[n]){ static assert(is(typeof(i) == int)); static assert(is(typeof(s) == string)); static assert(is(typeof(a) == int[])); assert(i == 10); assert(s == "str"); assert(a == [1,2]); } } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6711 void test6711() { struct A { int i; } struct B { A a; alias a this; } struct C { B b; alias b this; } B b; with (b) { i = 42; } assert(b.i == 42); C c; with (c) { i = 42; } assert(c.i == 42); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=12161 class A12161 { void m() {} } class B12161 { A12161 a; alias a this; } void test12161() { B12161 b = new B12161(); b.a = new A12161(); with (b) m(); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6759 struct Range { size_t front() { return 0; } void popFront() { empty = true; } bool empty; } struct ARange { Range range; alias range this; } void test6759() { ARange arange; assert(arange.front == 0); foreach(e; arange) { assert(e == 0); } } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6479 struct Memory6479 { mixin Wrapper6479!(); } struct Image6479 { Memory6479 sup; alias sup this; } mixin template Wrapper6479() { } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6832 void test6832() { static class Foo { } static struct Bar { Foo foo; alias foo this; } Bar bar; bar = new Foo; // ok assert(bar !is null); // ng struct Int { int n; alias n this; } Int a; int b; auto c = (true ? a : b); // TODO assert(c == a); } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6928 void test6928() { struct T { int* p; } // p is necessary. T tx; struct S { T get() const { return tx; } alias get this; } immutable(S) s; immutable(T) t; static assert(is(typeof(1? s:t))); // ok. static assert(is(typeof(1? t:s))); // ok. static assert(is(typeof(1? s:t)==typeof(1? t:s))); // fail. auto x = 1? t:s; // ok. auto y = 1? s:t; // compile error. } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=6929 struct S6929 { T6929 get() const { return T6929.init; } alias get this; } struct T6929 { S6929 get() const { return S6929.init; } alias get this; } void test6929() { T6929 t; S6929 s; static assert(!is(typeof(1? t:s))); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7136 void test7136() { struct X { Object get() immutable { return null; } alias get this; } immutable(X) x; Object y; static assert( is(typeof(1?x:y) == Object)); // fails static assert(!is(typeof(1?x:y) == const(Object))); // fails struct A { int[] get() immutable { return null; } alias get this; } immutable(A) a; int[] b; static assert( is(typeof(1?a:b) == int[])); // fails static assert(!is(typeof(1?a:b) == const(int[]))); // fails } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7731 struct A7731 { int a; } template Inherit7731(alias X) { X __super; alias __super this; } struct B7731 { mixin Inherit7731!A7731; int b; } struct PolyPtr7731(X) { X* _payload; static if (is(typeof(X.init.__super))) { alias typeof(X.init.__super) Super; @property auto getSuper(){ return PolyPtr7731!Super(&_payload.__super); } alias getSuper this; } } template create7731(X) { PolyPtr7731!X create7731(T...)(T args){ return PolyPtr7731!X(args); } } void f7731a(PolyPtr7731!A7731 a) {/*...*/} void f7731b(PolyPtr7731!B7731 b) {f7731a(b);/*...*/} void test7731() { auto b = create7731!B7731(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7808 struct Nullable7808(T) { private T _value; this()(T value) { _value = value; } @property ref inout(T) get() inout pure @safe { return _value; } alias get this; } class C7808 {} struct S7808 { C7808 c; } void func7808(S7808 s) {} void test7808() { auto s = Nullable7808!S7808(S7808(new C7808)); func7808(s); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7945 struct S7945 { int v; alias v this; } void foo7945(ref int n){} void test7945() { auto s = S7945(1); foo7945(s); // 1.NG -> OK s.foo7945(); // 2.OK, ufcs foo7945(s.v); // 3.OK s.v.foo7945(); // 4.OK, ufcs } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15674 // alias this on out parameter, consistent with 7945 case struct S15674 { int v; alias v this; } void foo15674(out int i){ i = 42; } void test15674() { S15674 s; s.v = 1; foo15674(s); assert(s.v == 42); s.v = 1; foo15674(s.v); assert(s.v == 42); s.v = 1; s.foo15674(); assert(s.v == 42); s.v = 1; s.v.foo15674(); assert(s.v == 42); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7979 void test7979() { static struct N { int val; alias val this; } N n = N(1); switch (n) { case 0: assert(0); case 1: break; default: assert(0); } static struct S { string val; alias val this; } S s = S("b"); switch (s) { case "a": assert(0); case "b": break; default: assert(0); } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7992 struct S7992 { int[] arr; alias arr this; } S7992 func7992(...) { S7992 ret; ret.arr.length = _arguments.length; return ret; } void test7992() { int[] arr; assert(arr.length == 0); arr ~= func7992(1, 2); //NG //arr = func7992(1, 2); //OK assert(arr.length == 2); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8169 void test8169() { static struct ValueImpl { static immutable(int) getValue() { return 42; } } static struct ValueUser { ValueImpl m_valueImpl; alias m_valueImpl this; } static assert(ValueImpl.getValue() == 42); // #0, OK static assert(ValueUser.getValue() == 42); // #1, NG -> OK static assert( ValueUser.m_valueImpl .getValue() == 42); // #2, NG -> OK static assert(typeof(ValueUser.m_valueImpl).getValue() == 42); // #3, OK } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8735 struct S8735(alias Arg) { alias Arg Val; alias Val this; } struct Tuple9709(T...) { alias T expand; alias expand this; } void test8735() { alias S8735!1 S; S s; int n = s; assert(n == 1); // https://issues.dlang.org/show_bug.cgi?id=11502 static void f(int i); S8735!f sf; // https://issues.dlang.org/show_bug.cgi?id=9709 alias A = Tuple9709!(1,int,"foo"); A a; //static assert(A[0] == 1); static assert(a[0] == 1); //static assert(is(A[1] == int)); //static assert(is(a[1] == int)); //static assert(A[2] == "foo"); static assert(a[2] == "foo"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9174 void test9174() { static struct Foo { char x; alias x this; } static assert(is(typeof(true ? 'A' : Foo()) == char)); static assert(is(typeof(true ? Foo() : 100) == int)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9177 struct S9177 { int foo(int){ return 0; } alias foo this; } pragma(msg, is(S9177 : int)); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9858 struct S9858() { @property int get() const { return 42; } alias get this; void opAssign(int) {} } void test9858() { const S9858!() s; int i = s; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9873 void test9873() { struct Tup(T...) { T field; alias field this; } auto seq1 = Seq!(1, "hi"); assert(Seq!(1, "hi") == Seq!(1, "hi")); assert(seq1 == Seq!(1, "hi")); assert(Seq!(1, "hi") == seq1); assert(seq1 == seq1); auto seq2 = Seq!(2, "hi"); assert(Seq!(1, "hi") != Seq!(2, "hi")); assert(seq2 != Seq!(1, "hi")); assert(Seq!(1, "hi") != seq2); assert(seq2 != seq1); auto tup1 = Tup!(int, string)(1, "hi"); assert(Seq!(1, "hi") == tup1); assert(seq1 == tup1); assert(tup1 == Seq!(1, "hi")); assert(tup1 == seq1); auto tup2 = Tup!(int, string)(2, "hi"); assert(Seq!(1, "hi") != tup2); assert(seq1 != tup2); assert(tup2 != Seq!(1, "hi")); assert(tup2 != seq1); static assert(!__traits(compiles, seq1 == Seq!(1, "hi", [1,2]))); static assert(!__traits(compiles, tup1 == Seq!(1, "hi", [1,2]))); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10178 void test10178() { struct S { static int count; } S s; assert((s.tupleof == s.tupleof) == true); assert((s.tupleof != s.tupleof) == false); S getS() { S s; ++S.count; return s; } assert(getS().tupleof == getS().tupleof); assert(S.count == 2); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10179 void test10179() { struct S { static int count; } S s; static assert(s.tupleof.length == 0); s.tupleof = s.tupleof; // error -> OK S getS() { S s; ++S.count; return s; } getS().tupleof = getS().tupleof; assert(S.count == 2); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9890 void test9890() { struct RefCounted(T) { T _payload; ref T refCountedPayload() { return _payload; } alias refCountedPayload this; } struct S(int x_) { alias x_ x; } alias RefCounted!(S!1) Rs; static assert(Rs.x == 1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10004 void test10004() { static int count = 0; static S make(S)() { ++count; // necessary to make this function impure S s; return s; } struct SX(T...) { T field; alias field this; } alias S = SX!(int, long); assert(make!S.field == make!S.field); assert(count == 2); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10180 template TypeTuple10180(TL...) { alias TypeTuple10180 = TL; } template Identity10180(alias T) { alias Identity10180 = T; } struct Tuple10180(Specs...) { static if (is(Specs)) { alias Types = Specs; Types expand; alias expand this; } else { alias Types = TypeTuple10180!(Specs[0]); Types expand; mixin("alias Identity10180!(expand[0]) "~Specs[1]~";"); @property ref Tuple10180!(Specs[0]) _Tuple_super() { return *cast(typeof(return)*) (&expand[0]); } alias _Tuple_super this; } } void test10180() { Tuple10180!(int, "a") x; auto o1 = x.a.offsetof; // OK auto o2 = x[0].offsetof; // NG: no property 'offsetof' for type 'int' auto o3 = x._Tuple_super[0].offsetof; // same as above assert(o2 == o3); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10456 void test10456() { S10456 s1, s2; auto x = s1 == s2; } struct S10456 { enum E { e }; alias E this; int[] x; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11261 template Tuple11261(Specs...) { struct Tuple11261 { static if (Specs.length != 4) // anonymous field version { alias Specs Types; Types expand; alias expand this; } else { alias Seq!(Specs[0], Specs[2]) Types; Types expand; ref inout(Tuple11261!Types) _Tuple_super() inout @trusted { return *cast(typeof(return)*) &(expand[0]); } // This is mostly to make t[n] work. alias _Tuple_super this; } this()(Types values) { expand[] = values[]; } } } interface InputRange11261(E) { @property bool empty(); @property E front(); void popFront(); int opApply(int delegate(E)); int opApply(int delegate(size_t, E)); } template InputRangeObject11261(R) { alias typeof(R.init.front()) E; class InputRangeObject11261 : InputRange11261!E { private R _range; this(R range) { this._range = range; } @property bool empty() { return _range.empty; } @property E front() { return _range.front; } void popFront() { _range.popFront(); } int opApply(int delegate(E) dg) { return 0; } int opApply(int delegate(size_t, E) dg) { return 0; } } } // ------ class Container11261 { alias Tuple11261!(string, "key", string, "value") Key; InputRange11261!Key opSlice() { Range r; return new InputRangeObject11261!Range(r); } private struct Range { enum empty = false; auto popFront() {} auto front() { return Key("myKey", "myValue"); } } } void test11261() { auto container = new Container11261(); foreach (k, v; container) // map the tuple of container[].front to (k, v) { static assert(is(typeof(k) == string) && is(typeof(v) == string)); break; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11333 alias id11333(a...) = a; struct Unit11333 { enum value = Unit11333.init.tupleof; alias value this; } void test11333() { void foo() {} id11333!() unit; unit = unit; // ok foo(unit); // ok unit = Unit11333.value; // ok foo(Unit11333.value); // ok Unit11333 unit2; unit = unit2; // ok <- segfault } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11538 struct NullableRef11538(T) { T* _value; inout(T) get() inout { return *_value; } alias get this; } struct S11538 { NullableRef11538!S11538 parent; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11800 struct A11800 { B11800 b; alias b this; } struct B11800 { static struct Value {} Value value; alias value this; void foo(ref const B11800 rhs) { } } void test11800() { A11800 a; B11800 b; b.foo(a); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12008 struct RefCounted12008(T) { struct RefCountedStore { private struct Impl { T _payload; } private void initialize(A...)(auto ref A args) { import core.memory; } void ensureInitialized() { initialize(); } } RefCountedStore _refCounted; void opAssign(T rhs) { } int refCountedPayload() { _refCounted.ensureInitialized(); return 0; } int refCountedPayload() inout { return 0; } alias refCountedPayload this; } struct SharedInput12008 { Group12008 unused; } struct Group12008 { RefCounted12008!SharedInput12008 _allGroups; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12038 bool f12038(void* p) { return true; } struct S12038 { @property p() { f12038(&this); } alias p this; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13490 struct S13490 { int i; alias i this; } struct T13490 { S13490[] a1, a2; } void test13490() { T13490 t; (true ? t.a1 : t.a2) ~= S13490(1); assert(t.a1 == [S13490(1)]); assert(t.a2 == []); (false ? t.a1 : t.a2) ~= S13490(2); assert(t.a1 == [S13490(1)]); assert(t.a2 == [S13490(2)]); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11355 struct A11355 { static int postblit; this(this) { ++postblit; } } struct B11355 { A11355 a; alias a this; } B11355 make11355() { return B11355(); } void test11355() { A11355 a1 = make11355(); assert(A11355.postblit == 1); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13009 struct T13009 { void put(char c) {} } struct S13009(bool rev) { T13009 t; static if (!rev) { @property T13009 getT() { return t; } @property inout(T13009) getT() inout { return t; } } else { @property inout(T13009) getT() inout { return t; } @property T13009 getT() { return t; } } alias getT this; } void test13009() { foreach (bool rev; Seq!(false, true)) { alias S = S13009!rev; alias MS = S; alias CS = const(S); alias WS = inout( S); alias WCS = inout(const S); alias SMS = shared( S); alias SCS = shared( const S); alias SWS = shared(inout S); alias SWCS = shared(inout const S); alias IS = immutable(S); alias MSput = MS .put; alias CSput = CS .put; alias WSput = WS .put; alias WCSput = WCS.put; static assert(!__traits(compiles, { alias SMSput = SMS .put; })); static assert(!__traits(compiles, { alias SCSput = SCS .put; })); static assert(!__traits(compiles, { alias SWSput = SWS .put; })); static assert(!__traits(compiles, { alias SWCSput = SWCS.put; })); alias ISput = IS .put; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14806 struct Nullable14806 { float get() { return float.nan; } alias get this; } struct Foo14806(T) { T bar; Nullable14806 baz; } void test14806() { Foo14806!int a, b; assert(a != b); // ==> a.tupleof != b.tupleof // ==> a.bar != b.bar || a.baz.get() != b.baz.get() Foo14806!string c, d; assert(c != d); // ==> c.tupleof != d.tupleof // ==> c.bar != d.bar || c.baz.get() != d.baz.get() } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14948 struct RefCounted14948(T) { struct Impl { T data; } Impl* impl; @property ref T payload() { return impl.data; } alias payload this; } struct HTTP14948 { struct Impl { } RefCounted14948!Impl p; } void test14948() { int[HTTP14948] aa; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=15292 struct NullableRef15292(T) { inout(T) get() inout { assert(false); } alias get this; } struct S15292 { NullableRef15292!S15292 n; // -> no segfault /* The field 'n' contains alias this, so to use it for the equality, * following helper function is automatically generated in buildXopEquals(). * * static bool __xopEquals(ref const S15292 p, ref const S15292 q) * { * return p == q; * } * * In its definition, const(S15292) equality is analyzed. It fails, then * the error is gagged. */ } /***************************************************/ struct S19284a { int x; } struct S19284b { S19284a s; alias s this; int t; void f() { void wrapped() { x = 1; t = 1; } wrapped(); // <-- 'x' not found, whereas 's.x' works fine } void f1() { x = 2; } void f2() { int x; void wrapped() { x = 7; } wrapped(); assert(x == 7); } void f3() { void wrapped() { void wrapped2() { x = 5; } wrapped2(); } wrapped(); } } void test19284() { S19284b t; // nested function modifies alias this t.f(); assert(t.x == 1); assert(t.t == 1); // member function modifies alias this t.f1(); assert(t.x == 2); // nested function does not modify alias this when it is shadowd by a local variable t.f2(); assert(t.x == 2); // multiple levels of nesting t.f3(); assert(t.x == 5); } int main() { test1(); test2(); test3(); test4(); test5(); test4617a(); test4617b(); test4773(); test5188(); test6(); test7(); test2781(); test6546(); test6736(); test2777a(); test2777b(); test5679(); test6508(); test6508x(); test6369a(); test6369b(); test6369c(); test6369d(); test6434(); test6366(); test6711(); test12161(); test6759(); test6832(); test6928(); test6929(); test7136(); test7731(); test7808(); test7945(); test15674(); test7979(); test7992(); test8169(); test8735(); test9174(); test9858(); test9873(); test10178(); test10179(); test9890(); test10004(); test10180(); test10456(); test11333(); test11800(); test13490(); test11355(); test14806(); test19284(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/argufilem.d ================================================ // EXTRA_SOURCES: imports/argufile.d // NOTE: The bug only works when main.d and argufile.d are put in // separate files and compiled like 'dmd main.d argufile.d' // Also, I'm sure writefln is causing the crash cause when I // use printf(), it doesn't crash. // main.d ------------------------------------------------------- import argufile; int main(string[] args) { string message = arguments("bob is ", 7, " years old"); writefln(message); argufile.useargs(); // will crash here return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/arrayop.d ================================================ import std.math; extern(C) int printf(const char*, ...); string abc; template Floating(T) { T[3] a; T[3] b; T[3] c; T[] A() { printf("A\n"); abc ~= "A"; return a; } T[] B() { printf("B\n"); abc ~= "B"; return b; } T[] C() { printf("C\n"); abc ~= "C"; return c; } T D() { printf("D\n"); abc ~= "D"; return 4; } void testx() { a = [11, 22, 33]; b = [1, 2, 3]; c = [4, 5, 6]; abc = null; A()[] = B()[] + C()[]; assert(abc == "ABC"); assert(a[0] == 5); assert(a[1] == 7); assert(a[2] == 9); abc = null; A()[] = B()[] + 4; assert(abc == "AB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = 4 + B()[]; assert(abc == "AB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = D() + B()[]; assert(abc == "ADB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [11, 22, 33]; abc = null; A()[] += B()[]; assert(abc == "AB"); assert(a[0] == 12); assert(a[1] == 24); assert(a[2] == 36); a = [11, 22, 33]; A()[] += 4; assert(a[0] == 15); assert(a[1] == 26); assert(a[2] == 37); a = [11, 22, 33]; A()[] -= 4; assert(a[0] == 7); assert(a[1] == 18); assert(a[2] == 29); a = [11, 22, 33]; A()[] *= 4; assert(a[0] == 44); assert(a[1] == 88); assert(a[2] == 132); a = [4, 8, 32]; A()[] /= 4; assert(a[0] == 1); assert(a[1] == 2); assert(a[2] == 8); a = [4, 8, 33]; A()[] %= 4; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 1); a = [11, 22, 33]; abc = null; A()[] += 4 + B()[]; assert(abc == "AB"); assert(a[0] == 16); assert(a[1] == 28); assert(a[2] == 40); abc = null; A()[] = B()[] - C()[]; assert(abc == "ABC"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == -3); assert(a[1] == -3); assert(a[2] == -3); abc = null; A()[] = -B()[] - C()[]; assert(abc == "ABC"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == -5); assert(a[1] == -7); assert(a[2] == -9); abc = null; A()[] = B()[] + C()[] * 4; assert(abc == "ABC"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 17); assert(a[1] == 22); assert(a[2] == 27); abc = null; A()[] = B()[] + C()[] * B()[]; assert(abc == "ABCB"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 5); assert(a[1] == 12); assert(a[2] == 21); abc = null; A()[] = B()[] + C()[] / 2; assert(abc == "ABC"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 3); assert(a[1] == 4.5); assert(a[2] == 6); abc = null; A()[] = B()[] + C()[] % 2; assert(abc == "ABC"); printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); assert(a[0] == 1); assert(a[1] == 3); assert(a[2] == 3); } } mixin Floating!(float) Ffloat; mixin Floating!(double) Fdouble; mixin Floating!(real) Freal; void test1() { Ffloat.testx(); Fdouble.testx(); Freal.testx(); } /************************************************************************/ template Integral(T) { T[3] a; T[3] b; T[3] c; T[] A() { printf("A\n"); abc ~= "A"; return a; } T[] B() { printf("B\n"); abc ~= "B"; return b; } T[] C() { printf("C\n"); abc ~= "C"; return c; } T D() { printf("D\n"); abc ~= "D"; return 4; } void testx() { a = [11, 22, 33]; b = [1, 2, 3]; c = [4, 5, 6]; abc = null; A()[] = B()[] + C()[]; assert(abc == "ABC"); assert(a[0] == 5); assert(a[1] == 7); assert(a[2] == 9); abc = null; A()[] = B()[] + 4; assert(abc == "AB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = 4 + B()[]; assert(abc == "AB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); abc = null; A()[] = D() + B()[]; assert(abc == "ADB"); assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [11, 22, 33]; abc = null; A()[] += B()[]; assert(abc == "AB"); assert(a[0] == 12); assert(a[1] == 24); assert(a[2] == 36); a = [11, 22, 33]; A()[] += 4; assert(a[0] == 15); assert(a[1] == 26); assert(a[2] == 37); a = [11, 22, 33]; A()[] -= 4; assert(a[0] == 7); assert(a[1] == 18); assert(a[2] == 29); a = [11, 22, 27]; A()[] *= 4; assert(a[0] == 44); assert(a[1] == 88); assert(a[2] == 108); a = [11, 22, 33]; A()[] /= 4; assert(a[0] == 2); assert(a[1] == 5); assert(a[2] == 8); a = [11, 22, 33]; A()[] %= 4; assert(a[0] == 3); assert(a[1] == 2); assert(a[2] == 1); a = [1, 2, 7]; A()[] &= 4; assert(a[0] == 0); assert(a[1] == 0); assert(a[2] == 4); a = [1, 2, 7]; A()[] |= 4; assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 7); a = [1, 2, 7]; A()[] ^= 4; assert(a[0] == 5); assert(a[1] == 6); assert(a[2] == 3); a = [11, 22, 33]; abc = null; A()[] += 4 + B()[]; assert(abc == "AB"); assert(a[0] == 16); assert(a[1] == 28); assert(a[2] == 40); abc = null; A()[] = B()[] - C()[]; assert(abc == "ABC"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == -3); assert(a[1] == -3); assert(a[2] == -3); abc = null; A()[] = -B()[] - C()[]; assert(abc == "ABC"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == -5); assert(a[1] == -7); assert(a[2] == -9); abc = null; A()[] = B()[] + C()[] * 4; assert(abc == "ABC"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 17); assert(a[1] == 22); assert(a[2] == 27); abc = null; A()[] = B()[] + C()[] * B()[]; assert(abc == "ABCB"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 5); assert(a[1] == 12); assert(a[2] == 21); abc = null; A()[] = B()[] + C()[] / 2; assert(abc == "ABC"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 3); assert(a[1] == 4); assert(a[2] == 6); abc = null; A()[] = B()[] + C()[] % 2; assert(abc == "ABC"); printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); assert(a[0] == 1); assert(a[1] == 3); assert(a[2] == 3); abc = null; A()[] = ~B()[]; assert(abc == "AB"); assert(a[0] == ~cast(T)1); assert(a[1] == ~cast(T)2); assert(a[2] == ~cast(T)3); abc = null; A()[] = B()[] & 2; assert(abc == "AB"); assert(a[0] == 0); assert(a[1] == 2); assert(a[2] == 2); abc = null; A()[] = B()[] | 2; assert(abc == "AB"); assert(a[0] == 3); assert(a[1] == 2); assert(a[2] == 3); abc = null; A()[] = B()[] ^ 2; assert(abc == "AB"); assert(a[0] == 3); assert(a[1] == 0); assert(a[2] == 1); } } /************************************************************************/ mixin Integral!(byte) Fbyte; mixin Integral!(short) Fshort; mixin Integral!(int) Fint; mixin Integral!(long) Flong; void test2() { Fbyte.testx(); Fshort.testx(); Fint.testx(); Flong.testx(); } /************************************************************************/ void test3() { auto a = new double[10], b = a.dup, c = a.dup, d = a.dup; a[] = -(b[] * (c[] + 4)) + 5 * d[] / 3.0; } /************************************************************************/ void test4() { int[] a, b; if (a && b) {} } /***************************************************/ void test4662() { immutable double[] nums = [1.0, 2.0]; static assert(!is(typeof({ nums[] += nums[]; }))); static assert(!is(typeof({ nums[] -= nums[]; }))); static assert(!is(typeof({ nums[] /= nums[]; }))); static assert(!is(typeof({ nums[] += 4; }))); static assert(!is(typeof({ nums[] /= 7; }))); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=5284 void bug5284_1() { class C { int v; } C [] mda; immutable(C)[] ida; static assert(!__traits(compiles, (mda[] = ida[]))); C [1] msa; immutable(C)[1] isa; static assert(!__traits(compiles, (msa[] = isa[]))); C m; immutable(C) i; static assert(!__traits(compiles, m = i)); } void bug5284_2a() { struct S { int v; } S [] mda; immutable(S)[] ida; mda[] = ida[]; S [1] msa; immutable(S)[1] isa; msa[] = isa[]; S m = S(); immutable(S) i = immutable(S)(); m = i; } void bug5284_2b() { struct S { int v; int[] arr; } S [] mda; immutable(S)[] ida; static assert(!__traits(compiles, (mda[] = ida[]))); S [1] msa; immutable(S)[1] isa; static assert(!__traits(compiles, (msa[] = isa[]))); S m; immutable(S) i; static assert(!__traits(compiles, m = i)); } void bug5284_3() { int [] ma; immutable(int)[] ia; ma[] = ia[]; int m; immutable(int) i; m = i; } void test5() { bug5284_1(); bug5284_2a(); bug5284_2b(); bug5284_3(); } /************************************************************************/ void test6() { int[10] a = [1,2,3,4,5,6,7,8,9,10]; int[10] b; b = a[] ^^ 2; assert(b[0] == 1); assert(b[1] == 4); assert(b[2] == 9); assert(b[3] == 16); assert(b[4] == 25); assert(b[5] == 36); assert(b[6] == 49); assert(b[7] == 64); assert(b[8] == 81); assert(b[9] == 100); int[10] c = 3; b = a[] ^^ c[]; assert(b[0] == 1); assert(b[1] == 8); assert(b[2] == 27); assert(b[3] == 64); assert(b[4] == 125); assert(b[5] == 216); assert(b[6] == 343); assert(b[7] == 512); assert(b[8] == 729); assert(b[9] == 1000); } /************************************************************************/ void test8390() { const int[] a = new int[5]; int[] b = new int[5]; b[] += a[]; } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8651 void test8651() { void test(T)() @safe pure nothrow { T[3] a = [11, 22, 33]; T[3] b = [1, 2, 3]; T[3] c = [4, 5, 6]; T d = 4; // Arithmetic array ops { a[] = b[] + c[]; a[] = b[] + 4; a[] = 4 + b[]; a[] = d + b[]; a[] += b[]; a[] += 4; a[] -= 4; a[] *= 4; a[] /= 4; a[] %= 4; a[] += 4 + b[]; a[] = b[] - c[]; a[] = -b[] - c[]; a[] = b[] + c[] * 4; a[] = b[] + c[] * b[]; a[] = b[] + c[] / 2; a[] = b[] + c[] % 2; } // Bitwise array ops static if (is(typeof(T.init & T.init))) { a[] &= 4; a[] |= 4; a[] ^= 4; a[] = ~b[]; a[] = b[] & 2; a[] = b[] | 2; a[] = b[] ^ 2; } } test!float(); test!double(); test!real(); test!byte(); test!short(); test!int(); test!long(); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=9656 void test9656() { static class C {} static struct S { immutable int[] narr1; immutable int[] narr2; immutable C[] carr1; immutable C[] carr2; this(int n) { narr1 = new int[](3); // OK, expected narr2 = [1,2,3].dup; // NG -> OK carr1 = [new C].dup; // NG -> OK C c = new C; static assert(!__traits(compiles, carr2 = [c])); } } { int[] ma = [1,2,3]; immutable ia = ma.idup; } { static struct V { int val; } V[] ma = [V(1), V(2)]; immutable ia = ma.idup; } { static struct R { int* ptr; } R[] ma = [R(new int), R(null)]; static assert(!__traits(compiles, { immutable ia = rarr.dup; })); } { C[] ma = [new C(), new C()]; static assert(!__traits(compiles, { immutable ia = carr.dup; })); } } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10282 void test10282() { int[3] a1 = [1, 3, 6]; int[3] a2 = [1, 3, 6] * 3; // OK const int[3] a3 = a1[] * 3; // OK <- Error const int[3] a4 = [1, 3, 6] * 3; // OK <- Error immutable int[3] a5 = [1, 3, 6] * 3; // OK <- Error assert(a1[0] == 1 && a1[1] == 3 && a1[2] == 6); assert(a2[0] == 3 && a2[1] == 9 && a2[2] == 18); assert(a3[0] == 3 && a3[1] == 9 && a3[2] == 18); assert(a4[0] == 3 && a4[1] == 9 && a4[2] == 18); assert(a5[0] == 3 && a5[1] == 9 && a5[2] == 18); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10433 void test10433() { void foo(T)(in int[] v1, in T v2) { int[2] r; r[] = v1[] + v2[]; } immutable int[] v = [10, 20]; foo(v, v); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10684 void test10684a() { int[] a = [0, 0]; a[] += [10, 20][]; } void test10684b() { int[] a = [1, 2, 3]; int[] b = [4, 5, 6]; // Allow array literal as the operand of array oeration a[] += [1, 2, 3]; assert(a == [2, 4, 6]); a[] *= b[] + [1, 1, 1]; assert(a == [2*(4+1), 4*(5+1), 6*(6+1)]); a[] = [9, 8, 7] - [1, 2, 3]; assert(a == [8, 6, 4]); a[] = [2, 4, 6] / 2; assert(a == [1,2,3]); // Disallow: [1,2,3] is not an lvalue static assert(!__traits(compiles, { [1,2,3] = a[] * 2; })); static assert(!__traits(compiles, { [1,2,3] += a[] * b[]; })); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11376 template TL11376(T...) { alias TL11376 = T; } auto sumArrs11376(T0, T1)(T0[] a, T1[] b) { a[] += b[]; //no ICE without this line return a; } static assert(!__traits(compiles, sumArrs11376(TL11376!(string[], string).init))); /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11525 void test11525() { static struct Complex(T) { T re, im; ref opOpAssign(string op : "*")(Complex z) { auto temp = re*z.re - im*z.im; im = im*z.re + re*z.im; re = temp; return this; } } auto a = [Complex!double(2, 2)]; assert(a.length == 1 && a[0].re == 2 && a[0].im == 2); a[] *= a[]; assert(a.length == 1 && a[0].re == 0 && a[0].im == 8); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12250 void f12250(inout int[] p, inout int[] q, int[] r) { r[] = p[] + q[]; assert(r == [5,7,9]); r[] -= p[] - q[]; assert(r == [8,10,12]); } void test12250() { immutable int[3] x = [1,2,3], y = [4,5,6]; int[3] z; f12250(x[], y[], z[]); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12179 void test12179() { void foo(int[]) {} int[1] a; foo(a[] = a[]); foo(a[] += a[]); foo(a[] -= a[]); foo(a[] *= a[]); foo(a[] /= a[]); foo(a[] %= a[]); foo(a[] ^= a[]); foo(a[] &= a[]); foo(a[] |= a[]); foo(a[] ^^= a[]); // from https://issues.dlang.org/show_bug.cgi?id=11992 int[] arr1; int[][] arr2; arr1 ~= (a[] = [1] + a[]); // OK arr2 ~= (a[] = [1] + a[]); // OK } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=12780 void test12780() { int ival = 2; int[] iarr = [1, 2, 3]; double dval = 2.0; double[] darr = [4, 5, 6]; double[] oarr = [0, 0, 0]; // multiply array operations oarr[] = dval * iarr[]; assert(oarr == [dval * iarr[0], dval * iarr[1], dval * iarr[2]]); oarr[] = iarr[] / dval; assert(oarr == [iarr[0] / dval, iarr[1] / dval, iarr[2] / dval]); oarr[] = dval * (ival + iarr[]); assert(oarr == [dval * (ival + iarr[0]), dval * (ival + iarr[1]), dval * (ival + iarr[2])]); oarr[] = (iarr[] & ival) / dval; assert(oarr == [(iarr[0] & ival) / dval, (iarr[1] & ival) / dval, (iarr[2] & ival) / dval]); oarr[] = darr[] + iarr[]; assert(oarr == [darr[0] + iarr[0], darr[1] + iarr[1], darr[2] + iarr[2]]); oarr[] = iarr[] - darr[]; assert(oarr == [iarr[0] - darr[0], iarr[1] - darr[1], iarr[2] - darr[2]]); oarr[] = darr[] * (ival & iarr[]); assert(oarr == [darr[0] * (ival & iarr[0]), darr[1] * (ival & iarr[1]), darr[2] * (ival & iarr[2])]); oarr[] = (iarr[] ^ ival) / darr[]; assert(oarr == [(iarr[0] ^ ival) / darr[0], (iarr[1] ^ ival) / darr[1], (iarr[2] ^ ival) / darr[2]]); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13497 void test13497() { int[1] a = [2], b = [3]; int[1] c1 = a[] * b[]; int[1] c2 = (a[] * b[])[]; assert(c1 == [6]); assert(c2 == [6]); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14649 void test14649() { char[] a = "abc".dup; char[] b = [char(1), char(2), char(3)]; string x = "abc"; string y = [char(1), char(2), char(3)]; char[] r = new char[](3); r[] = a[] + b[]; assert(r == "bdf"); r[] = x[] + y[]; assert(r == "bdf"); r[] = "hel"[] + "lo."[]; assert(r == [('h'+'l'), ('e'+'o'), ('l'+'.')]); enum s = "abc"; r[] = s[0..3] + "def"[0..3]; assert(r == [('a'+'d'), ('b'+'e'), ('c'+'f')]); } /************************************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14851 void test14851() { int[8] a, b, c; c = a[] | b[]; // OK <- NG from 2.068.0-b2 c = a[] ^ b[]; // OK <- NG from 2.068.0-b2 c[] = a[] | b[]; // OK c[] = a[] ^ b[]; // OK } /************************************************************************/ int main() { version(X86) { test1(); test2(); } else version(X86_64) { test1(); test2(); } else { pragma(msg, "arrayop.d:test1 Test skipped because arrayop evaluation" ~ " order is ill-defined. See GDC issue #8"); } test3(); test4(); test5(); test6(); test8390(); test8651(); test9656(); test10282(); test10433(); test10684a(); test10684b(); test11525(); test12250(); test12780(); test13497(); test14649(); test14851(); printf("Success\n"); return 0; } version (none) { extern (C) T[] _arraySliceSliceAddSliceAssignd(T[] a, T[] c, T[] b) { foreach (i; 0 .. a.length) a[i] = b[i] + c[i]; return a; } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/auto1.d ================================================ import core.stdc.stdio; /******************************************/ scope class Foo { static int x; ~this() { printf("Foo.~this()\n"); x++; } } int test1x() { scope Foo f = new Foo(); return 6; } void test1() { { scope Foo f = new Foo(); } int c; assert(Foo.x == 1); c = test1x(); assert(c == 6); assert(Foo.x == 2); if (c != 6) scope Foo h = new Foo(); assert(Foo.x == 2); if (c == 6) scope Foo j = new Foo(); assert(Foo.x == 3); { scope Foo g = null, k = new Foo(); assert(Foo.x == 3); } assert(Foo.x == 4); } /******************************************/ int ax; scope class A2 { this() { printf("A2.this()\n"); ax += 1; } ~this() { printf("A2.~this()\n"); ax += 1000; } }; void test2() { { scope A2 a = new A2(); printf("Hello world.\n"); } assert(ax == 1001); } /******************************************/ int status3; scope class Parent3 { } scope class Child3 : Parent3 { this(){ assert(status3==0); status3=1; } ~this(){ assert(status3==1); status3=2; } } void foo3() { scope Parent3 o = new Child3(); assert(status3==1); } void test3() { foo3(); assert(status3==2); } /******************************************/ int main() { test1(); test2(); test3(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/b16278.d ================================================ // REQUIRED_ARGS: -main class A() { static struct S { A a; } } enum e = is(A!()); ================================================ FILE: gcc/testsuite/gdc.test/runnable/b17073.d ================================================ struct S0 { int x = void; } struct S1 { S0 x = S0(42); } void main() { S1 x; assert(x.x.x == 42); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/b18034.d ================================================ // REQUIRED_ARGS: -O version (D_SIMD) { import core.simd; void check(void16 a) { foreach (x; (cast(ushort8)a).array) { assert(x == 1); } } void make(ushort x) { ushort8 v = ushort8(x); check(v); } void main() { make(1); } } else { void main() { } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/b26.d ================================================ // COMPILE_SEPARATELY // EXTRA_SOURCES: imports/b26a.d // PERMUTE_ARGS: // https://issues.dlang.org/show_bug.cgi?id=382 struct List(T) { interface A {} } int main(char[][] args) { List!(char) list; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/b6400.d ================================================ /* TEST_OUTPUT: --- Foo Bar Foo Bar Bar Foo Bar --- */ // https://issues.dlang.org/show_bug.cgi?id=6400 enum int base(string name) = 10 * (name[$-1] - '0'); struct Foo { int opDispatch(string name)() { pragma(msg, "Foo"); return base!name + 1; } } struct Bar { int opDispatch(string name)() { pragma(msg, "Bar"); return base!name + 2; } } struct Baz { } void main() { assert(test()); static assert(test()); } bool test() { auto foo = new Foo; auto bar = new Bar; auto baz = new Baz; with (foo) { assert(f1() == 11); with (baz) assert(f1() == 11); with (bar) { assert(f2() == 22); with (baz) assert(f2() == 22); with (foo) { assert(f3() == 31); with (baz) assert(f3() == 31); with (bar) { assert(f4() == 42); with (baz) assert(f4() == 42); with (baz) { assert(f5() == 52); with (baz) assert(f5() == 52); } with (foo) { assert(f6() == 61); with (baz) assert(f6() == 61); } with (bar) { assert(f7() == 72); with (baz) assert(f7() == 72); } } } } } return true; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bcraii.d ================================================ /* REQUIRED_ARGS: -betterC * PERMUTE_ARGS: */ import core.stdc.stdio; extern (C) int main() { auto j = test(1); assert(j == 3); return 0; } int test(int i) nothrow { { int j = i ? S(3).i : 3; printf("inside\n"); assert(Sctor == 1); assert(Sdtor == 1); return j; } printf("done\n"); return -1; } __gshared int Sctor; __gshared int Sdtor; struct S { int i; this(int i) nothrow { this.i += i; printf("S.this()\n"); ++Sctor; } ~this() nothrow { assert(i == 3); i = 0; printf("S.~this()\n"); ++Sdtor; } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bcraii2.d ================================================ /* REQUIRED_ARGS: -betterC * PERMUTE_ARGS: */ import core.stdc.stdio; extern (C) int main() { auto j = test(1); assert(j == 3); assert(Sdtor == 1); test2(); return 0; } int test(int i) nothrow { { S s = S(3); printf("inside\n"); assert(Sctor == 1); assert(Sdtor == 0); return s.i; } printf("done\n"); return -1; } __gshared int Sctor; __gshared int Sdtor; struct S { int i; this(int i) nothrow { this.i += i; printf("S.this()\n"); ++Sctor; } ~this() nothrow { assert(i == 3); i = 0; printf("S.~this()\n"); ++Sdtor; } } /*************************************/ void test2() { int i = 3; try { try { ++i; goto L10; } finally { i *= 2; printf("f1\n"); } } finally { i += 5; printf("f2\n"); } L10: printf("3\n"); assert(i == (3 + 1) * 2 + 5); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bench1.d ================================================ // REQUIRED_ARGS: // EXECUTE_ARGS: 10000 extern(C) int printf(const char *, ...); extern(C) int atoi(const char *); int main (string[] argv) { string s = ""; int count, loop; count = atoi((argv[1] ~ '\0').ptr); if (count == 0) count = 1; printf("count = %u\n", count); for (loop = 0; loop < count; loop ++) s ~= "hello\n"; for (loop = 0; loop < count; loop ++) s ~= "h"; printf ("%d\n", s.length); //printf("%.*s\n", s[0..100]); assert(s.length == count * (6 + 1)); s.length = 3; s.length = 10; s.length = 0; s.length = 1000; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/betterc.d ================================================ /* REQUIRED_ARGS: -betterC PERMUTE_ARGS: */ void test(int ij) { assert(ij); #line 100 "anotherfile" assert(ij,"it is not zero"); } /*******************************************/ // https://issues.dlang.org/show_bug.cgi?id=17843 struct S { double d = 0.0; int[] x; } /*******************************************/ extern (C) void main() { test(1); test18472(); testRuntimeLowerings(); test18457(); } /*******************************************/ // https://issues.dlang.org/show_bug.cgi?id=17605 extern (C) void test17605() { int a; enum bool works = __traits(compiles, { a = 1; }); a = 1; } /*******************************************/ // https://issues.dlang.org/show_bug.cgi?id=18472 void test18472() { version(D_LP64) { enum b = typeid(size_t) is typeid(ulong); } else { enum b = typeid(size_t) is typeid(uint); } assert(b); } /*******************************************/ // https://issues.dlang.org/show_bug.cgi?id=18493 struct S18493 { this(this) nothrow { } // Since this is attributed with `nothrow` there should be no error about using // try-catch with -betterC ~this() { } } struct S18493_2 { S18493 s1; S18493 s2; } /****************************************************** * tests to ensure there is sufficient runtime support * in imported object.d */ mixin template initArray() { static if (is(T == bool)) { T[6] a1 = [true, false, true, true, false, true]; } else static if (is(T == Sint)) { T[6] a1 = [Sint(1), Sint(2), Sint(3), Sint(1), Sint(2), Sint(3)]; } else { T[6] a1 = [1,2,3,1,2,3]; } } struct Sint { int x; this(int v) { x = v;} } void testRuntimeLowerings() { // test call to `object.__equals` void test__equals(T)() { mixin initArray; assert(a1[0..3] == a1[3..$]); } test__equals!int; test__equals!uint; test__equals!long; test__equals!ulong; test__equals!short; test__equals!ushort; test__equals!byte; test__equals!dchar; test__equals!wchar; test__equals!ubyte; test__equals!char; test__equals!(const char); test__equals!bool; test__equals!Sint; // test call to `object.__cmp` void test__cmp(T)() { mixin initArray; assert(a1[0..3] >= a1[3..$]); assert(a1[0..3] <= a1[3..$]); } test__cmp!int; test__cmp!uint; test__cmp!long; test__cmp!ulong; test__cmp!short; test__cmp!ushort; test__cmp!byte; test__cmp!dchar; test__cmp!wchar; test__cmp!ubyte; test__cmp!char; test__cmp!(const char); test__cmp!bool; test__cmp!Sint; // test call to `object.__switch`` auto s = "abc"; switch(s) { case "abc": break; default: break; } } /**********************************************/ // https://issues.dlang.org/show_bug.cgi?id=18457 __gshared int dtor; struct S18457 { int a = 3; ~this() { a = 0; ++dtor; } } S18457 myFunction() { S18457 s = S18457(); return s; } void test18457() { { S18457 s = myFunction(); assert(s.a == 3); assert(dtor == 0); } assert(dtor == 1); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bitops.d ================================================ // PERMUTE_ARGS: import core.stdc.stdio; import core.bitop; /*****************************************************/ void test1() { size_t[2] array; uint x; version (D_LP64) size_t bitToUse = 67; else size_t bitToUse = 35; array[0] = 2; array[1] = 0x100; printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); x = btc(array.ptr, bitToUse); printf("btc(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x == 0); assert(array[0] == 0x2 && array[1] == 0x108); x = btc(array.ptr, bitToUse); printf("btc(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); x = bts(array.ptr, bitToUse); printf("bts(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x == 0); assert(array[0] == 2 && array[1] == 0x108); x = btr(array.ptr, bitToUse); printf("btr(array, %d) = %d\n", bitToUse, x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); x = bt(array.ptr, 1); printf("bt(array, 1) = %d\n", x); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); assert(x != 0); assert(array[0] == 2 && array[1] == 0x100); } /*****************************************************/ void test2() { uint v; int x; v = 0x21; x = bsf(v); printf("bsf(x%x) = %d\n", v, x); assert(x == 0); x = bsr(v); printf("bsr(x%x) = %d\n", v, x); assert(x == 5); } /*****************************************************/ version (DigitalMars) void test3() { uint v; int b; b = inp(b); b = inpw(b); b = inpl(b); b = outp(v, cast(ubyte)b); b = outpw(v, cast(ushort)b); b = outpl(v, b); } /*****************************************************/ void test4() { uint i = 0x12_34_56_78; i = bswap(i); assert(i == 0x78_56_34_12); } /*****************************************************/ void test5() { size_t[2] array; array[0] = 2; array[1] = 0x100; printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("bts(array, 35) = %d\n", bts(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("btr(array, 35) = %d\n", btr(array.ptr, 35)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); printf("bt(array, 1) = %d\n", bt(array.ptr, 1)); printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); } /*****************************************************/ class Node { uint leaf = 0; int m() { return leaf ? 0 : bsf(leaf); } } void test6() { Node n = new Node(); } /*****************************************************/ int main() { test1(); test2(); //test3(); test4(); test5(); test6(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug11155.d ================================================ // PERMUTE_ARGS: version(D_SIMD) { alias float4 = __vector(float[4]); void foo(float4* ptr, float4 val) { assert((cast(ulong) &val & 0xf) == 0); } void main() { float4 v; foo(&v, v); } } else void main(){} ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug12928.d ================================================ // PERMUTE_ARGS: -inline -g -O import core.exception : RangeError; void main(string[] args) { int[2] a; try { foreach(const i; 0..3) a[i] = i; assert(0); } catch(RangeError){} } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug16146.d ================================================ struct X { int* rc; this (int n) { auto x = new int[](1); rc = x.ptr; *rc = n; } this (this) { ++*rc; } ~this () { --*rc; } @disable void opAssign (X src); } struct Y { X x; } void frob(X x) { Y y = { x: x }; // The 'rc' counter starts from 1 and gets bumped when: // - 'f0' is passed to 'frob' // - 'y' is initialized with 'x' assert(*y.x.rc == 3); } void main () { auto f0 = X(1); frob(f0); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug5.d ================================================ // REQUIRED_ARGS: -w class F { } int test1() { scope F f = new F(); // comment out and warning goes away return 0; } int test2() { // no return at end of function try { return 0; } finally { } } void main() { test1(); test2(); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug7068.d ================================================ // PERMUTE_ARGS: -inline -g -O -d void main() { auto darray1 = new int*[](10); foreach(ref v; darray1) v = new int; auto darray2 = new int*[](10); darray2[] = darray1[]; // calls memset instead of memcpy foreach(i; 0 .. 10) assert(darray1[i] == darray2[i]); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/bug846.d ================================================ // see also: bug 8 // EXTRA_SOURCES: imports/bug846.d import imports.bug846; void main() { auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } ); assert(num == 5); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/builtin.d ================================================ import std.stdio; import std.math; import core.bitop; version (DigitalMars) { version (X86_64) version = AnyX86; else version (X86) version = AnyX86; } /*******************************************/ void test1() { writefln("%a", sin(6.8L)); auto f = 6.8L; writefln("%a", sin(f)); assert(sin(f) == sin(6.8L)); static assert(approxEqual(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2)); writefln("%a", cos(6.8L)); f = 6.8L; writefln("%a", cos(f)); assert(cos(f) == cos(6.8L)); static assert(approxEqual(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1)); writefln("%a", tan(6.8L)); f = 6.8L; writefln("%a", tan(f)); version (Win64) { } else assert(tan(f) == tan(6.8L)); static assert(approxEqual(tan(6.8L), 0x1.22fd752af75cd08cp-1)); } /*******************************************/ void test2() { float i = 3; i = i ^^ 2; assert(i == 9); int j = 2; j = j ^^ 1; assert(j == 2); i = 4; i = i ^^ .5; assert(i == 2); } /**** https://issues.dlang.org/show_bug.cgi?id=5703 ****/ static assert({ int a = 0x80; int f = bsf(a); int r = bsr(a); a = 0x22; assert(bsf(a)==1); assert(bsr(a)==5); a = 0x8000000; assert(bsf(a)==27); assert(bsr(a)==27); a = 0x13f562c0; assert(bsf(a) == 6); assert(bsr(a) == 28); assert(bswap(0xAABBCCDD) == 0xDDCCBBAA); return true; }()); /*******************************************/ void test3() { version (AnyX86) { static assert( _popcnt( cast(ushort)0 ) == 0 ); static assert( _popcnt( cast(ushort)7 ) == 3 ); static assert( _popcnt( cast(ushort)0xAA )== 4); static assert( _popcnt( cast(ushort)0xFFFF ) == 16 ); static assert( _popcnt( cast(ushort)0xCCCC ) == 8 ); static assert( _popcnt( cast(ushort)0x7777 ) == 12 ); static assert( _popcnt( cast(uint)0 ) == 0 ); static assert( _popcnt( cast(uint)7 ) == 3 ); static assert( _popcnt( cast(uint)0xAA )== 4); static assert( _popcnt( cast(uint)0x8421_1248 ) == 8 ); static assert( _popcnt( cast(uint)0xFFFF_FFFF ) == 32 ); static assert( _popcnt( cast(uint)0xCCCC_CCCC ) == 16 ); static assert( _popcnt( cast(uint)0x7777_7777 ) == 24 ); version (X86_64) { static assert( _popcnt( cast(ulong)0 ) == 0 ); static assert( _popcnt( cast(ulong)7 ) == 3 ); static assert( _popcnt( cast(ulong)0xAA )== 4); static assert( _popcnt( cast(ulong)0x8421_1248 ) == 8 ); static assert( _popcnt( cast(ulong)0xFFFF_FFFF_FFFF_FFFF ) == 64 ); static assert( _popcnt( cast(ulong)0xCCCC_CCCC_CCCC_CCCC ) == 32 ); static assert( _popcnt( cast(ulong)0x7777_7777_7777_7777 ) == 48 ); } } } /*******************************************/ int main() { test1(); test2(); test3(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/c22.d ================================================ // EXTRA_SOURCES: imports/c22a.d imports/c22b.d // PERMUTE_ARGS: module main; import imports.c22a; import imports.c22b; int main() { afn1(); afn2(); bfn1(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/cabi1.d ================================================ // EXTRA_CPP_SOURCES: extra-files/cabi2.cpp import core.stdc.stdio; import core.stdc.config; struct Foo1 { char c; } struct Foo2 { short s; } struct Foo3 { char c; short s; } struct Foo4 { int i; } struct Foo5 { int i, j; } struct Foo6 { int i, j, k; } struct S7 { float a, b; } extern (C) Foo1 ctest1(); extern (C) Foo2 ctest2(); extern (C) Foo3 ctest3(); extern (C) Foo4 ctest4(); extern (C) Foo5 ctest5(); extern (C) Foo6 ctest6(); extern (C) S7 ctest10(); version(Windows) version = Windows_or_32bit; else version(X86) version = Windows_or_32bit; void test1() { Foo1 f1 = ctest1(); assert(f1.c == 3); Foo2 f2 = ctest2(); assert(f2.s == 0x1234); Foo3 f3 = ctest3(); assert(f3.s == 0x5678); Foo4 f4 = ctest4(); assert(f4.i == 0x12345678); Foo5 f5 = ctest5(); assert(f5.i == 0x12345678); assert(f5.j == 0x21436587); version(Windows_or_32bit) { Foo6 f6 = ctest6(); assert(f6.i == 0x12345678); assert(f6.j == 0x21463587); assert(f6.k == 0x24163857); } S7 s7 = ctest10(); assert(s7.a == 2.5); assert(s7.b == 1.5); } /*******************************************/ extern (C) { char ctest7(char); ubyte ctest8(ubyte); byte ctest9(byte); } void test2() { assert(ctest7('a') == 'b'); assert(ctest8(7) == 8); assert(ctest9(3) == 4); } /******************************************/ extern (C) { void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c); } void test3() { ctestrir(1,2,3,4,5,6, c_long_double(100.0), 67, c_long_double(200.0)); } /******************************************/ extern (C) void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c) { assert(a == 300.0); assert(b == 68); assert(c == 401.0); } extern (C) void test4(); /******************************************/ struct S11 { ubyte a, b, c; } extern (C) S11 ctest11(ubyte x, S11, ubyte y); void test11() { version (X86) { S11 t; assert(S11.sizeof == 3); t.a = 2; t.b = 3; t.c = 4; auto s = ctest11(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S12 { char a,d; char b,e; ubyte c; } extern (C) S12 ctest12(ubyte x, S12, ubyte y); void test12() { version (X86) { S12 t; printf("D sz = %d\n", cast(int)S12.sizeof); // assert(S12.sizeof == 5); t.a = 2; t.b = 3; t.c = 4; auto s = ctest12(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S13 { ushort a, b, c; } extern (C) S13 ctest13(ubyte x, S13, ubyte y); void test13() { version (X86) { S13 t; assert(S13.sizeof == 6); t.a = 2; t.b = 3; t.c = 4; auto s = ctest13(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S14 { char a,d,e,f; char b,g; ubyte c; } extern (C) S14 ctest14(ubyte x, S14, ubyte y); void test14() { version (X86) { S14 t; assert(S14.sizeof == 7); t.a = 2; t.b = 3; t.c = 4; auto s = ctest14(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ struct S15 { char a,d,e,f; char b,g,h,i; ubyte c; } extern (C) S15 ctest15(ubyte x, S15, ubyte y); void test15() { version (X86) { S15 t; assert(S15.sizeof == 9); t.a = 2; t.b = 3; t.c = 4; auto s = ctest15(1, t, 5); assert(s.a == 2); assert(s.b == 3); assert(s.c == 4); } } /******************************************/ // see https://issues.dlang.org/show_bug.cgi?id=17277 struct S16 { char[5] a; struct { char b; align(1) int c; } } extern (C) S16 ctest16(ubyte x, S16, ubyte y); void test16() { version (X86) // misaligned field { S16 t; assert(S16.sizeof == 10); assert(S16.alignof == 1); t.a = "hello"; t.b = 3; t.c = 0x11223344; auto s = ctest16(1, t, 5); assert(s.a == "hello"); assert(s.b == 3); assert(s.c == 0x11223344); } } /******************************************/ int main() { test1(); test2(); test3(); version (Win64) { } else { test4(); } test11(); test12(); test13(); test14(); test15(); test16(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/casting.d ================================================ extern(C) int printf(const char*, ...); template Seq(T...) { alias T Seq; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=3133 void test3133() { short[2] x = [1, 2]; auto y = cast(int[1])x; // no error } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7504 void test7504() pure nothrow @safe { auto n = null; char[] k = n; assert(k.ptr == null); assert(k.length == 0); double[] l; l = n; assert(l.ptr == null); assert(l.length == 0); immutable(int[]) m = n; assert(m.ptr == null); assert(m.length == 0); const(float)[] o; o = n; assert(o.ptr == null); assert(o.length == 0); auto c = create7504(null, null); assert(c.k.ptr == null); assert(c.k.length == 0); assert(c.l.ptr == null); assert(c.l.length == 0); } class C7504 { int[] k; string l; } C7504 create7504(T...)(T input) { auto obj = new C7504; obj.tupleof = input; return obj; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8119 struct S8119; void test8119() { void* v; auto sp1 = cast(S8119*)v; int* i; auto sp2 = cast(S8119*)i; S8119* s; auto ip = cast(int*)s; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8645 template TypeTuple8645(TL...) { alias TL TypeTuple8645; } void test8645() { alias TypeTuple8645!(int) Foo; int bar; static assert(!is(typeof( cast(Foo)bar ))); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10497 struct S10497; void test10497(S10497** s) { void* ptr; *s = cast(S10497*)ptr; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10793 struct RealFoo10793 { int i; } struct Foo10793; void test10793() { auto rf = RealFoo10793(10); void* prf = cast(void*)&rf; Foo10793* f = cast(Foo10793*)prf; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10834 void test10834() { struct S { int i; } S s; cast(void)s; class C { int i; } C c; cast(void)c; enum E { a, b } E e; cast(void)e; int[] ia; cast(void)ia; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10842 template Test10842(F, T) { bool res; F from() { res = true; return F.init; } T to() { // The cast operand had incorrectly been eliminated return cast(T)from(); } bool test() { res = false; to(); return res; } } void test10842() { foreach (From; Seq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) { foreach (To; Seq!(ifloat, idouble, ireal)) { if (!Test10842!(From, To).test()) assert(0); } } foreach (From; Seq!(ifloat, idouble, ireal)) { foreach (To; Seq!(/*bool*, */byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) { if (!Test10842!(From, To).test()) assert(0); } } if (!Test10842!(typeof(null), string).test()) // 10842 assert(0); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11722 class C11722 { T opCast(T)() { assert(0); } } void test11722() { C11722 c = new C11722(); shared C11722 sc = cast(shared)c; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14218 void test14218() { foreach (To; Seq!( byte, short, int, long, ubyte, ushort, uint, ulong, char, wchar, dchar, bool)) { auto x = cast(To)null; assert(x == 0); // false, '0x00' } version (DigitalMars) { // Questionable but currently accepted by DMD (but not GDC). foreach (To; Seq!( float, double, real, ifloat, idouble, ireal)) { auto x = cast(To)null; assert(x == 0); // 0i } // Internal error: backend/el.c in el_long() //foreach (To; Seq!(cfloat, cdouble, creal)) //{ // static assert(!__traits(compiles, { auto x = cast(To)null; })); //} } } /***************************************************/ int main() { test3133(); test7504(); test8119(); test8645(); test10793(); test10834(); test10842(); test11722(); test14218(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/circular.d ================================================ // REQUIRED_ARGS: -d // PERMUTE_ARGS: -dw // EXTRA_SOURCES: imports/circularA.d // This bug is typedef-specific. // https://issues.dlang.org/show_bug.cgi?id=4543 import core.stdc.stdio; import imports.circularA; class bclass {}; alias bclass Tclass; struct bstruct {} alias bstruct Tstruct; /************************************/ int main() { printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/closure.d ================================================ import core.stdc.stdio; struct S { int a,b,c,d; } alias int delegate() dg_t; alias int delegate(int) dg1_t; void fill() { int[100] x; } /************************************/ dg_t foo() { int x = 7; int bar() { return x + 3; } return &bar; } void test1() { dg_t dg = foo(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo2() { dg_t abc() { int x = 7; int bar() { return x + 3; } return &bar; } return abc(); } void test2() { dg_t dg = foo2(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo3() { dg_t abc(int x) { int bar() { return x + 3; } return &bar; } return abc(7); } void test3() { dg_t dg = foo3(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo4() { S s; s = S(4,5,6,7); dg_t abc(S t) { int bar() { return t.d + 3; } return &bar; } return abc(s); } void test4() { dg_t dg = foo4(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ void test5() { int x = 7; dg_t abc(ref int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 7); auto i = dg(); assert(x == 11); assert(i == 14); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test6() { int x = 7; dg_t abc(out int y) { int bar() { y += 4; return y + 3; } return &bar; } dg_t dg = abc(x); fill(); assert(x == 0); auto i = dg(); assert(x == 4); assert(i == 7); x = 8; i = dg(); assert(x == 12); assert(i == 15); } /************************************/ void test7() { int[3] a = [10,11,12]; dg_t abc(int[3] y) { int bar() { y[2] += 4; return y[2] + 3; } return &bar; } dg_t dg = abc(a); fill(); assert(a[2] == 12); auto i = dg(); assert(a[2] == 12); assert(i == 19); } /************************************/ void test8() { S s = S(7,8,9,10); dg_t abc(ref S t) { int bar() { t.d += 4; return t.c + 3; } return &bar; } dg_t dg = abc(s); fill(); assert(s.d == 10); auto i = dg(); assert(s.d == 14); assert(i == 12); } /************************************/ S foo9(out dg_t dg) { S s1 = S(7,8,9,10); dg_t abc() { int bar() { s1.d += 4; return s1.c + 3; } return &bar; } dg = abc(); return s1; } void test9() { dg_t dg; S s = foo9(dg); fill(); assert(s.a == 7); assert(s.b == 8); assert(s.c == 9); assert(s.d == 10); auto i = dg(); assert(s.d == 10); assert(i == 12); } /************************************/ dg_t foo10() { dg_t abc() { int x = 7; int bar() { int def() { return x + 3; } return def(); } return &bar; } return abc(); } void test10() { dg_t dg = foo10(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo11() { int x = 7; class T { int bar() { return x + 3; } } T t = new T; return &t.bar; } void test11() { dg_t dg = foo11(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo12() { int x = 7; class T { int bar() { return x + 3; } int xyz() { return bar(); } } T t = new T; return &t.xyz; } void test12() { dg_t dg = foo12(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo13() { int x = 7; class T { int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test13() { dg_t dg = foo13(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo14() { class T { int xyz() { int x = 7; int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test14() { dg_t dg = foo14(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo15() { class T { int x = 7; int xyz() { int bar() { return x + 3; } return bar(); } } T t = new T; return &t.xyz; } void test15() { dg_t dg = foo15(); fill(); printf("bar = %d\n", dg()); assert(dg() == 10); } /************************************/ dg_t foo16() { int a = 5; class T { int x = 7; int xyz() { int y = 8; int bar() { return a + x + y + 3; } return bar(); } } T t = new T; return &t.xyz; } void test16() { dg_t dg = foo16(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t foo17() { int a = 5; class T { int x = 7; dg_t xyz() { int y = 8; int bar() { return a + x + y + 3; } return &bar; } } T t = new T; return t.xyz(); } void test17() { dg_t dg = foo17(); fill(); printf("bar = %d\n", dg()); assert(dg() == 23); } /************************************/ dg_t dg18; void bar18() { int a = 7; int foo() { return a + 3; } dg18 = &foo; int i = dg18(); assert(i == 10); } void test18() { bar18(); fill(); int i = dg18(); assert(i == 10); } /************************************/ void abc19(void delegate() dg) { dg(); dg(); dg(); } struct S19 { static S19 call(int v) { S19 result; result.v = v; void nest() { result.v += 1; } abc19(&nest); return result; } int a; int v; int x,y,z; } int foo19() { auto s = S19.call(5); return s.v; } void test19() { int i = foo19(); printf("%d\n", i); assert(i == 8); } /************************************/ void enforce20(lazy int msg) { } void test20() { int x; foreach (j; 0 .. 10) { printf("%d\n", j); assert(j == x); x++; enforce20(j); } } /************************************/ void thrash21() { char[128] x = '\xfe'; } void delegate() dg21; int g_input = 11, g_output; void f21() { int i = g_input + 2; class X { // both 'private' and 'final' to make non-virtual private final void actual() { g_output = i; } void go() { actual(); } } dg21 = & (new X).go; } void test21() { f21(); thrash21(); dg21(); assert(g_output == 13); } /************************************/ void thrash22() { char[128] x = '\xfe'; } int gi22; void delegate() dg22; class A22 { int x = 42; void am() { int j; /* Making f access this variable causes f's chain to be am's frame. Otherwise, f's chain would be the A instance. */ void f() { int k = j; void g() { class B { void bm() { gi22 = x; /* No checkedNestedReference for A.am.this, so it is never placed in a closure. */ } } (new B).bm(); } dg22 = &g; } f(); } } void test22() { (new A22).am(); thrash22(); dg22(); assert(gi22 == 42); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=1759 void test1759() { struct S { int a, b, c; } struct SS { S obj; } static int delegate() makeSum1(S s) { with (s) return { return a + b + c; }; } static int delegate() makeSum2(S[1] sa) { with (sa[0]) return { return a + b + c; }; } static int delegate() makeSum3(SS ss) { with (ss.obj) return { return a + b + c; }; } static int delegate() makeSum4(SS[1] ssa) { with (ssa[0].obj) return { return a + b + c; }; } S s = {15, 30, 45}; SS ss = {s}; int delegate() sum; sum = makeSum1(s); assert(sum() == 90); sum = makeSum2([s]); assert(sum() == 90); sum = makeSum3(ss); assert(sum() == 90); sum = makeSum4([ss]); assert(sum() == 90); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=1841 int delegate() foo1841() { int stack; int heap = 3; int nested_func() { ++heap; return heap; } return delegate int() { return nested_func(); }; } int delegate() foo1841b() { int stack; int heap = 7; int nested_func() { ++heap; return heap; } int more_nested() { return nested_func(); } return delegate int() { return more_nested(); }; } void test1841() { auto z = foo1841(); auto p = foo1841(); assert(z() == 4); p(); assert(z() == 5); z = foo1841b(); p = foo1841b(); assert(z() == 8); p(); assert(z() == 9); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=5911 void writeln5911(const(char)[] str) {} void logout5911(lazy const(char)[] msg) { writeln5911(msg); } void test5911() { string str = "hello world"; logout5911((){ return str; }()); // closure 1 try { throw new Exception("exception!!"); } catch (Exception e) { assert(e !is null); logout5911(e.toString()); // closure2 SEGV : e is null. } } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=9685 auto get9685a(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(15); } } return Foo(5); } void test9685a() { uint a = 42; auto bar = get9685a!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } auto get9685b(alias fun)() { int x = 10; struct Foo { size_t data; @property clone() { return Foo(data + x); } } return Foo(5); } void test9685b() { uint a = 42; auto bar = get9685b!(() => a)(); auto qux = bar.clone; //printf("bar context pointer : %p\n", bar.tupleof[$-1]); //printf("qux context pointer : %p\n", qux.tupleof[$-1]); assert(bar.tupleof[$-1] == qux.tupleof[$-1]); assert(qux.data == 15); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=12406 auto createDg12406() { static struct Dg { Dg delegate() action; } static void fn(void delegate()) { } int x; fn({ x++; }); // required Dg dg; Dg createDg2() { int x; void unusedFun() { x++; } // required return Dg(() => dg); // lambda returns garbage instead of dg } return dg = Dg(&createDg2); } void test12406() { auto dgs = [createDg12406()]; //printf("dgs[%2d].action = %p:%p\n", 0, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); foreach (i; 1 .. 10+1) { dgs ~= dgs[i-1].action(); //printf("dgs[%2d].action = %p:%p\n", i, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); } foreach (i, dgx; dgs) { if (i % 2 == 0) { // All closures are equal with dgs[0]. assert(dgx.action.ptr is dgs[0].action.ptr); assert(dgx.action.funcptr is dgs[0].action.funcptr); // is: createDg2 } else { // Each closures has unique context. for (size_t j = i + 2; j < dgs.length; j += 2) assert(dgx.action.ptr !is dgs[j].action.ptr); assert(dgx.action.funcptr is dgs[1].action.funcptr); // is: lambda () => dg } } } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=14730 void test14730() { static auto makeS(int x) { struct S { int n; int get() { return x; } // x will be a closure variable } return S(x); } auto s = makeS(1); assert(s.get() == 1); // By inlining get() function call, it's rewritten to: // assert(*(s.tupleof[$-1] + x.offset) == 1); // --> In DotVarExp::toElem(), x->offset should be already nonzero. } // ---- // This is questionable case. Currently it works without any errors, // but not sure it's really intentional struct S14730x(alias f) { auto foo()() { return f(0); } void dummy() {} } auto makeS14730x() //@nogc { int x = 10; S14730x!(a => x) s; //assert(s.foo() == 10); return s; } void test14730x() { auto s = makeS14730x(); assert(s.tupleof[$-1] !is null); // instantiationg foo outside of makeS will place the variable x in closure // *after* the semantic3 completion of makeS() function. assert(s.foo() == 10); } /************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test15(); test16(); test17(); test18(); test19(); test20(); test21(); test22(); test1759(); test1841(); test5911(); test9685a(); test9685b(); test12406(); test14730(); test14730x(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/complex.d ================================================ // PERMUTE_ARGS: import std.stdio; import std.math; import core.stdc.stdio; /***************************************/ void test1() { creal c = 3.0 + 4.0i; c = sqrt(c); printf("re = %Lg, im = %Lg\n", c.re, c.im); assert(c.re == 2.0); assert(c.im == 1.0); float f = sqrt(25.0f); assert(f == 5.0); double d = sqrt(4.0); assert(d == 2.0); real r = sqrt(9.0L); assert(r == 3.0); } /***************************************/ ireal f2() { return 1i; } void test2() { creal v = 0+0i; v += f2(); assert(v == 0 + 1i); v = v + f2(); assert(v == 0 + 2i); } /***************************************/ cdouble[1] a3; cdouble[1] b3; cdouble[] concat3() { return a3~b3; } void test3() { a3[]=0.5+1.0i; b3[]=0.5+3.0i; cdouble[] arr=concat3(); assert(arr.length==2); assert(arr[0]==0.5+1.0i); assert(arr[1]==0.5+3.0i); } /***************************************/ creal[1] a4; creal[1] b4; creal[] concat4() { return a4~b4; } void test4() { a4[]=0.5+1.0i; b4[]=0.5+3.0i; creal[] arr=concat4(); assert(arr.length==2); assert(arr[0]==0.5+1.0i); assert(arr[1]==0.5+3.0i); } /***************************************/ void test5() { ifloat i=1.0fi; // i += 2.2; // assert(i == 1i); } /***************************************/ void test6() { float i=1.0f; // i /= 2.2fi; // assert(i == 0); } /***************************************/ void test7() { creal x=1.0i+2.0; creal[] arr; arr = arr ~ x; assert(arr.length==1); assert(arr[0]==1.0i+2.0); x=0.0i+5.0; assert(arr[0]==1.0i+2.0); } /****************************************/ creal[1] a8; creal[1] b8; creal[] concat8() { return a8 ~ b8; } void test8() { a8[]=0.5L+1.0Li; b8[]=0.5L+3.0Li; creal[] arr=concat8(); assert(arr.length==2); assert(arr[0]==0.5L+1.0Li); assert(arr[1]==0.5L+3.0Li); } /***************************************/ creal[1] a9; creal[1] b9; creal[] concat9() { return a9~b9; } void test9() { a9[]=0.5L+1.0Li; b9[]=0.5L+3.0Li; creal[] arr=concat9(); assert(arr.length==2); assert(arr[0]==0.5L+1.0Li); assert(arr[1]==0.5L+3.0Li); } /***************************************/ void test10() { ifloat a = 1.0i; assert(a.im == 1.0); const ifloat b = 2.0i; static assert(b.im == 2.0); // FAIL } /***************************************/ void test11() { real r = real.nan; assert( r!=0 ); if (r==0) assert(0); ireal ir = ireal.nan; assert( ir!=0 ); assert( ir!=0i ); if (ir==0) assert(0); if (ir==0i) assert(0); creal cr = creal.nan; assert( cr!=0 ); assert( cr!=0i ); if (cr==0) assert(0); if (cr==0i) assert(0); double d = double.nan; assert( d!=0 ); if (d==0) assert(0); idouble id = idouble.nan; assert( id!=0 ); assert( id!=0i ); if (id==0) assert(0); if (id==0i) assert(0); cdouble cd = cdouble.nan; assert( cd!=0 ); assert( cd!=0i ); if (cd==0) assert(0); if (cd==0i) assert(0); float f = float.nan; assert( f!=0 ); if (f==0) assert(0); ifloat ifx = ifloat.nan; assert( ifx!=0 ); assert( ifx!=0i ); if (ifx==0) assert(0); if (ifx==0i) assert(0); cfloat cf = cfloat.nan; assert( cf!=0 ); assert( cf!=0i ); if (cf==0) assert(0); if (cf==0i) assert(0); } /***************************************/ void test12() { real x = 3; creal a = (2 + 4i) % 3; writeln(a); assert(a == 2 + 1i); creal b = (2 + 4i) % x; writeln(b); assert(b == a); } /***************************************/ void test13() { ireal a = 5i; ireal b = a % 2; writeln(b); assert(b == 1i); } /***************************************/ cdouble inv( cdouble expr ) { return (1.0 + 0.0i) / expr; } /***************************************/ void test14() { cfloat c; cfloat d; assert(c != d); cdouble e; cdouble f; assert(e != f); creal g; creal h; assert(g != h); } /***************************************/ void test7581() { cfloat a() { return cfloat.nan; } assert(a() != 0); } /***************************************/ float f() { return 1.0f; } ifloat i() { return 1.0fi; } void test7594() { assert(f() + i() == 1.0f + 1.0fi); } /***************************************/ cdouble conv(cfloat a) { return a; } void test7593() { assert(conv(1.0f+1.0fi) == 1.0+1.0i); } /***************************************/ cfloat get() { return cfloat.nan; } void test7591() { assert(!(get() == 0)); } /***************************************/ void foo8966(cfloat x) { assert(x.re == 3.0f); } __gshared cfloat[] a8966; void test8966() { a8966 = new cfloat[2]; a8966[0] = 3.0f + 1.0fi; foo8966(a8966[0]); } /***************************************/ void formatTest2(cfloat s, double re, double im) { assert(s.re == re); assert(s.im == im); } cfloat getcf() { return 2 + 1i; } void test10677() { formatTest2( getcf(), 2, 1 ); } /***************************************/ void test7806() { for (idouble i = -2i; i <= 2i; i += .125i) for (double r = -2; r <= 2; r += .0625) { cdouble c = r + i; printf("%g %gi\n", c.re, c.im); } } /***************************************/ void test7976() { creal[] a = new creal[2]; auto b = a[0] = a[1]; } /***************************************/ cfloat foo15f(ifloat re, float im) { return re + im; } cfloat bar15f(float re, ifloat im) { return re + im; } cdouble foo15(idouble re, double im) { return re + im; } cdouble bar15(double re, idouble im) { return re + im; } creal foo15r(ireal re, real im) { return re + im; } creal bar15r(real re, ireal im) { return re + im; } void test15() { assert(foo15f(1.0fi, 2.0f) == 2.0f + 1.0fi); assert(bar15f(1.0f, 2.0fi) == 1.0f + 2.0fi); assert(foo15(1.0i, 2.0) == 2.0 + 1.0i); assert(bar15(1.0, 2.0i) == 1.0 + 2.0i); assert(foo15r(1.0Li, 2.0L) == 2.0L + 1.0Li); assert(bar15r(1.0L, 2.0Li) == 1.0L + 2.0Li); } /***************************************/ // https://issues.dlang.org/show_bug.cgi?id=17087 cfloat toComplex(int x) { return cast(cfloat)x; } void test17087() { assert (toComplex(1) == 1.0); } /***************************************/ // https://issues.dlang.org/show_bug.cgi?id=17677 void test17677() { cfloat v2 = 0.0f + 0.0fi; ulong v1 = 1; auto z = v2 + v1; assert(z == 1.0f); } /***************************************/ int main(char[][] args) { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); test13(); test14(); test7581(); test7594(); test7593(); test7591(); test8966(); test10677(); test7806(); test7976(); test15(); test17087(); test17677(); printf("Success!\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/constfold.d ================================================ #! blah static assert(__LINE__ == 3); // fails as __LINE__ is 2 import std.stdio; import std.math : signbit, sqrt; /************************************/ static assert(-(1) == -1); static assert(-(6i) == -6i); static assert(-(1 + 6i) == -1 - 6i); static assert(!27 == 0); static assert(!0 == 1); static assert(!6.2 == 0); static assert(!0.0 == 1); static assert(!3.7i == 0); static assert(!0.0i == 1); static assert(!(2+3.7i) == 0); static assert(!(0+3.7i) == 0); static assert(!(2+0.0i) == 0); static assert(!(0+0.0i) == 1); static assert(-6i + 2i == -4i); static assert(6i - 1i == 5i); static assert((3.6 + 7.2i) / (1 + 0i) == 3.6 + 7.2i); static assert((3.6 + 7.2i) / (0.0 + 1i) == 7.2 - 3.6i); static assert((6 % 4) == 2); static assert((6u % 4u) == 2u); static assert((cast(byte)0x109 >> 1) == 4); static assert((cast(byte)-1 >> 1) == -1); static assert((cast(ubyte)0x109 >> 1) == 4); static assert((cast(short)0x10009 >> 1) == 4); static assert((cast(short)-1 >> 1) == -1); static assert((cast(ushort)0x10009 >> 1) == 4); static assert((cast(long)0x1_0000_0000_0009 >> 1) == 0x8000_0000_0004); static assert((cast(long)-1L >> 1) == -1); static assert((cast(ulong)0x10009 >> 1) == 0x8004); static assert((cast(byte)0x109 >>> 1) == 4); static assert((cast(byte)-1 >>> 1) == int.max); static assert((cast(ubyte)0x109 >>> 1) == 4); static assert((cast(short)0x10009 >>> 1) == 4); static assert((cast(short)-1 >>> 1) == int.max); static assert((cast(ushort)0x10009 >>> 1) == 4); static assert((cast(long)0x1_0000_0000_0009 >>> 1) == 0x8000_0000_0004); static assert((cast(long)-1L >>> 1) == long.max); static assert((cast(ulong)0x10009 >>> 1) == 0x8004); static assert((3 ^ 5) == 6); static assert((0 && 0) == 0); static assert((0 && 5) == 0); static assert((10 && 0) == 0); static assert((58 && 10000) == 1); static assert((0.0 && 0.0) == 0); static assert((0.0 && 5.1) == 0); static assert((10.0 && 0.0) == 0); static assert((58.6 && 10000.7) == 1); static assert((0 || 0) == 0); static assert((0 || 5) == 1); static assert((10 || 0) == 1); static assert((58 || 10000) == 1); static assert((0.0 || 0.0) == 0); static assert((0.0 || 5.1) == 1); static assert((10.0 || 0.0) == 1); static assert((58.6 || 10000.7) == 1); static assert((5 < 3) == 0); static assert((5 < 5) == 0); static assert((5 < 6) == 1); static assert((5 <= 3) == 0); static assert((5 <= 5) == 1); static assert((5 <= 6) == 1); static assert((5 > 3) == 1); static assert((5 > 5) == 0); static assert((5 > 6) == 0); static assert((5 >= 3) == 1); static assert((5 >= 5) == 1); static assert((5 >= 6) == 0); static assert((-5 < -3) == 1); static assert((-5 < -5) == 0); static assert((-5 < -6) == 0); static assert((-5 <= -3) == 1); static assert((-5 <= -5) == 1); static assert((-5 <= -6) == 0); static assert((-5 > -3) == 0); static assert((-5 > -5) == 0); static assert((-5 > -6) == 1); static assert((-5 >= -3) == 0); static assert((-5 >= -5) == 1); static assert((-5 >= -6) == 1); static assert((5u < 3u) == 0); static assert((5u < 5u) == 0); static assert((5u < 6u) == 1); static assert((5u <= 3u) == 0); static assert((5u <= 5u) == 1); static assert((5u <= 6u) == 1); static assert((5u > 3u) == 1); static assert((5u > 5u) == 0); static assert((5u > 6u) == 0); static assert((5u >= 3u) == 1); static assert((5u >= 5u) == 1); static assert((5u >= 6u) == 0); static assert((-5u < 3) == 0); static assert((-5u <= 3) == 0); static assert((-5u > 3) == 1); static assert((-5u >= 3) == 1); static assert((-5 < 3u) == 0); static assert((-5 <= 3u) == 0); static assert((-5 > 3u) == 1); static assert((-5 >= 3u) == 1); static assert((5.2 < double.nan) == 0); static assert((5.2 <= double.nan) == 0); static assert((5.2 > double.nan) == 0); static assert((5.2 >= double.nan) == 0); static assert((double.nan < 6.2) == 0); static assert((double.nan <= 6.2) == 0); static assert((double.nan > 6.2) == 0); static assert((double.nan >= 6.2) == 0); static assert((double.nan < double.nan) == 0); static assert((double.nan <= double.nan) == 0); static assert((double.nan > double.nan) == 0); static assert((double.nan >= double.nan) == 0); static assert((5.2 < 6.2) == 1); static assert((5.2 <= 6.2) == 1); static assert((5.2 > 6.2) == 0); static assert((5.2 >= 6.2) == 0); static assert((5.2 < 5.2) == 0); static assert((5.2 <= 5.2) == 1); static assert((5.2 > 5.2) == 0); static assert((5.2 >= 5.2) == 1); static assert((7.2 < 6.2) == 0); static assert((7.2 <= 6.2) == 0); static assert((7.2 > 6.2) == 1); static assert((7.2 >= 6.2) == 1); static assert((7.2i < 6.2i) == 0); static assert((7.2i == 6.2i) == 0); static assert((7.2i != 6.2i) == 1); static assert((7.2 == 6.2) == 0); static assert((7.2 != 6.2) == 1); static assert((7.2i == 7.2i) == 1); static assert((7.2i != 7.2i) == 0); static assert((7.2 == 7.2) == 1); static assert((7.2 != 7.2) == 0); static assert((7.2 == double.nan) == 0); static assert((7.2 != double.nan) == 1); static assert((double.nan == double.nan) == 0); static assert((double.nan != double.nan) == 1); static assert((double.nan == 7.2) == 0); static assert((double.nan != 7.2) == 1); static assert((5 is 5) == 1); static assert((5 is 4) == 0); static assert((5 !is 5) == 0); static assert((5 !is 4) == 1); static assert((5.1 is 5.1) == 1); static assert((5.1 is 4.1) == 0); static assert((5.1 !is 5.1) == 0); static assert((5.1 !is 4.1) == 1); static assert((5.1 is 5.1i) == 0); static assert((5.1 !is 5.1i) == 1); static assert((5 ? 2 : 3) == 2); static assert((0 ? 2 : 3) == 3); static assert((5.0 ? 2 : 3) == 2); static assert((0.0 ? 2 : 3) == 3); static assert("abc" == "abc"); //static assert("abc"w.sizeof == 6); //static assert("\U00010000bc"w.sizeof == 8); static assert([1,2,3][1] == 2); static assert([1,2,3] ~ [4] == [1,2,3,4]); static assert([1,2,3][1..3] == [2,3]); static assert(['a','b','c','d'] == "abcd"); static assert("efgh" == ['e','f','g','h']); static assert("efgi" != ['e','f','g','h']); static assert((2 ^^ 8) == 256); static assert((3 ^^ 8.0) == 6561); static assert((4.0 ^^ 8) == 65536); static assert((5.0 ^^ 8.0) == 390625); static assert((0.5 ^^ 3) == 0.125); static assert((1.5 ^^ 3.0) == 3.375); static assert((2.5 ^^ 3) == 15.625); static assert((3.5 ^^ 3.0) == 42.875); static assert(((-2) ^^ -5.0) == -0.031250); static assert(((-2.0) ^^ -6) == 0.015625); static assert(((-2.0) ^^ -7.0) == -0.0078125); static assert((144 ^^ 0.5) == 12); static assert((1089 ^^ 0.5) == 33); static assert((1764 ^^ 0.5) == 42); static assert((650.25 ^^ 0.5) == 25.5); void test1() { int x; int y; int* p; p = &x + cast(size_t)&y; p = &x + 2; p = 4 + &y; p = &x - 1; assert((&x is &x) == 1); assert((&x is &y) == 0); assert((&x !is &x) == 0); assert((&x !is &y) == 1); } /************************************/ void test2() { // This test only tests undefined, architecture-dependant behavior. // E.g. the result of converting a float whose value doesn't fit into the integer // leads to an undefined result. version(GNU) return; float f = float.infinity; int i = cast(int) f; writeln(i); writeln(cast(int)float.max); assert(i == cast(int)float.max); assert(i == 0x80000000); } /************************************/ void test3() { real n = -0.0; const real m = -0.0; creal c = -0.0 + 3i; creal d = n + 3i; creal e = m + 3i; // should print "11111" writeln(signbit(n), signbit(m), signbit(c.re), signbit(d.re), signbit(e.re)); assert(signbit(n) == 1); assert(signbit(m) == 1); assert(signbit(c.re) == 1); assert(signbit(d.re) == 1); assert(signbit(e.re) == 1); } /************************************/ struct A4 { char [] a; } struct B4 { long x; } struct C4 { int a; static C4 opCall(int b) { C4 q; q.a=b; return q; } } static assert(!is(typeof( (){ A4 s; B4 q = s; }))); static assert(!is(typeof( (){ B4 x =1L; }))); static assert(is(typeof( (){ C4 g = 7; }))); static assert(is(typeof( (){ C4 g = 7; C4 h = g;}))); /************************************/ alias uint DWORD; MY_API_FUNCTION lpStartAddress; extern (Windows) alias DWORD function(void*) MY_API_FUNCTION; pragma(msg, MY_API_FUNCTION.stringof); static assert(MY_API_FUNCTION.stringof == "extern (Windows) uint function(void*)"); /************************************/ enum bug6 = cast(void*)0xFEFEFEFE; static assert(bug6 is bug6); /************************************/ struct S7{ double z; } int bug7(int x) { return x; } S7 s7; double e7 = 4; const double d7 = 4; static assert(!is(typeof(bug7(cast(long)e7)))); static assert(!is(typeof(bug7(cast(long)s7)))); version (LDC) {} else // cast in LDC undefined result w/ x > long.max static assert(!is(typeof(bug7(cast(long)3.256679e30)))); static assert(is(typeof(bug7(cast(long)d7)))); static assert(is(typeof(bug7(cast(long)3.256679e4)))); /************************************/ class C8 { int x; } alias C8.x F8; static assert(is(typeof(F8) == int)); static assert(is(typeof(C8.x) == int)); /************************************/ int foo9() { int u = cast(int)(0x1_0000_0000L); while (u) { if (u) { assert(u!=0); } assert(u!=0); } return 2; } static assert(foo9()==2); /************************************/ // https://issues.dlang.org/show_bug.cgi?id=6077 void test6077() { static string scat(string s1, string s2) { return s1 ~ s2; } static string scatass(string s1, string s2) { s1 ~= s2; return s1; } static string[] arycats(string[] ary, string s) { return ary ~ s; } static string[] scatary(string s, string[] ary) { return s ~ ary; } static string[] arycatasss(string[] ary, string s) { ary ~= s; return ary; } static assert(scat(null, null) is null); static assert(scatass(null, null) is null); static assert(arycats(null, null) == cast(string[])[null]); static assert(scatary(null, null) == cast(string[])[null]); static assert(arycatasss(null, null) == cast(string[])[null]); } /************************************/ int test4() { int i; dchar d; d >>= 1; d >>>= 1; d <<= 1; d = d >> 1; d = d >>> 1; d = d << 1; wchar w; w >>= 1; w >>>= 1; w <<= 1; w = w >> 1; w = w >>> 1; i = w << 1; // promoted to int char c; c >>= 1; c >>>= 1; c <<= 1; c = c >> 1; c = c >>> 1; i = c << 1; // promoted to int return d + w + c + i; } static assert(test4() == 24666); /************************************/ // https://issues.dlang.org/show_bug.cgi?id=8400 void test8400() { immutable a = [1,2]; int[a.length+0] b; // ok int[a.length ] c; // error } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=8939 void foo8939(T)(ref T) { } // same for `auto ref` void bar8939(ref const int) { } void bar8939(ref const S8939) { } static struct S8939 { int n; } const gn8939 = 1; // or `immutable` const gs8939 = S8939(3); static assert(__traits(compiles, foo8939(gn8939), bar8939(gn8939))); static assert(__traits(compiles, foo8939(gs8939), bar8939(gs8939))); void test8939() { foo8939(gn8939), bar8939(gn8939); foo8939(gs8939), bar8939(gs8939); const ln8939 = 1; const ls8939 = S8939(3); foo8939(ln8939), bar8939(ln8939); foo8939(ls8939), bar8939(ls8939); } class C8939regression { const int n1 = 0; const int n2 = 0; const int n3 = 0; const int n4 = 1; int refValue(V)(ref V var) { return 0; } void foo() { string[2] str; refValue(str[n1]); int[] da; refValue(da[n2]); int n; int* p = &n; refValue(*cast(int*)(p + n3)); refValue([1,2,n4].ptr[0]); } } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=9058 template TypeTuple9058(TL...) { alias TypeTuple9058 = TL; } template EnumMembers9058(T) { alias EnumMembers9058 = TypeTuple9058!(Foo9058.A, Foo9058.B); } enum Foo9058 { A, B } size_t bar9058(size_t n) { return 0; } void test9058() { Foo9058 x = [EnumMembers9058!Foo9058][bar9058($)]; } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=11159 void test11159() { import std.math : pow; enum ulong e_2_pow_64 = 2uL^^64, e_10_pow_19 = 10uL^^19, e_10_pow_20 = 10uL^^20; assert(e_2_pow_64 == pow(2uL, 64)); assert(e_10_pow_19 == pow(10uL, 19)); assert(e_10_pow_20 == pow(10uL, 20)); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=12306 void test12306() { struct Point3D { ubyte x, y, z; } enum Point3D pt1 = {x:1, y:1, z:1}; const Point3D pt2 = {x:1, y:1, z:1}; immutable Point3D pt3 = {x:1, y:1, z:1}; int[pt1.z][pt1.y][pt1.x] a1; int[pt2.z][pt2.y][pt2.x] a2; int[pt3.z][pt3.y][pt3.x] a3; ubyte a = 1; const Point3D ptx = {x:a, y:1, z:1}; static assert(!__traits(compiles, { int[ptx.z][ptx.y][ptx.x] ax; })); } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=13977 void test13977() { bool cond(bool b) { return b; } int x = 0; void check(int n = 1) { x = n; } cond(true) && check(); assert(x == 1); x = 0; cond(false) && check(); assert(x == 0); x = 0; true && check(); assert(x == 1); x = 0; false && check(); assert(x == 0); x = 0; (int[]).init && check(); assert(x == 0); x = 0; Object.init && check(); assert(x == 0); check(2); false && check(); assert(x == 2); x = 0; } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=13978 void test13978() { bool cond(bool b) { return b; } int x = 0; void check(int n = 1) { x = n; } cond(true) || check(); assert(x == 0); x = 0; cond(false) || check(); assert(x == 1); x = 0; true || check(); assert(x == 0); x = 0; false || check(); assert(x == 1); x = 0; (int[]).init || check(); assert(x == 1); x = 0; Object.init || check(); assert(x == 1); x = 0; check(2); true || check(); assert(x == 2); x = 0; } /************************************/ // Pull Request 3697 void test3697and() { enum x = 0; auto y = x && 1 / x; } void test3697or() { enum x = 0; enum y = 1; auto z = y || 1 / x; } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=14459 void test14459() { const char* s0 = "hi0"; const(char)* p0 = s0; assert(p0 == s0); const char* s1 = "hi1"; const char* s2 = "hi2"; const char* s3 = "hi3"; const char* s4 = "hi4"; const char* s5 = "hi5"; const char* s6 = "hi6"; const char* s7 = "hi7"; const char* s8 = "hi8"; const char* s9 = "hi9"; const char* s10 = "hi10"; const char* s11 = "hi11"; const char* s12 = "hi12"; const char* s13 = "hi13"; const char* s14 = "hi14"; const char* s15 = "hi15"; assert(p0 == s0); // ok const char* s16 = "hi16"; assert(p0 == s0); // ok <- fails } /************************************/ // https://issues.dlang.org/show_bug.cgi?id=15607 static immutable char[2][4] code_base = [ "??", 12 ]; static assert(code_base[0] == "??"); static assert(code_base[1] == [12, 12]); static assert(code_base[2] == typeof(code_base[2]).init); /************************************/ int main() { test1(); test2(); test3(); test3697and(); test3697or(); test6077(); test8400(); test8939(); test9058(); test11159(); test13977(); test13978(); test14459(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/cpp_abi_tests.d ================================================ // EXTRA_CPP_SOURCES: extra-files/cpp_abi_tests.cpp extern(C++) { struct S { float a = 1; } extern(C++, std) { struct test19248 {int a = 34;} } bool passthrough(bool value); byte passthrough(byte value); ubyte passthrough(ubyte value); char passthrough(char value); dchar passthrough(dchar value); short passthrough(short value); ushort passthrough(ushort value); int passthrough(int value); uint passthrough(uint value); long passthrough(long value); ulong passthrough(ulong value); float passthrough(float value); double passthrough(double value); S passthrough(S value); std.test19248 passthrough(const(std.test19248) value); bool passthrough_ptr(bool *value); byte passthrough_ptr(byte *value); ubyte passthrough_ptr(ubyte *value); char passthrough_ptr(char *value); dchar passthrough_ptr(dchar *value); short passthrough_ptr(short *value); ushort passthrough_ptr(ushort *value); int passthrough_ptr(int *value); uint passthrough_ptr(uint *value); long passthrough_ptr(long *value); ulong passthrough_ptr(ulong *value); float passthrough_ptr(float *value); double passthrough_ptr(double *value); S passthrough_ptr(S *value); std.test19248 passthrough_ptr(const(std.test19248)* value); bool passthrough_ref(ref bool value); byte passthrough_ref(ref byte value); ubyte passthrough_ref(ref ubyte value); char passthrough_ref(ref char value); dchar passthrough_ref(ref dchar value); short passthrough_ref(ref short value); ushort passthrough_ref(ref ushort value); int passthrough_ref(ref int value); uint passthrough_ref(ref uint value); long passthrough_ref(ref long value); ulong passthrough_ref(ref ulong value); float passthrough_ref(ref float value); double passthrough_ref(ref double value); S passthrough_ref(ref S value); std.test19248 passthrough_ref(ref const(std.test19248) value); } template IsSigned(T) { enum IsSigned = is(T==byte) || is(T==short) || is(T==int) || is(T==long); } template IsUnsigned(T) { enum IsUnsigned = is(T==ubyte) || is(T==ushort) || is(T==uint) || is(T==ulong); } template IsIntegral(T) { enum IsIntegral = IsSigned!T || IsUnsigned!T; } template IsFloatingPoint(T) { enum IsFloatingPoint = is(T==float) || is(T==double) || is(T==real); } template IsBoolean(T) { enum IsBoolean = is(T==bool); } template IsSomeChar(T) { enum IsSomeChar = is(T==char) || is(T==dchar); } void check(T)(T actual, T expected) { assert(actual is expected); } void check(T)(T value) { check(passthrough(value), value); check(passthrough_ptr(&value), value); check(passthrough_ref(value), value); } T[] values(T)() { T[] values; static if(IsBoolean!T) { values ~= true; values ~= false; } else static if(IsSomeChar!T) { values ~= T.init; values ~= T('a'); values ~= T('z'); } else { values ~= T(0); values ~= T(1); static if(IsIntegral!T) { static if(IsSigned!T) values ~= T.min; values ~= T.max; } else static if(IsFloatingPoint!T) { values ~= T.nan; values ~= T.min_normal; values ~= T.max; } else { assert(0); } } return values; } void main() { foreach(bool val; values!bool()) check(val); foreach(byte val; values!byte()) check(val); foreach(ubyte val; values!ubyte()) check(val); foreach(char val; values!char()) check(val); foreach(dchar val; values!dchar()) check(val); foreach(short val; values!short()) check(val); foreach(ushort val; values!ushort()) check(val); foreach(int val; values!int()) check(val); foreach(uint val; values!uint()) check(val); foreach(long val; values!long()) check(val); foreach(ulong val; values!ulong()) check(val); foreach(float val; values!float()) check(val); foreach(double val; values!double()) check(val); check(S()); check(std.test19248()); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/cpp_stdlib.d ================================================ // DISABLED: win32 win64 osx32 // EXTRA_CPP_SOURCES: cpp_stdlib.cpp // CXXFLAGS: -std=c++11 import core.stdc.stdio; // Disabled on windows because it needs bindings // Disabled on osx32 because size_t is not properly mangled version (CppRuntime_Clang) { extern(C++, `std`, `__1`) { struct allocator(T); struct vector (T, A = allocator!T); struct array (T, size_t N); } } else { extern(C++, `std`) { struct allocator(T); struct vector (T, A = allocator!T); struct array (T, size_t N); } } extern(C++): ref T identity (T) (ref T v); T** identityPP (T) (T** v); vector!T* getVector (T) (size_t length, const T* ptr); array!(T, N)* getArray(T, size_t N) (const T* ptr); void main () { int i = 42; float f = 21.0f; int* pi = &i; float* pf = &f; assert(42 == identity(i)); assert(21.0f == identity(f)); assert(&pi == identityPP(&pi)); assert(&pf == identityPP(&pf)); auto vi = getVector(1, &i); auto vf = getVector(3, [f, f, f].ptr); assert(vi !is null); assert(vf !is null); auto ai = getArray!(int, 4)([2012, 10, 11, 42].ptr); auto af = getArray!(float, 4)([42.0f, 21.0f, 14.0f, 1957.0f].ptr); assert(ai !is null); assert(af !is null); printf("Success\n"); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/cppa.d ================================================ // PERMUTE_ARGS: -g -version=PULL8152 // EXTRA_CPP_SOURCES: extra-files/cppb.cpp // EXTRA_FILES: extra-files/cppb.h import core.stdc.stdio; import core.stdc.stdarg; import core.stdc.config; import core.stdc.stdint; extern (C++) int foob(int i, int j, int k); class C { extern (C++) int bar(int i, int j, int k) { printf("this = %p\n", this); printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); return 1; } } extern (C++) int foo(int i, int j, int k) { printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); assert(i == 1); assert(j == 2); assert(k == 3); return 1; } void test1() { foo(1, 2, 3); auto i = foob(1, 2, 3); assert(i == 7); C c = new C(); c.bar(4, 5, 6); } /****************************************/ extern (C++) interface D { int bar(int i, int j, int k); } extern (C++) D getD(); void test2() { D d = getD(); int i = d.bar(9,10,11); assert(i == 8); } /****************************************/ extern (C++) int callE(E); extern (C++) interface E { int bar(int i, int j, int k); } class F : E { extern (C++) int bar(int i, int j, int k) { printf("F.bar: i = %d\n", i); printf("F.bar: j = %d\n", j); printf("F.bar: k = %d\n", k); assert(i == 11); assert(j == 12); assert(k == 13); return 8; } } void test3() { F f = new F(); int i = callE(f); assert(i == 8); } /****************************************/ extern (C++) void foo4(char* p); void test4() { foo4(null); } /****************************************/ extern(C++) { struct foo5 { int i; int j; void* p; } interface bar5{ foo5 getFoo(int i); } bar5 newBar(); } void test5() { bar5 b = newBar(); foo5 f = b.getFoo(4); printf("f.p = %p, b = %p\n", f.p, cast(void*)b); assert(f.p == cast(void*)b); } /****************************************/ extern(C++) { struct S6 { int i; double d; } union S6_2 { int i; double d; } enum S6_3 { A, B } S6 foo6(); S6_2 foo6_2(); S6_3 foo6_3(); } extern (C) int foosize6(); void test6() { S6 f = foo6(); printf("%d %d\n", foosize6(), S6.sizeof); assert(foosize6() == S6.sizeof); version (X86) { assert(f.i == 42); printf("f.d = %g\n", f.d); assert(f.d == 2.5); assert(foo6_2().i == 42); assert(foo6_3() == S6_3.A); } } /****************************************/ extern (C) int foo7(); struct S { int i; long l; } void test7() { printf("%d %d\n", foo7(), S.sizeof); assert(foo7() == S.sizeof); } /****************************************/ extern (C++) void foo8(const(char)*); void test8() { char c; foo8(&c); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=4059 struct elem9 { } extern(C++) void foobar9(elem9*, elem9*); void test9() { elem9 *a; foobar9(a, a); } /****************************************/ struct A11802; struct B11802; extern(C++) class C11802 { int x; void fun(A11802*) { x += 2; } void fun(B11802*) { x *= 2; } } extern(C++) class D11802 : C11802 { override void fun(A11802*) { x += 3; } override void fun(B11802*) { x *= 3; } } extern(C++) void test11802x(D11802); void test11802() { auto x = new D11802(); x.x = 0; test11802x(x); assert(x.x == 9); } /****************************************/ struct S13956 { } extern(C++) void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); extern(C++) void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { assert(arg0 == S13956()); assert(arg1 == 1); assert(arg2 == 2); assert(arg3 == 3); assert(arg4 == 4); assert(arg5 == 5); assert(arg6 == 6); } void test13956() { func13956(S13956(), 1, 2, 3, 4, 5, 6); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=5148 extern (C++) { void foo10(const(char)*, const(char)*); void foo10(const int, const int); void foo10(const char, const char); void foo10(bool, bool); struct MyStructType { } void foo10(const MyStructType s, const MyStructType t); enum MyEnumType { onemember } void foo10(const MyEnumType s, const MyEnumType t); } void test10() { char* p; foo10(p, p); foo10(1,2); foo10('c','d'); MyStructType s; foo10(s,s); MyEnumType e; foo10(e,e); } /****************************************/ extern (C++, N11.M) { void bar11(); } extern (C++, A11.B) { extern (C++, C) { void bar(); }} void test11() { bar11(); A11.B.C.bar(); } /****************************************/ struct Struct10071 { void *p; c_long_double r; } extern(C++) size_t offset10071(); void test10071() { assert(offset10071() == Struct10071.r.offsetof); } /****************************************/ char[100] valistbuffer; extern(C++) void myvprintfx(const(char)* format, va_list va) { vsprintf(valistbuffer.ptr, format, va); } extern(C++) void myvprintf(const(char)*, va_list); extern(C++) void myprintf(const(char)* format, ...) { va_list ap; va_start(ap, format); myvprintf(format, ap); va_end(ap); } void testvalist() { myprintf("hello %d", 999); assert(valistbuffer[0..9] == "hello 999"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=12825 extern(C++) class C12825 { uint a = 0x12345678; } void test12825() { auto c = new C12825(); } /****************************************/ struct S13955a { float a; double b; } struct S13955b { double a; float b; } struct S13955c { float a; float b; } struct S13955d { double a; double b; } extern(C++) void check13955(S13955a a, S13955b b, S13955c c, S13955d d) { assert(a.a == 2); assert(a.b == 4); assert(b.a == 8); assert(b.b == 16); assert(c.a == 32); assert(c.b == 64); assert(d.a == 128); assert(d.b == 256); } extern(C++) void func13955(S13955a a, S13955b b, S13955c c, S13955d d); void test13955() { func13955(S13955a(2, 4), S13955b(8, 16), S13955c(32, 64), S13955d(128, 256)); } /****************************************/ extern(C++) class C13161 { void dummyfunc(); long val_5; uint val_9; } extern(C++) class Test : C13161 { uint val_0; long val_1; } extern(C++) size_t getoffset13161(); extern(C++) class C13161a { void dummyfunc(); c_long_double val_5; uint val_9; } extern(C++) class Testa : C13161a { bool val_0; } extern(C++) size_t getoffset13161a(); void test13161() { assert(getoffset13161() == Test.val_0.offsetof); assert(getoffset13161a() == Testa.val_0.offsetof); } /****************************************/ version (linux) { extern(C++, __gnu_cxx) { struct new_allocator(T) { alias size_type = size_t; static if (is(T : char)) void deallocate(T*, size_type) { } else void deallocate(T*, size_type); } } } extern (C++, std) { extern (C++, class) struct allocator(T) { version (linux) { alias size_type = size_t; void deallocate(T* p, size_type sz) { (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); } } } class vector(T, A = allocator!T) { final void push_back(ref const T); } struct char_traits(T) { } // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html version (none) { extern (C++, __cxx11) { struct basic_string(T, C = char_traits!T, A = allocator!T) { } } } else { extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T) { } } struct basic_istream(T, C = char_traits!T) { } struct basic_ostream(T, C = char_traits!T) { } struct basic_iostream(T, C = char_traits!T) { } class exception { } // https://issues.dlang.org/show_bug.cgi?id=14956 extern(C++, N14956) { struct S14956 { } } } extern (C++) { version (linux) { void foo14(std.vector!(int) p); void foo14a(std.basic_string!(char) *p); void foo14b(std.basic_string!(int) *p); void foo14c(std.basic_istream!(char) *p); void foo14d(std.basic_ostream!(char) *p); void foo14e(std.basic_iostream!(char) *p); void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q); } } void test14() { version (linux) { std.vector!int p; foo14(p); foo14a(null); foo14b(null); foo14c(null); foo14d(null); foo14e(null); foo14f(null, null, null); } } version (linux) { void test14a(std.allocator!int * pa) { pa.deallocate(null, 0); } void gun(std.vector!int pa) { int x = 42; pa.push_back(x); } } void test13289() { assert(f13289_cpp_wchar_t('a') == 'A'); assert(f13289_cpp_wchar_t('B') == 'B'); assert(f13289_d_wchar('c') == 'C'); assert(f13289_d_wchar('D') == 'D'); assert(f13289_d_dchar('e') == 'E'); assert(f13289_d_dchar('F') == 'F'); assert(f13289_cpp_test()); } extern(C++) { bool f13289_cpp_test(); version(Posix) { dchar f13289_cpp_wchar_t(dchar); } else version(Windows) { wchar f13289_cpp_wchar_t(wchar); } wchar f13289_d_wchar(wchar ch) { if (ch <= 'z' && ch >= 'a') { return cast(wchar)(ch - ('a' - 'A')); } else { return ch; } } dchar f13289_d_dchar(dchar ch) { if (ch <= 'z' && ch >= 'a') { return ch - ('a' - 'A'); } else { return ch; } } } /****************************************/ version (CRuntime_Microsoft) { version (PULL8152) { enum __c_long_double : double; } else { struct __c_long_double { this(double d) { ld = d; } double ld; alias ld this; } } alias __c_long_double myld; } else alias c_long_double myld; extern (C++) myld testld(myld); void test15() { myld ld = 5.0; ld = testld(ld); assert(ld == 6.0); } /****************************************/ version( Windows ) { alias int x_long; alias uint x_ulong; } else { static if( (void*).sizeof > int.sizeof ) { alias long x_long; alias ulong x_ulong; } else { alias int x_long; alias uint x_ulong; } } version (PULL8152) { enum __c_long : x_long; enum __c_ulong : x_ulong; } else { struct __c_long { this(x_long d) { ld = d; } x_long ld; alias ld this; } struct __c_ulong { this(x_ulong d) { ld = d; } x_ulong ld; alias ld this; } } alias __c_long mylong; alias __c_ulong myulong; extern (C++) mylong testl(mylong); extern (C++) myulong testul(myulong); void test16() { { mylong ld = 5; ld = testl(ld); printf("ld = %lld, mylong.sizeof = %lld\n", cast(long)ld, cast(long)mylong.sizeof); assert(ld == 5 + mylong.sizeof); } { myulong ld = 5; ld = testul(ld); assert(ld == 5 + myulong.sizeof); } version (PULL8152) { static if (__c_long.sizeof == long.sizeof) { static assert(__c_long.max == long.max); static assert(__c_long.min == long.min); static assert(__c_long.init == long.init); static assert(__c_ulong.max == ulong.max); static assert(__c_ulong.min == ulong.min); static assert(__c_ulong.init == ulong.init); __c_long cl = 0; cl = cl + 1; long l = cl; cl = l; __c_ulong cul = 0; cul = cul + 1; ulong ul = cul; cul = ul; } else static if (__c_long.sizeof == int.sizeof) { static assert(__c_long.max == int.max); static assert(__c_long.min == int.min); static assert(__c_long.init == int.init); static assert(__c_ulong.max == uint.max); static assert(__c_ulong.min == uint.min); static assert(__c_ulong.init == uint.init); __c_long cl = 0; cl = cl + 1; int i = cl; cl = i; __c_ulong cul = 0; cul = cul + 1; uint u = cul; cul = u; } else static assert(0); } } /****************************************/ struct S13707 { void* a; void* b; this(void* a, void* b) { this.a = a; this.b = b; } } extern(C++) S13707 func13707(); void test13707() { auto p = func13707(); assert(p.a == null); assert(p.b == null); } /****************************************/ struct S13932(int x) { int member; } extern(C++) void func13932(S13932!(-1) s); /****************************************/ extern(C++, N13337.M13337) { struct S13337{} void foo13337(S13337 s); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=14195 struct Delegate1(T) {} struct Delegate2(T1, T2) {} template Signature(T) { alias Signature = typeof(*(T.init)); } extern(C++) { alias del1_t = Delegate1!(Signature!(void function())); alias del2_t = Delegate2!(Signature!(int function(float, double)), Signature!(int function(float, double))); void test14195a(del1_t); void test14195b(del2_t); } void test14195() { test14195a(del1_t()); test14195b(del2_t()); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=14200 template Tuple14200(T...) { alias Tuple14200 = T; } extern(C++) void test14200a(Tuple14200!(int)); extern(C++) void test14200b(float, Tuple14200!(int, double)); void test14200() { test14200a(1); test14200b(1.0f, 1, 1.0); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=14956 extern(C++) void test14956(S14956 s); /****************************************/ // check order of overloads in vtable extern (C++) class Statement {} extern (C++) class ErrorStatement {} extern (C++) class PeelStatement {} extern (C++) class ExpStatement {} extern (C++) class DtorExpStatement {} extern (C++) class Visitor { public: int visit(Statement) { return 1; } int visit(ErrorStatement) { return 2; } int visit(PeelStatement) { return 3; } } extern (C++) class Visitor2 : Visitor { int visit2(ExpStatement) { return 4; } int visit2(DtorExpStatement) { return 5; } } extern(C++) bool testVtableCpp(Visitor2 sv); extern(C++) Visitor2 getVisitor2(); bool testVtableD(Visitor2 sv) { Statement s1; ErrorStatement s2; PeelStatement s3; ExpStatement s4; DtorExpStatement s5; if (sv.visit(s1) != 1) return false; if (sv.visit(s2) != 2) return false; if (sv.visit(s3) != 3) return false; if (sv.visit2(s4) != 4) return false; if (sv.visit2(s5) != 5) return false; return true; } void testVtable() { Visitor2 dinst = new Visitor2; if (!testVtableCpp(dinst)) assert(0); Visitor2 cppinst = getVisitor2(); if (!testVtableD(cppinst)) assert(0); } /****************************************/ /* problems detected by fuzzer */ extern(C++) void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12); extern(C++) void fuzz1_dvararg(int64_t arg10, int64_t arg11, bool arg12) { fuzz1_checkValues(arg10, arg11, arg12); } extern(C++) void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12) { assert(arg10 == 103); assert(arg11 == 104); assert(arg12 == false); } void fuzz1() { long arg10 = 103; long arg11 = 104; bool arg12 = false; fuzz1_dvararg(arg10, arg11, arg12); fuzz1_cppvararg(arg10, arg11, arg12); } //////// extern(C++) void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12); extern(C++) void fuzz2_dvararg(uint64_t arg10, uint64_t arg11, bool arg12) { fuzz2_checkValues(arg10, arg11, arg12); } extern(C++) void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12) { assert(arg10 == 103); assert(arg11 == 104); assert(arg12 == false); } void fuzz2() { ulong arg10 = 103; ulong arg11 = 104; bool arg12 = false; fuzz2_dvararg(arg10, arg11, arg12); fuzz2_cppvararg(arg10, arg11, arg12); } //////// extern(C++) void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12); extern(C++) void fuzz3_dvararg(wchar arg10, wchar arg11, bool arg12) { fuzz2_checkValues(arg10, arg11, arg12); } extern(C++) void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12) { assert(arg10 == 103); assert(arg11 == 104); assert(arg12 == false); } void fuzz3() { wchar arg10 = 103; wchar arg11 = 104; bool arg12 = false; fuzz3_dvararg(arg10, arg11, arg12); fuzz3_cppvararg(arg10, arg11, arg12); } void fuzz() { fuzz1(); fuzz2(); fuzz3(); } /****************************************/ extern (C++) { void throwit(); } void testeh() { printf("testeh()\n"); version (linux) { version (X86_64) { bool caught; try { throwit(); } catch (std.exception e) { caught = true; } assert(caught); } } } /****************************************/ version (linux) { version (X86_64) { bool raii_works = false; struct RAIITest { ~this() { raii_works = true; } } void dFunction() { RAIITest rt; throwit(); } void testeh2() { printf("testeh2()\n"); try { dFunction(); } catch(std.exception e) { assert(raii_works); } } } else void testeh2() { } } else void testeh2() { } /****************************************/ extern (C++) { void throwle(); void throwpe(); } void testeh3() { printf("testeh3()\n"); version (linux) { version (X86_64) { bool caught = false; try { throwle(); } catch (std.exception e) //polymorphism test. { caught = true; } assert(caught); } } } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15576 extern (C++, ns15576) { extern __gshared int global15576; extern (C++, ns) { extern __gshared int n_global15576; } } void test15576() { global15576 = n_global15576 = 123; } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15579 extern (C++) { class Base { //~this() {} void based() { } ubyte x = 4; } interface Interface { int MethodCPP(); int MethodD(); } class Derived : Base, Interface { short y = 5; int MethodCPP(); int MethodD() { printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y); Derived p = this; //p = cast(Derived)(cast(void*)p - 16); assert(p.x == 4 || p.x == 7); assert(p.y == 5 || p.y == 8); return 3; } int Method() { return 6; } } Derived cppfoo(Derived); Interface cppfooi(Interface); } void test15579() { Derived d = new Derived(); printf("d = %p\n", d); assert(d.x == 4); assert(d.y == 5); assert((cast(Interface)d).MethodCPP() == 30); assert((cast(Interface)d).MethodD() == 3); assert(d.MethodCPP() == 30); assert(d.MethodD() == 3); assert(d.Method() == 6); d = cppfoo(d); assert(d.x == 7); assert(d.y == 8); printf("d2 = %p\n", d); /* Casting to an interface involves thunks in the vtbl[]. * g++ puts the thunks for MethodD in the same COMDAT as MethodD. * But D doesn't, so when the linker "picks one" of the D generated MethodD * or the g++ generated MethodD, it may wind up with a messed up thunk, * resulting in a seg fault. The solution is to not expect objects of the same * type to be constructed on both sides of the D/C++ divide if the same member * function (in this case, MethodD) is also defined on both sides. */ version (Windows) { assert((cast(Interface)d).MethodD() == 3); } assert((cast(Interface)d).MethodCPP() == 30); assert(d.Method() == 6); printf("d = %p, i = %p\n", d, cast(Interface)d); version (Windows) { Interface i = cppfooi(d); printf("i2: %p\n", i); assert(i.MethodD() == 3); assert(i.MethodCPP() == 30); } printf("test15579() done\n"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15610 extern(C++) class Base2 { int i; void baser() { } } extern(C++) interface Interface2 { abstract void f(); } extern(C++) class Derived2 : Base2, Interface2 { final override void f(); } void test15610() { auto c = new Derived2(); printf("test15610(): c = %p\n", c); c.i = 3; c.f(); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15455 struct X6 { ushort a; ushort b; ubyte c; ubyte d; } static assert(X6.sizeof == 6); struct X8 { ushort a; X6 b; } static assert(X8.sizeof == 8); void test15455a(X8 s) { assert(s.a == 1); assert(s.b.a == 2); assert(s.b.b == 3); assert(s.b.c == 4); assert(s.b.d == 5); } extern (C++) void test15455b(X8 s); void test15455() { X8 s; s.a = 1; s.b.a = 2; s.b.b = 3; s.b.c = 4; s.b.d = 5; test15455a(s); test15455b(s); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15372 extern(C++) int foo15372(T)(int v); void test15372() { version(Windows){} else assert(foo15372!int(1) == 1); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15802 extern(C++) { template Foo15802(T) { static int boo(T v); } } void test15802() { version(Windows){} else assert(Foo15802!(int).boo(1) == 1); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16536 // mangling mismatch on OSX version(OSX) extern(C++) uint64_t pass16536(uint64_t); void test16536() { version(OSX) assert(pass16536(123) == 123); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15589 // extern(C++) virtual destructors are not put in vtbl[] extern(C++) { class A15589 { extern(D) static int[] dtorSeq; struct S { this(int x) { this.x = x; } ~this() { dtorSeq ~= x; } int x; } int foo() { return 100; } // shift dtor to slot 1 ~this() { dtorSeq ~= 10; } S s1 = S(1); S s2 = S(2); } class B15589 : A15589 { int bar() { return 200;} // add an additional function AFTER the dtor at slot 2 ~this() { dtorSeq ~= 20; } S s3 = S(3); } void test15589b(A15589 p); } void test15589() { A15589 c = new B15589; assert(A15589.dtorSeq == null); assert(c.foo() == 100); assert((cast(B15589)c).bar() == 200); c.__xdtor(); // virtual dtor call assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy! A15589.dtorSeq = null; test15589b(c); assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy! } extern(C++) { class Cpp15589Base { public: final ~this(); void nonVirtual(); int a; } class Cpp15589Derived : Cpp15589Base { public: this(); final ~this(); int b; } class Cpp15589BaseVirtual { public: void beforeDtor(); this(); ~this(); void afterDtor(); int c = 1; } class Cpp15589DerivedVirtual : Cpp15589BaseVirtual { public: this(); ~this(); override void afterDtor(); int d; } class Cpp15589IntroducingVirtual : Cpp15589Base { public: this(); void beforeIntroducedVirtual(); ~this(); void afterIntroducedVirtual(int); int e; } struct Cpp15589Struct { ~this(); int s; } void trace15589(int ch) { traceBuf[traceBufPos++] = cast(char) ch; } } __gshared char[32] traceBuf; __gshared size_t traceBufPos; mixin template scopeAllocCpp(C) { // workaround for https://issues.dlang.org/show_bug.cgi?id=18986 version(OSX) enum cppCtorReturnsThis = false; else version(FreeBSD) enum cppCtorReturnsThis = false; else enum cppCtorReturnsThis = true; static if (cppCtorReturnsThis) scope C ptr = new C; else { ubyte[__traits(classInstanceSize, C)] data; C ptr = (){ auto p = cast(C) data.ptr; p.__ctor(); return p; }(); } } void test15589b() { traceBufPos = 0; { Cpp15589Struct struc = Cpp15589Struct(); mixin scopeAllocCpp!Cpp15589Derived derived; mixin scopeAllocCpp!Cpp15589DerivedVirtual derivedVirtual; mixin scopeAllocCpp!Cpp15589IntroducingVirtual introducingVirtual; introducingVirtual.ptr.destroy(); derivedVirtual.ptr.destroy(); derived.ptr.destroy(); } printf("traceBuf15589 %.*s\n", cast(int)traceBufPos, traceBuf.ptr); assert(traceBuf[0..traceBufPos] == "IbVvBbs"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=18928 // Win64: extern(C++) bad codegen, wrong calling convention extern(C++) struct Small18928 { int x; } extern(C++) class CC18928 { Small18928 getVirtual(); // { return S(3); } final Small18928 getFinal(); // { return S(4); } static Small18928 getStatic(); // { return S(5); } } extern(C++) CC18928 newCC18928(); void test18928() { auto cc = newCC18928(); Small18928 v = cc.getVirtual(); assert(v.x == 3); Small18928 f = cc.getFinal(); assert(f.x == 4); Small18928 s = cc.getStatic(); assert(s.x == 5); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=18953 // Win32: extern(C++) struct destructor not called correctly through runtime extern(C++) struct S18953 { char x; ~this() nothrow @nogc { traceBuf[traceBufPos++] = x; } } void test18953() { traceBufPos = 0; S18953[] arr = new S18953[3]; arr[1].x = '1'; arr[2].x = '2'; arr.length = 1; assumeSafeAppend(arr); // destroys arr[1] and arr[2] printf("traceBuf18953 %.*s\n", cast(int)traceBufPos, traceBuf.ptr); assert(traceBuf[0..traceBufPos] == "21"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=18966 extern(C++): class Base18966 { this() @safe nothrow; ~this(); void vf(); int x; } class Derived18966 : Base18966 { override void vf() { x = 200; } } class Explicit18966 : Base18966 { this() @safe { super(); } override void vf() { x = 250; } } class Implicit18966 : Base18966 { this() nothrow {} override void vf() { x = 300; } } // test vptr in full ctor chain of mixed D/C++ class hierarchies // TODO: Make this a D class and let C++ derive from it. This works on Windows, // but results in linker errors on Posix due to extra base ctor (`C2` // mangling) being called by the B ctor. class A18966 // in C++ { char[8] calledOverloads = 0; int i; this(); void foo(); } class B18966 : A18966 // in C++ { this(); override void foo(); } class C18966 : B18966 { this() { foo(); } override void foo() { calledOverloads[i++] = 'C'; } } class D18966 : C18966 { this() { foo(); } override void foo() { calledOverloads[i++] = 'D'; } } void test18966() { Derived18966 d = new Derived18966; assert(d.x == 10); d.vf(); assert(d.x == 200); Explicit18966 e = new Explicit18966; assert(e.x == 10); e.vf(); assert(e.x == 250); Implicit18966 i = new Implicit18966; assert(i.x == 10); i.vf(); assert(i.x == 300); // TODO: Allocating + constructing a C++ class with the D GC is not // supported on Posix. The returned pointer (probably from C++ ctor) // seems to be an offset and not the actual object address. version (Windows) { auto a = new A18966; assert(a.calledOverloads[0..2] == "A\0"); auto b = new B18966; assert(b.calledOverloads[0..3] == "AB\0"); } auto c = new C18966; assert(c.calledOverloads[0..4] == "ABC\0"); auto d2 = new D18966; // note: the vptr semantics in ctors of extern(C++) classes may be revised (to "ABCD") assert(d2.calledOverloads[0..5] == "ABDD\0"); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=19134 class Base19134 { int a = 123; this() { a += 42; } int foo() const { return a; } } class Derived19134 : Base19134 { int b = 666; this() { a *= 2; b -= 6; } override int foo() const { return b; } } void test19134() { static const d = new Derived19134; assert(d.a == (123 + 42) * 2); assert(d.b == 666 - 6); assert(d.foo() == 660); } // https://issues.dlang.org/show_bug.cgi?id=18955 alias std_string = std.basic_string!(char); extern(C++) void callback18955(ref const(std_string) str) { } extern(C++) void test18955(); /****************************************/ void main() { test1(); test2(); test3(); test4(); test13956(); test5(); test6(); test10071(); test7(); test8(); test11802(); test9(); test10(); test13955(); test11(); testvalist(); test12825(); test13161(); test14(); test13289(); test15(); test16(); func13707(); func13932(S13932!(-1)(0)); foo13337(S13337()); test14195(); test14200(); test14956(S14956()); testVtable(); fuzz(); testeh(); testeh2(); testeh3(); test15576(); test15579(); test15610(); test15455(); test15372(); test15802(); test16536(); test15589(); test15589b(); test18928(); test18953(); test18966(); test19134(); test18955(); printf("Success\n"); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/ctorpowtests.d ================================================ // PERMUTE_ARGS: int magicVariable() { if (__ctfe) return 3; version(GNU) { version(X86) asm { "nop"; } else version(X86_64) asm { "nop"; } else static assert(""); } else asm { nop; } return 2; } static assert(magicVariable()==3); void main() { assert(!__ctfe); assert(magicVariable()==2); } // https://issues.dlang.org/show_bug.cgi?id=991 -- invalid. // https://issues.dlang.org/show_bug.cgi?id=3500 -- is this related to 2127? // Tests for ^^ // TODO: These tests should not require import std.math. import std.math; // Test float ^^ int static assert( 27.0 ^^ 5 == 27.0 * 27.0 * 27.0 * 27.0 * 27.0); static assert( 2.0 ^^ 3 == 8.0); static assert( 2.0 ^^ 4 == 16.0); static assert( 2 ^^ 4 == 16); // Check the typing rules. static assert( is (typeof(2.0^^7) == double)); static assert( is (typeof(7^^3) == int)); static assert( is (typeof(7L^^3) == long)); static assert( is (typeof(7^^3L) == long)); enum short POW_SHORT_1 = 3; enum short POW_SHORT_3 = 7; static assert( is (typeof(POW_SHORT_1 * POW_SHORT_1) == typeof(POW_SHORT_1*POW_SHORT_1))); static assert( is (typeof(7.0^^3) == double)); static assert( is (typeof(7.0L^^3) == real)); static assert( is (typeof(7.0f^^3) == float)); static assert( is (typeof(POW_SHORT_1^^3.1) == double)); static assert( is (typeof(POW_SHORT_1^^3.1f) == float)); static assert( is (typeof(2.1f ^^ POW_SHORT_1) == float)); static assert( is (typeof(7.0f^^3.1) == double)); static assert( is (typeof(7.0^^3.1f) == double)); static assert( is (typeof(7.0f^^3.1f) == float)); static assert( is (typeof(7.0f^^3.1L) == real)); static assert( is (typeof(7.0L^^3.1f) == real)); // Check typing for special cases static assert( is (typeof(7.0f^^2) == float)); static assert( is (typeof(7.0f^^2.0) == double)); static assert( is (typeof(7.0f^^8.0) == double)); static assert( is (typeof(1^^0.5f) == float)); static assert( is (typeof(7^^0.5f) == float)); static assert( is (typeof(3L^^0.5) == double)); static assert( is (typeof(123^^17.0f) == float)); static assert(POW_SHORT_1 ^^ 2 == 9); static assert(4.0 ^^ POW_SHORT_1 == 4.0*4.0*4.0); static assert(4.0 ^^ 7.0 == 4.0*4.0*4.0*4.0*4.0*4.0*4.0); // ^^ has higher precedence than multiply static assert( 2 * 2 ^^ 3 + 1 == 17); static assert( 2 ^^ 3 * 2 + 1 == 17); // ^^ has higher precedence than negate static assert( -2 ^^ 3 * 2 - 1 == -17); // ^^ is right associative static assert( 2 ^^ 3 ^^ 2 == 2 ^^ 9); static assert( 2.0 ^^ -3 ^^ 2 == 2.0 ^^ -9); // 1 ^^ n is always 1, even if n is negative static assert( 1 ^^ -5 == 1); // -1 ^^ n gets transformed into n & 1 ? -1 : 1 // even if n is negative static assert( (-1) ^^ -5 == -1); static assert( (-1) ^^ -4 == 1); static assert( (-1) ^^ 0 == 1); // n ^^ 0 is always 1 static assert( (-5) ^^ 0 == 1); // n ^^ 1 is always n static assert( 6.0 ^^ 1 == 6.0); // n ^^ -1.0 gets transformed into 1.0 / n, even if n is negative static assert( (-4) ^^ -1.0 == 1.0 / -4); static assert( 9 ^^ -1.0 == 1.0 / 9); // Other integers raised to negative powers create an error static assert( !is(typeof(2 ^^ -5))); static assert( !is(typeof((-2) ^^ -4))); // https://issues.dlang.org/show_bug.cgi?id=3535 struct StructWithCtor { this(int _n) { n = _n; x = 5; } this(int _n, float _x) { n = _n; x = _x; } int n; float x; } int containsAsm() { version(GNU) { version(X86) asm { "nop"; } else version(X86_64) asm { "nop"; } else static assert(""); } else asm { nop; } return 0; } enum A = StructWithCtor(1); enum B = StructWithCtor(7, 2.3); static assert(A.n == 1); static assert(A.x == 5.0); static assert(B.n == 7); static assert(B.x == 2.3); int bazra(int x) { StructWithCtor p = StructWithCtor(4); return p.n ^^ 3; } static assert(bazra(14)==64); void moreCommaTests() { (containsAsm(), containsAsm()); auto k = containsAsm(); for (int i=0; i< k^^2; i+=StructWithCtor(1).n) {} } // Test copy constructors struct CopyTest { double x; this(double a) { x = a * 10.0;} this(this) { x+=2.0;} } struct CopyTest2 { int x; int x1; int x2; int x3; this(int a) { x = a * 2; x1 = 3;} this(this) { x1+=17;} } const CopyTest z = CopyTest(5.3); /+ // TODO: This is not yet supported. But it // generates an error message instead of wrong-code. const CopyTest w = z; static assert(z.x==55.0); +/ int copytest1() { CopyTest z = CopyTest(3.4); CopyTest w = z; assert(w.x == 36.0); CopyTest2 q = CopyTest2(7); CopyTest2 q2 = q; CopyTest2 q3 = q2; assert(q3.x1 == 37); return 123; } static assert(copytest1()==123); // This must not cause a segfault alias int FILTH; struct Filth { struct Impl { FILTH * handle = null; this(FILTH* h, uint r, string n) { handle = h; } } Impl * p; this(string name, in char[] stdioOpenmode = "rb") { } ~this() { if (!p) return; } this(this) { if (!p) return; } } struct InputByChar { private Filth _f; this(Filth f) { _f = f; } } static int nastyForCtfe=4; // Can't use a global variable static assert(!is(typeof( (){ static assert(0!=nastyForCtfe^^2); }))); int anotherPowTest() { double x = 5.0; return x^^4 > 2.0 ? 3: 2; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/debug_info.d ================================================ // REQUIRED_ARGS: -g void main() { version(OSX) testDebugLineMacOS(); } version (OSX): struct mach_header; struct mach_header_64; struct section; struct section_64; version (D_LP64) { alias MachHeader = mach_header_64; alias Section = section_64; } else { alias MachHeader = mach_header; alias Section = section; } extern (C) { MachHeader* _dyld_get_image_header(uint image_index); const(section)* getsectbynamefromheader(in mach_header* mhp, in char* segname, in char* sectname); const(section_64)* getsectbynamefromheader_64(in mach_header_64* mhp, in char* segname, in char* sectname); } const(Section)* getSectByNameFromHeader(MachHeader* mhp, in char* segname, in char* sectname) { version (D_LP64) return getsectbynamefromheader_64(mhp, segname, sectname); else return getsectbynamefromheader(mhp, segname, sectname); } void testDebugLineMacOS() { auto header = _dyld_get_image_header(0); assert(header); auto section = getSectByNameFromHeader(header, "__DWARF", "__debug_line"); // verify that the __debug_line section is present in the final executable assert(section); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/declaration.d ================================================ extern(C) int printf(const char*, ...); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6475 class Foo6475(Value) { template T1(size_t n){ alias int T1; } } void test6475() { alias Foo6475!(int) C1; alias C1.T1!0 X1; static assert(is(X1 == int)); alias const(Foo6475!(int)) C2; alias C2.T1!0 X2; static assert(is(X2 == int)); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=6905 void test6905() { auto foo1() { static int n; return n; } auto foo2() { int n; return n; } auto foo3() { return 1; } static assert(typeof(&foo1).stringof == "int delegate() nothrow @nogc @safe"); static assert(typeof(&foo2).stringof == "int delegate() pure nothrow @nogc @safe"); static assert(typeof(&foo3).stringof == "int delegate() pure nothrow @nogc @safe"); ref bar1() { static int n; return n; } static assert(!__traits(compiles, { ref bar2() { int n; return n; } })); static assert(!__traits(compiles, { ref bar3() { return 1; } })); auto ref baz1() { static int n; return n; } auto ref baz2() { int n; return n; } auto ref baz3() { return 1; } static assert(typeof(&baz1).stringof == "int delegate() nothrow @nogc ref @safe"); static assert(typeof(&baz2).stringof == "int delegate() pure nothrow @nogc @safe"); static assert(typeof(&baz3).stringof == "int delegate() pure nothrow @nogc @safe"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7019 struct S7019 { int store; this(int n) { store = n << 3; } } S7019 rt_gs = 2; enum S7019 ct_gs = 2; pragma(msg, ct_gs, ", ", ct_gs.store); void test7019() { S7019 rt_ls = 3; // this compiles fine enum S7019 ct_ls = 3; pragma(msg, ct_ls, ", ", ct_ls.store); static class C { S7019 rt_fs = 4; enum S7019 ct_fs = 4; pragma(msg, ct_fs, ", ", ct_fs.store); } auto c = new C; assert(rt_gs == S7019(2) && rt_gs.store == 16); assert(rt_ls == S7019(3) && rt_ls.store == 24); assert(c.rt_fs == S7019(4) && c.rt_fs.store == 32); static assert(ct_gs == S7019(2) && ct_gs.store == 16); static assert(ct_ls == S7019(3) && ct_ls.store == 24); static assert(C.ct_fs == S7019(4) && C.ct_fs.store == 32); void foo(S7019 s = 5) // fixing bug 7152 { assert(s.store == 5 << 3); } foo(); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=7239 struct vec7239 { float x, y, z, w; alias x r; //! for color access alias y g; //! ditto alias z b; //! ditto alias w a; //! ditto } void test7239() { vec7239 a = {x: 0, g: 0, b: 0, a: 1}; assert(a.r == 0); assert(a.g == 0); assert(a.b == 0); assert(a.a == 1); } /***************************************************/ struct S10635 { string str; this(string[] v) { str = v[0]; } this(string[string] v) { str = v.keys[0]; } } S10635 s10635a = ["getnonce"]; S10635 s10635b = ["getnonce" : "str"]; void test10635() { S10635 sa = ["getnonce"]; S10635 sb = ["getnonce" : "str"]; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8123 void test8123() { struct S { } struct AS { alias S Alias; } struct Wrapper { AS as; } Wrapper w; static assert(is(typeof(w.as).Alias == S)); // fail static assert(is(AS.Alias == S)); // ok static assert(is(typeof(w.as) == AS)); // ok static assert(is(typeof(w.as).Alias == AS.Alias)); // fail } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8147 enum A8147 { a, b, c } @property ref T front8147(T)(T[] a) if (!is(T[] == void[])) { return a[0]; } template ElementType8147(R) { static if (is(typeof({ R r = void; return r.front8147; }()) T)) alias T ElementType8147; else alias void ElementType8147; } void test8147() { auto arr = [A8147.a]; alias typeof(arr) R; auto e = ElementType8147!R.init; } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8410 void test8410() { struct Foo { int[15] x; string s; } Foo[5] a1 = Foo([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "hello"); // OK Foo f = { s: "hello" }; // OK (not static) Foo[5] a2 = { s: "hello" }; // error } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8942 alias const int A8942_0; static assert(is(A8942_0 == const int)); // passes void test8942() { alias const int A8942_1; static assert(is(A8942_1 == const int)); // passes static struct S { int i; } foreach (Unused; typeof(S.tupleof)) { alias const(int) A8942_2; static assert(is(A8942_2 == const int)); // also passes alias const int A8942_3; static assert(is(A8942_3 == const int)); // fails // Error: static assert (is(int == const(int))) is false } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10144 final class TNFA10144(char_t) { enum Act { don } const Act[] action_lookup1 = [ Act.don, ]; } alias X10144 = TNFA10144!char; class C10144 { enum Act { don } synchronized { enum x1 = [Act.don]; } override { enum x2 = [Act.don]; } abstract { enum x3 = [Act.don]; } final { enum x4 = [Act.don]; } synchronized { static s1 = [Act.don]; } override { static s2 = [Act.don]; } abstract { static s3 = [Act.don]; } final { static s4 = [Act.don]; } synchronized { __gshared gs1 = [Act.don]; } override { __gshared gs2 = [Act.don]; } abstract { __gshared gs3 = [Act.don]; } final { __gshared gs4 = [Act.don]; } } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10142 class File10142 { enum Access : ubyte { Read = 0x01 } enum Open : ubyte { Exists = 0 } enum Share : ubyte { None = 0 } enum Cache : ubyte { None = 0x00 } struct Style { Access access; Open open; Share share; Cache cache; } enum Style ReadExisting = { Access.Read, Open.Exists }; this (const(char[]) path, Style style = ReadExisting) { assert(style.access == Access.Read); assert(style.open == Open .Exists); assert(style.share == Share .None); assert(style.cache == Cache .None); } } void test10142() { auto f = new File10142("dummy"); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11421 void test11421() { // AAs in array const a1 = [[1:2], [3:4]]; // ok <- error const int[int][] a2 = [[1:2], [3:4]]; // ok static assert(is(typeof(a1) == typeof(a2))); // AAs in AA auto aa = [1:["a":1.0], 2:["b":2.0]]; static assert(is(typeof(aa) == double[string][int])); assert(aa[1]["a"] == 1.0); assert(aa[2]["b"] == 2.0); } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13776 enum a13776(T) = __traits(compiles, { T; }); enum b13776(A...) = 1; template x13776s() { struct S; alias x13776s = b13776!(a13776!S); } template y13776s() { struct S; alias x2 = b13776!(a13776!S); alias y13776s = x2; } template z13776s() { struct S; alias x1 = a13776!S; alias x2 = b13776!(x1); alias z13776s = x2; } template x13776c() { class C; alias x13776c = b13776!(a13776!C); } template y13776c() { class C; alias x2 = b13776!(a13776!C); alias y13776c = x2; } template z13776c() { class C; alias x1 = a13776!C; alias x2 = b13776!(x1); alias z13776c = x2; } void test13776() { alias xs = x13776s!(); // ok <- ng alias ys = y13776s!(); // ok <- ng alias zs = z13776s!(); // ok alias xc = x13776c!(); // ok <- ng alias yc = y13776c!(); // ok <- ng alias zc = z13776c!(); // ok } /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14090 template Packed14090(Args...) { enum x = __traits(compiles, { Args[0] v; }); // Args[0] is an opaque struct Empty, so the variable declaration fails to compile. // The error message creation calls TypeStruct('_Empty')->toChars(), and // it wrongly calls TemplateInstance('RoundRobin!()')->toAlias(). // Finally it will cause incorrect "recursive template instantiation" error. } template Map14090(A...) { alias Map14090 = A[0]; } template RoundRobin14090() { struct Empty; alias RoundRobin14090 = Map14090!(Packed14090!(Empty)); } alias roundRobin14090 = RoundRobin14090!(); /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=13950 template Tuple13950(T...) { alias T Tuple13950; } void f13950(int x = 0, Tuple13950!() xs = Tuple13950!()) { assert(x == 0); assert(xs.length == 0); } void test13950() { f13950(); } /***************************************************/ int main() { test6475(); test6905(); test7019(); test7239(); test8123(); test8147(); test8410(); test8942(); test10142(); test11421(); test13950(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/delegate.d ================================================ // REQUIRED_ARGS: import core.stdc.stdio; /********************************************************/ //int delegate(int, char[]) *p; class Foo { int bar(int i, char[] s) { return 4; } } class Bar : Foo { override int bar(int i, char[] s) { return 5; } } void test1() { int delegate(int, char[]) dg; Foo f = new Foo(); Bar b = new Bar(); int x; dg = &f.bar; x = dg(3, null); assert(x == 4); f = b; dg = &f.bar; x = dg(3, null); assert(x == 5); } /********************************************************/ int foo2() { return 3; } void test2() { int function () fp; fp = &foo2; assert(fp() == 3); } /********************************************************/ class Foo3 { int bar(int i, char[] s) { return 47; } void test() { int delegate(int, char[]) dg; dg = &bar; printf("%d %d\n", dg(3, null), result()); assert(dg(3, null) == result()); dg = &this.bar; printf("%d %d\n", dg(3, null), result()); assert(dg(3, null) == result()); } int result() { return 47; } } class Bar3 : Foo3 { override int bar(int i, char[] s) { return 48; } override int result() { return 48; } void test2() { int delegate(int, char[]) dg; dg = &super.bar; assert(dg(3, null) == 47); } } void test3() { Foo3 f = new Foo3(); f.test(); Bar3 b = new Bar3(); b.test(); b.test2(); } /********************************************************/ int foo4(int x) { return 1; } int foo4(char x) { return 2; } int foo4(int x, int y) { return 3; } void test4() { int function (char) fp; fp = &foo4; assert(fp(0) == 2); } /********************************************************/ class Abc { int foo1(int x) { return 1; } int foo1(char x) { return 2; } int foo1(int x, int y) { return 3; } } void test5() { int delegate(char) dg; Abc a = new Abc(); dg = &a.foo1; assert(dg(0) == 2); } /********************************************************/ int delegate(int) bar6; int[int delegate(int)] aa6; void test6() { aa6[bar6] = 0; } /********************************************************/ void foo7(void delegate(int) dg) { dg(1); //writefln("%s", dg(3)); } void test7() { foo7(delegate(int i) { printf("i = %d\n", i); } ); } /********************************************************/ void foo8(int delegate(int) dg) { printf("%d\n", dg(3)); assert(dg(3) == 6); } void test8() { foo8(delegate(int i) { return i * 2; } ); } /********************************************************/ void foo9(int delegate(int) dg) { assert(dg(3) == 6); } void test9() { foo9( (int i) { return i * 2; } ); } /********************************************************/ // https://issues.dlang.org/show_bug.cgi?id=8257 struct S8257 { static int g() { return 6; } } void test8257() { S8257 s; int w = 2; S8257 func() { ++w; return s; } auto k = &(func()).g; // check that the call to func() still happened assert(w == 3); assert( k() == 6); } auto f8257(string m)() { return &__traits(getMember, S8257.init, m); } static assert (__traits(compiles, f8257!"g"())); /********************************************************/ void foo10(int delegate() dg) { assert(dg() == 6); } void test10() { int i = 3; foo10( { return i * 2; } ); } /********************************************************/ class A12 { public: int delegate(int, int)[4] dgs; int function(int, int)[4] fps; int delegate(int, int) dg; int function(int, int) fp; int f(int x, int y) { printf("here "); int res = x + y; printf("%d\n", res); return res; } void bug_1() { // fp = &f; // fp(1,2); dg = &f; dg(1,2); // fps[] = [&f, &f, &f, &(f)]; // bug 1: this line shouldn't compile // this.fps[0](1, 2); // seg-faults here! dgs[] = [&(f), &(f), &(f), &(f)]; // bug 1: why this line can't compile? this.dgs[0](1, 2); dgs[] = [&(this.f), &(this.f), &(this.f), &(this.f)]; this.dgs[0](1, 2); } } void test12() { A12 a = new A12(); a.bug_1(); } /********************************************************/ // https://issues.dlang.org/show_bug.cgi?id=1570 class A13 { int f() { return 1; } } class B13 : A13 { override int f() { return 2; } } void test13() { B13 b = new B13; assert(b.f() == 2); assert(b.A13.f() == 1); assert((&b.f)() == 2); assert((&b.A13.f)() == 1); } /********************************************************/ // https://issues.dlang.org/show_bug.cgi?id=2472 class A2472 { void foo() {} } void test2472() { auto a = new A2472; auto fp1 = (&a.foo).funcptr; auto dg = &a.foo; auto fp2 = dg.funcptr; assert(fp1 == fp2); } /********************************************************/ void testAssign() { static class C { int a; this(int a) { this.a = a; } int funca() { return a; } int funcb() { return a + 1; } } auto x = new C(5); auto y = new C(7); auto dg = &x.funca; assert(dg() == 5); dg.funcptr = &C.funcb; assert(dg() == 6); dg.ptr = cast(void*)y; assert(dg() == 8); dg.funcptr = &C.funca; assert(dg() == 7); } /********************************************************/ int main() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test12(); test13(); test2472(); test8257(); testAssign(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/dhry.d ================================================ // PERMUTE_ARGS: // REQUIRED_ARGS: -release -O -g -inline // DISABLED: freebsd dragonflybsd /* ************************************************************************* * * "DHRYSTONE" Benchmark Program * ----------------------------- * * Version: C, Version 2.1 * * File: dhry.h (part 1 of 3) * * Date: May 25, 1988 * * Author: Reinhold P. Weicker * Siemens Nixdorf Inf. Syst. * STM OS 32 * Otto-Hahn-Ring 6 * W-8000 Muenchen 83 * Germany * Phone: [+49]-89-636-42436 * (8-17 Central European Time) * UUCP: weicker@ztivax.uucp@unido.uucp * Internet: weicker@ztivax.siemens.com * * Original Version (in Ada) published in * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), * pp. 1013 - 1030, together with the statistics * on which the distribution of statements etc. is based. * * In this C version, the following C library functions are * used: * - strcpy, strcmp (inside the measurement loop) * - printf, scanf (outside the measurement loop) * * Collection of Results: * Reinhold Weicker (address see above) and * * Rick Richardson * PC Research. Inc. * 94 Apple Orchard Drive * Tinton Falls, NJ 07724 * Phone: (201) 834-1378 (9-17 EST) * UUCP: ...!uunet!pcrat!rick * * Please send results to Rick Richardson and/or Reinhold Weicker. * Complete information should be given on hardware and software * used. Hardware information includes: Machine type, CPU, type and * size of caches; for microprocessors: clock frequency, memory speed * (number of wait states). Software information includes: Compiler * (and runtime library) manufacturer and version, compilation * switches, OS version. The Operating System version may give an * indication about the compiler; Dhrystone itself performs no OS * calls in the measurement loop. * * The complete output generated by the program should be mailed * such that at least some checks for correctness can be made. * ************************************************************************* * * History: This version C/2.1 has been made for two reasons: * * 1) There is an obvious need for a common C version of * Dhrystone, since C is at present the most popular system * programming language for the class of processors * (microcomputers, minicomputers) where Dhrystone is used * most. There should be, as far as possible, only one C * version of Dhrystone such that results can be compared * without restrictions. In the past, the C versions * distributed by Rick Richardson (Version 1.1) and by * Reinhold Weicker had small (though not significant) * differences. * * 2) As far as it is possible without changes to the * Dhrystone statistics, optimizing compilers should be * prevented from removing significant statements. * * This C version has been developed in cooperation with * Rick Richardson (Tinton Falls, NJ), it incorporates many * ideas from the "Version 1.1" distributed previously by * him over the UNIX network Usenet. * I also thank Chaim Benedelac (National Semiconductor), * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) * for their help with comments on earlier versions of the * benchmark. * * Changes: In the initialization part, this version follows mostly * Rick Richardson's version distributed via Usenet, not the * version distributed earlier via floppy disk by Reinhold * Weicker. As a concession to older compilers, names have * been made unique within the first 8 characters. Inside the * measurement loop, this version follows the version * previously distributed by Reinhold Weicker. * * At several places in the benchmark, code has been added, * but within the measurement loop only in branches that * are not executed. The intention is that optimizing * compilers should be prevented from moving code out of the * measurement loop, or from removing code altogether. Since * the statements that are executed within the measurement * loop have NOT been changed, the numbers defining the * "Dhrystone distribution" (distribution of statements, * operand types and locality) still hold. Except for * sophisticated optimizing compilers, execution times for * this version should be the same as for previous versions. * * Since it has proven difficult to subtract the time for the * measurement loop overhead in a correct way, the loop check * has been made a part of the benchmark. This does have * an impact - though a very minor one - on the distribution * statistics which have been updated for this version. * * All changes within the measurement loop are described * and discussed in the companion paper "Rationale for * Dhrystone version 2". * * Because of the self-imposed limitation that the order and * distribution of the executed statements should not be * changed, there are still cases where optimizing compilers * may not generate code for some statements. To a certain * degree, this is unavoidable for small synthetic * benchmarks. Users of the benchmark are advised to check * code listings whether code is generated for all statements * of Dhrystone. * * Version 2.1 is identical to version 2.0 distributed via * the UNIX network Usenet in March 1988 except that it * corrects some minor deficiencies that were found by users * of version 2.0. The only change within the measurement * loop is that a non-executed "else" part was added to the * "if" statement in Func_3, and a non-executed "else" part * removed from Proc_3. * ************************************************************************* * * Defines: The following "Defines" are possible: * -DROPT (default: Not defined) * As an approximation to what an average C * programmer might do, the "register" storage class * is applied (if enabled by -DROPT) * - for local variables, if they are used * (dynamically) five or more times * - for parameters if they are used (dynamically) * six or more times * Note that an optimal "register" strategy is * compiler-dependent, and that "register" * declarations do not necessarily lead to faster * execution. * -DNOSTRUCTASSIGN (default: Not defined) * Define if the C compiler does not support * assignment of structures. * -DNOENUMS (default: Not defined) * Define if the C compiler does not support * enumeration types. * ************************************************************************* * * Compilation model and measurement (IMPORTANT): * * This C version of Dhrystone consists of three files: * - dhry.h (this file, containing global definitions and comments) * - dhry_1.c (containing the code corresponding to Ada package Pack_1) * - dhry_2.c (containing the code corresponding to Ada package Pack_2) * * The following "ground rules" apply for measurements: * - Separate compilation * - No procedure merging * - Otherwise, compiler optimizations are allowed but should be * indicated * - Default results are those without register declarations * See the companion paper "Rationale for Dhrystone Version 2" for a more * detailed discussion of these ground rules. * * For 16-Bit processors (e.g. 80186, 80286), times for all compilation * models ("small", "medium", "large" etc.) should be given if possible, * together with a definition of these models for the compiler system * used. * ************************************************************************* * * Dhrystone (C version) statistics: * * [Comment from the first distribution, updated for version 2. * Note that because of language differences, the numbers are slightly * different from the Ada version.] * * The following program contains statements of a high level programming * language (here: C) in a distribution considered representative: * * assignments 52 (51.0 %) * control statements 33 (32.4 %) * procedure, function calls 17 (16.7 %) * * 103 statements are dynamically executed. The program is balanced with * respect to the three aspects: * * - statement type * - operand type * - operand locality * operand global, local, parameter, or constant. * * The combination of these three aspects is balanced only approximately. * * 1. Statement Type: * ----------------- number * * V1 = V2 9 * (incl. V1 = F(..) * V = Constant 12 * Assignment, 7 * with array element * Assignment, 6 * with record component * -- * 34 34 * * X = Y +|-|"&&"|"|" Z 5 * X = Y +|-|"==" Constant 6 * X = X +|- 1 3 * X = Y *|/ Z 2 * X = Expression, 1 * two operators * X = Expression, 1 * three operators * -- * 18 18 * * if .... 14 * with "else" 7 * without "else" 7 * executed 3 * not executed 4 * for ... 7 | counted every time * while ... 4 | the loop condition * do ... while 1 | is evaluated * switch ... 1 * break 1 * declaration with 1 * initialization * -- * 34 34 * * P (...) procedure call 11 * user procedure 10 * library procedure 1 * X = F (...) * function call 6 * user function 5 * library function 1 * -- * 17 17 * --- * 103 * * The average number of parameters in procedure or function calls * is 1.82 (not counting the function values as implicit parameters). * * * 2. Operators * ------------ * number approximate * percentage * * Arithmetic 32 50.8 * * + 21 33.3 * - 7 11.1 * * 3 4.8 * / (int div) 1 1.6 * * Comparison 27 42.8 * * == 9 14.3 * /= 4 6.3 * > 1 1.6 * < 3 4.8 * >= 1 1.6 * <= 9 14.3 * * Logic 4 6.3 * * && (AND-THEN) 1 1.6 * | (OR) 1 1.6 * ! (NOT) 2 3.2 * * -- ----- * 63 100.1 * * * 3. Operand Type (counted once per operand reference): * --------------- * number approximate * percentage * * Integer 175 72.3 % * Character 45 18.6 % * Pointer 12 5.0 % * String30 6 2.5 % * Array 2 0.8 % * Record 2 0.8 % * --- ------- * 242 100.0 % * * When there is an access path leading to the final operand (e.g. a * record component), only the final data type on the access path is * counted. * * * 4. Operand Locality: * ------------------- * number approximate * percentage * * local variable 114 47.1 % * global variable 22 9.1 % * parameter 45 18.6 % * value 23 9.5 % * reference 22 9.1 % * function result 6 2.5 % * constant 55 22.7 % * --- ------- * 242 100.0 % * * * The program does not compute anything meaningful, but it is * syntactically and semantically correct. All variables have a value * assigned to them before they are used as a source operand. * * There has been no explicit effort to account for the effects of a * cache, or to balance the use of long or short displacements for code * or data. * ************************************************************************* */ import core.stdc.stdio; import core.stdc.string; import core.stdc.stdlib; import std.string; /* Compiler and system dependent definitions: */ const double Mic_secs_Per_Second = 1000000.0; /* Berkeley UNIX C returns process times in seconds/HZ */ enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} alias int Enumeration; /* for boolean and enumeration types in Ada, Pascal */ /* General definitions: */ const int StrLen = 30; alias int One_Thirty; alias int One_Fifty; alias char Capital_Letter; alias bool Boolean; alias char[StrLen] Str_30; alias int[50] Arr_1_Dim; alias int[50][50] Arr_2_Dim; struct record { record *Ptr_Comp; Enumeration Discr; union V { struct V1 { Enumeration Enum_Comp; int Int_Comp; char[StrLen] Str_Comp; } V1 var_1; struct V2 { Enumeration E_Comp_2; char [StrLen] Str_2_Comp; } V2 var_2; struct V3 { char Ch_1_Comp; char Ch_2_Comp; } V3 var_3; } V variant; } alias record Rec_Type; alias record *Rec_Pointer; /* Global Variables: */ Rec_Pointer Ptr_Glob, Next_Ptr_Glob; int Int_Glob; Boolean Bool_Glob; char Ch_1_Glob, Ch_2_Glob; int[50] Arr_1_Glob; int[50][50] Arr_2_Glob; char[StrLen] Reg_Define = "Register option selected."; /* variables for time measurement: */ const int Too_Small_Time = 2; /* Measurements should last at least 2 seconds */ double Begin_Time, End_Time, User_Time; double Microseconds, Dhrystones_Per_Second, Vax_Mips; /* end of variables for time measurement */ void main () /*****/ /* main program, corresponds to procedures */ /* Main and Proc_0 in the Ada version */ { One_Fifty Int_1_Loc; One_Fifty Int_2_Loc; One_Fifty Int_3_Loc; char Ch_Index; Enumeration Enum_Loc; Str_30 Str_1_Loc; Str_30 Str_2_Loc; int Run_Index; int Number_Of_Runs; /+ FILE *Ap; /* Initializations */ if ((Ap = fopen("dhry.res","a+")) == null) { printf("Can not open dhry.res\n\n"); exit(1); } +/ Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); Ptr_Glob.Ptr_Comp = Next_Ptr_Glob; Ptr_Glob.Discr = Ident_1; Ptr_Glob.variant.var_1.Enum_Comp = Ident_3; Ptr_Glob.variant.var_1.Int_Comp = 40; // strcpy (Ptr_Glob.variant.var_1.Str_Comp, // "DHRYSTONE PROGRAM, SOME STRING"); // strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING"; Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING"; Arr_2_Glob [8][7] = 10; /* Was missing in published program. Without this statement, */ /* Arr_2_Glob [8][7] would have an undefined value. */ /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ /* overflow may occur for this array element. */ printf ("\n"); printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n"); printf ("\n"); printf ("Please give the number of runs through the benchmark: "); { int n; //scanf ("%d", &n); n = 10000000; Number_Of_Runs = n; } printf ("\n"); printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs); /***************/ /* Start timer */ /***************/ Begin_Time = dtime(); for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) { Proc_5(); Proc_4(); /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ Int_1_Loc = 2; Int_2_Loc = 3; //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING"; Enum_Loc = Ident_2; Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); /* Bool_Glob == 1 */ while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ { Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; /* Int_3_Loc == 7 */ Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); /* Int_3_Loc == 7 */ Int_1_Loc += 1; } /* while */ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); /* Int_Glob == 5 */ Proc_1 (Ptr_Glob); for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) /* loop body executed twice */ { if (Enum_Loc == Func_1 (Ch_Index, 'C')) /* then, not executed */ { Proc_6 (Ident_1, &Enum_Loc); //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING"; Int_2_Loc = Run_Index; Int_Glob = Run_Index; } } /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Int_2_Loc = Int_2_Loc * Int_1_Loc; Int_1_Loc = Int_2_Loc / Int_3_Loc; Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ Proc_2 (&Int_1_Loc); /* Int_1_Loc == 5 */ } /* loop "for Run_Index" */ /**************/ /* Stop timer */ /**************/ End_Time = dtime(); printf ("Execution ends\n"); printf ("\n"); printf ("Final values of the variables used in the benchmark:\n"); printf ("\n"); printf ("Int_Glob: %d\n", Int_Glob); printf (" should be: %d\n", 5); printf ("Bool_Glob: %d\n", Bool_Glob); printf (" should be: %d\n", 1); printf ("Ch_1_Glob: %c\n", Ch_1_Glob); printf (" should be: %c\n", cast(int)'A'); printf ("Ch_2_Glob: %c\n", Ch_2_Glob); printf (" should be: %c\n", cast(int)'B'); printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); printf (" should be: %d\n", 7); printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); printf (" should be: Number_Of_Runs + 10\n"); printf ("Ptr_Glob.\n"); printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp); printf (" should be: (implementation-dependent)\n"); printf (" Discr: %d\n", Ptr_Glob.Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp); printf (" should be: %d\n", 2); printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp); printf (" should be: %d\n", 17); printf (" Str_Comp: %.*s\n", Ptr_Glob.variant.var_1.Str_Comp.length, Ptr_Glob.variant.var_1.Str_Comp.ptr); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Next_Ptr_Glob.\n"); printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp); printf (" should be: (implementation-dependent), same as above\n"); printf (" Discr: %d\n", Next_Ptr_Glob.Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp); printf (" should be: %d\n", 1); printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp); printf (" should be: %d\n", 18); printf (" Str_Comp: %.*s\n", Next_Ptr_Glob.variant.var_1.Str_Comp.length, Next_Ptr_Glob.variant.var_1.Str_Comp.ptr); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Int_1_Loc: %d\n", Int_1_Loc); printf (" should be: %d\n", 5); printf ("Int_2_Loc: %d\n", Int_2_Loc); printf (" should be: %d\n", 13); printf ("Int_3_Loc: %d\n", Int_3_Loc); printf (" should be: %d\n", 7); printf ("Enum_Loc: %d\n", Enum_Loc); printf (" should be: %d\n", 1); printf ("Str_1_Loc: %.*s\n", Str_1_Loc.length, Str_1_Loc.ptr); printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); printf ("Str_2_Loc: %.*s\n", Str_2_Loc.length, Str_2_Loc.ptr); printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); printf ("\n"); User_Time = End_Time - Begin_Time; if (User_Time < Too_Small_Time) { printf ("Measured time too small to obtain meaningful results\n"); printf ("Please increase number of runs\n"); printf ("\n"); } else { Microseconds = User_Time * Mic_secs_Per_Second / cast(double) Number_Of_Runs; Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time; Vax_Mips = Dhrystones_Per_Second / 1757.0; printf ("Register option selected? NO\n"); strcpy(Reg_Define.ptr, "Register option not selected."); printf ("Microseconds for one run through Dhrystone: "); printf ("%7.1lf \n", Microseconds); printf ("Dhrystones per Second: "); printf ("%10.1lf \n", Dhrystones_Per_Second); printf ("VAX MIPS rating = %10.3lf \n",Vax_Mips); printf ("\n"); /+ fprintf(Ap,"\n"); fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: D)\n"); fprintf(Ap,"%.*s\n",Reg_Define.length, Reg_Define.ptr); fprintf(Ap,"Microseconds for one loop: %7.1lf\n",Microseconds); fprintf(Ap,"Dhrystones per second: %10.1lf\n",Dhrystones_Per_Second); fprintf(Ap,"VAX MIPS rating: %10.3lf\n",Vax_Mips); fclose(Ap); +/ } } void Proc_1 (Rec_Pointer Ptr_Val_Par) /******************/ /* executed once */ { Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp; /* == Ptr_Glob_Next */ /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */ /* corresponds to "rename" in Ada, "with" in Pascal */ *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob; Ptr_Val_Par.variant.var_1.Int_Comp = 5; Next_Record.variant.var_1.Int_Comp = Ptr_Val_Par.variant.var_1.Int_Comp; Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp; Proc_3 (&Next_Record.Ptr_Comp); /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp == Ptr_Glob.Ptr_Comp */ if (Next_Record.Discr == Ident_1) /* then, executed */ { Next_Record.variant.var_1.Int_Comp = 6; Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp, &Next_Record.variant.var_1.Enum_Comp); Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp; Proc_7 (Next_Record.variant.var_1.Int_Comp, 10, &Next_Record.variant.var_1.Int_Comp); } else /* not executed */ *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp; } /* Proc_1 */ void Proc_2 (One_Fifty *Int_Par_Ref) /******************/ /* executed once */ /* *Int_Par_Ref == 1, becomes 4 */ { One_Fifty Int_Loc; Enumeration Enum_Loc; Int_Loc = *Int_Par_Ref + 10; do /* executed once */ if (Ch_1_Glob == 'A') /* then, executed */ { Int_Loc -= 1; *Int_Par_Ref = Int_Loc - Int_Glob; Enum_Loc = Ident_1; } /* if */ while (Enum_Loc != Ident_1); /* true */ } /* Proc_2 */ void Proc_3 (Rec_Pointer *Ptr_Ref_Par) /******************/ /* executed once */ /* Ptr_Ref_Par becomes Ptr_Glob */ { if (Ptr_Glob != null) /* then, executed */ *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp; Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp); } /* Proc_3 */ void Proc_4 () /* without parameters */ /*******/ /* executed once */ { Boolean Bool_Loc; Bool_Loc = Ch_1_Glob == 'A'; Bool_Glob = Bool_Loc | Bool_Glob; Ch_2_Glob = 'B'; } /* Proc_4 */ void Proc_5 () /* without parameters */ /*******/ /* executed once */ { Ch_1_Glob = 'A'; Bool_Glob = false; } /* Proc_5 */ void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par) /*********************************/ /* executed once */ /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ { *Enum_Ref_Par = Enum_Val_Par; if (! Func_3 (Enum_Val_Par)) /* then, not executed */ *Enum_Ref_Par = Ident_4; final switch (Enum_Val_Par) { case Ident_1: *Enum_Ref_Par = Ident_1; break; case Ident_2: if (Int_Glob > 100) /* then */ *Enum_Ref_Par = Ident_1; else *Enum_Ref_Par = Ident_4; break; case Ident_3: /* executed */ *Enum_Ref_Par = Ident_2; break; case Ident_4: break; case Ident_5: *Enum_Ref_Par = Ident_3; break; } /* switch */ } /* Proc_6 */ void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref) /**********************************************/ /* executed three times */ /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ /* Int_Par_Ref becomes 7 */ /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ /* Int_Par_Ref becomes 17 */ /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ /* Int_Par_Ref becomes 18 */ { One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 2; *Int_Par_Ref = Int_2_Par_Val + Int_Loc; } /* Proc_7 */ void Proc_8 (ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val) /*********************************************************************/ /* executed once */ /* Int_Par_Val_1 == 3 */ /* Int_Par_Val_2 == 7 */ { One_Fifty Int_Index; One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 5; Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; Int_Glob = 5; } /* Proc_8 */ Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val) /*************************************************/ /* executed three times */ /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ { Capital_Letter Ch_1_Loc; Capital_Letter Ch_2_Loc; Ch_1_Loc = Ch_1_Par_Val; Ch_2_Loc = Ch_1_Loc; if (Ch_2_Loc != Ch_2_Par_Val) /* then, executed */ return (Ident_1); else /* not executed */ { Ch_1_Glob = Ch_1_Loc; return (Ident_2); } } /* Func_1 */ Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref) /*************************************************/ /* executed once */ /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ { One_Thirty Int_Loc; Capital_Letter Ch_Loc; Int_Loc = 2; while (Int_Loc <= 2) /* loop body executed once */ if (Func_1 (Str_1_Par_Ref[Int_Loc], Str_2_Par_Ref[Int_Loc+1]) == Ident_1) /* then, executed */ { Ch_Loc = 'A'; Int_Loc += 1; } /* if, while */ if (Ch_Loc >= 'W' && Ch_Loc < 'Z') /* then, not executed */ Int_Loc = 7; if (Ch_Loc == 'R') /* then, not executed */ return (true); else /* executed */ { //if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) //if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0) if (Str_1_Par_Ref > Str_2_Par_Ref) /* then, not executed */ { Int_Loc += 7; Int_Glob = Int_Loc; return (true); } else /* executed */ return (false); } /* if Ch_Loc */ } /* Func_2 */ Boolean Func_3 (Enumeration Enum_Par_Val) /***************************/ /* executed once */ /* Enum_Par_Val == Ident_3 */ { Enumeration Enum_Loc; Enum_Loc = Enum_Par_Val; if (Enum_Loc == Ident_3) /* then, executed */ return (true); else /* not executed */ return (false); } /* Func_3 */ version (Windows) { import core.sys.windows.windows; double dtime() { double q; q = cast(double)GetTickCount() * 1.0e-03; return q; } } version (linux) { import core.stdc.time; double dtime() { double q; q = cast(double)time(null); return q; } } version (OSX) // supplied by Anders F Bjorklund { import core.sys.posix.sys.time; double dtime() { double q; timeval tv; gettimeofday(&tv,null); q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6; return q; } } version (NetBSD) { import core.sys.posix.sys.time; double dtime() { double q; timeval tv; gettimeofday(&tv,null); q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6; return q; } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/eh.d ================================================ // PERMUTE_ARGS: -O -fPIC extern(C) int printf(const char*, ...); /****************************************************/ class Abc : Exception { this() { super(""); } int i; } int y; alias int boo; void foo(int x) { y = cast(boo)1; L6: try { printf("try 1\n"); y += 4; if (y == 5) goto L6; y += 3; } finally { y += 5; printf("finally 1\n"); } try { printf("try 2\n"); y = 1; if (y == 4) goto L6; y++; } catch (Abc c) { printf("catch 2\n"); y = 2 + c.i; } y++; printf("done\n"); } /****************************************************/ class IntException : Exception { this(int i) { m_i = i; super(""); } int getValue() { return m_i; } int m_i; } void test2() { int cIterations = 10; int i; long total_x = 0; long total_nox = 0; for(int WARMUPS = 2; WARMUPS-- > 0; ) { for(total_x = 0, i = 0; i < cIterations; ++i) { total_nox += fn2_nox(); } printf("foo\n"); for(total_nox = 0, i = 0; i < cIterations; ++i) { printf("i = %d\n", i); try { int z = 1; throw new IntException(z); } catch(IntException x) { printf("catch, i = %d\n", i); total_x += x.getValue(); } } } printf("iterations %d totals: %ld, %ld\n", cIterations, total_x, total_nox); } int fn2_nox() { return 47; } /****************************************************/ void test3() { static int x; try { } finally { printf("a\n"); assert(x == 0); x++; } printf("--\n"); assert(x == 1); try { printf("tb\n"); assert(x == 1); } finally { printf("b\n"); assert(x == 1); x++; } assert(x == 2); } /****************************************************/ class Tester { this(void delegate() dg_) { dg = dg_; } void delegate() dg; void stuff() { dg(); } } void test4() { printf("Starting test\n"); int a = 0; int b = 0; int c = 0; int d = 0; try { a++; throw new Exception("test1"); a++; } catch(Exception e) { auto es = e.toString(); printf("%.*s\n", es.length, es.ptr); b++; } finally { c++; } printf("initial test.\n"); assert(a == 1); assert(b == 1); assert(c == 1); printf("pass\n"); Tester t = new Tester( delegate void() { try { a++; throw new Exception("test2"); a++; } catch(Exception e) { b++; throw e; b++; } }); try { c++; t.stuff(); c++; } catch(Exception e) { d++; string es = e.toString; printf("%.*s\n", es.length, es.ptr); } assert(a == 2); assert(b == 2); assert(c == 2); assert(d == 1); int q0 = 0; int q1 = 0; int q2 = 0; int q3 = 0; Tester t2 = new Tester( delegate void() { try { q0++; throw new Exception("test3"); q0++; } catch(Exception e) { printf("Never called.\n"); q1++; throw e; q1++; } }); try { q2++; t2.stuff(); q2++; } catch(Exception e) { q3++; string es = e.toString; printf("%.*s\n", es.length, es.ptr); } assert(q0 == 1); assert(q1 == 1); assert(q2 == 1); assert(q3 == 1); printf("Passed!\n"); } /****************************************************/ void test5() { char[] result; int i = 3; while(i--) { try { printf("i: %d\n", i); result ~= 't'; if (i == 1) continue; } finally { printf("finally\n"); result ~= cast(char)('a' + i); } } printf("--- %.*s", result.length, result.ptr); if (result != "tctbta") assert(0); } /****************************************************/ void test6() { char[] result; while (true) { try { printf("one\n"); result ~= 'a'; break; } finally { printf("two\n"); result ~= 'b'; } } printf("three\n"); result ~= 'c'; if (result != "abc") assert(0); } /****************************************************/ string a7; void doScan(int i) { a7 ~= "a"; try { try { a7 ~= "b"; return; } finally { a7 ~= "c"; } } finally { a7 ~= "d"; } } void test7() { doScan(0); assert(a7 == "abcd"); } /**************************************************** * Exception chaining tests. See also test4.d * Don writes about the complexity: I can explain this, since I did the original implementation. When I originally implemented this, I discovered that the idea of "chained exceptions" was hopeless naive. The idea was that while processing one exception, if you encounter a second one, and you chain them together. Then you get a third, fourth, etc. The problem is that it's much more complicated than that. Each of the exceptions can be a chain of exceptions themselves. This means that you don't end up with a chain of exceptions, but rather a tree of exceptions. That's why there are those really nasty test cases in the test suite. The examples in the test suite are very difficult to understand if you expect it to be a simple chain! On the one hand, I was very proud that I was able to work out the barely-documented behaviour of Windows SEH, and it was really thorough. In the initial implementation, all the complexity was covered. It wasn't the bugfix-driven-development which dmd usually operates under . But on the other hand, once you can see all of the complexity, exception chaining becomes much less convincing as a concept. Sure, the full exception tree is available in the final exception which you catch. But, is it of any use? I doubt it very much. It's pretty clearly a nett loss to the language, it increases complexity with negligible benefit. Fortunately in this case, the cost isn't really high. https://digitalmars.com/d/archives/digitalmars/D/Dicebot_on_leaving_D_It_is_anarchy_driven_development_in_all_its_317950.html#N318305 ****************************************************/ int result1513; void bug1513a() { throw new Exception("d"); } void bug1513b() { try { try { bug1513a(); } finally { result1513 |=4; throw new Exception("f"); } } catch(Exception e) { assert(e.msg == "d"); assert(e.next.msg == "f"); assert(!e.next.next); int i; foreach (u; e) { if (i) assert(u.msg == "f"); else assert(u.msg == "d"); ++i; } } } void bug1513c() { try { try { throw new Exception("a"); } finally { result1513 |= 1; throw new Exception("b"); } } finally { bug1513b(); result1513 |= 2; throw new Exception("c"); } } void bug1513() { result1513 = 0; try { bug1513c(); } catch(Exception e) { assert(result1513 == 7); assert(e.msg == "a"); assert(e.next.msg == "b"); assert(e.next.next.msg == "c"); } } void collideone() { try { throw new Exception("x"); } finally { throw new Exception("y"); } } void doublecollide() { try { try { try { throw new Exception("p"); } finally { throw new Exception("q"); } } finally { collideone(); } } catch(Exception e) { assert(e.msg == "p"); assert(e.next.msg == "q"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } void collidetwo() { try { try { throw new Exception("p2"); } finally { throw new Exception("q2"); } } finally { collideone(); } } void collideMixed() { int works = 6; try { try { try { throw new Exception("e"); } finally { throw new Error("t"); } } catch(Exception f) { // Doesn't catch, because Error is chained to it. works += 2; } } catch(Error z) { works += 4; assert(z.msg=="t"); // Error comes first assert(z.next is null); assert(z.bypassedException.msg == "e"); } assert(works == 10); } class AnotherException : Exception { this(string s) { super(s); } } void multicollide() { try { try { try { try { throw new Exception("m2"); } finally { throw new AnotherException("n2"); } } catch(AnotherException s) { // Not caught -- we needed to catch the root cause "m2", not // just the collateral "n2" (which would leave m2 uncaught). assert(0); } } finally { collidetwo(); } } catch(Exception f) { assert(f.msg == "m2"); assert(f.next.msg == "n2"); Throwable e = f.next.next; assert(e.msg == "p2"); assert(e.next.msg == "q2"); assert(e.next.next.msg == "x"); assert(e.next.next.next.msg == "y"); assert(!e.next.next.next.next); } } /****************************************************/ void use9568(char [] x, char [] y) {} int bug9568() { try return 7; finally use9568(null,null); } void test9568() { assert( bug9568() == 7 ); } /****************************************************/ version (DigitalMars) { void test8a() { int a; goto L2; // L2 is not addressable. try { a += 2; } catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8b() { int a; goto L2; // L2 is not addressable. try { } catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8c() { int a; goto L2; // L2 is not addressable. try static assert(true); catch (Exception) { a += 3; L2: ; a += 100; } assert(a == 100); } void test8() { test8a(); test8b(); test8c(); } } /****************************************************/ uint foo9(uint i) { try { ++i; return 3; } catch (Exception e) { debug printf("Exception happened\n"); } return 4; } void test9() { assert(foo9(7) == 3); } /****************************************************/ // https://issues.dlang.org/show_bug.cgi?id=10964 void test10964() { static struct S { this(this) { throw new Exception("BOOM!"); } } S ss; S[1] sa; int result; result = 0; try { ss = ss; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); try { sa = ss; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); try { sa = sa; } catch (Exception e) result = 1; catch (Error e) result = 2; catch (Throwable e) result = 3; assert(result == 1); } /****************************************************/ alias Action = void delegate(); class A10 { invariant() { } public Action foo(Action a) { synchronized { B10 elements = new B10; Action[] actions = [a]; elements.bar(actions); if (actions.length > 1) elements.bar(actions); return actions[0]; } return null; } } class B10 { public bool bar(ref Action[]) { return false; } } class D10 { void baz() { } } void test12989() { auto a = new A10; auto d = new D10; assert(a.foo(&d.baz) == &d.baz); } /****************************************************/ int bar10(int c) { if (c <= 0xFFFF) { L3: return 3; } throw new Exception("msg"); goto L3; } void test10() { int x; try { bar10(0x110000); } catch (Exception e) { printf("caught\n"); x = 1; } assert(x == 1); printf("test10 success\n"); } /****************************************************/ class ParseException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } class OverflowException : Exception { @safe pure nothrow this( string msg ) { super( msg ); } } void test11() { int x; try { printf("test11()\n"); throw new ParseException("msg"); } catch( OverflowException e ) { printf( "catch OverflowException\n" ); } catch( ParseException e ) { printf( "catch ParseException: %.*s\n", cast(int) e.msg.length, e.msg.ptr ); x = 1; } assert(x == 1); } /****************************************************/ // https://issues.dlang.org/show_bug.cgi?id=17481 class C17481 { synchronized void trigger(){ new ubyte[1]; } } void test17481() { auto k = new shared C17481; k.trigger; } /****************************************************/ // a nothrow function, even though it is not marked as nothrow void test12() { int i = 3; try { try { ++i; goto L10; } finally { i *= 2; printf("f1\n"); } } finally { i += 5; printf("f2\n"); } L10: printf("3\n"); assert(i == (3 + 1) * 2 + 5); } /****************************************************/ void foo13() { } void test13() { int i = 3; try { try { foo13(); // compiler assumes it throws ++i; goto L10; } finally { i *= 2; printf("f1\n"); } } finally { i += 5; printf("f2\n"); } L10: printf("3\n"); assert(i == (3 + 1) * 2 + 5); } /****************************************************/ int main() { printf("start\n"); foo(3); test2(); test3(); test4(); test5(); test6(); test7(); bug1513(); doublecollide(); collideMixed(); multicollide(); test9568(); version(DigitalMars) test8(); test9(); test10964(); test12989(); test10(); test11(); test17481(); test12(); test13(); printf("finish\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/eh2.d ================================================ // PERMUTE_ARGS: -fPIC extern(C) int printf(const char*, ...); class Abc : Throwable { this() pure { super(""); } static int x; int a,b,c; synchronized void test() { printf("test 1\n"); x |= 1; foo(); printf("test 2\n"); x |= 2; } shared void foo() { printf("foo 1\n"); x |= 4; throw this; printf("foo 2\n"); x |= 8; } } struct RefCounted { void *p; ~this() { p = null; } } struct S { RefCounted _data; int get() @property { throw new Exception(""); } } void b9438() { try { S s; S().get; } catch (Exception e){ } } int main() { printf("hello world\n"); auto a = new shared(Abc)(); printf("hello 2\n"); Abc.x |= 0x10; try { Abc.x |= 0x20; a.test(); Abc.x |= 0x40; } catch (shared(Abc) b) { Abc.x |= 0x80; printf("Caught %p, x = x%x\n", b, Abc.x); assert(a is b); assert(Abc.x == 0xB5); } printf("Success!\n"); b9438(); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/entity1.d ================================================ // $HeadURL$ // $Date$ // $Author$ module dstress.run.named_entity_02; // "-//W3C//ENTITIES Symbolic//EN//HTML" int main(){ assert('\ƒ'==402); assert('\Α'==913); assert('\Β'==914); assert('\Γ'==915); assert('\Δ'==916); assert('\Ε'==917); assert('\Ζ'==918); assert('\Η'==919); assert('\Θ'==920); assert('\Ι'==921); assert('\Κ'==922); assert('\Λ'==923); assert('\Μ'==924); assert('\Ν'==925); assert('\Ξ'==926); assert('\Ο'==927); assert('\Π'==928); assert('\Ρ'==929); assert('\Σ'==931); assert('\Τ'==932); assert('\Υ'==933); assert('\Φ'==934); assert('\Χ'==935); assert('\Ψ'==936); assert('\Ω'==937); assert('\α'==945); assert('\β'==946); assert('\γ'==947); assert('\δ'==948); assert('\ε'==949); assert('\ζ'==950); assert('\η'==951); assert('\θ'==952); assert('\ι'==953); assert('\κ'==954); assert('\λ'==955); assert('\μ'==956); assert('\ν'==957); assert('\ξ'==958); assert('\ο'==959); assert('\π'==960); assert('\ρ'==961); assert('\ς'==962); assert('\σ'==963); assert('\τ'==964); assert('\υ'==965); assert('\φ'==966); assert('\χ'==967); assert('\ψ'==968); assert('\ω'==969); assert('\ϑ'==977); assert('\ϒ'==978); assert('\ϖ'==982); assert('\•'==8226); assert('\…'==8230); assert('\′'==8242); assert('\″'==8243); assert('\‾'==8254); assert('\⁄'==8260); assert('\℘'==8472); assert('\ℑ'==8465); assert('\ℜ'==8476); assert('\™'==8482); assert('\ℵ'==8501); assert('\←'==8592); assert('\↑'==8593); assert('\→'==8594); assert('\↓'==8595); assert('\↔'==8596); assert('\↵'==8629); assert('\⇐'==8656); assert('\⇑'==8657); assert('\⇒'==8658); assert('\⇓'==8659); assert('\⇔'==8660); assert('\∀'==8704); assert('\∂'==8706); assert('\∃'==8707); assert('\∅'==8709); assert('\∇'==8711); assert('\∈'==8712); assert('\∉'==8713); assert('\∋'==8715); assert('\∏'==8719); assert('\∑'==8721); assert('\−'==8722); assert('\∗'==8727); assert('\√'==8730); assert('\∝'==8733); assert('\∞'==8734); assert('\∠'==8736); assert('\∧'==8743); assert('\∨'==8744); assert('\∩'==8745); assert('\∪'==8746); assert('\∫'==8747); assert('\∴'==8756); assert('\∼'==8764); assert('\≅'==8773); assert('\≈'==8776); assert('\≠'==8800); assert('\≡'==8801); assert('\≤'==8804); assert('\≥'==8805); assert('\⊂'==8834); assert('\⊃'==8835); assert('\⊄'==8836); assert('\⊆'==8838); assert('\⊇'==8839); assert('\⊕'==8853); assert('\⊗'==8855); assert('\⊥'==8869); assert('\⋅'==8901); assert('\⌈'==8968); assert('\⌉'==8969); assert('\⌊'==8970); assert('\⌋'==8971); //assert('\⟨'==9001); // U+2329 valid for HTML 4.01; changed in HTML5 //assert('\⟩'==9002); // U+232A valid for HTML 4.01; changed in HTML5 assert('\⟨'==0x27E8); // valid for HTML 5 and later. The character was introduced in HTML 3.2 assert('\⟩'==0x27E9); // valid for HTML 5 and later. The character was introduced in HTML 3.2 assert('\◊'==9674); assert('\♠'==9824); assert('\♣'==9827); assert('\♥'==9829); assert('\♦'==9830); return 0; } // https://issues.dlang.org/show_bug.cgi?id=5221 static assert('\✓'==10003); static assert('\≲'==8818); static assert('\№'==8470); static assert('\⌝'==8989); static assert('\Ż'==379); ================================================ FILE: gcc/testsuite/gdc.test/runnable/evalorder.d ================================================ extern(C) int printf(const char*, ...); void test14040() { uint[] values = [0, 1, 2, 3, 4, 5, 6, 7]; uint offset = 0; auto a1 = values[offset .. offset += 2]; if (a1 != [0, 1] || offset != 2) assert(0); uint[] fun() { offset += 2; return values; } auto a2 = fun()[offset .. offset += 2]; if (a2 != [4, 5] || offset != 6) assert(0); // Also test an offset of type size_t such that it is used // directly without any implicit conversion in the slice expression. size_t offset_szt = 0; auto a3 = values[offset_szt .. offset_szt += 2]; if (a3 != [0, 1] || offset_szt != 2) assert(0); } /******************************************/ int add8ret3(T)(ref T s) { s += 8; return 3; } int mul11ret3(T)(ref T s) { s *= 11; return 3; } void add() { static int test1(int val) { val += add8ret3(val); return val; } assert(test1(1) == (1 + 8 + 3)); static assert(test1(1) == (1 + 8 + 3)); static int test2(int val) { val = val + add8ret3(val); return val; } // FIXME: assert(test2(1) == (1 + 3)); static assert(test2(1) == (1 + 3)); static int test3(int val) { (val += 7) += mul11ret3(val); return val; } assert(test3(2) == (((2+7)*11) + 3)); static assert(test3(2) == (((2+7)*11) + 3)); } void min() { static int test1(int val) { val -= add8ret3(val); return val; } assert(test1(1) == (1 + 8 - 3)); static assert(test1(1) == (1 + 8 - 3)); static int test2(int val) { val = val - add8ret3(val); return val; } // FIXME: assert(test2(1) == (1 - 3)); static assert(test2(1) == (1 - 3)); static int test3(int val) { (val -= 7) -= mul11ret3(val); return val; } assert(test3(2) == (((2-7)*11) - 3)); static assert(test3(2) == (((2-7)*11) - 3)); } void mul() { static int test1(int val) { val *= add8ret3(val); return val; } assert(test1(7) == ((7 + 8) * 3)); static assert(test1(7) == ((7 + 8) * 3)); static int test2(int val) { val = val * add8ret3(val); return val; } // FIXME: assert(test2(7) == (7 * 3)); static assert(test2(7) == (7 * 3)); static int test3(int val) { (val *= 7) *= add8ret3(val); return val; } assert(test3(2) == (((2*7)+8) * 3)); static assert(test3(2) == (((2*7)+8) * 3)); } void xor() { static int test1(int val) { val ^= add8ret3(val); return val; } assert(test1(1) == ((1 + 8) ^ 3)); static assert(test1(1) == ((1 + 8) ^ 3)); static int test2(int val) { val = val ^ add8ret3(val); return val; } // FIXME: assert(test2(1) == (1 ^ 3)); static assert(test2(1) == (1 ^ 3)); static int test3(int val) { (val ^= 7) ^= add8ret3(val); return val; } assert(test3(2) == (((2^7)+8) ^ 3)); static assert(test3(2) == (((2^7)+8) ^ 3)); } void addptr() { static int* test1(int* val) { val += add8ret3(val); return val; } assert(test1(cast(int*)4) == ((cast(int*)4) + 8 + 3)); static int* test2(int* val) { val = val + add8ret3(val); return val; } // FIXME: assert(test2(cast(int*)4) == ((cast(int*)4) + 3)); static int* test3(int* val) { (val += 7) += add8ret3(val); return val; } assert(test3(cast(int*)16) == ((cast(int*)16) + 7 + 8 + 3)); } void lhsCast() { static byte test(byte val) { // lhs type `byte`, rhs type `int` => // rewritten to `cast(int)(cast(int)val += 10) -= mul11ret3(val)` (val += 10) -= mul11ret3(val); return val; } assert(test(1) == ((1 + 10) * 11 - 3)); static assert(test(1) == ((1 + 10) * 11 - 3)); } void shr() { static ubyte test(ubyte val) { // lhs type `ubyte`, rhs type `int` => // rewritten to `cast(int)val >>= 1` // we still want a logical (unsigned) right-shift though val >>= 1; return val; } assert(test(0x80) == 0x40); static assert(test(0x80) == 0x40); } void ldc_github_1617() { add(); min(); mul(); xor(); addptr(); lhsCast(); shr(); } /******************************************/ int main() { test14040(); ldc_github_1617(); printf("Success\n"); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extern1.d ================================================ // note: not actually imported, just built and linked against // EXTRA_SOURCES: imports/extern1a.d // PERMUTE_ARGS: extern (C) { extern int x; } int main() { assert(x == 3); return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/externmangle.d ================================================ // EXTRA_CPP_SOURCES: extra-files/externmangle.cpp import core.stdc.config; import core.stdc.stdint; extern(C++): struct Foo(X) { X* v; } struct Boo(X) { X* v; } void test1(Foo!int arg1); void test2(int* arg2, Boo!(int*) arg1); struct Test3(int X, int Y) { } void test3(Test3!(3,3) arg1); void test4(Foo!(int*) arg1, Boo!(int*) arg2, Boo!(int*) arg3, int*, Foo!(double)); void test5(Foo!(int*) arg1, Boo!(int*) arg2, Boo!(int*) arg3); struct Goo { struct Foo(X) { X* v; } struct Boo(X) { struct Xoo(Y) { Y* v; }; X* v; } void test6(Foo!(Boo!(Foo!(void))) arg1); void test7(Boo!(void).Xoo!(int) arg1); } struct P1 { struct Mem(T) { } } struct P2 { struct Mem(T) { } } void test8(P1.Mem!int, P2.Mem!int); void test9(Foo!(int**), Foo!(int*), int**, int*); interface Test10 { private final void test10(); public final void test11(); protected final void test12(); public final void test13() const; private void test14(); public void test15(); protected void test16(); private static void test17(); public static void test18(); protected static void test19(); }; Test10 Test10Ctor(); void Test10Dtor(ref Test10 ptr); struct Test20 { __gshared: private extern int test20; protected extern int test21; public extern int test22; }; int test23(Test10*, Test10, Test10**, const(Test10)); int test23b(const Test10*, const Test10, Test10); void test24(int function(int,int)); void test25(int[291][6][5]* arr); int test26(int[291][6]* arr); void test27(int, ...); void test28(int); void test29(float); void test30(const float); struct Array(T) { int dim; } interface Module { public static void imports(Module); public static int dim(Array!Module*); }; uint64_t testlongmangle(int a, uint b, int64_t c, uint64_t d); cpp_ulong testCppLongMangle(cpp_long a, cpp_ulong b); cpp_ulonglong testCppLongLongMangle(cpp_longlong a, cpp_ulonglong b); // direct size_t/ptrdiff_t interop is fine except on 32-bit OS X version (OSX) { version (D_LP64) {} else version = OSX_32; } version (OSX_32) cpp_size_t testCppSizeTMangle(cpp_ptrdiff_t a, cpp_size_t b); else size_t testCppSizeTMangle(ptrdiff_t a, size_t b); __gshared extern int[2][2][2] test31; __gshared extern int* test32; alias int function(Expression , void* ) apply_fp_t; interface Expression { public final int apply(apply_fp_t fp, apply_fp_t fp2, void* param); public final int getType(); public static Expression create(int); public static void dispose(ref Expression); } //int test34(int[0][0]*); version(CRuntime_Microsoft){} else { int test35(real arg); } const(char)* test36(const(char)*); final class Test37 { static Test37 create() { return new Test37; } bool test() { return true; } } bool test37(); interface Test38 { final int test(int, ...); public static Test38 create(); public static void dispose(ref Test38); } extern(C++) int test39cpp(C2!char, S2!(int)*); extern(C++, class) struct S1 { private int val; static S1* init(int); int value(); } extern(C++, class) struct S2(T) { private T val; static S2!T* init(int); T value(); } extern(C++, struct) class C1 { const(char)* data; static C1 init(const(char)* p); const(char)* getDataCPP(); extern(C++) const(char)* getDataD() { return data; } } extern(C++, struct) class C2(T) { const(T)* data; static C2!T init(const(T)* p); const(T)* getData(); } void test39() { S1* s1 = S1.init(42); assert(s1.value == 42); assert(S2!int.init(43).value == 43); const(char)* ptr = "test".ptr; C1 c1 = C1.init(ptr); assert(c1.getDataCPP() == ptr); assert(c1.getDataD() == ptr); C2!char c2 = C2!char.init(ptr); assert(c2.getData() == ptr); auto result = test39cpp(c2, S2!int.init(43)); assert(result == 0); } void main() { test1(Foo!int()); test2(null, Boo!(int*)()); test3(Test3!(3,3)()); test4(Foo!(int*)(), Boo!(int*)(), Boo!(int*)(), null, Foo!(double)()); test5(Foo!(int*)(), Boo!(int*)(), Boo!(int*)()); Goo goo; goo.test6(Goo.Foo!(Goo.Boo!(Goo.Foo!(void)))()); goo.test7(Goo.Boo!(void).Xoo!(int)()); test8(P1.Mem!int(), P2.Mem!int()); test9(Foo!(int**)(), Foo!(int*)(), null, null); auto t10 = Test10Ctor(); scope(exit) Test10Dtor(t10); t10.test10(); t10.test11(); t10.test12(); t10.test13(); t10.test14(); t10.test15(); t10.test16(); t10.test17(); t10.test18(); t10.test19(); assert(Test20.test20 == 20); assert(Test20.test21 == 21); assert(Test20.test22 == 22); assert(test23(null, null, null, null) == 1); assert(test23b(null, null, null) == 1); extern(C++) static int cb(int a, int b){return a+b;} test24(&cb); int[291][6][5] arr; arr[1][1][1] = 42; test25(&arr); assert(test26(&arr[0]) == 42); test27(3,4,5); test28(3); test29(3.14f); test30(3.14f); auto t32 = &Module.imports; Array!Module arr2; arr2.dim = 20; assert(Module.dim(&arr2) == 20); assert(testlongmangle(1, 2, 3, 4) == 10); assert(testCppLongMangle(1, 2) == 3); assert(testCppLongLongMangle(3, 4) == 7); assert(testCppSizeTMangle(3, 4) == 7); assert(test31 == [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]); assert(test32 == null); auto ee = Expression.create(42); extern(C++) static int efun(Expression e, void* p) { return cast(int)(cast(size_t)p ^ e.getType()); } extern(C++) static int efun2(Expression e, void* p) { return cast(int)(cast(size_t)p * e.getType()); } auto test33 = ee.apply(&efun, &efun2, cast(void*)&Expression.create); assert(test33 == cast(int)(cast(size_t)cast(void*)&Expression.create ^ 42) * cast(int)(cast(size_t)cast(void*)&Expression.create * 42)); Expression.dispose(ee); assert(ee is null); //assert(test34(null) == 0); version(CRuntime_Microsoft){} else { assert(test35(3.14L) == 3); } const char* hello = "hello"; assert(test36(hello) == hello); assert(test37()); auto t38 = Test38.create(); assert(t38.test(1, 2, 3) == 1); Test38.dispose(t38); test39(); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/externmangle2.d ================================================ // EXTRA_CPP_SOURCES: extra-files/externmangle2.cpp version(Windows) { void main() { } } else { extern(C++): struct Test32NS1 { struct Foo(X) { X *v; } struct Bar(X) { X *v; } }; struct Test32NS2 { struct Foo(X) { X *v; } }; struct Test32(alias Y, alias Z) { Y!(int)* field; }; void test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo) arg); void test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar) arg); void test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg); void test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg1, Test32!(Test32NS2.Foo, Test32NS1.Foo) arg2); interface XXX { } void test33a(XXX, XXX*); struct Test33(alias A, alias B) { } /* void test33(XXX, Test33!(test33a, test33a) arg, XXX); struct Test34(alias A) { }; struct Test34A { static void foo(int); }; void test34(Test34!(Test34A.foo) arg); */ __gshared extern int test36; /* struct Test37(alias A) { }; struct Test37A { __gshared extern int t38; }; void test37(Test37!(test36) arg); void test38(Test37!(Test37A.t38) arg); */ struct Test39 { struct T39A(X) { } } struct T39A { } void test39(Test39.T39A!(.T39A)); version(none) { version(Posix) //Only for g++ with -std=c++0x and Visual Studio 2013+ { struct Test40(T, V...) { } void test40(Test40!(int, double, void)) { } } else version(Win64) //Only for g++ with -std=c++0x and Visual Studio 2013+ { struct Test40(T, V...) { } void test40(Test40!(int, double, void)) { } } } __gshared extern const XXX test41; struct Test42 { __gshared extern const XXX test42; } __gshared extern int[4] test43; const(XXX) test44(); void main() { test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo)()); test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar)()); test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo)()); test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo)(), Test32!(Test32NS2.Foo, Test32NS1.Foo)()); //test33a(null, null); //test33(null, Test33!(test33a, test33a)(), null); //test34(Test34!(Test34A.foo)()); assert(test36 == 36); //test37(Test37!(test36)()); //test38(Test37!(Test37A.t38)()); test39(Test39.T39A!(.T39A)()); assert(test41 is null); assert(Test42.test42 is null); assert(test43 == [1, 2, 3, 4]); auto ptr = &test44; } } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/alice30.txt ================================================ ALICE'S ADVENTURES IN WONDERLAND Lewis Carroll THE MILLENNIUM FULCRUM EDITION 3.0 CHAPTER I Down the Rabbit-Hole Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, `and what is the use of a book,' thought Alice `without pictures or conversation?' So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her. There was nothing so VERY remarkable in that; nor did Alice think it so VERY much out of the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!' (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT- POCKET, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge. In another moment down went Alice after it, never once considering how in the world she was to get out again. The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well. Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled `ORANGE MARMALADE', but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it. `Well!' thought Alice to herself, `after such a fall as this, I shall think nothing of tumbling down stairs! How brave they'll all think me at home! Why, I wouldn't say anything about it, even if I fell off the top of the house!' (Which was very likely true.) Down, down, down. Would the fall NEVER come to an end! `I wonder how many miles I've fallen by this time?' she said aloud. `I must be getting somewhere near the centre of the earth. Let me see: that would be four thousand miles down, I think--' (for, you see, Alice had learnt several things of this sort in her lessons in the schoolroom, and though this was not a VERY good opportunity for showing off her knowledge, as there was no one to listen to her, still it was good practice to say it over) `--yes, that's about the right distance--but then I wonder what Latitude or Longitude I've got to?' (Alice had no idea what Latitude was, or Longitude either, but thought they were nice grand words to say.) Presently she began again. `I wonder if I shall fall right THROUGH the earth! How funny it'll seem to come out among the people that walk with their heads downward! The Antipathies, I think--' (she was rather glad there WAS no one listening, this time, as it didn't sound at all the right word) `--but I shall have to ask them what the name of the country is, you know. Please, Ma'am, is this New Zealand or Australia?' (and she tried to curtsey as she spoke--fancy CURTSEYING as you're falling through the air! Do you think you could manage it?) `And what an ignorant little girl she'll think me for asking! No, it'll never do to ask: perhaps I shall see it written up somewhere.' Down, down, down. There was nothing else to do, so Alice soon began talking again. `Dinah'll miss me very much to-night, I should think!' (Dinah was the cat.) `I hope they'll remember her saucer of milk at tea-time. Dinah my dear! I wish you were down here with me! There are no mice in the air, I'm afraid, but you might catch a bat, and that's very like a mouse, you know. But do cats eat bats, I wonder?' And here Alice began to get rather sleepy, and went on saying to herself, in a dreamy sort of way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do bats eat cats?' for, you see, as she couldn't answer either question, it didn't much matter which way she put it. She felt that she was dozing off, and had just begun to dream that she was walking hand in hand with Dinah, and saying to her very earnestly, `Now, Dinah, tell me the truth: did you ever eat a bat?' when suddenly, thump! thump! down she came upon a heap of sticks and dry leaves, and the fall was over. Alice was not a bit hurt, and she jumped up on to her feet in a moment: she looked up, but it was all dark overhead; before her was another long passage, and the White Rabbit was still in sight, hurrying down it. There was not a moment to be lost: away went Alice like the wind, and was just in time to hear it say, as it turned a corner, `Oh my ears and whiskers, how late it's getting!' She was close behind it when she turned the corner, but the Rabbit was no longer to be seen: she found herself in a long, low hall, which was lit up by a row of lamps hanging from the roof. There were doors all round the hall, but they were all locked; and when Alice had been all the way down one side and up the other, trying every door, she walked sadly down the middle, wondering how she was ever to get out again. Suddenly she came upon a little three-legged table, all made of solid glass; there was nothing on it except a tiny golden key, and Alice's first thought was that it might belong to one of the doors of the hall; but, alas! either the locks were too large, or the key was too small, but at any rate it would not open any of them. However, on the second time round, she came upon a low curtain she had not noticed before, and behind it was a little door about fifteen inches high: she tried the little golden key in the lock, and to her great delight it fitted! Alice opened the door and found that it led into a small passage, not much larger than a rat-hole: she knelt down and looked along the passage into the loveliest garden you ever saw. How she longed to get out of that dark hall, and wander about among those beds of bright flowers and those cool fountains, but she could not even get her head though the doorway; `and even if my head would go through,' thought poor Alice, `it would be of very little use without my shoulders. Oh, how I wish I could shut up like a telescope! I think I could, if I only know how to begin.' For, you see, so many out-of-the-way things had happened lately, that Alice had begun to think that very few things indeed were really impossible. There seemed to be no use in waiting by the little door, so she went back to the table, half hoping she might find another key on it, or at any rate a book of rules for shutting people up like telescopes: this time she found a little bottle on it, (`which certainly was not here before,' said Alice,) and round the neck of the bottle was a paper label, with the words `DRINK ME' beautifully printed on it in large letters. It was all very well to say `Drink me,' but the wise little Alice was not going to do THAT in a hurry. `No, I'll look first,' she said, `and see whether it's marked "poison" or not'; for she had read several nice little histories about children who had got burnt, and eaten up by wild beasts and other unpleasant things, all because they WOULD not remember the simple rules their friends had taught them: such as, that a red-hot poker will burn you if you hold it too long; and that if you cut your finger VERY deeply with a knife, it usually bleeds; and she had never forgotten that, if you drink much from a bottle marked `poison,' it is almost certain to disagree with you, sooner or later. However, this bottle was NOT marked `poison,' so Alice ventured to taste it, and finding it very nice, (it had, in fact, a sort of mixed flavour of cherry-tart, custard, pine-apple, roast turkey, toffee, and hot buttered toast,) she very soon finished it off. * * * * * * * * * * * * * * * * * * * * `What a curious feeling!' said Alice; `I must be shutting up like a telescope.' And so it was indeed: she was now only ten inches high, and her face brightened up at the thought that she was now the right size for going through the little door into that lovely garden. First, however, she waited for a few minutes to see if she was going to shrink any further: she felt a little nervous about this; `for it might end, you know,' said Alice to herself, `in my going out altogether, like a candle. I wonder what I should be like then?' And she tried to fancy what the flame of a candle is like after the candle is blown out, for she could not remember ever having seen such a thing. After a while, finding that nothing more happened, she decided on going into the garden at once; but, alas for poor Alice! when she got to the door, she found she had forgotten the little golden key, and when she went back to the table for it, she found she could not possibly reach it: she could see it quite plainly through the glass, and she tried her best to climb up one of the legs of the table, but it was too slippery; and when she had tired herself out with trying, the poor little thing sat down and cried. `Come, there's no use in crying like that!' said Alice to herself, rather sharply; `I advise you to leave off this minute!' She generally gave herself very good advice, (though she very seldom followed it), and sometimes she scolded herself so severely as to bring tears into her eyes; and once she remembered trying to box her own ears for having cheated herself in a game of croquet she was playing against herself, for this curious child was very fond of pretending to be two people. `But it's no use now,' thought poor Alice, `to pretend to be two people! Why, there's hardly enough of me left to make ONE respectable person!' Soon her eye fell on a little glass box that was lying under the table: she opened it, and found in it a very small cake, on which the words `EAT ME' were beautifully marked in currants. `Well, I'll eat it,' said Alice, `and if it makes me grow larger, I can reach the key; and if it makes me grow smaller, I can creep under the door; so either way I'll get into the garden, and I don't care which happens!' She ate a little bit, and said anxiously to herself, `Which way? Which way?', holding her hand on the top of her head to feel which way it was growing, and she was quite surprised to find that she remained the same size: to be sure, this generally happens when one eats cake, but Alice had got so much into the way of expecting nothing but out-of-the-way things to happen, that it seemed quite dull and stupid for life to go on in the common way. So she set to work, and very soon finished off the cake. * * * * * * * * * * * * * * * * * * * * CHAPTER II The Pool of Tears `Curiouser and curiouser!' cried Alice (she was so much surprised, that for the moment she quite forgot how to speak good English); `now I'm opening out like the largest telescope that ever was! Good-bye, feet!' (for when she looked down at her feet, they seemed to be almost out of sight, they were getting so far off). `Oh, my poor little feet, I wonder who will put on your shoes and stockings for you now, dears? I'm sure _I_ shan't be able! I shall be a great deal too far off to trouble myself about you: you must manage the best way you can; --but I must be kind to them,' thought Alice, `or perhaps they won't walk the way I want to go! Let me see: I'll give them a new pair of boots every Christmas.' And she went on planning to herself how she would manage it. `They must go by the carrier,' she thought; `and how funny it'll seem, sending presents to one's own feet! And how odd the directions will look! ALICE'S RIGHT FOOT, ESQ. HEARTHRUG, NEAR THE FENDER, (WITH ALICE'S LOVE). Oh dear, what nonsense I'm talking!' Just then her head struck against the roof of the hall: in fact she was now more than nine feet high, and she at once took up the little golden key and hurried off to the garden door. Poor Alice! It was as much as she could do, lying down on one side, to look through into the garden with one eye; but to get through was more hopeless than ever: she sat down and began to cry again. `You ought to be ashamed of yourself,' said Alice, `a great girl like you,' (she might well say this), `to go on crying in this way! Stop this moment, I tell you!' But she went on all the same, shedding gallons of tears, until there was a large pool all round her, about four inches deep and reaching half down the hall. After a time she heard a little pattering of feet in the distance, and she hastily dried her eyes to see what was coming. It was the White Rabbit returning, splendidly dressed, with a pair of white kid gloves in one hand and a large fan in the other: he came trotting along in a great hurry, muttering to himself as he came, `Oh! the Duchess, the Duchess! Oh! won't she be savage if I've kept her waiting!' Alice felt so desperate that she was ready to ask help of any one; so, when the Rabbit came near her, she began, in a low, timid voice, `If you please, sir--' The Rabbit started violently, dropped the white kid gloves and the fan, and skurried away into the darkness as hard as he could go. Alice took up the fan and gloves, and, as the hall was very hot, she kept fanning herself all the time she went on talking: `Dear, dear! How queer everything is to-day! And yesterday things went on just as usual. I wonder if I've been changed in the night? Let me think: was I the same when I got up this morning? I almost think I can remember feeling a little different. But if I'm not the same, the next question is, Who in the world am I? Ah, THAT'S the great puzzle!' And she began thinking over all the children she knew that were of the same age as herself, to see if she could have been changed for any of them. `I'm sure I'm not Ada,' she said, `for her hair goes in such long ringlets, and mine doesn't go in ringlets at all; and I'm sure I can't be Mabel, for I know all sorts of things, and she, oh! she knows such a very little! Besides, SHE'S she, and I'm I, and--oh dear, how puzzling it all is! I'll try if I know all the things I used to know. Let me see: four times five is twelve, and four times six is thirteen, and four times seven is--oh dear! I shall never get to twenty at that rate! However, the Multiplication Table doesn't signify: let's try Geography. London is the capital of Paris, and Paris is the capital of Rome, and Rome--no, THAT'S all wrong, I'm certain! I must have been changed for Mabel! I'll try and say "How doth the little--"' and she crossed her hands on her lap as if she were saying lessons, and began to repeat it, but her voice sounded hoarse and strange, and the words did not come the same as they used to do:-- `How doth the little crocodile Improve his shining tail, And pour the waters of the Nile On every golden scale! `How cheerfully he seems to grin, How neatly spread his claws, And welcome little fishes in With gently smiling jaws!' `I'm sure those are not the right words,' said poor Alice, and her eyes filled with tears again as she went on, `I must be Mabel after all, and I shall have to go and live in that poky little house, and have next to no toys to play with, and oh! ever so many lessons to learn! No, I've made up my mind about it; if I'm Mabel, I'll stay down here! It'll be no use their putting their heads down and saying "Come up again, dear!" I shall only look up and say "Who am I then? Tell me that first, and then, if I like being that person, I'll come up: if not, I'll stay down here till I'm somebody else"--but, oh dear!' cried Alice, with a sudden burst of tears, `I do wish they WOULD put their heads down! I am so VERY tired of being all alone here!' As she said this she looked down at her hands, and was surprised to see that she had put on one of the Rabbit's little white kid gloves while she was talking. `How CAN I have done that?' she thought. `I must be growing small again.' She got up and went to the table to measure herself by it, and found that, as nearly as she could guess, she was now about two feet high, and was going on shrinking rapidly: she soon found out that the cause of this was the fan she was holding, and she dropped it hastily, just in time to avoid shrinking away altogether. `That WAS a narrow escape!' said Alice, a good deal frightened at the sudden change, but very glad to find herself still in existence; `and now for the garden!' and she ran with all speed back to the little door: but, alas! the little door was shut again, and the little golden key was lying on the glass table as before, `and things are worse than ever,' thought the poor child, `for I never was so small as this before, never! And I declare it's too bad, that it is!' As she said these words her foot slipped, and in another moment, splash! she was up to her chin in salt water. Her first idea was that she had somehow fallen into the sea, `and in that case I can go back by railway,' she said to herself. (Alice had been to the seaside once in her life, and had come to the general conclusion, that wherever you go to on the English coast you find a number of bathing machines in the sea, some children digging in the sand with wooden spades, then a row of lodging houses, and behind them a railway station.) However, she soon made out that she was in the pool of tears which she had wept when she was nine feet high. `I wish I hadn't cried so much!' said Alice, as she swam about, trying to find her way out. `I shall be punished for it now, I suppose, by being drowned in my own tears! That WILL be a queer thing, to be sure! However, everything is queer to-day.' Just then she heard something splashing about in the pool a little way off, and she swam nearer to make out what it was: at first she thought it must be a walrus or hippopotamus, but then she remembered how small she was now, and she soon made out that it was only a mouse that had slipped in like herself. `Would it be of any use, now,' thought Alice, `to speak to this mouse? Everything is so out-of-the-way down here, that I should think very likely it can talk: at any rate, there's no harm in trying.' So she began: `O Mouse, do you know the way out of this pool? I am very tired of swimming about here, O Mouse!' (Alice thought this must be the right way of speaking to a mouse: she had never done such a thing before, but she remembered having seen in her brother's Latin Grammar, `A mouse--of a mouse--to a mouse--a mouse--O mouse!' The Mouse looked at her rather inquisitively, and seemed to her to wink with one of its little eyes, but it said nothing. `Perhaps it doesn't understand English,' thought Alice; `I daresay it's a French mouse, come over with William the Conqueror.' (For, with all her knowledge of history, Alice had no very clear notion how long ago anything had happened.) So she began again: `Ou est ma chatte?' which was the first sentence in her French lesson-book. The Mouse gave a sudden leap out of the water, and seemed to quiver all over with fright. `Oh, I beg your pardon!' cried Alice hastily, afraid that she had hurt the poor animal's feelings. `I quite forgot you didn't like cats.' `Not like cats!' cried the Mouse, in a shrill, passionate voice. `Would YOU like cats if you were me?' `Well, perhaps not,' said Alice in a soothing tone: `don't be angry about it. And yet I wish I could show you our cat Dinah: I think you'd take a fancy to cats if you could only see her. She is such a dear quiet thing,' Alice went on, half to herself, as she swam lazily about in the pool, `and she sits purring so nicely by the fire, licking her paws and washing her face--and she is such a nice soft thing to nurse--and she's such a capital one for catching mice--oh, I beg your pardon!' cried Alice again, for this time the Mouse was bristling all over, and she felt certain it must be really offended. `We won't talk about her any more if you'd rather not.' `We indeed!' cried the Mouse, who was trembling down to the end of his tail. `As if I would talk on such a subject! Our family always HATED cats: nasty, low, vulgar things! Don't let me hear the name again!' `I won't indeed!' said Alice, in a great hurry to change the subject of conversation. `Are you--are you fond--of--of dogs?' The Mouse did not answer, so Alice went on eagerly: `There is such a nice little dog near our house I should like to show you! A little bright-eyed terrier, you know, with oh, such long curly brown hair! And it'll fetch things when you throw them, and it'll sit up and beg for its dinner, and all sorts of things--I can't remember half of them--and it belongs to a farmer, you know, and he says it's so useful, it's worth a hundred pounds! He says it kills all the rats and--oh dear!' cried Alice in a sorrowful tone, `I'm afraid I've offended it again!' For the Mouse was swimming away from her as hard as it could go, and making quite a commotion in the pool as it went. So she called softly after it, `Mouse dear! Do come back again, and we won't talk about cats or dogs either, if you don't like them!' When the Mouse heard this, it turned round and swam slowly back to her: its face was quite pale (with passion, Alice thought), and it said in a low trembling voice, `Let us get to the shore, and then I'll tell you my history, and you'll understand why it is I hate cats and dogs.' It was high time to go, for the pool was getting quite crowded with the birds and animals that had fallen into it: there were a Duck and a Dodo, a Lory and an Eaglet, and several other curious creatures. Alice led the way, and the whole party swam to the shore. CHAPTER III A Caucus-Race and a Long Tale They were indeed a queer-looking party that assembled on the bank--the birds with draggled feathers, the animals with their fur clinging close to them, and all dripping wet, cross, and uncomfortable. The first question of course was, how to get dry again: they had a consultation about this, and after a few minutes it seemed quite natural to Alice to find herself talking familiarly with them, as if she had known them all her life. Indeed, she had quite a long argument with the Lory, who at last turned sulky, and would only say, `I am older than you, and must know better'; and this Alice would not allow without knowing how old it was, and, as the Lory positively refused to tell its age, there was no more to be said. At last the Mouse, who seemed to be a person of authority among them, called out, `Sit down, all of you, and listen to me! I'LL soon make you dry enough!' They all sat down at once, in a large ring, with the Mouse in the middle. Alice kept her eyes anxiously fixed on it, for she felt sure she would catch a bad cold if she did not get dry very soon. `Ahem!' said the Mouse with an important air, `are you all ready? This is the driest thing I know. Silence all round, if you please! "William the Conqueror, whose cause was favoured by the pope, was soon submitted to by the English, who wanted leaders, and had been of late much accustomed to usurpation and conquest. Edwin and Morcar, the earls of Mercia and Northumbria--"' `Ugh!' said the Lory, with a shiver. `I beg your pardon!' said the Mouse, frowning, but very politely: `Did you speak?' `Not I!' said the Lory hastily. `I thought you did,' said the Mouse. `--I proceed. "Edwin and Morcar, the earls of Mercia and Northumbria, declared for him: and even Stigand, the patriotic archbishop of Canterbury, found it advisable--"' `Found WHAT?' said the Duck. `Found IT,' the Mouse replied rather crossly: `of course you know what "it" means.' `I know what "it" means well enough, when I find a thing,' said the Duck: `it's generally a frog or a worm. The question is, what did the archbishop find?' The Mouse did not notice this question, but hurriedly went on, `"--found it advisable to go with Edgar Atheling to meet William and offer him the crown. William's conduct at first was moderate. But the insolence of his Normans--" How are you getting on now, my dear?' it continued, turning to Alice as it spoke. `As wet as ever,' said Alice in a melancholy tone: `it doesn't seem to dry me at all.' `In that case,' said the Dodo solemnly, rising to its feet, `I move that the meeting adjourn, for the immediate adoption of more energetic remedies--' `Speak English!' said the Eaglet. `I don't know the meaning of half those long words, and, what's more, I don't believe you do either!' And the Eaglet bent down its head to hide a smile: some of the other birds tittered audibly. `What I was going to say,' said the Dodo in an offended tone, `was, that the best thing to get us dry would be a Caucus-race.' `What IS a Caucus-race?' said Alice; not that she wanted much to know, but the Dodo had paused as if it thought that SOMEBODY ought to speak, and no one else seemed inclined to say anything. `Why,' said the Dodo, `the best way to explain it is to do it.' (And, as you might like to try the thing yourself, some winter day, I will tell you how the Dodo managed it.) First it marked out a race-course, in a sort of circle, (`the exact shape doesn't matter,' it said,) and then all the party were placed along the course, here and there. There was no `One, two, three, and away,' but they began running when they liked, and left off when they liked, so that it was not easy to know when the race was over. However, when they had been running half an hour or so, and were quite dry again, the Dodo suddenly called out `The race is over!' and they all crowded round it, panting, and asking, `But who has won?' This question the Dodo could not answer without a great deal of thought, and it sat for a long time with one finger pressed upon its forehead (the position in which you usually see Shakespeare, in the pictures of him), while the rest waited in silence. At last the Dodo said, `EVERYBODY has won, and all must have prizes.' `But who is to give the prizes?' quite a chorus of voices asked. `Why, SHE, of course,' said the Dodo, pointing to Alice with one finger; and the whole party at once crowded round her, calling out in a confused way, `Prizes! Prizes!' Alice had no idea what to do, and in despair she put her hand in her pocket, and pulled out a box of comfits, (luckily the salt water had not got into it), and handed them round as prizes. There was exactly one a-piece all round. `But she must have a prize herself, you know,' said the Mouse. `Of course,' the Dodo replied very gravely. `What else have you got in your pocket?' he went on, turning to Alice. `Only a thimble,' said Alice sadly. `Hand it over here,' said the Dodo. Then they all crowded round her once more, while the Dodo solemnly presented the thimble, saying `We beg your acceptance of this elegant thimble'; and, when it had finished this short speech, they all cheered. Alice thought the whole thing very absurd, but they all looked so grave that she did not dare to laugh; and, as she could not think of anything to say, she simply bowed, and took the thimble, looking as solemn as she could. The next thing was to eat the comfits: this caused some noise and confusion, as the large birds complained that they could not taste theirs, and the small ones choked and had to be patted on the back. However, it was over at last, and they sat down again in a ring, and begged the Mouse to tell them something more. `You promised to tell me your history, you know,' said Alice, `and why it is you hate--C and D,' she added in a whisper, half afraid that it would be offended again. `Mine is a long and a sad tale!' said the Mouse, turning to Alice, and sighing. `It IS a long tail, certainly,' said Alice, looking down with wonder at the Mouse's tail; `but why do you call it sad?' And she kept on puzzling about it while the Mouse was speaking, so that her idea of the tale was something like this:-- `Fury said to a mouse, That he met in the house, "Let us both go to law: I will prosecute YOU. --Come, I'll take no denial; We must have a trial: For really this morning I've nothing to do." Said the mouse to the cur, "Such a trial, dear Sir, With no jury or judge, would be wasting our breath." "I'll be judge, I'll be jury," Said cunning old Fury: "I'll try the whole cause, and condemn you to death."' `You are not attending!' said the Mouse to Alice severely. `What are you thinking of?' `I beg your pardon,' said Alice very humbly: `you had got to the fifth bend, I think?' `I had NOT!' cried the Mouse, sharply and very angrily. `A knot!' said Alice, always ready to make herself useful, and looking anxiously about her. `Oh, do let me help to undo it!' `I shall do nothing of the sort,' said the Mouse, getting up and walking away. `You insult me by talking such nonsense!' `I didn't mean it!' pleaded poor Alice. `But you're so easily offended, you know!' The Mouse only growled in reply. `Please come back and finish your story!' Alice called after it; and the others all joined in chorus, `Yes, please do!' but the Mouse only shook its head impatiently, and walked a little quicker. `What a pity it wouldn't stay!' sighed the Lory, as soon as it was quite out of sight; and an old Crab took the opportunity of saying to her daughter `Ah, my dear! Let this be a lesson to you never to lose YOUR temper!' `Hold your tongue, Ma!' said the young Crab, a little snappishly. `You're enough to try the patience of an oyster!' `I wish I had our Dinah here, I know I do!' said Alice aloud, addressing nobody in particular. `She'd soon fetch it back!' `And who is Dinah, if I might venture to ask the question?' said the Lory. Alice replied eagerly, for she was always ready to talk about her pet: `Dinah's our cat. And she's such a capital one for catching mice you can't think! And oh, I wish you could see her after the birds! Why, she'll eat a little bird as soon as look at it!' This speech caused a remarkable sensation among the party. Some of the birds hurried off at once: one old Magpie began wrapping itself up very carefully, remarking, `I really must be getting home; the night-air doesn't suit my throat!' and a Canary called out in a trembling voice to its children, `Come away, my dears! It's high time you were all in bed!' On various pretexts they all moved off, and Alice was soon left alone. `I wish I hadn't mentioned Dinah!' she said to herself in a melancholy tone. `Nobody seems to like her, down here, and I'm sure she's the best cat in the world! Oh, my dear Dinah! I wonder if I shall ever see you any more!' And here poor Alice began to cry again, for she felt very lonely and low-spirited. In a little while, however, she again heard a little pattering of footsteps in the distance, and she looked up eagerly, half hoping that the Mouse had changed his mind, and was coming back to finish his story. CHAPTER IV The Rabbit Sends in a Little Bill It was the White Rabbit, trotting slowly back again, and looking anxiously about as it went, as if it had lost something; and she heard it muttering to itself `The Duchess! The Duchess! Oh my dear paws! Oh my fur and whiskers! She'll get me executed, as sure as ferrets are ferrets! Where CAN I have dropped them, I wonder?' Alice guessed in a moment that it was looking for the fan and the pair of white kid gloves, and she very good-naturedly began hunting about for them, but they were nowhere to be seen--everything seemed to have changed since her swim in the pool, and the great hall, with the glass table and the little door, had vanished completely. Very soon the Rabbit noticed Alice, as she went hunting about, and called out to her in an angry tone, `Why, Mary Ann, what ARE you doing out here? Run home this moment, and fetch me a pair of gloves and a fan! Quick, now!' And Alice was so much frightened that she ran off at once in the direction it pointed to, without trying to explain the mistake it had made. `He took me for his housemaid,' she said to herself as she ran. `How surprised he'll be when he finds out who I am! But I'd better take him his fan and gloves--that is, if I can find them.' As she said this, she came upon a neat little house, on the door of which was a bright brass plate with the name `W. RABBIT' engraved upon it. She went in without knocking, and hurried upstairs, in great fear lest she should meet the real Mary Ann, and be turned out of the house before she had found the fan and gloves. `How queer it seems,' Alice said to herself, `to be going messages for a rabbit! I suppose Dinah'll be sending me on messages next!' And she began fancying the sort of thing that would happen: `"Miss Alice! Come here directly, and get ready for your walk!" "Coming in a minute, nurse! But I've got to see that the mouse doesn't get out." Only I don't think,' Alice went on, `that they'd let Dinah stop in the house if it began ordering people about like that!' By this time she had found her way into a tidy little room with a table in the window, and on it (as she had hoped) a fan and two or three pairs of tiny white kid gloves: she took up the fan and a pair of the gloves, and was just going to leave the room, when her eye fell upon a little bottle that stood near the looking- glass. There was no label this time with the words `DRINK ME,' but nevertheless she uncorked it and put it to her lips. `I know SOMETHING interesting is sure to happen,' she said to herself, `whenever I eat or drink anything; so I'll just see what this bottle does. I do hope it'll make me grow large again, for really I'm quite tired of being such a tiny little thing!' It did so indeed, and much sooner than she had expected: before she had drunk half the bottle, she found her head pressing against the ceiling, and had to stoop to save her neck from being broken. She hastily put down the bottle, saying to herself `That's quite enough--I hope I shan't grow any more--As it is, I can't get out at the door--I do wish I hadn't drunk quite so much!' Alas! it was too late to wish that! She went on growing, and growing, and very soon had to kneel down on the floor: in another minute there was not even room for this, and she tried the effect of lying down with one elbow against the door, and the other arm curled round her head. Still she went on growing, and, as a last resource, she put one arm out of the window, and one foot up the chimney, and said to herself `Now I can do no more, whatever happens. What WILL become of me?' Luckily for Alice, the little magic bottle had now had its full effect, and she grew no larger: still it was very uncomfortable, and, as there seemed to be no sort of chance of her ever getting out of the room again, no wonder she felt unhappy. `It was much pleasanter at home,' thought poor Alice, `when one wasn't always growing larger and smaller, and being ordered about by mice and rabbits. I almost wish I hadn't gone down that rabbit-hole--and yet--and yet--it's rather curious, you know, this sort of life! I do wonder what CAN have happened to me! When I used to read fairy-tales, I fancied that kind of thing never happened, and now here I am in the middle of one! There ought to be a book written about me, that there ought! And when I grow up, I'll write one--but I'm grown up now,' she added in a sorrowful tone; `at least there's no room to grow up any more HERE.' `But then,' thought Alice, `shall I NEVER get any older than I am now? That'll be a comfort, one way--never to be an old woman-- but then--always to have lessons to learn! Oh, I shouldn't like THAT!' `Oh, you foolish Alice!' she answered herself. `How can you learn lessons in here? Why, there's hardly room for YOU, and no room at all for any lesson-books!' And so she went on, taking first one side and then the other, and making quite a conversation of it altogether; but after a few minutes she heard a voice outside, and stopped to listen. `Mary Ann! Mary Ann!' said the voice. `Fetch me my gloves this moment!' Then came a little pattering of feet on the stairs. Alice knew it was the Rabbit coming to look for her, and she trembled till she shook the house, quite forgetting that she was now about a thousand times as large as the Rabbit, and had no reason to be afraid of it. Presently the Rabbit came up to the door, and tried to open it; but, as the door opened inwards, and Alice's elbow was pressed hard against it, that attempt proved a failure. Alice heard it say to itself `Then I'll go round and get in at the window.' `THAT you won't' thought Alice, and, after waiting till she fancied she heard the Rabbit just under the window, she suddenly spread out her hand, and made a snatch in the air. She did not get hold of anything, but she heard a little shriek and a fall, and a crash of broken glass, from which she concluded that it was just possible it had fallen into a cucumber-frame, or something of the sort. Next came an angry voice--the Rabbit's--`Pat! Pat! Where are you?' And then a voice she had never heard before, `Sure then I'm here! Digging for apples, yer honour!' `Digging for apples, indeed!' said the Rabbit angrily. `Here! Come and help me out of THIS!' (Sounds of more broken glass.) `Now tell me, Pat, what's that in the window?' `Sure, it's an arm, yer honour!' (He pronounced it `arrum.') `An arm, you goose! Who ever saw one that size? Why, it fills the whole window!' `Sure, it does, yer honour: but it's an arm for all that.' `Well, it's got no business there, at any rate: go and take it away!' There was a long silence after this, and Alice could only hear whispers now and then; such as, `Sure, I don't like it, yer honour, at all, at all!' `Do as I tell you, you coward!' and at last she spread out her hand again, and made another snatch in the air. This time there were TWO little shrieks, and more sounds of broken glass. `What a number of cucumber-frames there must be!' thought Alice. `I wonder what they'll do next! As for pulling me out of the window, I only wish they COULD! I'm sure I don't want to stay in here any longer!' She waited for some time without hearing anything more: at last came a rumbling of little cartwheels, and the sound of a good many voices all talking together: she made out the words: `Where's the other ladder?--Why, I hadn't to bring but one; Bill's got the other--Bill! fetch it here, lad!--Here, put 'em up at this corner--No, tie 'em together first--they don't reach half high enough yet--Oh! they'll do well enough; don't be particular-- Here, Bill! catch hold of this rope--Will the roof bear?--Mind that loose slate--Oh, it's coming down! Heads below!' (a loud crash)--`Now, who did that?--It was Bill, I fancy--Who's to go down the chimney?--Nay, I shan't! YOU do it!--That I won't, then!--Bill's to go down--Here, Bill! the master says you're to go down the chimney!' `Oh! So Bill's got to come down the chimney, has he?' said Alice to herself. `Shy, they seem to put everything upon Bill! I wouldn't be in Bill's place for a good deal: this fireplace is narrow, to be sure; but I THINK I can kick a little!' She drew her foot as far down the chimney as she could, and waited till she heard a little animal (she couldn't guess of what sort it was) scratching and scrambling about in the chimney close above her: then, saying to herself `This is Bill,' she gave one sharp kick, and waited to see what would happen next. The first thing she heard was a general chorus of `There goes Bill!' then the Rabbit's voice along--`Catch him, you by the hedge!' then silence, and then another confusion of voices--`Hold up his head--Brandy now--Don't choke him--How was it, old fellow? What happened to you? Tell us all about it!' Last came a little feeble, squeaking voice, (`That's Bill,' thought Alice,) `Well, I hardly know--No more, thank ye; I'm better now--but I'm a deal too flustered to tell you--all I know is, something comes at me like a Jack-in-the-box, and up I goes like a sky-rocket!' `So you did, old fellow!' said the others. `We must burn the house down!' said the Rabbit's voice; and Alice called out as loud as she could, `If you do. I'll set Dinah at you!' There was a dead silence instantly, and Alice thought to herself, `I wonder what they WILL do next! If they had any sense, they'd take the roof off.' After a minute or two, they began moving about again, and Alice heard the Rabbit say, `A barrowful will do, to begin with.' `A barrowful of WHAT?' thought Alice; but she had not long to doubt, for the next moment a shower of little pebbles came rattling in at the window, and some of them hit her in the face. `I'll put a stop to this,' she said to herself, and shouted out, `You'd better not do that again!' which produced another dead silence. Alice noticed with some surprise that the pebbles were all turning into little cakes as they lay on the floor, and a bright idea came into her head. `If I eat one of these cakes,' she thought, `it's sure to make SOME change in my size; and as it can't possibly make me larger, it must make me smaller, I suppose.' So she swallowed one of the cakes, and was delighted to find that she began shrinking directly. As soon as she was small enough to get through the door, she ran out of the house, and found quite a crowd of little animals and birds waiting outside. The poor little Lizard, Bill, was in the middle, being held up by two guinea-pigs, who were giving it something out of a bottle. They all made a rush at Alice the moment she appeared; but she ran off as hard as she could, and soon found herself safe in a thick wood. `The first thing I've got to do,' said Alice to herself, as she wandered about in the wood, `is to grow to my right size again; and the second thing is to find my way into that lovely garden. I think that will be the best plan.' It sounded an excellent plan, no doubt, and very neatly and simply arranged; the only difficulty was, that she had not the smallest idea how to set about it; and while she was peering about anxiously among the trees, a little sharp bark just over her head made her look up in a great hurry. An enormous puppy was looking down at her with large round eyes, and feebly stretching out one paw, trying to touch her. `Poor little thing!' said Alice, in a coaxing tone, and she tried hard to whistle to it; but she was terribly frightened all the time at the thought that it might be hungry, in which case it would be very likely to eat her up in spite of all her coaxing. Hardly knowing what she did, she picked up a little bit of stick, and held it out to the puppy; whereupon the puppy jumped into the air off all its feet at once, with a yelp of delight, and rushed at the stick, and made believe to worry it; then Alice dodged behind a great thistle, to keep herself from being run over; and the moment she appeared on the other side, the puppy made another rush at the stick, and tumbled head over heels in its hurry to get hold of it; then Alice, thinking it was very like having a game of play with a cart-horse, and expecting every moment to be trampled under its feet, ran round the thistle again; then the puppy began a series of short charges at the stick, running a very little way forwards each time and a long way back, and barking hoarsely all the while, till at last it sat down a good way off, panting, with its tongue hanging out of its mouth, and its great eyes half shut. This seemed to Alice a good opportunity for making her escape; so she set off at once, and ran till she was quite tired and out of breath, and till the puppy's bark sounded quite faint in the distance. `And yet what a dear little puppy it was!' said Alice, as she leant against a buttercup to rest herself, and fanned herself with one of the leaves: `I should have liked teaching it tricks very much, if--if I'd only been the right size to do it! Oh dear! I'd nearly forgotten that I've got to grow up again! Let me see--how IS it to be managed? I suppose I ought to eat or drink something or other; but the great question is, what?' The great question certainly was, what? Alice looked all round her at the flowers and the blades of grass, but she did not see anything that looked like the right thing to eat or drink under the circumstances. There was a large mushroom growing near her, about the same height as herself; and when she had looked under it, and on both sides of it, and behind it, it occurred to her that she might as well look and see what was on the top of it. She stretched herself up on tiptoe, and peeped over the edge of the mushroom, and her eyes immediately met those of a large caterpillar, that was sitting on the top with its arms folded, quietly smoking a long hookah, and taking not the smallest notice of her or of anything else. CHAPTER V Advice from a Caterpillar The Caterpillar and Alice looked at each other for some time in silence: at last the Caterpillar took the hookah out of its mouth, and addressed her in a languid, sleepy voice. `Who are YOU?' said the Caterpillar. This was not an encouraging opening for a conversation. Alice replied, rather shyly, `I--I hardly know, sir, just at present-- at least I know who I WAS when I got up this morning, but I think I must have been changed several times since then.' `What do you mean by that?' said the Caterpillar sternly. `Explain yourself!' `I can't explain MYSELF, I'm afraid, sir' said Alice, `because I'm not myself, you see.' `I don't see,' said the Caterpillar. `I'm afraid I can't put it more clearly,' Alice replied very politely, `for I can't understand it myself to begin with; and being so many different sizes in a day is very confusing.' `It isn't,' said the Caterpillar. `Well, perhaps you haven't found it so yet,' said Alice; `but when you have to turn into a chrysalis--you will some day, you know--and then after that into a butterfly, I should think you'll feel it a little queer, won't you?' `Not a bit,' said the Caterpillar. `Well, perhaps your feelings may be different,' said Alice; `all I know is, it would feel very queer to ME.' `You!' said the Caterpillar contemptuously. `Who are YOU?' Which brought them back again to the beginning of the conversation. Alice felt a little irritated at the Caterpillar's making such VERY short remarks, and she drew herself up and said, very gravely, `I think, you ought to tell me who YOU are, first.' `Why?' said the Caterpillar. Here was another puzzling question; and as Alice could not think of any good reason, and as the Caterpillar seemed to be in a VERY unpleasant state of mind, she turned away. `Come back!' the Caterpillar called after her. `I've something important to say!' This sounded promising, certainly: Alice turned and came back again. `Keep your temper,' said the Caterpillar. `Is that all?' said Alice, swallowing down her anger as well as she could. `No,' said the Caterpillar. Alice thought she might as well wait, as she had nothing else to do, and perhaps after all it might tell her something worth hearing. For some minutes it puffed away without speaking, but at last it unfolded its arms, took the hookah out of its mouth again, and said, `So you think you're changed, do you?' `I'm afraid I am, sir,' said Alice; `I can't remember things as I used--and I don't keep the same size for ten minutes together!' `Can't remember WHAT things?' said the Caterpillar. `Well, I've tried to say "HOW DOTH THE LITTLE BUSY BEE," but it all came different!' Alice replied in a very melancholy voice. `Repeat, "YOU ARE OLD, FATHER WILLIAM,"' said the Caterpillar. Alice folded her hands, and began:-- `You are old, Father William,' the young man said, `And your hair has become very white; And yet you incessantly stand on your head-- Do you think, at your age, it is right?' `In my youth,' Father William replied to his son, `I feared it might injure the brain; But, now that I'm perfectly sure I have none, Why, I do it again and again.' `You are old,' said the youth, `as I mentioned before, And have grown most uncommonly fat; Yet you turned a back-somersault in at the door-- Pray, what is the reason of that?' `In my youth,' said the sage, as he shook his grey locks, `I kept all my limbs very supple By the use of this ointment--one shilling the box-- Allow me to sell you a couple?' `You are old,' said the youth, `and your jaws are too weak For anything tougher than suet; Yet you finished the goose, with the bones and the beak-- Pray how did you manage to do it?' `In my youth,' said his father, `I took to the law, And argued each case with my wife; And the muscular strength, which it gave to my jaw, Has lasted the rest of my life.' `You are old,' said the youth, `one would hardly suppose That your eye was as steady as ever; Yet you balanced an eel on the end of your nose-- What made you so awfully clever?' `I have answered three questions, and that is enough,' Said his father; `don't give yourself airs! Do you think I can listen all day to such stuff? Be off, or I'll kick you down stairs!' `That is not said right,' said the Caterpillar. `Not QUITE right, I'm afraid,' said Alice, timidly; `some of the words have got altered.' `It is wrong from beginning to end,' said the Caterpillar decidedly, and there was silence for some minutes. The Caterpillar was the first to speak. `What size do you want to be?' it asked. `Oh, I'm not particular as to size,' Alice hastily replied; `only one doesn't like changing so often, you know.' `I DON'T know,' said the Caterpillar. Alice said nothing: she had never been so much contradicted in her life before, and she felt that she was losing her temper. `Are you content now?' said the Caterpillar. `Well, I should like to be a LITTLE larger, sir, if you wouldn't mind,' said Alice: `three inches is such a wretched height to be.' `It is a very good height indeed!' said the Caterpillar angrily, rearing itself upright as it spoke (it was exactly three inches high). `But I'm not used to it!' pleaded poor Alice in a piteous tone. And she thought of herself, `I wish the creatures wouldn't be so easily offended!' `You'll get used to it in time,' said the Caterpillar; and it put the hookah into its mouth and began smoking again. This time Alice waited patiently until it chose to speak again. In a minute or two the Caterpillar took the hookah out of its mouth and yawned once or twice, and shook itself. Then it got down off the mushroom, and crawled away in the grass, merely remarking as it went, `One side will make you grow taller, and the other side will make you grow shorter.' `One side of WHAT? The other side of WHAT?' thought Alice to herself. `Of the mushroom,' said the Caterpillar, just as if she had asked it aloud; and in another moment it was out of sight. Alice remained looking thoughtfully at the mushroom for a minute, trying to make out which were the two sides of it; and as it was perfectly round, she found this a very difficult question. However, at last she stretched her arms round it as far as they would go, and broke off a bit of the edge with each hand. `And now which is which?' she said to herself, and nibbled a little of the right-hand bit to try the effect: the next moment she felt a violent blow underneath her chin: it had struck her foot! She was a good deal frightened by this very sudden change, but she felt that there was no time to be lost, as she was shrinking rapidly; so she set to work at once to eat some of the other bit. Her chin was pressed so closely against her foot, that there was hardly room to open her mouth; but she did it at last, and managed to swallow a morsel of the lefthand bit. * * * * * * * * * * * * * * * * * * * * `Come, my head's free at last!' said Alice in a tone of delight, which changed into alarm in another moment, when she found that her shoulders were nowhere to be found: all she could see, when she looked down, was an immense length of neck, which seemed to rise like a stalk out of a sea of green leaves that lay far below her. `What CAN all that green stuff be?' said Alice. `And where HAVE my shoulders got to? And oh, my poor hands, how is it I can't see you?' She was moving them about as she spoke, but no result seemed to follow, except a little shaking among the distant green leaves. As there seemed to be no chance of getting her hands up to her head, she tried to get her head down to them, and was delighted to find that her neck would bend about easily in any direction, like a serpent. She had just succeeded in curving it down into a graceful zigzag, and was going to dive in among the leaves, which she found to be nothing but the tops of the trees under which she had been wandering, when a sharp hiss made her draw back in a hurry: a large pigeon had flown into her face, and was beating her violently with its wings. `Serpent!' screamed the Pigeon. `I'm NOT a serpent!' said Alice indignantly. `Let me alone!' `Serpent, I say again!' repeated the Pigeon, but in a more subdued tone, and added with a kind of sob, `I've tried every way, and nothing seems to suit them!' `I haven't the least idea what you're talking about,' said Alice. `I've tried the roots of trees, and I've tried banks, and I've tried hedges,' the Pigeon went on, without attending to her; `but those serpents! There's no pleasing them!' Alice was more and more puzzled, but she thought there was no use in saying anything more till the Pigeon had finished. `As if it wasn't trouble enough hatching the eggs,' said the Pigeon; `but I must be on the look-out for serpents night and day! Why, I haven't had a wink of sleep these three weeks!' `I'm very sorry you've been annoyed,' said Alice, who was beginning to see its meaning. `And just as I'd taken the highest tree in the wood,' continued the Pigeon, raising its voice to a shriek, `and just as I was thinking I should be free of them at last, they must needs come wriggling down from the sky! Ugh, Serpent!' `But I'm NOT a serpent, I tell you!' said Alice. `I'm a--I'm a--' `Well! WHAT are you?' said the Pigeon. `I can see you're trying to invent something!' `I--I'm a little girl,' said Alice, rather doubtfully, as she remembered the number of changes she had gone through that day. `A likely story indeed!' said the Pigeon in a tone of the deepest contempt. `I've seen a good many little girls in my time, but never ONE with such a neck as that! No, no! You're a serpent; and there's no use denying it. I suppose you'll be telling me next that you never tasted an egg!' `I HAVE tasted eggs, certainly,' said Alice, who was a very truthful child; `but little girls eat eggs quite as much as serpents do, you know.' `I don't believe it,' said the Pigeon; `but if they do, why then they're a kind of serpent, that's all I can say.' This was such a new idea to Alice, that she was quite silent for a minute or two, which gave the Pigeon the opportunity of adding, `You're looking for eggs, I know THAT well enough; and what does it matter to me whether you're a little girl or a serpent?' `It matters a good deal to ME,' said Alice hastily; `but I'm not looking for eggs, as it happens; and if I was, I shouldn't want YOURS: I don't like them raw.' `Well, be off, then!' said the Pigeon in a sulky tone, as it settled down again into its nest. Alice crouched down among the trees as well as she could, for her neck kept getting entangled among the branches, and every now and then she had to stop and untwist it. After a while she remembered that she still held the pieces of mushroom in her hands, and she set to work very carefully, nibbling first at one and then at the other, and growing sometimes taller and sometimes shorter, until she had succeeded in bringing herself down to her usual height. It was so long since she had been anything near the right size, that it felt quite strange at first; but she got used to it in a few minutes, and began talking to herself, as usual. `Come, there's half my plan done now! How puzzling all these changes are! I'm never sure what I'm going to be, from one minute to another! However, I've got back to my right size: the next thing is, to get into that beautiful garden--how IS that to be done, I wonder?' As she said this, she came suddenly upon an open place, with a little house in it about four feet high. `Whoever lives there,' thought Alice, `it'll never do to come upon them THIS size: why, I should frighten them out of their wits!' So she began nibbling at the righthand bit again, and did not venture to go near the house till she had brought herself down to nine inches high. CHAPTER VI Pig and Pepper For a minute or two she stood looking at the house, and wondering what to do next, when suddenly a footman in livery came running out of the wood--(she considered him to be a footman because he was in livery: otherwise, judging by his face only, she would have called him a fish)--and rapped loudly at the door with his knuckles. It was opened by another footman in livery, with a round face, and large eyes like a frog; and both footmen, Alice noticed, had powdered hair that curled all over their heads. She felt very curious to know what it was all about, and crept a little way out of the wood to listen. The Fish-Footman began by producing from under his arm a great letter, nearly as large as himself, and this he handed over to the other, saying, in a solemn tone, `For the Duchess. An invitation from the Queen to play croquet.' The Frog-Footman repeated, in the same solemn tone, only changing the order of the words a little, `From the Queen. An invitation for the Duchess to play croquet.' Then they both bowed low, and their curls got entangled together. Alice laughed so much at this, that she had to run back into the wood for fear of their hearing her; and when she next peeped out the Fish-Footman was gone, and the other was sitting on the ground near the door, staring stupidly up into the sky. Alice went timidly up to the door, and knocked. `There's no sort of use in knocking,' said the Footman, `and that for two reasons. First, because I'm on the same side of the door as you are; secondly, because they're making such a noise inside, no one could possibly hear you.' And certainly there was a most extraordinary noise going on within--a constant howling and sneezing, and every now and then a great crash, as if a dish or kettle had been broken to pieces. `Please, then,' said Alice, `how am I to get in?' `There might be some sense in your knocking,' the Footman went on without attending to her, `if we had the door between us. For instance, if you were INSIDE, you might knock, and I could let you out, you know.' He was looking up into the sky all the time he was speaking, and this Alice thought decidedly uncivil. `But perhaps he can't help it,' she said to herself; `his eyes are so VERY nearly at the top of his head. But at any rate he might answer questions.--How am I to get in?' she repeated, aloud. `I shall sit here,' the Footman remarked, `till tomorrow--' At this moment the door of the house opened, and a large plate came skimming out, straight at the Footman's head: it just grazed his nose, and broke to pieces against one of the trees behind him. `--or next day, maybe,' the Footman continued in the same tone, exactly as if nothing had happened. `How am I to get in?' asked Alice again, in a louder tone. `ARE you to get in at all?' said the Footman. `That's the first question, you know.' It was, no doubt: only Alice did not like to be told so. `It's really dreadful,' she muttered to herself, `the way all the creatures argue. It's enough to drive one crazy!' The Footman seemed to think this a good opportunity for repeating his remark, with variations. `I shall sit here,' he said, `on and off, for days and days.' `But what am I to do?' said Alice. `Anything you like,' said the Footman, and began whistling. `Oh, there's no use in talking to him,' said Alice desperately: `he's perfectly idiotic!' And she opened the door and went in. The door led right into a large kitchen, which was full of smoke from one end to the other: the Duchess was sitting on a three-legged stool in the middle, nursing a baby; the cook was leaning over the fire, stirring a large cauldron which seemed to be full of soup. `There's certainly too much pepper in that soup!' Alice said to herself, as well as she could for sneezing. There was certainly too much of it in the air. Even the Duchess sneezed occasionally; and as for the baby, it was sneezing and howling alternately without a moment's pause. The only things in the kitchen that did not sneeze, were the cook, and a large cat which was sitting on the hearth and grinning from ear to ear. `Please would you tell me,' said Alice, a little timidly, for she was not quite sure whether it was good manners for her to speak first, `why your cat grins like that?' `It's a Cheshire cat,' said the Duchess, `and that's why. Pig!' She said the last word with such sudden violence that Alice quite jumped; but she saw in another moment that it was addressed to the baby, and not to her, so she took courage, and went on again:-- `I didn't know that Cheshire cats always grinned; in fact, I didn't know that cats COULD grin.' `They all can,' said the Duchess; `and most of 'em do.' `I don't know of any that do,' Alice said very politely, feeling quite pleased to have got into a conversation. `You don't know much,' said the Duchess; `and that's a fact.' Alice did not at all like the tone of this remark, and thought it would be as well to introduce some other subject of conversation. While she was trying to fix on one, the cook took the cauldron of soup off the fire, and at once set to work throwing everything within her reach at the Duchess and the baby --the fire-irons came first; then followed a shower of saucepans, plates, and dishes. The Duchess took no notice of them even when they hit her; and the baby was howling so much already, that it was quite impossible to say whether the blows hurt it or not. `Oh, PLEASE mind what you're doing!' cried Alice, jumping up and down in an agony of terror. `Oh, there goes his PRECIOUS nose'; as an unusually large saucepan flew close by it, and very nearly carried it off. `If everybody minded their own business,' the Duchess said in a hoarse growl, `the world would go round a deal faster than it does.' `Which would NOT be an advantage,' said Alice, who felt very glad to get an opportunity of showing off a little of her knowledge. `Just think of what work it would make with the day and night! You see the earth takes twenty-four hours to turn round on its axis--' `Talking of axes,' said the Duchess, `chop off her head!' Alice glanced rather anxiously at the cook, to see if she meant to take the hint; but the cook was busily stirring the soup, and seemed not to be listening, so she went on again: `Twenty-four hours, I THINK; or is it twelve? I--' `Oh, don't bother ME,' said the Duchess; `I never could abide figures!' And with that she began nursing her child again, singing a sort of lullaby to it as she did so, and giving it a violent shake at the end of every line: `Speak roughly to your little boy, And beat him when he sneezes: He only does it to annoy, Because he knows it teases.' CHORUS. (In which the cook and the baby joined):-- `Wow! wow! wow!' While the Duchess sang the second verse of the song, she kept tossing the baby violently up and down, and the poor little thing howled so, that Alice could hardly hear the words:-- `I speak severely to my boy, I beat him when he sneezes; For he can thoroughly enjoy The pepper when he pleases!' CHORUS. `Wow! wow! wow!' `Here! you may nurse it a bit, if you like!' the Duchess said to Alice, flinging the baby at her as she spoke. `I must go and get ready to play croquet with the Queen,' and she hurried out of the room. The cook threw a frying-pan after her as she went out, but it just missed her. Alice caught the baby with some difficulty, as it was a queer- shaped little creature, and held out its arms and legs in all directions, `just like a star-fish,' thought Alice. The poor little thing was snorting like a steam-engine when she caught it, and kept doubling itself up and straightening itself out again, so that altogether, for the first minute or two, it was as much as she could do to hold it. As soon as she had made out the proper way of nursing it, (which was to twist it up into a sort of knot, and then keep tight hold of its right ear and left foot, so as to prevent its undoing itself,) she carried it out into the open air. `IF I don't take this child away with me,' thought Alice, `they're sure to kill it in a day or two: wouldn't it be murder to leave it behind?' She said the last words out loud, and the little thing grunted in reply (it had left off sneezing by this time). `Don't grunt,' said Alice; `that's not at all a proper way of expressing yourself.' The baby grunted again, and Alice looked very anxiously into its face to see what was the matter with it. There could be no doubt that it had a VERY turn-up nose, much more like a snout than a real nose; also its eyes were getting extremely small for a baby: altogether Alice did not like the look of the thing at all. `But perhaps it was only sobbing,' she thought, and looked into its eyes again, to see if there were any tears. No, there were no tears. `If you're going to turn into a pig, my dear,' said Alice, seriously, `I'll have nothing more to do with you. Mind now!' The poor little thing sobbed again (or grunted, it was impossible to say which), and they went on for some while in silence. Alice was just beginning to think to herself, `Now, what am I to do with this creature when I get it home?' when it grunted again, so violently, that she looked down into its face in some alarm. This time there could be NO mistake about it: it was neither more nor less than a pig, and she felt that it would be quite absurd for her to carry it further. So she set the little creature down, and felt quite relieved to see it trot away quietly into the wood. `If it had grown up,' she said to herself, `it would have made a dreadfully ugly child: but it makes rather a handsome pig, I think.' And she began thinking over other children she knew, who might do very well as pigs, and was just saying to herself, `if one only knew the right way to change them--' when she was a little startled by seeing the Cheshire Cat sitting on a bough of a tree a few yards off. The Cat only grinned when it saw Alice. It looked good- natured, she thought: still it had VERY long claws and a great many teeth, so she felt that it ought to be treated with respect. `Cheshire Puss,' she began, rather timidly, as she did not at all know whether it would like the name: however, it only grinned a little wider. `Come, it's pleased so far,' thought Alice, and she went on. `Would you tell me, please, which way I ought to go from here?' `That depends a good deal on where you want to get to,' said the Cat. `I don't much care where--' said Alice. `Then it doesn't matter which way you go,' said the Cat. `--so long as I get SOMEWHERE,' Alice added as an explanation. `Oh, you're sure to do that,' said the Cat, `if you only walk long enough.' Alice felt that this could not be denied, so she tried another question. `What sort of people live about here?' `In THAT direction,' the Cat said, waving its right paw round, `lives a Hatter: and in THAT direction,' waving the other paw, `lives a March Hare. Visit either you like: they're both mad.' `But I don't want to go among mad people,' Alice remarked. `Oh, you can't help that,' said the Cat: `we're all mad here. I'm mad. You're mad.' `How do you know I'm mad?' said Alice. `You must be,' said the Cat, `or you wouldn't have come here.' Alice didn't think that proved it at all; however, she went on `And how do you know that you're mad?' `To begin with,' said the Cat, `a dog's not mad. You grant that?' `I suppose so,' said Alice. `Well, then,' the Cat went on, `you see, a dog growls when it's angry, and wags its tail when it's pleased. Now I growl when I'm pleased, and wag my tail when I'm angry. Therefore I'm mad.' `I call it purring, not growling,' said Alice. `Call it what you like,' said the Cat. `Do you play croquet with the Queen to-day?' `I should like it very much,' said Alice, `but I haven't been invited yet.' `You'll see me there,' said the Cat, and vanished. Alice was not much surprised at this, she was getting so used to queer things happening. While she was looking at the place where it had been, it suddenly appeared again. `By-the-bye, what became of the baby?' said the Cat. `I'd nearly forgotten to ask.' `It turned into a pig,' Alice quietly said, just as if it had come back in a natural way. `I thought it would,' said the Cat, and vanished again. Alice waited a little, half expecting to see it again, but it did not appear, and after a minute or two she walked on in the direction in which the March Hare was said to live. `I've seen hatters before,' she said to herself; `the March Hare will be much the most interesting, and perhaps as this is May it won't be raving mad--at least not so mad as it was in March.' As she said this, she looked up, and there was the Cat again, sitting on a branch of a tree. `Did you say pig, or fig?' said the Cat. `I said pig,' replied Alice; `and I wish you wouldn't keep appearing and vanishing so suddenly: you make one quite giddy.' `All right,' said the Cat; and this time it vanished quite slowly, beginning with the end of the tail, and ending with the grin, which remained some time after the rest of it had gone. `Well! I've often seen a cat without a grin,' thought Alice; `but a grin without a cat! It's the most curious thing I ever saw in my life!' She had not gone much farther before she came in sight of the house of the March Hare: she thought it must be the right house, because the chimneys were shaped like ears and the roof was thatched with fur. It was so large a house, that she did not like to go nearer till she had nibbled some more of the lefthand bit of mushroom, and raised herself to about two feet high: even then she walked up towards it rather timidly, saying to herself `Suppose it should be raving mad after all! I almost wish I'd gone to see the Hatter instead!' CHAPTER VII A Mad Tea-Party There was a table set out under a tree in front of the house, and the March Hare and the Hatter were having tea at it: a Dormouse was sitting between them, fast asleep, and the other two were using it as a cushion, resting their elbows on it, and talking over its head. `Very uncomfortable for the Dormouse,' thought Alice; `only, as it's asleep, I suppose it doesn't mind.' The table was a large one, but the three were all crowded together at one corner of it: `No room! No room!' they cried out when they saw Alice coming. `There's PLENTY of room!' said Alice indignantly, and she sat down in a large arm-chair at one end of the table. `Have some wine,' the March Hare said in an encouraging tone. Alice looked all round the table, but there was nothing on it but tea. `I don't see any wine,' she remarked. `There isn't any,' said the March Hare. `Then it wasn't very civil of you to offer it,' said Alice angrily. `It wasn't very civil of you to sit down without being invited,' said the March Hare. `I didn't know it was YOUR table,' said Alice; `it's laid for a great many more than three.' `Your hair wants cutting,' said the Hatter. He had been looking at Alice for some time with great curiosity, and this was his first speech. `You should learn not to make personal remarks,' Alice said with some severity; `it's very rude.' The Hatter opened his eyes very wide on hearing this; but all he SAID was, `Why is a raven like a writing-desk?' `Come, we shall have some fun now!' thought Alice. `I'm glad they've begun asking riddles.--I believe I can guess that,' she added aloud. `Do you mean that you think you can find out the answer to it?' said the March Hare. `Exactly so,' said Alice. `Then you should say what you mean,' the March Hare went on. `I do,' Alice hastily replied; `at least--at least I mean what I say--that's the same thing, you know.' `Not the same thing a bit!' said the Hatter. `You might just as well say that "I see what I eat" is the same thing as "I eat what I see"!' `You might just as well say,' added the March Hare, `that "I like what I get" is the same thing as "I get what I like"!' `You might just as well say,' added the Dormouse, who seemed to be talking in his sleep, `that "I breathe when I sleep" is the same thing as "I sleep when I breathe"!' `It IS the same thing with you,' said the Hatter, and here the conversation dropped, and the party sat silent for a minute, while Alice thought over all she could remember about ravens and writing-desks, which wasn't much. The Hatter was the first to break the silence. `What day of the month is it?' he said, turning to Alice: he had taken his watch out of his pocket, and was looking at it uneasily, shaking it every now and then, and holding it to his ear. Alice considered a little, and then said `The fourth.' `Two days wrong!' sighed the Hatter. `I told you butter wouldn't suit the works!' he added looking angrily at the March Hare. `It was the BEST butter,' the March Hare meekly replied. `Yes, but some crumbs must have got in as well,' the Hatter grumbled: `you shouldn't have put it in with the bread-knife.' The March Hare took the watch and looked at it gloomily: then he dipped it into his cup of tea, and looked at it again: but he could think of nothing better to say than his first remark, `It was the BEST butter, you know.' Alice had been looking over his shoulder with some curiosity. `What a funny watch!' she remarked. `It tells the day of the month, and doesn't tell what o'clock it is!' `Why should it?' muttered the Hatter. `Does YOUR watch tell you what year it is?' `Of course not,' Alice replied very readily: `but that's because it stays the same year for such a long time together.' `Which is just the case with MINE,' said the Hatter. Alice felt dreadfully puzzled. The Hatter's remark seemed to have no sort of meaning in it, and yet it was certainly English. `I don't quite understand you,' she said, as politely as she could. `The Dormouse is asleep again,' said the Hatter, and he poured a little hot tea upon its nose. The Dormouse shook its head impatiently, and said, without opening its eyes, `Of course, of course; just what I was going to remark myself.' `Have you guessed the riddle yet?' the Hatter said, turning to Alice again. `No, I give it up,' Alice replied: `what's the answer?' `I haven't the slightest idea,' said the Hatter. `Nor I,' said the March Hare. Alice sighed wearily. `I think you might do something better with the time,' she said, `than waste it in asking riddles that have no answers.' `If you knew Time as well as I do,' said the Hatter, `you wouldn't talk about wasting IT. It's HIM.' `I don't know what you mean,' said Alice. `Of course you don't!' the Hatter said, tossing his head contemptuously. `I dare say you never even spoke to Time!' `Perhaps not,' Alice cautiously replied: `but I know I have to beat time when I learn music.' `Ah! that accounts for it,' said the Hatter. `He won't stand beating. Now, if you only kept on good terms with him, he'd do almost anything you liked with the clock. For instance, suppose it were nine o'clock in the morning, just time to begin lessons: you'd only have to whisper a hint to Time, and round goes the clock in a twinkling! Half-past one, time for dinner!' (`I only wish it was,' the March Hare said to itself in a whisper.) `That would be grand, certainly,' said Alice thoughtfully: `but then--I shouldn't be hungry for it, you know.' `Not at first, perhaps,' said the Hatter: `but you could keep it to half-past one as long as you liked.' `Is that the way YOU manage?' Alice asked. The Hatter shook his head mournfully. `Not I!' he replied. `We quarrelled last March--just before HE went mad, you know--' (pointing with his tea spoon at the March Hare,) `--it was at the great concert given by the Queen of Hearts, and I had to sing "Twinkle, twinkle, little bat! How I wonder what you're at!" You know the song, perhaps?' `I've heard something like it,' said Alice. `It goes on, you know,' the Hatter continued, `in this way:-- "Up above the world you fly, Like a tea-tray in the sky. Twinkle, twinkle--"' Here the Dormouse shook itself, and began singing in its sleep `Twinkle, twinkle, twinkle, twinkle--' and went on so long that they had to pinch it to make it stop. `Well, I'd hardly finished the first verse,' said the Hatter, `when the Queen jumped up and bawled out, "He's murdering the time! Off with his head!"' `How dreadfully savage!' exclaimed Alice. `And ever since that,' the Hatter went on in a mournful tone, `he won't do a thing I ask! It's always six o'clock now.' A bright idea came into Alice's head. `Is that the reason so many tea-things are put out here?' she asked. `Yes, that's it,' said the Hatter with a sigh: `it's always tea-time, and we've no time to wash the things between whiles.' `Then you keep moving round, I suppose?' said Alice. `Exactly so,' said the Hatter: `as the things get used up.' `But what happens when you come to the beginning again?' Alice ventured to ask. `Suppose we change the subject,' the March Hare interrupted, yawning. `I'm getting tired of this. I vote the young lady tells us a story.' `I'm afraid I don't know one,' said Alice, rather alarmed at the proposal. `Then the Dormouse shall!' they both cried. `Wake up, Dormouse!' And they pinched it on both sides at once. The Dormouse slowly opened his eyes. `I wasn't asleep,' he said in a hoarse, feeble voice: `I heard every word you fellows were saying.' `Tell us a story!' said the March Hare. `Yes, please do!' pleaded Alice. `And be quick about it,' added the Hatter, `or you'll be asleep again before it's done.' `Once upon a time there were three little sisters,' the Dormouse began in a great hurry; `and their names were Elsie, Lacie, and Tillie; and they lived at the bottom of a well--' `What did they live on?' said Alice, who always took a great interest in questions of eating and drinking. `They lived on treacle,' said the Dormouse, after thinking a minute or two. `They couldn't have done that, you know,' Alice gently remarked; `they'd have been ill.' `So they were,' said the Dormouse; `VERY ill.' Alice tried to fancy to herself what such an extraordinary ways of living would be like, but it puzzled her too much, so she went on: `But why did they live at the bottom of a well?' `Take some more tea,' the March Hare said to Alice, very earnestly. `I've had nothing yet,' Alice replied in an offended tone, `so I can't take more.' `You mean you can't take LESS,' said the Hatter: `it's very easy to take MORE than nothing.' `Nobody asked YOUR opinion,' said Alice. `Who's making personal remarks now?' the Hatter asked triumphantly. Alice did not quite know what to say to this: so she helped herself to some tea and bread-and-butter, and then turned to the Dormouse, and repeated her question. `Why did they live at the bottom of a well?' The Dormouse again took a minute or two to think about it, and then said, `It was a treacle-well.' `There's no such thing!' Alice was beginning very angrily, but the Hatter and the March Hare went `Sh! sh!' and the Dormouse sulkily remarked, `If you can't be civil, you'd better finish the story for yourself.' `No, please go on!' Alice said very humbly; `I won't interrupt again. I dare say there may be ONE.' `One, indeed!' said the Dormouse indignantly. However, he consented to go on. `And so these three little sisters--they were learning to draw, you know--' `What did they draw?' said Alice, quite forgetting her promise. `Treacle,' said the Dormouse, without considering at all this time. `I want a clean cup,' interrupted the Hatter: `let's all move one place on.' He moved on as he spoke, and the Dormouse followed him: the March Hare moved into the Dormouse's place, and Alice rather unwillingly took the place of the March Hare. The Hatter was the only one who got any advantage from the change: and Alice was a good deal worse off than before, as the March Hare had just upset the milk-jug into his plate. Alice did not wish to offend the Dormouse again, so she began very cautiously: `But I don't understand. Where did they draw the treacle from?' `You can draw water out of a water-well,' said the Hatter; `so I should think you could draw treacle out of a treacle-well--eh, stupid?' `But they were IN the well,' Alice said to the Dormouse, not choosing to notice this last remark. `Of course they were', said the Dormouse; `--well in.' This answer so confused poor Alice, that she let the Dormouse go on for some time without interrupting it. `They were learning to draw,' the Dormouse went on, yawning and rubbing its eyes, for it was getting very sleepy; `and they drew all manner of things--everything that begins with an M--' `Why with an M?' said Alice. `Why not?' said the March Hare. Alice was silent. The Dormouse had closed its eyes by this time, and was going off into a doze; but, on being pinched by the Hatter, it woke up again with a little shriek, and went on: `--that begins with an M, such as mouse-traps, and the moon, and memory, and muchness-- you know you say things are "much of a muchness"--did you ever see such a thing as a drawing of a muchness?' `Really, now you ask me,' said Alice, very much confused, `I don't think--' `Then you shouldn't talk,' said the Hatter. This piece of rudeness was more than Alice could bear: she got up in great disgust, and walked off; the Dormouse fell asleep instantly, and neither of the others took the least notice of her going, though she looked back once or twice, half hoping that they would call after her: the last time she saw them, they were trying to put the Dormouse into the teapot. `At any rate I'll never go THERE again!' said Alice as she picked her way through the wood. `It's the stupidest tea-party I ever was at in all my life!' Just as she said this, she noticed that one of the trees had a door leading right into it. `That's very curious!' she thought. `But everything's curious today. I think I may as well go in at once.' And in she went. Once more she found herself in the long hall, and close to the little glass table. `Now, I'll manage better this time,' she said to herself, and began by taking the little golden key, and unlocking the door that led into the garden. Then she went to work nibbling at the mushroom (she had kept a piece of it in her pocket) till she was about a foot high: then she walked down the little passage: and THEN--she found herself at last in the beautiful garden, among the bright flower-beds and the cool fountains. CHAPTER VIII The Queen's Croquet-Ground A large rose-tree stood near the entrance of the garden: the roses growing on it were white, but there were three gardeners at it, busily painting them red. Alice thought this a very curious thing, and she went nearer to watch them, and just as she came up to them she heard one of them say, `Look out now, Five! Don't go splashing paint over me like that!' `I couldn't help it,' said Five, in a sulky tone; `Seven jogged my elbow.' On which Seven looked up and said, `That's right, Five! Always lay the blame on others!' `YOU'D better not talk!' said Five. `I heard the Queen say only yesterday you deserved to be beheaded!' `What for?' said the one who had spoken first. `That's none of YOUR business, Two!' said Seven. `Yes, it IS his business!' said Five, `and I'll tell him--it was for bringing the cook tulip-roots instead of onions.' Seven flung down his brush, and had just begun `Well, of all the unjust things--' when his eye chanced to fall upon Alice, as she stood watching them, and he checked himself suddenly: the others looked round also, and all of them bowed low. `Would you tell me,' said Alice, a little timidly, `why you are painting those roses?' Five and Seven said nothing, but looked at Two. Two began in a low voice, `Why the fact is, you see, Miss, this here ought to have been a RED rose-tree, and we put a white one in by mistake; and if the Queen was to find it out, we should all have our heads cut off, you know. So you see, Miss, we're doing our best, afore she comes, to--' At this moment Five, who had been anxiously looking across the garden, called out `The Queen! The Queen!' and the three gardeners instantly threw themselves flat upon their faces. There was a sound of many footsteps, and Alice looked round, eager to see the Queen. First came ten soldiers carrying clubs; these were all shaped like the three gardeners, oblong and flat, with their hands and feet at the corners: next the ten courtiers; these were ornamented all over with diamonds, and walked two and two, as the soldiers did. After these came the royal children; there were ten of them, and the little dears came jumping merrily along hand in hand, in couples: they were all ornamented with hearts. Next came the guests, mostly Kings and Queens, and among them Alice recognised the White Rabbit: it was talking in a hurried nervous manner, smiling at everything that was said, and went by without noticing her. Then followed the Knave of Hearts, carrying the King's crown on a crimson velvet cushion; and, last of all this grand procession, came THE KING AND QUEEN OF HEARTS. Alice was rather doubtful whether she ought not to lie down on her face like the three gardeners, but she could not remember ever having heard of such a rule at processions; `and besides, what would be the use of a procession,' thought she, `if people had all to lie down upon their faces, so that they couldn't see it?' So she stood still where she was, and waited. When the procession came opposite to Alice, they all stopped and looked at her, and the Queen said severely `Who is this?' She said it to the Knave of Hearts, who only bowed and smiled in reply. `Idiot!' said the Queen, tossing her head impatiently; and, turning to Alice, she went on, `What's your name, child?' `My name is Alice, so please your Majesty,' said Alice very politely; but she added, to herself, `Why, they're only a pack of cards, after all. I needn't be afraid of them!' `And who are THESE?' said the Queen, pointing to the three gardeners who were lying round the rosetree; for, you see, as they were lying on their faces, and the pattern on their backs was the same as the rest of the pack, she could not tell whether they were gardeners, or soldiers, or courtiers, or three of her own children. `How should I know?' said Alice, surprised at her own courage. `It's no business of MINE.' The Queen turned crimson with fury, and, after glaring at her for a moment like a wild beast, screamed `Off with her head! Off--' `Nonsense!' said Alice, very loudly and decidedly, and the Queen was silent. The King laid his hand upon her arm, and timidly said `Consider, my dear: she is only a child!' The Queen turned angrily away from him, and said to the Knave `Turn them over!' The Knave did so, very carefully, with one foot. `Get up!' said the Queen, in a shrill, loud voice, and the three gardeners instantly jumped up, and began bowing to the King, the Queen, the royal children, and everybody else. `Leave off that!' screamed the Queen. `You make me giddy.' And then, turning to the rose-tree, she went on, `What HAVE you been doing here?' `May it please your Majesty,' said Two, in a very humble tone, going down on one knee as he spoke, `we were trying--' `I see!' said the Queen, who had meanwhile been examining the roses. `Off with their heads!' and the procession moved on, three of the soldiers remaining behind to execute the unfortunate gardeners, who ran to Alice for protection. `You shan't be beheaded!' said Alice, and she put them into a large flower-pot that stood near. The three soldiers wandered about for a minute or two, looking for them, and then quietly marched off after the others. `Are their heads off?' shouted the Queen. `Their heads are gone, if it please your Majesty!' the soldiers shouted in reply. `That's right!' shouted the Queen. `Can you play croquet?' The soldiers were silent, and looked at Alice, as the question was evidently meant for her. `Yes!' shouted Alice. `Come on, then!' roared the Queen, and Alice joined the procession, wondering very much what would happen next. `It's--it's a very fine day!' said a timid voice at her side. She was walking by the White Rabbit, who was peeping anxiously into her face. `Very,' said Alice: `--where's the Duchess?' `Hush! Hush!' said the Rabbit in a low, hurried tone. He looked anxiously over his shoulder as he spoke, and then raised himself upon tiptoe, put his mouth close to her ear, and whispered `She's under sentence of execution.' `What for?' said Alice. `Did you say "What a pity!"?' the Rabbit asked. `No, I didn't,' said Alice: `I don't think it's at all a pity. I said "What for?"' `She boxed the Queen's ears--' the Rabbit began. Alice gave a little scream of laughter. `Oh, hush!' the Rabbit whispered in a frightened tone. `The Queen will hear you! You see, she came rather late, and the Queen said--' `Get to your places!' shouted the Queen in a voice of thunder, and people began running about in all directions, tumbling up against each other; however, they got settled down in a minute or two, and the game began. Alice thought she had never seen such a curious croquet-ground in her life; it was all ridges and furrows; the balls were live hedgehogs, the mallets live flamingoes, and the soldiers had to double themselves up and to stand on their hands and feet, to make the arches. The chief difficulty Alice found at first was in managing her flamingo: she succeeded in getting its body tucked away, comfortably enough, under her arm, with its legs hanging down, but generally, just as she had got its neck nicely straightened out, and was going to give the hedgehog a blow with its head, it WOULD twist itself round and look up in her face, with such a puzzled expression that she could not help bursting out laughing: and when she had got its head down, and was going to begin again, it was very provoking to find that the hedgehog had unrolled itself, and was in the act of crawling away: besides all this, there was generally a ridge or furrow in the way wherever she wanted to send the hedgehog to, and, as the doubled-up soldiers were always getting up and walking off to other parts of the ground, Alice soon came to the conclusion that it was a very difficult game indeed. The players all played at once without waiting for turns, quarrelling all the while, and fighting for the hedgehogs; and in a very short time the Queen was in a furious passion, and went stamping about, and shouting `Off with his head!' or `Off with her head!' about once in a minute. Alice began to feel very uneasy: to be sure, she had not as yet had any dispute with the Queen, but she knew that it might happen any minute, `and then,' thought she, `what would become of me? They're dreadfully fond of beheading people here; the great wonder is, that there's any one left alive!' She was looking about for some way of escape, and wondering whether she could get away without being seen, when she noticed a curious appearance in the air: it puzzled her very much at first, but, after watching it a minute or two, she made it out to be a grin, and she said to herself `It's the Cheshire Cat: now I shall have somebody to talk to.' `How are you getting on?' said the Cat, as soon as there was mouth enough for it to speak with. Alice waited till the eyes appeared, and then nodded. `It's no use speaking to it,' she thought, `till its ears have come, or at least one of them.' In another minute the whole head appeared, and then Alice put down her flamingo, and began an account of the game, feeling very glad she had someone to listen to her. The Cat seemed to think that there was enough of it now in sight, and no more of it appeared. `I don't think they play at all fairly,' Alice began, in rather a complaining tone, `and they all quarrel so dreadfully one can't hear oneself speak--and they don't seem to have any rules in particular; at least, if there are, nobody attends to them--and you've no idea how confusing it is all the things being alive; for instance, there's the arch I've got to go through next walking about at the other end of the ground--and I should have croqueted the Queen's hedgehog just now, only it ran away when it saw mine coming!' `How do you like the Queen?' said the Cat in a low voice. `Not at all,' said Alice: `she's so extremely--' Just then she noticed that the Queen was close behind her, listening: so she went on, `--likely to win, that it's hardly worth while finishing the game.' The Queen smiled and passed on. `Who ARE you talking to?' said the King, going up to Alice, and looking at the Cat's head with great curiosity. `It's a friend of mine--a Cheshire Cat,' said Alice: `allow me to introduce it.' `I don't like the look of it at all,' said the King: `however, it may kiss my hand if it likes.' `I'd rather not,' the Cat remarked. `Don't be impertinent,' said the King, `and don't look at me like that!' He got behind Alice as he spoke. `A cat may look at a king,' said Alice. `I've read that in some book, but I don't remember where.' `Well, it must be removed,' said the King very decidedly, and he called the Queen, who was passing at the moment, `My dear! I wish you would have this cat removed!' The Queen had only one way of settling all difficulties, great or small. `Off with his head!' she said, without even looking round. `I'll fetch the executioner myself,' said the King eagerly, and he hurried off. Alice thought she might as well go back, and see how the game was going on, as she heard the Queen's voice in the distance, screaming with passion. She had already heard her sentence three of the players to be executed for having missed their turns, and she did not like the look of things at all, as the game was in such confusion that she never knew whether it was her turn or not. So she went in search of her hedgehog. The hedgehog was engaged in a fight with another hedgehog, which seemed to Alice an excellent opportunity for croqueting one of them with the other: the only difficulty was, that her flamingo was gone across to the other side of the garden, where Alice could see it trying in a helpless sort of way to fly up into a tree. By the time she had caught the flamingo and brought it back, the fight was over, and both the hedgehogs were out of sight: `but it doesn't matter much,' thought Alice, `as all the arches are gone from this side of the ground.' So she tucked it away under her arm, that it might not escape again, and went back for a little more conversation with her friend. When she got back to the Cheshire Cat, she was surprised to find quite a large crowd collected round it: there was a dispute going on between the executioner, the King, and the Queen, who were all talking at once, while all the rest were quite silent, and looked very uncomfortable. The moment Alice appeared, she was appealed to by all three to settle the question, and they repeated their arguments to her, though, as they all spoke at once, she found it very hard indeed to make out exactly what they said. The executioner's argument was, that you couldn't cut off a head unless there was a body to cut it off from: that he had never had to do such a thing before, and he wasn't going to begin at HIS time of life. The King's argument was, that anything that had a head could be beheaded, and that you weren't to talk nonsense. The Queen's argument was, that if something wasn't done about it in less than no time she'd have everybody executed, all round. (It was this last remark that had made the whole party look so grave and anxious.) Alice could think of nothing else to say but `It belongs to the Duchess: you'd better ask HER about it.' `She's in prison,' the Queen said to the executioner: `fetch her here.' And the executioner went off like an arrow. The Cat's head began fading away the moment he was gone, and, by the time he had come back with the Dutchess, it had entirely disappeared; so the King and the executioner ran wildly up and down looking for it, while the rest of the party went back to the game. CHAPTER IX The Mock Turtle's Story `You can't think how glad I am to see you again, you dear old thing!' said the Duchess, as she tucked her arm affectionately into Alice's, and they walked off together. Alice was very glad to find her in such a pleasant temper, and thought to herself that perhaps it was only the pepper that had made her so savage when they met in the kitchen. `When I'M a Duchess,' she said to herself, (not in a very hopeful tone though), `I won't have any pepper in my kitchen AT ALL. Soup does very well without--Maybe it's always pepper that makes people hot-tempered,' she went on, very much pleased at having found out a new kind of rule, `and vinegar that makes them sour--and camomile that makes them bitter--and--and barley-sugar and such things that make children sweet-tempered. I only wish people knew that: then they wouldn't be so stingy about it, you know--' She had quite forgotten the Duchess by this time, and was a little startled when she heard her voice close to her ear. `You're thinking about something, my dear, and that makes you forget to talk. I can't tell you just now what the moral of that is, but I shall remember it in a bit.' `Perhaps it hasn't one,' Alice ventured to remark. `Tut, tut, child!' said the Duchess. `Everything's got a moral, if only you can find it.' And she squeezed herself up closer to Alice's side as she spoke. Alice did not much like keeping so close to her: first, because the Duchess was VERY ugly; and secondly, because she was exactly the right height to rest her chin upon Alice's shoulder, and it was an uncomfortably sharp chin. However, she did not like to be rude, so she bore it as well as she could. `The game's going on rather better now,' she said, by way of keeping up the conversation a little. `'Tis so,' said the Duchess: `and the moral of that is--"Oh, 'tis love, 'tis love, that makes the world go round!"' `Somebody said,' Alice whispered, `that it's done by everybody minding their own business!' `Ah, well! It means much the same thing,' said the Duchess, digging her sharp little chin into Alice's shoulder as she added, `and the moral of THAT is--"Take care of the sense, and the sounds will take care of themselves."' `How fond she is of finding morals in things!' Alice thought to herself. `I dare say you're wondering why I don't put my arm round your waist,' the Duchess said after a pause: `the reason is, that I'm doubtful about the temper of your flamingo. Shall I try the experiment?' `HE might bite,' Alice cautiously replied, not feeling at all anxious to have the experiment tried. `Very true,' said the Duchess: `flamingoes and mustard both bite. And the moral of that is--"Birds of a feather flock together."' `Only mustard isn't a bird,' Alice remarked. `Right, as usual,' said the Duchess: `what a clear way you have of putting things!' `It's a mineral, I THINK,' said Alice. `Of course it is,' said the Duchess, who seemed ready to agree to everything that Alice said; `there's a large mustard-mine near here. And the moral of that is--"The more there is of mine, the less there is of yours."' `Oh, I know!' exclaimed Alice, who had not attended to this last remark, `it's a vegetable. It doesn't look like one, but it is.' `I quite agree with you,' said the Duchess; `and the moral of that is--"Be what you would seem to be"--or if you'd like it put more simply--"Never imagine yourself not to be otherwise than what it might appear to others that what you were or might have been was not otherwise than what you had been would have appeared to them to be otherwise."' `I think I should understand that better,' Alice said very politely, `if I had it written down: but I can't quite follow it as you say it.' `That's nothing to what I could say if I chose,' the Duchess replied, in a pleased tone. `Pray don't trouble yourself to say it any longer than that,' said Alice. `Oh, don't talk about trouble!' said the Duchess. `I make you a present of everything I've said as yet.' `A cheap sort of present!' thought Alice. `I'm glad they don't give birthday presents like that!' But she did not venture to say it out loud. `Thinking again?' the Duchess asked, with another dig of her sharp little chin. `I've a right to think,' said Alice sharply, for she was beginning to feel a little worried. `Just about as much right,' said the Duchess, `as pigs have to fly; and the m--' But here, to Alice's great surprise, the Duchess's voice died away, even in the middle of her favourite word `moral,' and the arm that was linked into hers began to tremble. Alice looked up, and there stood the Queen in front of them, with her arms folded, frowning like a thunderstorm. `A fine day, your Majesty!' the Duchess began in a low, weak voice. `Now, I give you fair warning,' shouted the Queen, stamping on the ground as she spoke; `either you or your head must be off, and that in about half no time! Take your choice!' The Duchess took her choice, and was gone in a moment. `Let's go on with the game,' the Queen said to Alice; and Alice was too much frightened to say a word, but slowly followed her back to the croquet-ground. The other guests had taken advantage of the Queen's absence, and were resting in the shade: however, the moment they saw her, they hurried back to the game, the Queen merely remarking that a moment's delay would cost them their lives. All the time they were playing the Queen never left off quarrelling with the other players, and shouting `Off with his head!' or `Off with her head!' Those whom she sentenced were taken into custody by the soldiers, who of course had to leave off being arches to do this, so that by the end of half an hour or so there were no arches left, and all the players, except the King, the Queen, and Alice, were in custody and under sentence of execution. Then the Queen left off, quite out of breath, and said to Alice, `Have you seen the Mock Turtle yet?' `No,' said Alice. `I don't even know what a Mock Turtle is.' `It's the thing Mock Turtle Soup is made from,' said the Queen. `I never saw one, or heard of one,' said Alice. `Come on, then,' said the Queen, `and he shall tell you his history,' As they walked off together, Alice heard the King say in a low voice, to the company generally, `You are all pardoned.' `Come, THAT'S a good thing!' she said to herself, for she had felt quite unhappy at the number of executions the Queen had ordered. They very soon came upon a Gryphon, lying fast asleep in the sun. (IF you don't know what a Gryphon is, look at the picture.) `Up, lazy thing!' said the Queen, `and take this young lady to see the Mock Turtle, and to hear his history. I must go back and see after some executions I have ordered'; and she walked off, leaving Alice alone with the Gryphon. Alice did not quite like the look of the creature, but on the whole she thought it would be quite as safe to stay with it as to go after that savage Queen: so she waited. The Gryphon sat up and rubbed its eyes: then it watched the Queen till she was out of sight: then it chuckled. `What fun!' said the Gryphon, half to itself, half to Alice. `What IS the fun?' said Alice. `Why, SHE,' said the Gryphon. `It's all her fancy, that: they never executes nobody, you know. Come on!' `Everybody says "come on!" here,' thought Alice, as she went slowly after it: `I never was so ordered about in all my life, never!' They had not gone far before they saw the Mock Turtle in the distance, sitting sad and lonely on a little ledge of rock, and, as they came nearer, Alice could hear him sighing as if his heart would break. She pitied him deeply. `What is his sorrow?' she asked the Gryphon, and the Gryphon answered, very nearly in the same words as before, `It's all his fancy, that: he hasn't got no sorrow, you know. Come on!' So they went up to the Mock Turtle, who looked at them with large eyes full of tears, but said nothing. `This here young lady,' said the Gryphon, `she wants for to know your history, she do.' `I'll tell it her,' said the Mock Turtle in a deep, hollow tone: `sit down, both of you, and don't speak a word till I've finished.' So they sat down, and nobody spoke for some minutes. Alice thought to herself, `I don't see how he can EVEN finish, if he doesn't begin.' But she waited patiently. `Once,' said the Mock Turtle at last, with a deep sigh, `I was a real Turtle.' These words were followed by a very long silence, broken only by an occasional exclamation of `Hjckrrh!' from the Gryphon, and the constant heavy sobbing of the Mock Turtle. Alice was very nearly getting up and saying, `Thank you, sir, for your interesting story,' but she could not help thinking there MUST be more to come, so she sat still and said nothing. `When we were little,' the Mock Turtle went on at last, more calmly, though still sobbing a little now and then, `we went to school in the sea. The master was an old Turtle--we used to call him Tortoise--' `Why did you call him Tortoise, if he wasn't one?' Alice asked. `We called him Tortoise because he taught us,' said the Mock Turtle angrily: `really you are very dull!' `You ought to be ashamed of yourself for asking such a simple question,' added the Gryphon; and then they both sat silent and looked at poor Alice, who felt ready to sink into the earth. At last the Gryphon said to the Mock Turtle, `Drive on, old fellow! Don't be all day about it!' and he went on in these words: `Yes, we went to school in the sea, though you mayn't believe it--' `I never said I didn't!' interrupted Alice. `You did,' said the Mock Turtle. `Hold your tongue!' added the Gryphon, before Alice could speak again. The Mock Turtle went on. `We had the best of educations--in fact, we went to school every day--' `I'VE been to a day-school, too,' said Alice; `you needn't be so proud as all that.' `With extras?' asked the Mock Turtle a little anxiously. `Yes,' said Alice, `we learned French and music.' `And washing?' said the Mock Turtle. `Certainly not!' said Alice indignantly. `Ah! then yours wasn't a really good school,' said the Mock Turtle in a tone of great relief. `Now at OURS they had at the end of the bill, "French, music, AND WASHING--extra."' `You couldn't have wanted it much,' said Alice; `living at the bottom of the sea.' `I couldn't afford to learn it.' said the Mock Turtle with a sigh. `I only took the regular course.' `What was that?' inquired Alice. `Reeling and Writhing, of course, to begin with,' the Mock Turtle replied; `and then the different branches of Arithmetic-- Ambition, Distraction, Uglification, and Derision.' `I never heard of "Uglification,"' Alice ventured to say. `What is it?' The Gryphon lifted up both its paws in surprise. `What! Never heard of uglifying!' it exclaimed. `You know what to beautify is, I suppose?' `Yes,' said Alice doubtfully: `it means--to--make--anything--prettier.' `Well, then,' the Gryphon went on, `if you don't know what to uglify is, you ARE a simpleton.' Alice did not feel encouraged to ask any more questions about it, so she turned to the Mock Turtle, and said `What else had you to learn?' `Well, there was Mystery,' the Mock Turtle replied, counting off the subjects on his flappers, `--Mystery, ancient and modern, with Seaography: then Drawling--the Drawling-master was an old conger-eel, that used to come once a week: HE taught us Drawling, Stretching, and Fainting in Coils.' `What was THAT like?' said Alice. `Well, I can't show it you myself,' the Mock Turtle said: `I'm too stiff. And the Gryphon never learnt it.' `Hadn't time,' said the Gryphon: `I went to the Classics master, though. He was an old crab, HE was.' `I never went to him,' the Mock Turtle said with a sigh: `he taught Laughing and Grief, they used to say.' `So he did, so he did,' said the Gryphon, sighing in his turn; and both creatures hid their faces in their paws. `And how many hours a day did you do lessons?' said Alice, in a hurry to change the subject. `Ten hours the first day,' said the Mock Turtle: `nine the next, and so on.' `What a curious plan!' exclaimed Alice. `That's the reason they're called lessons,' the Gryphon remarked: `because they lessen from day to day.' This was quite a new idea to Alice, and she thought it over a little before she made her next remark. `Then the eleventh day must have been a holiday?' `Of course it was,' said the Mock Turtle. `And how did you manage on the twelfth?' Alice went on eagerly. `That's enough about lessons,' the Gryphon interrupted in a very decided tone: `tell her something about the games now.' CHAPTER X The Lobster Quadrille The Mock Turtle sighed deeply, and drew the back of one flapper across his eyes. He looked at Alice, and tried to speak, but for a minute or two sobs choked his voice. `Same as if he had a bone in his throat,' said the Gryphon: and it set to work shaking him and punching him in the back. At last the Mock Turtle recovered his voice, and, with tears running down his cheeks, he went on again:-- `You may not have lived much under the sea--' (`I haven't,' said Alice)-- `and perhaps you were never even introduced to a lobster--' (Alice began to say `I once tasted--' but checked herself hastily, and said `No, never') `--so you can have no idea what a delightful thing a Lobster Quadrille is!' `No, indeed,' said Alice. `What sort of a dance is it?' `Why,' said the Gryphon, `you first form into a line along the sea-shore--' `Two lines!' cried the Mock Turtle. `Seals, turtles, salmon, and so on; then, when you've cleared all the jelly-fish out of the way--' `THAT generally takes some time,' interrupted the Gryphon. `--you advance twice--' `Each with a lobster as a partner!' cried the Gryphon. `Of course,' the Mock Turtle said: `advance twice, set to partners--' `--change lobsters, and retire in same order,' continued the Gryphon. `Then, you know,' the Mock Turtle went on, `you throw the--' `The lobsters!' shouted the Gryphon, with a bound into the air. `--as far out to sea as you can--' `Swim after them!' screamed the Gryphon. `Turn a somersault in the sea!' cried the Mock Turtle, capering wildly about. `Change lobsters again!' yelled the Gryphon at the top of its voice. `Back to land again, and that's all the first figure,' said the Mock Turtle, suddenly dropping his voice; and the two creatures, who had been jumping about like mad things all this time, sat down again very sadly and quietly, and looked at Alice. `It must be a very pretty dance,' said Alice timidly. `Would you like to see a little of it?' said the Mock Turtle. `Very much indeed,' said Alice. `Come, let's try the first figure!' said the Mock Turtle to the Gryphon. `We can do without lobsters, you know. Which shall sing?' `Oh, YOU sing,' said the Gryphon. `I've forgotten the words.' So they began solemnly dancing round and round Alice, every now and then treading on her toes when they passed too close, and waving their forepaws to mark the time, while the Mock Turtle sang this, very slowly and sadly:-- `"Will you walk a little faster?" said a whiting to a snail. "There's a porpoise close behind us, and he's treading on my tail. See how eagerly the lobsters and the turtles all advance! They are waiting on the shingle--will you come and join the dance? Will you, won't you, will you, won't you, will you join the dance? Will you, won't you, will you, won't you, won't you join the dance? "You can really have no notion how delightful it will be When they take us up and throw us, with the lobsters, out to sea!" But the snail replied "Too far, too far!" and gave a look askance-- Said he thanked the whiting kindly, but he would not join the dance. Would not, could not, would not, could not, would not join the dance. Would not, could not, would not, could not, could not join the dance. `"What matters it how far we go?" his scaly friend replied. "There is another shore, you know, upon the other side. The further off from England the nearer is to France-- Then turn not pale, beloved snail, but come and join the dance. Will you, won't you, will you, won't you, will you join the dance? Will you, won't you, will you, won't you, won't you join the dance?"' `Thank you, it's a very interesting dance to watch,' said Alice, feeling very glad that it was over at last: `and I do so like that curious song about the whiting!' `Oh, as to the whiting,' said the Mock Turtle, `they--you've seen them, of course?' `Yes,' said Alice, `I've often seen them at dinn--' she checked herself hastily. `I don't know where Dinn may be,' said the Mock Turtle, `but if you've seen them so often, of course you know what they're like.' `I believe so,' Alice replied thoughtfully. `They have their tails in their mouths--and they're all over crumbs.' `You're wrong about the crumbs,' said the Mock Turtle: `crumbs would all wash off in the sea. But they HAVE their tails in their mouths; and the reason is--' here the Mock Turtle yawned and shut his eyes.--`Tell her about the reason and all that,' he said to the Gryphon. `The reason is,' said the Gryphon, `that they WOULD go with the lobsters to the dance. So they got thrown out to sea. So they had to fall a long way. So they got their tails fast in their mouths. So they couldn't get them out again. That's all.' `Thank you,' said Alice, `it's very interesting. I never knew so much about a whiting before.' `I can tell you more than that, if you like,' said the Gryphon. `Do you know why it's called a whiting?' `I never thought about it,' said Alice. `Why?' `IT DOES THE BOOTS AND SHOES.' the Gryphon replied very solemnly. Alice was thoroughly puzzled. `Does the boots and shoes!' she repeated in a wondering tone. `Why, what are YOUR shoes done with?' said the Gryphon. `I mean, what makes them so shiny?' Alice looked down at them, and considered a little before she gave her answer. `They're done with blacking, I believe.' `Boots and shoes under the sea,' the Gryphon went on in a deep voice, `are done with a whiting. Now you know.' `And what are they made of?' Alice asked in a tone of great curiosity. `Soles and eels, of course,' the Gryphon replied rather impatiently: `any shrimp could have told you that.' `If I'd been the whiting,' said Alice, whose thoughts were still running on the song, `I'd have said to the porpoise, "Keep back, please: we don't want YOU with us!"' `They were obliged to have him with them,' the Mock Turtle said: `no wise fish would go anywhere without a porpoise.' `Wouldn't it really?' said Alice in a tone of great surprise. `Of course not,' said the Mock Turtle: `why, if a fish came to ME, and told me he was going a journey, I should say "With what porpoise?"' `Don't you mean "purpose"?' said Alice. `I mean what I say,' the Mock Turtle replied in an offended tone. And the Gryphon added `Come, let's hear some of YOUR adventures.' `I could tell you my adventures--beginning from this morning,' said Alice a little timidly: `but it's no use going back to yesterday, because I was a different person then.' `Explain all that,' said the Mock Turtle. `No, no! The adventures first,' said the Gryphon in an impatient tone: `explanations take such a dreadful time.' So Alice began telling them her adventures from the time when she first saw the White Rabbit. She was a little nervous about it just at first, the two creatures got so close to her, one on each side, and opened their eyes and mouths so VERY wide, but she gained courage as she went on. Her listeners were perfectly quiet till she got to the part about her repeating `YOU ARE OLD, FATHER WILLIAM,' to the Caterpillar, and the words all coming different, and then the Mock Turtle drew a long breath, and said `That's very curious.' `It's all about as curious as it can be,' said the Gryphon. `It all came different!' the Mock Turtle repeated thoughtfully. `I should like to hear her try and repeat something now. Tell her to begin.' He looked at the Gryphon as if he thought it had some kind of authority over Alice. `Stand up and repeat "'TIS THE VOICE OF THE SLUGGARD,"' said the Gryphon. `How the creatures order one about, and make one repeat lessons!' thought Alice; `I might as well be at school at once.' However, she got up, and began to repeat it, but her head was so full of the Lobster Quadrille, that she hardly knew what she was saying, and the words came very queer indeed:-- `'Tis the voice of the Lobster; I heard him declare, "You have baked me too brown, I must sugar my hair." As a duck with its eyelids, so he with his nose Trims his belt and his buttons, and turns out his toes.' [later editions continued as follows When the sands are all dry, he is gay as a lark, And will talk in contemptuous tones of the Shark, But, when the tide rises and sharks are around, His voice has a timid and tremulous sound.] `That's different from what I used to say when I was a child,' said the Gryphon. `Well, I never heard it before,' said the Mock Turtle; `but it sounds uncommon nonsense.' Alice said nothing; she had sat down with her face in her hands, wondering if anything would EVER happen in a natural way again. `I should like to have it explained,' said the Mock Turtle. `She can't explain it,' said the Gryphon hastily. `Go on with the next verse.' `But about his toes?' the Mock Turtle persisted. `How COULD he turn them out with his nose, you know?' `It's the first position in dancing.' Alice said; but was dreadfully puzzled by the whole thing, and longed to change the subject. `Go on with the next verse,' the Gryphon repeated impatiently: `it begins "I passed by his garden."' Alice did not dare to disobey, though she felt sure it would all come wrong, and she went on in a trembling voice:-- `I passed by his garden, and marked, with one eye, How the Owl and the Panther were sharing a pie--' [later editions continued as follows The Panther took pie-crust, and gravy, and meat, While the Owl had the dish as its share of the treat. When the pie was all finished, the Owl, as a boon, Was kindly permitted to pocket the spoon: While the Panther received knife and fork with a growl, And concluded the banquet--] `What IS the use of repeating all that stuff,' the Mock Turtle interrupted, `if you don't explain it as you go on? It's by far the most confusing thing I ever heard!' `Yes, I think you'd better leave off,' said the Gryphon: and Alice was only too glad to do so. `Shall we try another figure of the Lobster Quadrille?' the Gryphon went on. `Or would you like the Mock Turtle to sing you a song?' `Oh, a song, please, if the Mock Turtle would be so kind,' Alice replied, so eagerly that the Gryphon said, in a rather offended tone, `Hm! No accounting for tastes! Sing her "Turtle Soup," will you, old fellow?' The Mock Turtle sighed deeply, and began, in a voice sometimes choked with sobs, to sing this:-- `Beautiful Soup, so rich and green, Waiting in a hot tureen! Who for such dainties would not stoop? Soup of the evening, beautiful Soup! Soup of the evening, beautiful Soup! Beau--ootiful Soo--oop! Beau--ootiful Soo--oop! Soo--oop of the e--e--evening, Beautiful, beautiful Soup! `Beautiful Soup! Who cares for fish, Game, or any other dish? Who would not give all else for two Pennyworth only of beautiful Soup? Pennyworth only of beautiful Soup? Beau--ootiful Soo--oop! Beau--ootiful Soo--oop! Soo--oop of the e--e--evening, Beautiful, beauti--FUL SOUP!' `Chorus again!' cried the Gryphon, and the Mock Turtle had just begun to repeat it, when a cry of `The trial's beginning!' was heard in the distance. `Come on!' cried the Gryphon, and, taking Alice by the hand, it hurried off, without waiting for the end of the song. `What trial is it?' Alice panted as she ran; but the Gryphon only answered `Come on!' and ran the faster, while more and more faintly came, carried on the breeze that followed them, the melancholy words:-- `Soo--oop of the e--e--evening, Beautiful, beautiful Soup!' CHAPTER XI Who Stole the Tarts? The King and Queen of Hearts were seated on their throne when they arrived, with a great crowd assembled about them--all sorts of little birds and beasts, as well as the whole pack of cards: the Knave was standing before them, in chains, with a soldier on each side to guard him; and near the King was the White Rabbit, with a trumpet in one hand, and a scroll of parchment in the other. In the very middle of the court was a table, with a large dish of tarts upon it: they looked so good, that it made Alice quite hungry to look at them--`I wish they'd get the trial done,' she thought, `and hand round the refreshments!' But there seemed to be no chance of this, so she began looking at everything about her, to pass away the time. Alice had never been in a court of justice before, but she had read about them in books, and she was quite pleased to find that she knew the name of nearly everything there. `That's the judge,' she said to herself, `because of his great wig.' The judge, by the way, was the King; and as he wore his crown over the wig, (look at the frontispiece if you want to see how he did it,) he did not look at all comfortable, and it was certainly not becoming. `And that's the jury-box,' thought Alice, `and those twelve creatures,' (she was obliged to say `creatures,' you see, because some of them were animals, and some were birds,) `I suppose they are the jurors.' She said this last word two or three times over to herself, being rather proud of it: for she thought, and rightly too, that very few little girls of her age knew the meaning of it at all. However, `jury-men' would have done just as well. The twelve jurors were all writing very busily on slates. `What are they doing?' Alice whispered to the Gryphon. `They can't have anything to put down yet, before the trial's begun.' `They're putting down their names,' the Gryphon whispered in reply, `for fear they should forget them before the end of the trial.' `Stupid things!' Alice began in a loud, indignant voice, but she stopped hastily, for the White Rabbit cried out, `Silence in the court!' and the King put on his spectacles and looked anxiously round, to make out who was talking. Alice could see, as well as if she were looking over their shoulders, that all the jurors were writing down `stupid things!' on their slates, and she could even make out that one of them didn't know how to spell `stupid,' and that he had to ask his neighbour to tell him. `A nice muddle their slates'll be in before the trial's over!' thought Alice. One of the jurors had a pencil that squeaked. This of course, Alice could not stand, and she went round the court and got behind him, and very soon found an opportunity of taking it away. She did it so quickly that the poor little juror (it was Bill, the Lizard) could not make out at all what had become of it; so, after hunting all about for it, he was obliged to write with one finger for the rest of the day; and this was of very little use, as it left no mark on the slate. `Herald, read the accusation!' said the King. On this the White Rabbit blew three blasts on the trumpet, and then unrolled the parchment scroll, and read as follows:-- `The Queen of Hearts, she made some tarts, All on a summer day: The Knave of Hearts, he stole those tarts, And took them quite away!' `Consider your verdict,' the King said to the jury. `Not yet, not yet!' the Rabbit hastily interrupted. `There's a great deal to come before that!' `Call the first witness,' said the King; and the White Rabbit blew three blasts on the trumpet, and called out, `First witness!' The first witness was the Hatter. He came in with a teacup in one hand and a piece of bread-and-butter in the other. `I beg pardon, your Majesty,' he began, `for bringing these in: but I hadn't quite finished my tea when I was sent for.' `You ought to have finished,' said the King. `When did you begin?' The Hatter looked at the March Hare, who had followed him into the court, arm-in-arm with the Dormouse. `Fourteenth of March, I think it was,' he said. `Fifteenth,' said the March Hare. `Sixteenth,' added the Dormouse. `Write that down,' the King said to the jury, and the jury eagerly wrote down all three dates on their slates, and then added them up, and reduced the answer to shillings and pence. `Take off your hat,' the King said to the Hatter. `It isn't mine,' said the Hatter. `Stolen!' the King exclaimed, turning to the jury, who instantly made a memorandum of the fact. `I keep them to sell,' the Hatter added as an explanation; `I've none of my own. I'm a hatter.' Here the Queen put on her spectacles, and began staring at the Hatter, who turned pale and fidgeted. `Give your evidence,' said the King; `and don't be nervous, or I'll have you executed on the spot.' This did not seem to encourage the witness at all: he kept shifting from one foot to the other, looking uneasily at the Queen, and in his confusion he bit a large piece out of his teacup instead of the bread-and-butter. Just at this moment Alice felt a very curious sensation, which puzzled her a good deal until she made out what it was: she was beginning to grow larger again, and she thought at first she would get up and leave the court; but on second thoughts she decided to remain where she was as long as there was room for her. `I wish you wouldn't squeeze so.' said the Dormouse, who was sitting next to her. `I can hardly breathe.' `I can't help it,' said Alice very meekly: `I'm growing.' `You've no right to grow here,' said the Dormouse. `Don't talk nonsense,' said Alice more boldly: `you know you're growing too.' `Yes, but I grow at a reasonable pace,' said the Dormouse: `not in that ridiculous fashion.' And he got up very sulkily and crossed over to the other side of the court. All this time the Queen had never left off staring at the Hatter, and, just as the Dormouse crossed the court, she said to one of the officers of the court, `Bring me the list of the singers in the last concert!' on which the wretched Hatter trembled so, that he shook both his shoes off. `Give your evidence,' the King repeated angrily, `or I'll have you executed, whether you're nervous or not.' `I'm a poor man, your Majesty,' the Hatter began, in a trembling voice, `--and I hadn't begun my tea--not above a week or so--and what with the bread-and-butter getting so thin--and the twinkling of the tea--' `The twinkling of the what?' said the King. `It began with the tea,' the Hatter replied. `Of course twinkling begins with a T!' said the King sharply. `Do you take me for a dunce? Go on!' `I'm a poor man,' the Hatter went on, `and most things twinkled after that--only the March Hare said--' `I didn't!' the March Hare interrupted in a great hurry. `You did!' said the Hatter. `I deny it!' said the March Hare. `He denies it,' said the King: `leave out that part.' `Well, at any rate, the Dormouse said--' the Hatter went on, looking anxiously round to see if he would deny it too: but the Dormouse denied nothing, being fast asleep. `After that,' continued the Hatter, `I cut some more bread- and-butter--' `But what did the Dormouse say?' one of the jury asked. `That I can't remember,' said the Hatter. `You MUST remember,' remarked the King, `or I'll have you executed.' The miserable Hatter dropped his teacup and bread-and-butter, and went down on one knee. `I'm a poor man, your Majesty,' he began. `You're a very poor speaker,' said the King. Here one of the guinea-pigs cheered, and was immediately suppressed by the officers of the court. (As that is rather a hard word, I will just explain to you how it was done. They had a large canvas bag, which tied up at the mouth with strings: into this they slipped the guinea-pig, head first, and then sat upon it.) `I'm glad I've seen that done,' thought Alice. `I've so often read in the newspapers, at the end of trials, "There was some attempts at applause, which was immediately suppressed by the officers of the court," and I never understood what it meant till now.' `If that's all you know about it, you may stand down,' continued the King. `I can't go no lower,' said the Hatter: `I'm on the floor, as it is.' `Then you may SIT down,' the King replied. Here the other guinea-pig cheered, and was suppressed. `Come, that finished the guinea-pigs!' thought Alice. `Now we shall get on better.' `I'd rather finish my tea,' said the Hatter, with an anxious look at the Queen, who was reading the list of singers. `You may go,' said the King, and the Hatter hurriedly left the court, without even waiting to put his shoes on. `--and just take his head off outside,' the Queen added to one of the officers: but the Hatter was out of sight before the officer could get to the door. `Call the next witness!' said the King. The next witness was the Duchess's cook. She carried the pepper-box in her hand, and Alice guessed who it was, even before she got into the court, by the way the people near the door began sneezing all at once. `Give your evidence,' said the King. `Shan't,' said the cook. The King looked anxiously at the White Rabbit, who said in a low voice, `Your Majesty must cross-examine THIS witness.' `Well, if I must, I must,' the King said, with a melancholy air, and, after folding his arms and frowning at the cook till his eyes were nearly out of sight, he said in a deep voice, `What are tarts made of?' `Pepper, mostly,' said the cook. `Treacle,' said a sleepy voice behind her. `Collar that Dormouse,' the Queen shrieked out. `Behead that Dormouse! Turn that Dormouse out of court! Suppress him! Pinch him! Off with his whiskers!' For some minutes the whole court was in confusion, getting the Dormouse turned out, and, by the time they had settled down again, the cook had disappeared. `Never mind!' said the King, with an air of great relief. `Call the next witness.' And he added in an undertone to the Queen, `Really, my dear, YOU must cross-examine the next witness. It quite makes my forehead ache!' Alice watched the White Rabbit as he fumbled over the list, feeling very curious to see what the next witness would be like, `--for they haven't got much evidence YET,' she said to herself. Imagine her surprise, when the White Rabbit read out, at the top of his shrill little voice, the name `Alice!' CHAPTER XII Alice's Evidence `Here!' cried Alice, quite forgetting in the flurry of the moment how large she had grown in the last few minutes, and she jumped up in such a hurry that she tipped over the jury-box with the edge of her skirt, upsetting all the jurymen on to the heads of the crowd below, and there they lay sprawling about, reminding her very much of a globe of goldfish she had accidentally upset the week before. `Oh, I BEG your pardon!' she exclaimed in a tone of great dismay, and began picking them up again as quickly as she could, for the accident of the goldfish kept running in her head, and she had a vague sort of idea that they must be collected at once and put back into the jury-box, or they would die. `The trial cannot proceed,' said the King in a very grave voice, `until all the jurymen are back in their proper places-- ALL,' he repeated with great emphasis, looking hard at Alice as he said do. Alice looked at the jury-box, and saw that, in her haste, she had put the Lizard in head downwards, and the poor little thing was waving its tail about in a melancholy way, being quite unable to move. She soon got it out again, and put it right; `not that it signifies much,' she said to herself; `I should think it would be QUITE as much use in the trial one way up as the other.' As soon as the jury had a little recovered from the shock of being upset, and their slates and pencils had been found and handed back to them, they set to work very diligently to write out a history of the accident, all except the Lizard, who seemed too much overcome to do anything but sit with its mouth open, gazing up into the roof of the court. `What do you know about this business?' the King said to Alice. `Nothing,' said Alice. `Nothing WHATEVER?' persisted the King. `Nothing whatever,' said Alice. `That's very important,' the King said, turning to the jury. They were just beginning to write this down on their slates, when the White Rabbit interrupted: `UNimportant, your Majesty means, of course,' he said in a very respectful tone, but frowning and making faces at him as he spoke. `UNimportant, of course, I meant,' the King hastily said, and went on to himself in an undertone, `important--unimportant-- unimportant--important--' as if he were trying which word sounded best. Some of the jury wrote it down `important,' and some `unimportant.' Alice could see this, as she was near enough to look over their slates; `but it doesn't matter a bit,' she thought to herself. At this moment the King, who had been for some time busily writing in his note-book, cackled out `Silence!' and read out from his book, `Rule Forty-two. ALL PERSONS MORE THAN A MILE HIGH TO LEAVE THE COURT.' Everybody looked at Alice. `I'M not a mile high,' said Alice. `You are,' said the King. `Nearly two miles high,' added the Queen. `Well, I shan't go, at any rate,' said Alice: `besides, that's not a regular rule: you invented it just now.' `It's the oldest rule in the book,' said the King. `Then it ought to be Number One,' said Alice. The King turned pale, and shut his note-book hastily. `Consider your verdict,' he said to the jury, in a low, trembling voice. `There's more evidence to come yet, please your Majesty,' said the White Rabbit, jumping up in a great hurry; `this paper has just been picked up.' `What's in it?' said the Queen. `I haven't opened it yet,' said the White Rabbit, `but it seems to be a letter, written by the prisoner to--to somebody.' `It must have been that,' said the King, `unless it was written to nobody, which isn't usual, you know.' `Who is it directed to?' said one of the jurymen. `It isn't directed at all,' said the White Rabbit; `in fact, there's nothing written on the OUTSIDE.' He unfolded the paper as he spoke, and added `It isn't a letter, after all: it's a set of verses.' `Are they in the prisoner's handwriting?' asked another of the jurymen. `No, they're not,' said the White Rabbit, `and that's the queerest thing about it.' (The jury all looked puzzled.) `He must have imitated somebody else's hand,' said the King. (The jury all brightened up again.) `Please your Majesty,' said the Knave, `I didn't write it, and they can't prove I did: there's no name signed at the end.' `If you didn't sign it,' said the King, `that only makes the matter worse. You MUST have meant some mischief, or else you'd have signed your name like an honest man.' There was a general clapping of hands at this: it was the first really clever thing the King had said that day. `That PROVES his guilt,' said the Queen. `It proves nothing of the sort!' said Alice. `Why, you don't even know what they're about!' `Read them,' said the King. The White Rabbit put on his spectacles. `Where shall I begin, please your Majesty?' he asked. `Begin at the beginning,' the King said gravely, `and go on till you come to the end: then stop.' These were the verses the White Rabbit read:-- `They told me you had been to her, And mentioned me to him: She gave me a good character, But said I could not swim. He sent them word I had not gone (We know it to be true): If she should push the matter on, What would become of you? I gave her one, they gave him two, You gave us three or more; They all returned from him to you, Though they were mine before. If I or she should chance to be Involved in this affair, He trusts to you to set them free, Exactly as we were. My notion was that you had been (Before she had this fit) An obstacle that came between Him, and ourselves, and it. Don't let him know she liked them best, For this must ever be A secret, kept from all the rest, Between yourself and me.' `That's the most important piece of evidence we've heard yet,' said the King, rubbing his hands; `so now let the jury--' `If any one of them can explain it,' said Alice, (she had grown so large in the last few minutes that she wasn't a bit afraid of interrupting him,) `I'll give him sixpence. _I_ don't believe there's an atom of meaning in it.' The jury all wrote down on their slates, `SHE doesn't believe there's an atom of meaning in it,' but none of them attempted to explain the paper. `If there's no meaning in it,' said the King, `that saves a world of trouble, you know, as we needn't try to find any. And yet I don't know,' he went on, spreading out the verses on his knee, and looking at them with one eye; `I seem to see some meaning in them, after all. "--SAID I COULD NOT SWIM--" you can't swim, can you?' he added, turning to the Knave. The Knave shook his head sadly. `Do I look like it?' he said. (Which he certainly did NOT, being made entirely of cardboard.) `All right, so far,' said the King, and he went on muttering over the verses to himself: `"WE KNOW IT TO BE TRUE--" that's the jury, of course-- "I GAVE HER ONE, THEY GAVE HIM TWO--" why, that must be what he did with the tarts, you know--' `But, it goes on "THEY ALL RETURNED FROM HIM TO YOU,"' said Alice. `Why, there they are!' said the King triumphantly, pointing to the tarts on the table. `Nothing can be clearer than THAT. Then again--"BEFORE SHE HAD THIS FIT--" you never had fits, my dear, I think?' he said to the Queen. `Never!' said the Queen furiously, throwing an inkstand at the Lizard as she spoke. (The unfortunate little Bill had left off writing on his slate with one finger, as he found it made no mark; but he now hastily began again, using the ink, that was trickling down his face, as long as it lasted.) `Then the words don't FIT you,' said the King, looking round the court with a smile. There was a dead silence. `It's a pun!' the King added in an offended tone, and everybody laughed, `Let the jury consider their verdict,' the King said, for about the twentieth time that day. `No, no!' said the Queen. `Sentence first--verdict afterwards.' `Stuff and nonsense!' said Alice loudly. `The idea of having the sentence first!' `Hold your tongue!' said the Queen, turning purple. `I won't!' said Alice. `Off with her head!' the Queen shouted at the top of her voice. Nobody moved. `Who cares for you?' said Alice, (she had grown to her full size by this time.) `You're nothing but a pack of cards!' At this the whole pack rose up into the air, and came flying down upon her: she gave a little scream, half of fright and half of anger, and tried to beat them off, and found herself lying on the bank, with her head in the lap of her sister, who was gently brushing away some dead leaves that had fluttered down from the trees upon her face. `Wake up, Alice dear!' said her sister; `Why, what a long sleep you've had!' `Oh, I've had such a curious dream!' said Alice, and she told her sister, as well as she could remember them, all these strange Adventures of hers that you have just been reading about; and when she had finished, her sister kissed her, and said, `It WAS a curious dream, dear, certainly: but now run in to your tea; it's getting late.' So Alice got up and ran off, thinking while she ran, as well she might, what a wonderful dream it had been. But her sister sat still just as she left her, leaning her head on her hand, watching the setting sun, and thinking of little Alice and all her wonderful Adventures, till she too began dreaming after a fashion, and this was her dream:-- First, she dreamed of little Alice herself, and once again the tiny hands were clasped upon her knee, and the bright eager eyes were looking up into hers--she could hear the very tones of her voice, and see that queer little toss of her head to keep back the wandering hair that WOULD always get into her eyes--and still as she listened, or seemed to listen, the whole place around her became alive the strange creatures of her little sister's dream. The long grass rustled at her feet as the White Rabbit hurried by--the frightened Mouse splashed his way through the neighbouring pool--she could hear the rattle of the teacups as the March Hare and his friends shared their never-ending meal, and the shrill voice of the Queen ordering off her unfortunate guests to execution--once more the pig-baby was sneezing on the Duchess's knee, while plates and dishes crashed around it--once more the shriek of the Gryphon, the squeaking of the Lizard's slate-pencil, and the choking of the suppressed guinea-pigs, filled the air, mixed up with the distant sobs of the miserable Mock Turtle. So she sat on, with closed eyes, and half believed herself in Wonderland, though she knew she had but to open them again, and all would change to dull reality--the grass would be only rustling in the wind, and the pool rippling to the waving of the reeds--the rattling teacups would change to tinkling sheep- bells, and the Queen's shrill cries to the voice of the shepherd boy--and the sneeze of the baby, the shriek of the Gryphon, and all thy other queer noises, would change (she knew) to the confused clamour of the busy farm-yard--while the lowing of the cattle in the distance would take the place of the Mock Turtle's heavy sobs. Lastly, she pictured to herself how this same little sister of hers would, in the after-time, be herself a grown woman; and how she would keep, through all her riper years, the simple and loving heart of her childhood: and how she would gather about her other little children, and make THEIR eyes bright and eager with many a strange tale, perhaps even with the dream of Wonderland of long ago: and how she would feel with all their simple sorrows, and find a pleasure in all their simple joys, remembering her own child-life, and the happy summer days. THE END  ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/cabi2.cpp ================================================ #include #include #include #if __cplusplus extern "C" { #endif struct Foo1 { char c; }; struct Foo1 ctest1() { struct Foo1 f; f.c = 3; return f; } struct Foo2 { short s; }; struct Foo2 ctest2() { struct Foo2 f; f.s = 0x1234; return f; } struct Foo3 { char c; short s; }; struct Foo3 ctest3() { struct Foo3 f; f.s = 0x5678; return f; } struct Foo4 { int i; }; struct Foo4 ctest4() { struct Foo4 f; f.i = 0x12345678; return f; } struct Foo5 { int i, j; }; struct Foo5 ctest5() { struct Foo5 f; f.i = 0x12345678; f.j = 0x21436587; return f; } struct Foo6 { int i, j, k; }; struct Foo6 ctest6() { struct Foo6 f; f.i = 0x12345678; f.j = 0x21463587; f.k = 0x24163857; return f; } struct S7 { float a,b; }; struct S7 ctest10() { struct S7 f; f.a = 2.5; f.b = 1.5; return f; } // ================================= char ctest7(char c) { return c + 1; } unsigned char ctest8(unsigned char c) { return c + 1; } signed char ctest9(signed char c) { return c + 1; } /***********************************************/ void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c) { assert(a == 100.0); assert(b == 67); assert(c == 200.0); } /***********************************************/ extern void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c); void test4() { dtestrir(1,2,3,4,5,6, 300.0, 68, 401.0); } /**********************************************/ typedef struct S11 { char a; char b; char c; } S11; S11 ctest11(char x, S11 s, char y) { printf("C sz = %d\n", (int)sizeof(S11)); assert(sizeof(S11) == 3); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S12 { char a,d; char b,e; char c; } S12; S12 ctest12(char x, S12 s, char y) { printf("C sz = %d\n", (int)sizeof(S12)); assert(sizeof(S12) == 5); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S13 { short a; short b; short c; } S13; S13 ctest13(char x, S13 s, char y) { printf("C sz = %d\n", (int)sizeof(S13)); assert(sizeof(S13) == 6); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S14 { char a,d,e,f; char b,g; char c; } S14; S14 ctest14(char x, S14 s, char y) { printf("C sz = %d\n", (int)sizeof(S14)); assert(sizeof(S14) == 7); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S15 { char a,d,e,f; char b,g,h,i; char c; } S15; S15 ctest15(char x, S15 s, char y) { printf("C sz = %d\n", (int)sizeof(S15)); assert(sizeof(S15) == 9); printf("x = %d\n", (int)x); printf("s.a = %d\n", (int)s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", (int)s.c); printf("y = %d\n", (int)y); return s; } /**********************************************/ typedef struct S16 { char a[5]; #ifdef __GNUC__ struct __attribute__((packed)) #else #pragma pack(push, 1) struct #endif { char b; int c; }; #ifndef __GNUC__ #pragma pack(pop) #endif } S16; S16 ctest16(char x, S16 s, char y) { printf("C sz = %d\n", (int)sizeof(S16)); assert(sizeof(S16) == 10); printf("x = %d\n", (int)x); printf("s.a = %.*s\n", 5, s.a); printf("s.b = %d\n", (int)s.b); printf("s.c = %d\n", s.c); printf("y = %d\n", (int)y); return s; } #if __cplusplus } #endif ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/cpp_abi_tests.cpp ================================================ struct S{ float a; }; namespace std { struct test19248 {int a;}; }; bool passthrough(bool value) { return value; } signed char passthrough(signed char value) { return value; } unsigned char passthrough(unsigned char value) { return value; } char passthrough(char value) { return value; } wchar_t passthrough(wchar_t value) { return value; } short passthrough(short value) { return value; } unsigned short passthrough(unsigned short value) { return value; } int passthrough(int value) { return value; } unsigned int passthrough(unsigned int value) { return value; } long passthrough(long value) { return value; } unsigned long passthrough(unsigned long value) { return value; } long long passthrough(long long value) { return value; } unsigned long long passthrough(unsigned long long value) { return value; } float passthrough(float value) { return value; } double passthrough(double value) { return value; } S passthrough(S value) { return value; } std::test19248 passthrough(const std::test19248 value) { return value; } bool passthrough_ptr(bool *value) { return *value; } signed char passthrough_ptr(signed char *value) { return *value; } unsigned char passthrough_ptr(unsigned char *value) { return *value; } char passthrough_ptr(char *value) { return *value; } wchar_t passthrough_ptr(wchar_t *value) { return *value; } short passthrough_ptr(short *value) { return *value; } unsigned short passthrough_ptr(unsigned short *value) { return *value; } int passthrough_ptr(int *value) { return *value; } unsigned int passthrough_ptr(unsigned int *value) { return *value; } long passthrough_ptr(long *value) { return *value; } unsigned long passthrough_ptr(unsigned long *value) { return *value; } long long passthrough_ptr(long long *value) { return *value; } unsigned long long passthrough_ptr(unsigned long long *value) { return *value; } float passthrough_ptr(float *value) { return *value; } double passthrough_ptr(double *value) { return *value; } S passthrough_ptr(S *value) { return *value; } std::test19248 passthrough_ptr(const std::test19248 *value) { return *value; } bool passthrough_ref(bool &value) { return value; } signed char passthrough_ref(signed char &value) { return value; } unsigned char passthrough_ref(unsigned char &value) { return value; } char passthrough_ref(char &value) { return value; } wchar_t passthrough_ref(wchar_t &value) { return value; } short passthrough_ref(short &value) { return value; } unsigned short passthrough_ref(unsigned short &value) { return value; } int passthrough_ref(int &value) { return value; } unsigned int passthrough_ref(unsigned int &value) { return value; } long passthrough_ref(long &value) { return value; } unsigned long passthrough_ref(unsigned long &value) { return value; } long long passthrough_ref(long long &value) { return value; } unsigned long long passthrough_ref(unsigned long long &value) { return value; } float passthrough_ref(float &value) { return value; } double passthrough_ref(double &value) { return value; } S passthrough_ref(S &value) { return value; } std::test19248 passthrough_ref(const std::test19248 &value) { return value; } // Uncomment when mangling is fixed // typedef void(*fn0)(); // fn0 passthrough_fn0 (fn0 value) { return value; } // typedef int (*fn1)(int); // fn1 passthrough_fn1 (fn1 value) { return value; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/cpp_stdlib.cpp ================================================ #include #include #include template T& identity (T& v) { return v; } template T** identityPP (T** v) { return v; } template std::vector* getVector(size_t len, const T* ptr) { std::vector* ret = new std::vector(len); for (size_t i = 0; i < len; ++i) (*ret)[i] = ptr[i]; return ret; } std::string* getString(int len, const char* ptr) { return new std::string(ptr, len); } template std::array* getArray(const T* ptr) { std::array* ret = new std::array(); for (size_t x = 0; x < N; ++x) (*ret)[x] = ptr[x]; return ret; } // This function should never be called void instantiate () { int i; float f; int* pi; float* pf; identityPP(&pi); identityPP(&pf); identity(i); identity(f); getVector(0, 0); getVector(0, 0); getVector >(0, 0); getArray(0); getArray(0); //getArray, 4>(0); } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/cppb.cpp ================================================ /* GCC 5.1 introduced new implementations of std::string and std::list: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html This causes e.g. std::string to be actually defined as std::__cxx11::string. On machines with GCC 5.1, this manifests as a linker error when running the cppa.d / cppb.cpp test: cppa.o: In function `_D4cppa6test14FZv': cppa.d:(.text._D4cppa6test14FZv+0x11): undefined reference to `foo14a(std::string*)' cppa.d:(.text._D4cppa6test14FZv+0x18): undefined reference to `foo14b(std::basic_string, std::allocator >*)' cppa.d:(.text._D4cppa6test14FZv+0x3a): undefined reference to `foo14f(std::char_traits*, std::string*, std::string*)' cppa.o: In function `_D4cppa7testeh3FZv': cppa.d:(.text._D4cppa7testeh3FZv+0x19): undefined reference to `throwle()' collect2: error: ld returned 1 exit status --- errorlevel 1 When the .cpp file is compiled with g++ 5.3.0, the actual function signatures in the cppb.o object file are: foo14a(std::__cxx11::basic_string, std::allocator >*) foo14b(std::__cxx11::basic_string, std::allocator >*) foo14f(std::char_traits*, std::__cxx11::basic_string, std::allocator >*, std::__cxx11::basic_string, std::allocator >*) Fortunately, it is easily possible to disable the new feature by defining _GLIBCXX_USE_CXX11_ABI as 0 before including any standard headers. */ #define _GLIBCXX_USE_CXX11_ABI 0 #include #include #include #include #include #include "cppb.h" /**************************************/ int foo(int i, int j, int k); int foob(int i, int j, int k) { printf("i = %d\n", i); printf("j = %d\n", j); printf("k = %d\n", k); assert(i == 1); assert(j == 2); assert(k == 3); foo(i, j, k); return 7; } /**************************************/ class D *dthis; class D { public: virtual int bar(int i, int j, int k) { printf("this = %p\n", this); assert(this == dthis); printf("D.bar: i = %d\n", i); printf("D.bar: j = %d\n", j); printf("D.bar: k = %d\n", k); assert(i == 9); assert(j == 10); assert(k == 11); return 8; } }; D* getD() { D *d = new D(); dthis = d; return d; } /**************************************/ class E { public: virtual int bar(int i, int j, int k); }; int callE(E *e) { return e->bar(11,12,13); } /**************************************/ void foo4(char *p) { } /**************************************/ struct foo5 { int i; int j; void *p; }; class bar5 { public: virtual foo5 getFoo(int i){ printf("This = %p\n", this); foo5 f; f.i = 1; f.j = 2 + i; f.p = (void*)this; return f; } }; bar5* newBar() { bar5* b = new bar5(); printf("bar = %p\n", b); return b; } /**************************************/ struct A11802; struct B11802; class C11802 { public: virtual void fun(A11802 *); virtual void fun(B11802 *); }; class D11802 : public C11802 { public: void fun(A11802 *); void fun(B11802 *); }; void test11802x(D11802 *c) { c->fun((A11802 *)0); c->fun((B11802 *)0); } /**************************************/ typedef struct { int i; double d; } S6; union S6_2 { int i; double d; }; enum S6_3 { A, B }; S6 foo6(void) { S6 s; s.i = 42; s.d = 2.5; return s; } S6_2 foo6_2(void) { S6_2 s; s.i = 42; return s; } S6_3 foo6_3(void) { S6_3 s = A; return s; } extern "C" { int foosize6() { return sizeof(S6); } } /**************************************/ typedef struct { int i; long long d; } S7; extern "C" { int foo7() { return sizeof(S7); } } /**************************************/ struct S13955a { float a; double b; }; struct S13955b { double a; float b; }; struct S13955c { float a; float b; }; struct S13955d { double a; double b; }; void check13955(S13955a a, S13955b b, S13955c c, S13955d d); void func13955(S13955a a, S13955b b, S13955c c, S13955d d) { check13955(a, b, c, d); } /**************************************/ struct Struct10071 { void *p; long double r; }; size_t offset10071() { Struct10071 s; return (char *)&s.r - (char *)&s; } /**************************************/ void foo8(const char *p) { } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=4059 struct elem9 { }; void foobar9(elem9*, elem9*) { } /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=5148 void foo10(const char*, const char*) { } void foo10(const int, const int) { } void foo10(const char, const char) { } void foo10(bool, bool) { } struct MyStructType { }; void foo10(const MyStructType s, const MyStructType t) { } enum MyEnumType { onemember }; void foo10(const MyEnumType s, const MyEnumType t) { } /**************************************/ namespace N11 { namespace M { void bar11() { } } } namespace A11 { namespace B { namespace C { void bar() { } } } } /**************************************/ void myvprintfx(const char* format, va_list); void myvprintf(const char* format, va_list va) { myvprintfx(format, va); } /**************************************/ class C13161 { public: virtual void dummyfunc() {} long long val_5; unsigned val_9; }; class Test : public C13161 { public: unsigned val_0; long long val_1; }; size_t getoffset13161() { Test s; return (char *)&s.val_0 - (char *)&s; } class C13161a { public: virtual void dummyfunc() {} long double val_5; unsigned val_9; }; class Testa : public C13161a { public: bool val_0; }; size_t getoffset13161a() { Testa s; return (char *)&s.val_0 - (char *)&s; } /****************************************************/ #if __linux__ || __APPLE__ || __FreeBSD__ || __DragonFly__ #include #include #include #if __linux__ template struct std::allocator; template struct std::vector; void foo15() { std::allocator* p; p->deallocate(0, 0); } #endif // _Z5foo14PSt6vectorIiSaIiEE void foo14(std::vector > *p) { } void foo14a(std::basic_string *p) { } void foo14b(std::basic_string *p) { } void foo14c(std::basic_istream *p) { } void foo14d(std::basic_ostream *p) { } void foo14e(std::basic_iostream *p) { } void foo14f(std::char_traits* x, std::basic_string *p, std::basic_string *q) { } #endif /**************************************/ struct S13956 { }; void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { check13956(arg0, arg1, arg2, arg3, arg4, arg5, arg6); } /**************************************/ wchar_t f13289_cpp_wchar_t(wchar_t ch) { if (ch <= L'z' && ch >= L'a') { return ch - (L'a' - L'A'); } else { return ch; } } #if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ || __DragonFly__ unsigned short f13289_d_wchar(unsigned short ch); wchar_t f13289_d_dchar(wchar_t ch); #elif _WIN32 wchar_t f13289_d_wchar(wchar_t ch); unsigned int f13289_d_dchar(unsigned int ch); #endif bool f13289_cpp_test() { #if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ || __DragonFly__ if (!(f13289_d_wchar((unsigned short)'c') == (unsigned short)'C')) return false; if (!(f13289_d_wchar((unsigned short)'D') == (unsigned short)'D')) return false; if (!(f13289_d_dchar(L'e') == L'E')) return false; if (!(f13289_d_dchar(L'F') == L'F')) return false; return true; #elif _WIN32 if (!(f13289_d_wchar(L'c') == L'C')) return false; if (!(f13289_d_wchar(L'D') == L'D')) return false; if (!(f13289_d_dchar((unsigned int)'e') == (unsigned int)'E')) return false; if (!(f13289_d_dchar((unsigned int)'F') == (unsigned int)'F')) return false; return true; #else return false; #endif } /******************************************/ long double testld(long double ld) { assert(ld == 5); return ld + 1; } long testl(long lng) { assert(lng == 5); return lng + sizeof(long); } unsigned long testul(unsigned long ul) { assert(ul == 5); return ul + sizeof(unsigned long); } /******************************************/ struct S13707 { void* a; void* b; S13707(void *a, void* b) { this->a = a; this->b = b; } }; S13707 func13707() { S13707 pt(NULL, NULL); return pt; } /******************************************/ template struct S13932 { int member; }; void func13932(S13932<-1> s) {} /******************************************/ namespace N13337 { namespace M13337 { struct S13337 { }; void foo13337(S13337 s) { } } } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=14195 template struct Delegate1 {}; template struct Delegate1 < R1() > {}; template struct Delegate2 {}; template < typename R1, typename T1, typename T2, typename R2, typename T3, typename T4 > struct Delegate2 {}; void test14195a(Delegate1 func) {} void test14195b(Delegate2 func) {} /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=14200 void test14200a(int a) {}; void test14200b(float a, int b, double c) {}; /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=14956 namespace std { namespace N14956 { struct S14956 { }; } } void test14956(std::N14956::S14956 s) { } /******************************************/ // check order of overloads in vtable class Statement; class ErrorStatement; class PeelStatement; class ExpStatement; class DtorExpStatement; class Visitor { public: virtual int visit(Statement*) { return 1; } virtual int visit(ErrorStatement*) { return 2; } virtual int visit(PeelStatement*) { return 3; } }; class Visitor2 : public Visitor { public: virtual int visit2(ExpStatement*) { return 4; } virtual int visit2(DtorExpStatement*) { return 5; } }; bool testVtableCpp(Visitor2* sv) { if (sv->visit((Statement*)0) != 1) return false; if (sv->visit((ErrorStatement*)0) != 2) return false; if (sv->visit((PeelStatement*)0) != 3) return false; if (sv->visit2((ExpStatement*)0) != 4) return false; if (sv->visit2((DtorExpStatement*)0) != 5) return false; return true; } Visitor2 inst; Visitor2* getVisitor2() { return &inst; } /******************************************/ // issues detected by fuzzer void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12); void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12) { fuzz1_checkValues(arg10, arg11, arg12); } void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12); void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12) { fuzz2_checkValues(arg10, arg11, arg12); } #if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ || __DragonFly__ #define wchar unsigned short #elif _WIN32 #define wchar wchar_t #endif void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12); void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12) { fuzz3_checkValues(arg10, arg11, arg12); } /******************************************/ void throwit() { #if _WIN32 #else std::exception se; throw se; #endif } /******************************************/ #if linux #include void throwle() { std::logic_error le("test"); throw le; } #endif /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15579 /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15579 class Base { public: //virtual ~Base() {} virtual void base(); unsigned char x; }; class Interface { public: virtual int MethodCPP() = 0; virtual int MethodD() = 0; }; class Derived : public Base, public Interface { public: Derived(); short y; int MethodCPP(); #if _WIN32 || _WIN64 int MethodD(); virtual int Method(); #else int MethodD() { return 3; } // need def or vtbl[] is not generated virtual int Method() { return 6; } // need def or vtbl[] is not generated #endif }; void Base::base() { } int Derived::MethodCPP() { printf("Derived::MethodCPP() this = %p, x = %d, y = %d\n", this, x, y); assert(x == 4 || x == 7); assert(y == 5 || y == 8); return 30; } Derived::Derived() { } Derived *cppfoo(Derived *d) { printf("cppfoo(): d = %p\n", d); assert(d->x == 4); assert(d->y == 5); assert(d->MethodD() == 3); assert(d->MethodCPP() == 30); assert(d->Method() == 6); d = new Derived(); d->x = 7; d->y = 8; assert(d->MethodD() == 3); assert(d->MethodCPP() == 30); assert(d->Method() == 6); printf("d1 = %p\n", d); return d; } Interface *cppfooi(Interface *i) { printf("cppfooi(): i = %p\n", i); assert(i->MethodD() == 3); assert(i->MethodCPP() == 30); Derived *d = new Derived(); d->x = 7; d->y = 8; printf("d = %p, i = %p\n", d, (Interface *)d); return d; } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15610 class Base2 { public: int i; virtual void baser() { } }; class Interface2 { public: virtual void f() = 0; }; class Derived2 : public Base2, public Interface2 { public: void f(); }; void Derived2::f() { printf("Derived2::f() this = %p i = %d\n", this, i); assert(i == 3); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15455 struct X6 { unsigned short a; unsigned short b; unsigned char c; unsigned char d; }; struct X8 { unsigned short a; X6 b; }; void test15455b(X8 s) { assert(sizeof(X6) == 6); assert(sizeof(X8) == 8); assert(s.a == 1); assert(s.b.a == 2); assert(s.b.b == 3); assert(s.b.c == 4); assert(s.b.d == 5); } /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=15372 template int foo15372(int value) { return value; } void test15372b() { int t = foo15372(1); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15576 namespace ns15576 { int global15576; namespace ns { int n_global15576; } } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15802 template class Foo15802 { public: static int boo(int value) { return value; } }; void test15802b() { int t = Foo15802::boo(1); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=16536 // mangling mismatch on OSX #if defined(__APPLE__) uint64_t pass16536(uint64_t a) { return a; } #endif /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15589 // extern(C++) virtual destructors are not put in vtbl[] class A15589 { public: struct S { public: int x; }; virtual int foo(); virtual ~A15589(); S s1; S s2; }; class B15589 : public A15589 { public: virtual int bar(); virtual ~B15589(); S s3; }; void test15589b(A15589 *p) { assert(p->foo() == 100); assert(((B15589*)p)->bar() == 200); p->~A15589(); } ///////////////// void trace15589(int ch); Cpp15589Base::~Cpp15589Base() { trace15589('b'); } Cpp15589Derived::Cpp15589Derived() { b = 1; } Cpp15589Derived::~Cpp15589Derived() { trace15589('B'); } Cpp15589BaseVirtual::Cpp15589BaseVirtual() { c = 2; } Cpp15589BaseVirtual::~Cpp15589BaseVirtual() { trace15589('v'); } Cpp15589DerivedVirtual::Cpp15589DerivedVirtual() { d = 3; } Cpp15589DerivedVirtual::~Cpp15589DerivedVirtual() { trace15589('V'); } Cpp15589IntroducingVirtual::Cpp15589IntroducingVirtual() { e = 4; } Cpp15589IntroducingVirtual::~Cpp15589IntroducingVirtual() { trace15589('I'); } Cpp15589Struct::~Cpp15589Struct() { trace15589('s'); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=18928 struct Small18928 { int x; }; class CC18928 { public: virtual Small18928 getVirtual(); Small18928 getFinal(); static Small18928 getStatic(); }; Small18928 CC18928::getVirtual() { Small18928 s = {3}; return s; } Small18928 CC18928::getFinal() { Small18928 s = {4}; return s; } Small18928 CC18928::getStatic() { Small18928 s = {5}; return s; } CC18928* newCC18928() { return new CC18928(); } /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=18966 Base18966::Base18966() { x = 10; } Base18966::~Base18966() {} void Base18966::vf() { x = 100; } A18966::A18966() : calledOverloads(/*zero-init*/), i(0) { foo(); } void A18966::foo() { calledOverloads[i++] = 'A'; } B18966::B18966() { foo(); } void B18966::foo() { calledOverloads[i++] = 'B'; } #if _WIN32 // otherwise defined in C header files! // https://issues.dlang.org/show_bug.cgi?id=18955 namespace std { template struct char_traits { }; template class allocator { }; template class basic_string { }; typedef basic_string, allocator > string; } #endif // _WIN32 void callback18955(const std::string& s); void test18955() { std::string s; // TODO: on OSX and FreeBSD, std is mangled as std::__1 #if !__APPLE__ && !__FreeBSD__ callback18955(s); #endif } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/cppb.h ================================================ // avoid declaration in cpp file so the C/C++ compiler does no assume // these are inaccessible from elsewhere class Cpp15589Base { public: ~Cpp15589Base(); virtual void nonVirtual() {} int a; }; class Cpp15589Derived : public Cpp15589Base { public: Cpp15589Derived(); ~Cpp15589Derived(); int b; }; class Cpp15589BaseVirtual { public: virtual void beforeDtor() {} Cpp15589BaseVirtual(); virtual ~Cpp15589BaseVirtual(); virtual void afterDtor() {} int c; }; class Cpp15589DerivedVirtual : public Cpp15589BaseVirtual { public: Cpp15589DerivedVirtual(); // explicit C++ ctor needed, see https://issues.dlang.org/show_bug.cgi?id=18966 virtual ~Cpp15589DerivedVirtual(); virtual void afterDtor() {} int d; }; class Cpp15589IntroducingVirtual : public Cpp15589Base { public: Cpp15589IntroducingVirtual(); virtual void beforeIntroducedVirtual() {} virtual ~Cpp15589IntroducingVirtual(); virtual void afterIntroducedVirtual(int) {} int e; }; struct Cpp15589Struct { ~Cpp15589Struct(); int s; }; class Base18966 { public: Base18966(); virtual ~Base18966(); virtual void vf(); int x; }; class A18966 { public: char calledOverloads[8]; int i; A18966(); virtual void foo(); }; class B18966 : public A18966 { public: B18966(); void foo() /*override*/; }; ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/depsprot.d ================================================ import depsprot_default; private import depsprot_private; public import depsprot_public; ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/externmangle.cpp ================================================ #include #include template struct Foo { X *v; }; template struct Boo { X *v; }; void test1(Foo arg1) { } void test2(int* arg2, Boo arg1) { } template struct Test3 { }; void test3(Test3<3,3> arg1) { } void test4(Foo arg1, Boo arg2, Boo arg3, int*, Foo) { } void test5(Foo arg1, Boo arg2, Boo arg3) { } struct Goo { template struct Foo { X* v; }; template struct Boo { template struct Xoo { Y* v; }; X* v; }; void test6(Foo > > arg1); void test7(Boo::Xoo arg1); }; void Goo::test6(Goo::Foo > > arg1) { } void Goo::test7(Goo::Boo::Xoo arg1) { } struct P1 { template struct Mem { }; }; struct P2 { template struct Mem { }; }; void test8(P1::Mem, P2::Mem){} void test9(Foo, Foo, int**, int*){} class Test10 { private: void test10(); public: void test11(); protected: void test12(); public: void test13() const; private: void test14(); // Private methods in D are always non-virtual public: virtual void test15(); protected: virtual void test16(); private: static void test17(); public: static void test18(); protected: static void test19(); }; Test10* Test10Ctor() { return new Test10(); } void Test10Dtor(Test10*& ptr) { delete ptr; ptr = 0; } void Test10::test10(){} void Test10::test11(){} void Test10::test12(){} void Test10::test13() const{} void Test10::test14(){} void Test10::test15(){} void Test10::test16(){} void Test10::test17(){} void Test10::test18(){} void Test10::test19(){} struct Test20 { private: static int test20; protected: static int test21; public: static int test22; }; int Test20::test20 = 20; int Test20::test21 = 21; int Test20::test22 = 22; int test23(Test10**, Test10*, Test10***, Test10 const *const) { return 1; } int test23b(Test10 const *const *const, Test10 const* const, Test10*) { return 1; } void test24(int(*)(int,int)) { } void test25(int arr[2][5][6][291]) { } int test26(int arr[5][6][291]) { return arr[1][1][1]; } void test27(int, ...){} void test28(int){} void test29(float){} void test30(const float){} template struct Array { int dim; }; class Module { public: static void imports(Module*); static int dim(Array*); }; void Module::imports(Module*) { } int Module::dim(Array* arr) { return arr->dim; } uint64_t testlongmangle(int a, unsigned int b, int64_t c, uint64_t d) { return a + b + c + d; } unsigned long testCppLongMangle(long a, unsigned long b) { return a + b; } unsigned long long testCppLongLongMangle(long long a, unsigned long long b) { return a + b; } size_t testCppSizeTMangle(ptrdiff_t a, size_t b) { return a + b; } int test31[2][2][2] = {1, 1, 1, 1, 1, 1, 1, 1}; int *test32 = 0; class Expression; typedef int (*apply_fp_t)(Expression*, void*); class Expression { int type; public: int apply(apply_fp_t fp, apply_fp_t fp2, void *param); int getType(); static Expression* create(int v); static void dispose(Expression*&); }; int Expression::apply(apply_fp_t fp, apply_fp_t fp2, void *param) { return fp(this, param) * fp2(this, param); } int Expression::getType() { return type; } Expression* Expression::create(int v) { Expression *e = new Expression(); e->type = v; return e; } void Expression::dispose(Expression *&e) { if (e) delete e; e = 0; } /*int test34(int v[0][0][0]) { return 0; }*/ #ifndef _MSC_VER int test35(long double arg) { return (int)arg; } #endif const char *test36(const char *arg) { return arg; } class Test37 { public: static Test37 *create(); bool test(); }; bool test37() { Test37 *o = Test37::create(); return o->test(); } class Test38 { public: int test(int, ...); static Test38* create(); static void dispose(Test38*&); }; int Test38::test(int a, ...) { return a; } Test38* Test38::create() { Test38 *t = new Test38(); return t; } void Test38::dispose(Test38 *&t) { if (t) delete t; t = 0; } class S1 { int val; public: static S1* init(int); S1(int v) : val(v) {} int value(); }; S1* S1::init(int x) { return new S1(x); } int S1::value() { return val; } template class S2 { T val; public: static S2* init(T); S2(T v) : val(v) {} T value(); }; template<> S2* S2::init(int x) { return new S2(x); } template<> int S2::value() { return val; } struct C1 { const char *data; static C1* init(const char *p); C1(const char* p) : data(p) { } virtual const char* getDataCPP(); virtual const char* getDataD(); }; C1* C1::init(const char *p) { return new C1(p); } const char* C1::getDataCPP() { return data; } template struct C2 { const T *data; static C2* init(const T *p); C2(const T* p) : data(p) { } virtual const T* getData(); }; template<> C2* C2::init(const char *p) { return new C2(p); } template<> const char* C2::getData() { return data; } int test39cpp(C2* c2, S2* s2) { C2* otherC2 = C2::init(c2->getData()); if (c2->getData() != otherC2->getData()) return 1; S2* otherS2 = S2::init(s2->value()); if (s2->value() != otherS2->value()) return 2; return 0; } ================================================ FILE: gcc/testsuite/gdc.test/runnable/extra-files/externmangle2.cpp ================================================ struct Test32NS1 { template struct Foo { X *v; }; template struct Bar { X *v; }; }; struct Test32NS2 { template struct Foo { X *v; }; }; template