d: Merge upstream dmd 47871363d, druntime, c52e28b7, phobos 99e9c1b77.
authorIain Buclaw <ibuclaw@gdcproject.org>
Tue, 29 Mar 2022 14:57:10 +0000 (16:57 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Sat, 2 Apr 2022 21:56:52 +0000 (23:56 +0200)
D front-end changes:

    - Import dmd v2.099.1-beta.1.
    - The address of NRVO variables is now stored in scoped closures
      when they have nested references.
    - Using `__traits(parameters)' in foreach loops now always returns
      the parameters to the function the foreach appears within.
      Previously, when used inside a `foreach' using an overloaded
      `opApply', the trait would yield the parameters to the delegate.
    - The deprecation period of unannotated `asm' blocks has been ended.
    - The `inout' attribute no longer implies the `return' attribute.
    - Added new `D_PreConditions', `D_PostConditions', and
      `D_Invariants' version identifiers.

D runtime changes:

    - Import druntime v2.099.1-beta.1.

Phobos changes:

    - Import phobos v2.099.1-beta.1.
    - `Nullable' in `std.typecons' can now act as a range.
    - std.experimental.logger default level changed to `info' instead of
      `warning'.

gcc/d/ChangeLog:

* dmd/MERGE: Merge upstream dmd 47871363d.
* d-builtins.cc (d_init_versions): Add predefined version identifiers
D_PreConditions, D_PostConditions, and D_Invariants.
* d-codegen.cc (d_build_call): Update for new front-end interface.
(build_frame_type): Generate reference field for NRVO variables with
nested references.
(build_closure): Generate assignment of return address to closure.
* d-tree.h (DECL_INSTANTIATED): Use DECL_LANG_FLAG_2.
(bind_expr): Remove.
* decl.cc (DeclVisitor::visit (FuncDeclaration *)): Update for new
front-end interface.
(get_symbol_decl): Likewise.
(get_decl_tree): Check DECL_LANG_FRAME_FIELD before DECL_LANG_NRVO.
Dereference the field when both are set.
* expr.cc (ExprVisitor::visit (DeleteExp *)): Update for new front-end
interface.
* modules.cc (get_internal_fn): Likewise.
* toir.cc (IRVisitor::visit (ReturnStatement *)): Likewise.

libphobos/ChangeLog:

* libdruntime/MERGE: Merge upstream druntime c52e28b7.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES_OPENBSD): Add
core/sys/openbsd/pwd.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 99e9c1b77.
* testsuite/libphobos.exceptions/message_with_null.d: New test.

gcc/testsuite/ChangeLog:

* gdc.dg/nrvo1.d: New test.

527 files changed:
gcc/d/d-builtins.cc
gcc/d/d-codegen.cc
gcc/d/d-tree.h
gcc/d/decl.cc
gcc/d/dmd/MERGE
gcc/d/dmd/VERSION
gcc/d/dmd/aggregate.d
gcc/d/dmd/aliasthis.d
gcc/d/dmd/arrayop.d
gcc/d/dmd/arraytypes.d
gcc/d/dmd/arraytypes.h
gcc/d/dmd/blockexit.d
gcc/d/dmd/clone.d
gcc/d/dmd/constfold.d
gcc/d/dmd/cparse.d
gcc/d/dmd/ctfeexpr.d
gcc/d/dmd/ctorflow.d
gcc/d/dmd/dcast.d
gcc/d/dmd/declaration.d
gcc/d/dmd/declaration.h
gcc/d/dmd/denum.d
gcc/d/dmd/dinterpret.d
gcc/d/dmd/dmangle.d
gcc/d/dmd/dmodule.d
gcc/d/dmd/dscope.d
gcc/d/dmd/dsymbol.d
gcc/d/dmd/dsymbol.h
gcc/d/dmd/dsymbolsem.d
gcc/d/dmd/dtemplate.d
gcc/d/dmd/dtoh.d
gcc/d/dmd/escape.d
gcc/d/dmd/expression.d
gcc/d/dmd/expressionsem.d
gcc/d/dmd/file_manager.d
gcc/d/dmd/foreachvar.d
gcc/d/dmd/func.d
gcc/d/dmd/globals.d
gcc/d/dmd/globals.h
gcc/d/dmd/hdrgen.d
gcc/d/dmd/importc.d
gcc/d/dmd/init.h
gcc/d/dmd/initsem.d
gcc/d/dmd/lexer.d
gcc/d/dmd/mtype.d
gcc/d/dmd/nogc.d
gcc/d/dmd/ob.d
gcc/d/dmd/opover.d
gcc/d/dmd/optimize.d
gcc/d/dmd/parse.d
gcc/d/dmd/printast.d
gcc/d/dmd/root/aav.d
gcc/d/dmd/root/array.h
gcc/d/dmd/root/bitarray.d
gcc/d/dmd/root/file.d
gcc/d/dmd/root/stringtable.d
gcc/d/dmd/sapply.d
gcc/d/dmd/semantic3.d
gcc/d/dmd/statement.d
gcc/d/dmd/statementsem.d
gcc/d/dmd/tokens.d
gcc/d/dmd/tokens.h
gcc/d/dmd/traits.d
gcc/d/dmd/typesem.d
gcc/d/dmd/utils.d
gcc/d/expr.cc
gcc/d/modules.cc
gcc/d/toir.cc
gcc/testsuite/gdc.dg/nrvo1.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/Test16206.d
gcc/testsuite/gdc.test/compilable/aliasassign.d
gcc/testsuite/gdc.test/compilable/art4769.d
gcc/testsuite/gdc.test/compilable/b21285.d
gcc/testsuite/gdc.test/compilable/b33.d
gcc/testsuite/gdc.test/compilable/b6395.d
gcc/testsuite/gdc.test/compilable/b9490.d
gcc/testsuite/gdc.test/compilable/betterCarray.d
gcc/testsuite/gdc.test/compilable/betterCswitch.d
gcc/testsuite/gdc.test/compilable/ccompile.d
gcc/testsuite/gdc.test/compilable/cdcmp.d
gcc/testsuite/gdc.test/compilable/const.d
gcc/testsuite/gdc.test/compilable/ddoc1.d
gcc/testsuite/gdc.test/compilable/ddoc11.d
gcc/testsuite/gdc.test/compilable/ddoc12706.d
gcc/testsuite/gdc.test/compilable/ddoc12745.d
gcc/testsuite/gdc.test/compilable/ddoc13.d
gcc/testsuite/gdc.test/compilable/ddoc14.d
gcc/testsuite/gdc.test/compilable/ddoc2.d
gcc/testsuite/gdc.test/compilable/ddoc2273.d
gcc/testsuite/gdc.test/compilable/ddoc3.d
gcc/testsuite/gdc.test/compilable/ddoc5.d
gcc/testsuite/gdc.test/compilable/ddoc6.d
gcc/testsuite/gdc.test/compilable/ddoc6491.d
gcc/testsuite/gdc.test/compilable/ddoc7.d
gcc/testsuite/gdc.test/compilable/ddoc9369.d
gcc/testsuite/gdc.test/compilable/ddoc9475.d
gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d
gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d
gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
gcc/testsuite/gdc.test/compilable/dtoh_mangling.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/extra-files/header1.d
gcc/testsuite/gdc.test/compilable/fail137.d
gcc/testsuite/gdc.test/compilable/fix17686.d
gcc/testsuite/gdc.test/compilable/fix20416.d
gcc/testsuite/gdc.test/compilable/fix21647.d
gcc/testsuite/gdc.test/compilable/fix22291.d
gcc/testsuite/gdc.test/compilable/ice20092.d
gcc/testsuite/gdc.test/compilable/imports/art4769a.d
gcc/testsuite/gdc.test/compilable/imports/art4769b.d
gcc/testsuite/gdc.test/compilable/imports/b33a.d
gcc/testsuite/gdc.test/compilable/imports/b3682.d
gcc/testsuite/gdc.test/compilable/imports/defaa.d
gcc/testsuite/gdc.test/compilable/imports/defab.d
gcc/testsuite/gdc.test/compilable/imports/imp16080.d
gcc/testsuite/gdc.test/compilable/imports/plainpackage/plainmodule.d
gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d
gcc/testsuite/gdc.test/compilable/imports/test16709c.d
gcc/testsuite/gdc.test/compilable/imports/test16709d.d
gcc/testsuite/gdc.test/compilable/imports/test4003a.d
gcc/testsuite/gdc.test/compilable/imports/test50a.d
gcc/testsuite/gdc.test/compilable/imports/test55a.d
gcc/testsuite/gdc.test/compilable/imports/test62a.d
gcc/testsuite/gdc.test/compilable/imports/test63a.d
gcc/testsuite/gdc.test/compilable/imports/test67a.d
gcc/testsuite/gdc.test/compilable/imports/test68a.d
gcc/testsuite/gdc.test/compilable/imports/test9276decl.d
gcc/testsuite/gdc.test/compilable/imports/test9276expr.d
gcc/testsuite/gdc.test/compilable/imports/test9276parser.d
gcc/testsuite/gdc.test/compilable/imports/test9276sem.d
gcc/testsuite/gdc.test/compilable/imports/test9276type.d
gcc/testsuite/gdc.test/compilable/imports/test9276util.d
gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d
gcc/testsuite/gdc.test/compilable/imports/wax16798.d
gcc/testsuite/gdc.test/compilable/isreturnonstack.d
gcc/testsuite/gdc.test/compilable/issue15478.d
gcc/testsuite/gdc.test/compilable/issue21813b.d
gcc/testsuite/gdc.test/compilable/json.d
gcc/testsuite/gdc.test/compilable/line.d
gcc/testsuite/gdc.test/compilable/mixintype.d
gcc/testsuite/gdc.test/compilable/test10073.d
gcc/testsuite/gdc.test/compilable/test1238.d
gcc/testsuite/gdc.test/compilable/test12527.d
gcc/testsuite/gdc.test/compilable/test13193.d
gcc/testsuite/gdc.test/compilable/test13194.d
gcc/testsuite/gdc.test/compilable/test13600.d
gcc/testsuite/gdc.test/compilable/test13858.d
gcc/testsuite/gdc.test/compilable/test15019.d
gcc/testsuite/gdc.test/compilable/test15389_y.d
gcc/testsuite/gdc.test/compilable/test15464.d
gcc/testsuite/gdc.test/compilable/test15565.d
gcc/testsuite/gdc.test/compilable/test15578.d
gcc/testsuite/gdc.test/compilable/test15762.d
gcc/testsuite/gdc.test/compilable/test15898.d
gcc/testsuite/gdc.test/compilable/test16037.d
gcc/testsuite/gdc.test/compilable/test16080.d
gcc/testsuite/gdc.test/compilable/test16225.d
gcc/testsuite/gdc.test/compilable/test16798.d
gcc/testsuite/gdc.test/compilable/test17057.d
gcc/testsuite/gdc.test/compilable/test17421.d
gcc/testsuite/gdc.test/compilable/test17468.d
gcc/testsuite/gdc.test/compilable/test17512.d
gcc/testsuite/gdc.test/compilable/test17942.d
gcc/testsuite/gdc.test/compilable/test18020.d
gcc/testsuite/gdc.test/compilable/test18584.d
gcc/testsuite/gdc.test/compilable/test18936.d
gcc/testsuite/gdc.test/compilable/test19203.d
gcc/testsuite/gdc.test/compilable/test19227.d
gcc/testsuite/gdc.test/compilable/test20596.d
gcc/testsuite/gdc.test/compilable/test20653.d
gcc/testsuite/gdc.test/compilable/test20717.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test20906.d
gcc/testsuite/gdc.test/compilable/test20990.d
gcc/testsuite/gdc.test/compilable/test22639.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22665.d
gcc/testsuite/gdc.test/compilable/test22825.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22859.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22860.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22919.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test3775.d
gcc/testsuite/gdc.test/compilable/test4003.d
gcc/testsuite/gdc.test/compilable/test4375.d
gcc/testsuite/gdc.test/compilable/test50.d
gcc/testsuite/gdc.test/compilable/test5227.d
gcc/testsuite/gdc.test/compilable/test602.d
gcc/testsuite/gdc.test/compilable/test6089.d
gcc/testsuite/gdc.test/compilable/test63.d
gcc/testsuite/gdc.test/compilable/test6395.d
gcc/testsuite/gdc.test/compilable/test66.d
gcc/testsuite/gdc.test/compilable/test67.d
gcc/testsuite/gdc.test/compilable/test68.d
gcc/testsuite/gdc.test/compilable/test7399.d
gcc/testsuite/gdc.test/compilable/test8296.d
gcc/testsuite/gdc.test/compilable/test8922b.d
gcc/testsuite/gdc.test/compilable/test8922d.d
gcc/testsuite/gdc.test/compilable/test9057.d
gcc/testsuite/gdc.test/compilable/test9436.d
gcc/testsuite/gdc.test/compilable/testAliasLookup.d
gcc/testsuite/gdc.test/compilable/testInference.d
gcc/testsuite/gdc.test/compilable/testprofile.d
gcc/testsuite/gdc.test/compilable/testsctreturn.d
gcc/testsuite/gdc.test/compilable/typeid_name.d
gcc/testsuite/gdc.test/compilable/vcg-ast.d
gcc/testsuite/gdc.test/compilable/version.d
gcc/testsuite/gdc.test/fail_compilation/bug5.d
gcc/testsuite/gdc.test/fail_compilation/bug5b.d
gcc/testsuite/gdc.test/fail_compilation/bug9631.d
gcc/testsuite/gdc.test/fail_compilation/circ10280.d
gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d
gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d
gcc/testsuite/gdc.test/fail_compilation/diag12640.d
gcc/testsuite/gdc.test/fail_compilation/diag14145.d
gcc/testsuite/gdc.test/fail_compilation/diag16271.d
gcc/testsuite/gdc.test/fail_compilation/diag1730.d
gcc/testsuite/gdc.test/fail_compilation/diag18574.d
gcc/testsuite/gdc.test/fail_compilation/diag8510.d
gcc/testsuite/gdc.test/fail_compilation/dip25.d
gcc/testsuite/gdc.test/fail_compilation/fail10905.d
gcc/testsuite/gdc.test/fail_compilation/fail11163.d
gcc/testsuite/gdc.test/fail_compilation/fail118.d
gcc/testsuite/gdc.test/fail_compilation/fail12.d
gcc/testsuite/gdc.test/fail_compilation/fail131.d
gcc/testsuite/gdc.test/fail_compilation/fail13902.d
gcc/testsuite/gdc.test/fail_compilation/fail14486.d
gcc/testsuite/gdc.test/fail_compilation/fail15.d
gcc/testsuite/gdc.test/fail_compilation/fail15691.d
gcc/testsuite/gdc.test/fail_compilation/fail16.d
gcc/testsuite/gdc.test/fail_compilation/fail160.d
gcc/testsuite/gdc.test/fail_compilation/fail16001.d
gcc/testsuite/gdc.test/fail_compilation/fail16600.d
gcc/testsuite/gdc.test/fail_compilation/fail17.d
gcc/testsuite/gdc.test/fail_compilation/fail17275.d
gcc/testsuite/gdc.test/fail_compilation/fail17419.d
gcc/testsuite/gdc.test/fail_compilation/fail17421.d
gcc/testsuite/gdc.test/fail_compilation/fail17842.d
gcc/testsuite/gdc.test/fail_compilation/fail17906.d
gcc/testsuite/gdc.test/fail_compilation/fail17927.d
gcc/testsuite/gdc.test/fail_compilation/fail19441.d
gcc/testsuite/gdc.test/fail_compilation/fail19744.d
gcc/testsuite/gdc.test/fail_compilation/fail19898a.d
gcc/testsuite/gdc.test/fail_compilation/fail19898b.d
gcc/testsuite/gdc.test/fail_compilation/fail19922.d
gcc/testsuite/gdc.test/fail_compilation/fail19923.d
gcc/testsuite/gdc.test/fail_compilation/fail20084.d
gcc/testsuite/gdc.test/fail_compilation/fail201.d
gcc/testsuite/gdc.test/fail_compilation/fail202.d
gcc/testsuite/gdc.test/fail_compilation/fail203.d
gcc/testsuite/gdc.test/fail_compilation/fail204.d
gcc/testsuite/gdc.test/fail_compilation/fail20448.d
gcc/testsuite/gdc.test/fail_compilation/fail205.d
gcc/testsuite/gdc.test/fail_compilation/fail206.d
gcc/testsuite/gdc.test/fail_compilation/fail20800.d
gcc/testsuite/gdc.test/fail_compilation/fail217.d
gcc/testsuite/gdc.test/fail_compilation/fail21868b.d
gcc/testsuite/gdc.test/fail_compilation/fail22118.d
gcc/testsuite/gdc.test/fail_compilation/fail22825a.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail22825b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail2361.d
gcc/testsuite/gdc.test/fail_compilation/fail249.d
gcc/testsuite/gdc.test/fail_compilation/fail258.d
gcc/testsuite/gdc.test/fail_compilation/fail259.d
gcc/testsuite/gdc.test/fail_compilation/fail261.d
gcc/testsuite/gdc.test/fail_compilation/fail346.d
gcc/testsuite/gdc.test/fail_compilation/fail359.d
gcc/testsuite/gdc.test/fail_compilation/fail3895.d
gcc/testsuite/gdc.test/fail_compilation/fail4269a.d
gcc/testsuite/gdc.test/fail_compilation/fail4269b.d
gcc/testsuite/gdc.test/fail_compilation/fail4269c.d
gcc/testsuite/gdc.test/fail_compilation/fail4375a.d
gcc/testsuite/gdc.test/fail_compilation/fail4375b.d
gcc/testsuite/gdc.test/fail_compilation/fail4375c.d
gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
gcc/testsuite/gdc.test/fail_compilation/fail4375e.d
gcc/testsuite/gdc.test/fail_compilation/fail4375f.d
gcc/testsuite/gdc.test/fail_compilation/fail4375g.d
gcc/testsuite/gdc.test/fail_compilation/fail4375h.d
gcc/testsuite/gdc.test/fail_compilation/fail4375i.d
gcc/testsuite/gdc.test/fail_compilation/fail4375j.d
gcc/testsuite/gdc.test/fail_compilation/fail4375k.d
gcc/testsuite/gdc.test/fail_compilation/fail4375l.d
gcc/testsuite/gdc.test/fail_compilation/fail4375m.d
gcc/testsuite/gdc.test/fail_compilation/fail4375o.d
gcc/testsuite/gdc.test/fail_compilation/fail4375p.d
gcc/testsuite/gdc.test/fail_compilation/fail4375q.d
gcc/testsuite/gdc.test/fail_compilation/fail4375r.d
gcc/testsuite/gdc.test/fail_compilation/fail4375s.d
gcc/testsuite/gdc.test/fail_compilation/fail4375t.d
gcc/testsuite/gdc.test/fail_compilation/fail4375u.d
gcc/testsuite/gdc.test/fail_compilation/fail4375v.d
gcc/testsuite/gdc.test/fail_compilation/fail4375w.d
gcc/testsuite/gdc.test/fail_compilation/fail4375x.d
gcc/testsuite/gdc.test/fail_compilation/fail4375y.d
gcc/testsuite/gdc.test/fail_compilation/fail44.d
gcc/testsuite/gdc.test/fail_compilation/fail47.d
gcc/testsuite/gdc.test/fail_compilation/fail58.d
gcc/testsuite/gdc.test/fail_compilation/fail60.d
gcc/testsuite/gdc.test/fail_compilation/fail6107.d
gcc/testsuite/gdc.test/fail_compilation/fail7178.d
gcc/testsuite/gdc.test/fail_compilation/fail72.d
gcc/testsuite/gdc.test/fail_compilation/fail7234.d
gcc/testsuite/gdc.test/fail_compilation/fail73.d
gcc/testsuite/gdc.test/fail_compilation/fail7369.d
gcc/testsuite/gdc.test/fail_compilation/fail7424c.d
gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
gcc/testsuite/gdc.test/fail_compilation/fail7424g.d
gcc/testsuite/gdc.test/fail_compilation/fail7424h.d
gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
gcc/testsuite/gdc.test/fail_compilation/fail7524a.d
gcc/testsuite/gdc.test/fail_compilation/fail7524b.d
gcc/testsuite/gdc.test/fail_compilation/fail77.d
gcc/testsuite/gdc.test/fail_compilation/fail78.d
gcc/testsuite/gdc.test/fail_compilation/fail7851.d
gcc/testsuite/gdc.test/fail_compilation/fail7859.d
gcc/testsuite/gdc.test/fail_compilation/fail7861.d
gcc/testsuite/gdc.test/fail_compilation/fail7862.d
gcc/testsuite/gdc.test/fail_compilation/fail79.d
gcc/testsuite/gdc.test/fail_compilation/fail8009.d
gcc/testsuite/gdc.test/fail_compilation/fail8179b.d
gcc/testsuite/gdc.test/fail_compilation/fail8373.d
gcc/testsuite/gdc.test/fail_compilation/fail9199.d
gcc/testsuite/gdc.test/fail_compilation/fail92.d
gcc/testsuite/gdc.test/fail_compilation/fail95.d
gcc/testsuite/gdc.test/fail_compilation/fail9665a.d
gcc/testsuite/gdc.test/fail_compilation/fail9735.d
gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
gcc/testsuite/gdc.test/fail_compilation/failcontracts.d
gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
gcc/testsuite/gdc.test/fail_compilation/failsafec.d
gcc/testsuite/gdc.test/fail_compilation/fix18575.d
gcc/testsuite/gdc.test/fail_compilation/fix21585.d
gcc/testsuite/gdc.test/fail_compilation/fix5212.d
gcc/testsuite/gdc.test/fail_compilation/fob1.d
gcc/testsuite/gdc.test/fail_compilation/fob2.d
gcc/testsuite/gdc.test/fail_compilation/format.d
gcc/testsuite/gdc.test/fail_compilation/goto1.d
gcc/testsuite/gdc.test/fail_compilation/goto3.d
gcc/testsuite/gdc.test/fail_compilation/ice10283.d
gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
gcc/testsuite/gdc.test/fail_compilation/ice11968.d
gcc/testsuite/gdc.test/fail_compilation/ice13027.d
gcc/testsuite/gdc.test/fail_compilation/ice6538.d
gcc/testsuite/gdc.test/fail_compilation/ice9254a.d
gcc/testsuite/gdc.test/fail_compilation/ice9254b.d
gcc/testsuite/gdc.test/fail_compilation/ice9254c.d
gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d
gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d
gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d
gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d
gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d
gcc/testsuite/gdc.test/fail_compilation/imports/test18480a.d
gcc/testsuite/gdc.test/fail_compilation/imports/test21164a.d
gcc/testsuite/gdc.test/fail_compilation/imports/test21164b.d
gcc/testsuite/gdc.test/fail_compilation/imports/test21164c.d
gcc/testsuite/gdc.test/fail_compilation/imports/test21164d.d
gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d
gcc/testsuite/gdc.test/fail_compilation/issue22820.d
gcc/testsuite/gdc.test/fail_compilation/issue22826.d
gcc/testsuite/gdc.test/fail_compilation/lexer1.d
gcc/testsuite/gdc.test/fail_compilation/lexer4.d
gcc/testsuite/gdc.test/fail_compilation/mangle2.d
gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d
gcc/testsuite/gdc.test/fail_compilation/nogc1.d
gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
gcc/testsuite/gdc.test/fail_compilation/pragmainline.d
gcc/testsuite/gdc.test/fail_compilation/pragmas.d
gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
gcc/testsuite/gdc.test/fail_compilation/retscope2.d
gcc/testsuite/gdc.test/fail_compilation/retscope3.d
gcc/testsuite/gdc.test/fail_compilation/retscope5.d
gcc/testsuite/gdc.test/fail_compilation/retscope6.d
gcc/testsuite/gdc.test/fail_compilation/shared.d
gcc/testsuite/gdc.test/fail_compilation/switches.d
gcc/testsuite/gdc.test/fail_compilation/test1021.d
gcc/testsuite/gdc.test/fail_compilation/test11047.d
gcc/testsuite/gdc.test/fail_compilation/test11176.d
gcc/testsuite/gdc.test/fail_compilation/test13536.d
gcc/testsuite/gdc.test/fail_compilation/test13537.d
gcc/testsuite/gdc.test/fail_compilation/test14496.d
gcc/testsuite/gdc.test/fail_compilation/test15399.d
gcc/testsuite/gdc.test/fail_compilation/test15544.d
gcc/testsuite/gdc.test/fail_compilation/test15660.d
gcc/testsuite/gdc.test/fail_compilation/test15672.d
gcc/testsuite/gdc.test/fail_compilation/test15703.d
gcc/testsuite/gdc.test/fail_compilation/test15704.d
gcc/testsuite/gdc.test/fail_compilation/test15989.d
gcc/testsuite/gdc.test/fail_compilation/test16188.d
gcc/testsuite/gdc.test/fail_compilation/test16193.d
gcc/testsuite/gdc.test/fail_compilation/test16195.d
gcc/testsuite/gdc.test/fail_compilation/test16381.d
gcc/testsuite/gdc.test/fail_compilation/test16589.d
gcc/testsuite/gdc.test/fail_compilation/test17284.d
gcc/testsuite/gdc.test/fail_compilation/test17425.d
gcc/testsuite/gdc.test/fail_compilation/test17450.d
gcc/testsuite/gdc.test/fail_compilation/test18282.d
gcc/testsuite/gdc.test/fail_compilation/test18484.d
gcc/testsuite/gdc.test/fail_compilation/test18644.d
gcc/testsuite/gdc.test/fail_compilation/test18708.d
gcc/testsuite/gdc.test/fail_compilation/test21353.d
gcc/testsuite/gdc.test/fail_compilation/test21927.d
gcc/testsuite/gdc.test/fail_compilation/test21939.d
gcc/testsuite/gdc.test/fail_compilation/test22145.d
gcc/testsuite/gdc.test/fail_compilation/test22541.d
gcc/testsuite/gdc.test/fail_compilation/test22840.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test22910.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test3818.d
gcc/testsuite/gdc.test/fail_compilation/test64.d
gcc/testsuite/gdc.test/fail_compilation/testpull1810.d
gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d
gcc/testsuite/gdc.test/fail_compilation/varargsstc.d
gcc/testsuite/gdc.test/fail_compilation/warn12809.d
gcc/testsuite/gdc.test/runnable/betterc.d
gcc/testsuite/gdc.test/runnable/bug846.d
gcc/testsuite/gdc.test/runnable/fix22372.d
gcc/testsuite/gdc.test/runnable/functype.d
gcc/testsuite/gdc.test/runnable/imports/a18a.d
gcc/testsuite/gdc.test/runnable/imports/a21a.d
gcc/testsuite/gdc.test/runnable/imports/bug846.d
gcc/testsuite/gdc.test/runnable/imports/c22a.d
gcc/testsuite/gdc.test/runnable/imports/c22b.d
gcc/testsuite/gdc.test/runnable/imports/link7745b.d
gcc/testsuite/gdc.test/runnable/imports/m1a.d
gcc/testsuite/gdc.test/runnable/imports/template2962a.d
gcc/testsuite/gdc.test/runnable/imports/test10441b.d
gcc/testsuite/gdc.test/runnable/imports/test10441c.d
gcc/testsuite/gdc.test/runnable/imports/test10a.d
gcc/testsuite/gdc.test/runnable/imports/test11039b.d
gcc/testsuite/gdc.test/runnable/imports/test13a.d
gcc/testsuite/gdc.test/runnable/imports/test27a.d
gcc/testsuite/gdc.test/runnable/imports/test29a.d
gcc/testsuite/gdc.test/runnable/imports/test31a.d
gcc/testsuite/gdc.test/runnable/imports/test32a.d
gcc/testsuite/gdc.test/runnable/imports/test35a.d
gcc/testsuite/gdc.test/runnable/imports/test40a.d
gcc/testsuite/gdc.test/runnable/imports/test41a.d
gcc/testsuite/gdc.test/runnable/imports/test45a.d
gcc/testsuite/gdc.test/runnable/imports/test45b.d
gcc/testsuite/gdc.test/runnable/imports/test46b.d
gcc/testsuite/gdc.test/runnable/imports/test46c.d
gcc/testsuite/gdc.test/runnable/imports/test49a.d
gcc/testsuite/gdc.test/runnable/imports/test57a.d
gcc/testsuite/gdc.test/runnable/imports/test57b.d
gcc/testsuite/gdc.test/runnable/imports/test58a.d
gcc/testsuite/gdc.test/runnable/imports/testminitAA.d
gcc/testsuite/gdc.test/runnable/imports/testminitBB.d
gcc/testsuite/gdc.test/runnable/imports/testmod1b.d
gcc/testsuite/gdc.test/runnable/imports/tlsa.d
gcc/testsuite/gdc.test/runnable/manboy.d
gcc/testsuite/gdc.test/runnable/nrvo.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/pi.d
gcc/testsuite/gdc.test/runnable/template2962.d
gcc/testsuite/gdc.test/runnable/test10441.d
gcc/testsuite/gdc.test/runnable/test10942.d
gcc/testsuite/gdc.test/runnable/test11.d
gcc/testsuite/gdc.test/runnable/test11039.d
gcc/testsuite/gdc.test/runnable/test12.d
gcc/testsuite/gdc.test/runnable/test15568.d
gcc/testsuite/gdc.test/runnable/test16140.d
gcc/testsuite/gdc.test/runnable/test17.d
gcc/testsuite/gdc.test/runnable/test17246.d
gcc/testsuite/gdc.test/runnable/test19735.d
gcc/testsuite/gdc.test/runnable/test20036.d
gcc/testsuite/gdc.test/runnable/test20565.d
gcc/testsuite/gdc.test/runnable/test21.d
gcc/testsuite/gdc.test/runnable/test22175.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test22945.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test27.d
gcc/testsuite/gdc.test/runnable/test28.d
gcc/testsuite/gdc.test/runnable/test3.d
gcc/testsuite/gdc.test/runnable/test30.d
gcc/testsuite/gdc.test/runnable/test32.d
gcc/testsuite/gdc.test/runnable/test34.d
gcc/testsuite/gdc.test/runnable/test40.d
gcc/testsuite/gdc.test/runnable/test41.d
gcc/testsuite/gdc.test/runnable/test57.d
gcc/testsuite/gdc.test/runnable/test7932.d
gcc/testsuite/gdc.test/runnable/test9495.d
gcc/testsuite/gdc.test/runnable/testmain.d
gcc/testsuite/gdc.test/runnable/testmod2.d
gcc/testsuite/gdc.test/runnable/testscope2.d
gcc/testsuite/gdc.test/runnable/testthread2.d
gcc/testsuite/gdc.test/runnable/tls.d
gcc/testsuite/gdc.test/runnable/tls_dup.d
gcc/testsuite/gdc.test/runnable/xtest55.d
gcc/testsuite/gdc.test/runnable_cxx/extra-files/cabi2.cpp
gcc/testsuite/gdc.test/runnable_cxx/test6716.d
libphobos/libdruntime/MERGE
libphobos/libdruntime/Makefile.am
libphobos/libdruntime/Makefile.in
libphobos/libdruntime/core/atomic.d
libphobos/libdruntime/core/demangle.d
libphobos/libdruntime/core/internal/array/casting.d
libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
libphobos/libdruntime/core/stdc/stdlib.d
libphobos/libdruntime/core/stdcpp/string.d
libphobos/libdruntime/core/sys/openbsd/pwd.d [new file with mode: 0644]
libphobos/libdruntime/core/thread/context.d
libphobos/libdruntime/rt/dmain2.d
libphobos/src/MERGE
libphobos/src/std/conv.d
libphobos/src/std/datetime/systime.d
libphobos/src/std/experimental/logger/core.d
libphobos/src/std/experimental/logger/filelogger.d
libphobos/src/std/experimental/logger/multilogger.d
libphobos/src/std/file.d
libphobos/src/std/format/internal/write.d
libphobos/src/std/format/package.d
libphobos/src/std/format/read.d
libphobos/src/std/format/write.d
libphobos/src/std/functional.d
libphobos/src/std/json.d
libphobos/src/std/outbuffer.d
libphobos/src/std/parallelism.d
libphobos/src/std/process.d
libphobos/src/std/socket.d
libphobos/src/std/stdio.d
libphobos/src/std/sumtype.d
libphobos/src/std/typecons.d
libphobos/src/std/uni/package.d
libphobos/src/std/windows/charset.d
libphobos/src/std/windows/syserror.d
libphobos/testsuite/libphobos.exceptions/message_with_null.d [new file with mode: 0644]

index 73b4766..7e7fb75 100644 (file)
@@ -484,6 +484,15 @@ d_init_versions (void)
   if (global.params.useAssert == CHECKENABLEon)
     VersionCondition::addPredefinedGlobalIdent ("assert");
 
+  if (global.params.useIn == CHECKENABLEon)
+    VersionCondition::addPredefinedGlobalIdent("D_PreConditions");
+
+  if (global.params.useOut == CHECKENABLEon)
+    VersionCondition::addPredefinedGlobalIdent("D_PostConditions");
+
+  if (global.params.useInvariants == CHECKENABLEon)
+    VersionCondition::addPredefinedGlobalIdent("D_Invariants");
+
   if (global.params.useArrayBounds == CHECKENABLEoff)
     VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
 
index 3206edd..bb96b2f 100644 (file)
@@ -2207,9 +2207,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
                              build_address (targ));
            }
 
-         /* Type `noreturn` is a terminator, as no other arguments can possibly
-            be evaluated after it.  */
-         if (TREE_TYPE (targ) == noreturn_type_node)
+         /* Type `noreturn` is a terminator, as no other arguments can possibly
+            be evaluated after it.  */
+         if (TREE_TYPE (targ) == noreturn_type_node)
            noreturn_call = true;
 
          vec_safe_push (args, targ);
@@ -2690,9 +2690,15 @@ build_frame_type (tree ffi, FuncDeclaration *fd)
       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 (DECL_LANG_NRVO (vsym))
+       {
+         /* Store the nrvo variable in the frame by reference.  */
+         TREE_TYPE (field) = build_reference_type (TREE_TYPE (field));
+
+         /* Can't do nrvo if the variable is put in a closure, since what the
+            return slot points to may no longer exist.  */
+         gcc_assert (!FRAMEINFO_IS_CLOSURE (ffi));
+       }
 
       if (FRAMEINFO_IS_CLOSURE (ffi))
        {
@@ -2769,13 +2775,17 @@ build_closure (FuncDeclaration *fd)
   for (size_t i = 0; i < fd->closureVars.length; i++)
     {
       VarDeclaration *v = fd->closureVars[i];
+      tree vsym = get_symbol_decl (v);
 
-      if (!v->isParameter ())
+      if (TREE_CODE (vsym) != PARM_DECL && !DECL_LANG_NRVO (vsym))
        continue;
 
-      tree vsym = get_symbol_decl (v);
-
       tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
+
+      /* Variable is an alias for the NRVO slot, store the reference.  */
+      if (DECL_LANG_NRVO (vsym))
+       vsym = build_address (DECL_LANG_NRVO (vsym));
+
       tree expr = modify_expr (field, vsym);
       add_stmt (expr);
     }
index 5dec2e6..d93d02c 100644 (file)
@@ -392,7 +392,7 @@ lang_tree_node
 
 /* True if the decl comes from a template instance.  */
 #define DECL_INSTANTIATED(NODE) \
-  (DECL_LANG_FLAG_1 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
+  (DECL_LANG_FLAG_2 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
 
 enum d_tree_index
 {
@@ -580,7 +580,6 @@ extern tree build_bounds_index_condition (IndexExp *, tree, tree);
 extern tree build_bounds_slice_condition (SliceExp *, tree, tree, tree);
 extern bool array_bounds_check (void);
 extern bool checkaction_trap_p (void);
-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 *);
index 7ec0caf..ea8baef 100644 (file)
@@ -791,7 +791,7 @@ public:
          return;
       }
 
-    if (d->semantic3Errors)
+    if (d->hasSemantic3Errors ())
       return;
 
     if (d->isNested ())
@@ -805,7 +805,7 @@ public:
              break;
 
            /* Parent failed to compile, but errors were gagged.  */
-           if (fdp->semantic3Errors)
+           if (fdp->hasSemantic3Errors ())
              return;
          }
       }
@@ -921,15 +921,6 @@ public:
          }
       }
 
-    /* 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.
@@ -951,7 +942,7 @@ public:
        else
          d->shidden = resdecl;
 
-       if (d->nrvo_can && d->nrvo_var)
+       if (d->isNRVO () && d->nrvo_var)
          {
            tree var = get_symbol_decl (d->nrvo_var);
 
@@ -966,6 +957,15 @@ public:
          }
       }
 
+    /* May change cfun->static_chain.  */
+    build_closure (d);
+
+    if (d->vresult)
+      declare_local_var (d->vresult);
+
+    if (d->v_argptr)
+      push_stmt_list ();
+
     build_function_body (d);
 
     /* Initialize the _argptr variable.  */
@@ -1284,26 +1284,26 @@ get_symbol_decl (Declaration *decl)
       /* In [pragma/crtctor], Annotates a function so it is run after the C
         runtime library is initialized and before the D runtime library is
         initialized.  */
-      if (fd->isCrtCtorDtor == 1)
+      if (fd->isCrtCtor ())
        {
          DECL_STATIC_CONSTRUCTOR (decl->csym) = 1;
          decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
        }
-      else if (fd->isCrtCtorDtor == 2)
+      else if (fd->isCrtDtor ())
        {
          DECL_STATIC_DESTRUCTOR (decl->csym) = 1;
          decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
-               }
+       }
 
       /* Function was declared `naked'.  */
-      if (fd->naked)
+      if (fd->isNaked ())
        {
          insert_decl_attribute (decl->csym, "naked");
          DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
        }
 
       /* Mark compiler generated functions as artificial.  */
-      if (fd->generated)
+      if (fd->isGenerated ())
        DECL_ARTIFICIAL (decl->csym) = 1;
 
       /* Ensure and require contracts are lexically nested in the function they
@@ -1486,20 +1486,26 @@ get_decl_tree (Declaration *decl)
   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));
+      tree field = component_ref (build_deref (frame_ref),
+                                 DECL_LANG_FRAME_FIELD (t));
+      /* Frame field can also be a reference to the DECL_RESULT of a function.
+        Dereference it to get the value.  */
+      if (DECL_LANG_NRVO (t))
+       field = build_deref (field);
+
+      return field;
     }
 
+  /* Get the named return value.  */
+  if (DECL_LANG_NRVO (t))
+    return DECL_LANG_NRVO (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.  */
index 3e3e113..ca409df 100644 (file)
@@ -1,4 +1,4 @@
-2503f17e5767bc4fcd0cf3889c90fa0415b0edaa
+47871363d804f54b29ccfd444b082c19716c2301
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
index 17724c6..16f49a7 100644 (file)
@@ -1 +1 @@
-v2.099.0
+v2.099.1-beta.1
index f790730..8895aa5 100644 (file)
@@ -547,7 +547,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         if (overflow) assert(0);
 
         // Skip no-op for noreturn without custom aligment
-        if (memsize != 0 || !alignment.isDefault())
+        if (memalignsize != 0 || !alignment.isDefault())
             alignmember(alignment, memalignsize, &ofs);
 
         uint memoffset = ofs;
@@ -570,7 +570,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
          * definitions exposed some issues in their TypeInfo generation in DMD.
          * Related PR: https://github.com/dlang/dmd/pull/13312
          */
-        if (semanticRun == PASS.init && !isInterfaceDeclaration())
+        if (semanticRun == PASS.initial && !isInterfaceDeclaration())
         {
             auto stc = storage_class;
             if (_scope)
@@ -747,7 +747,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
                 extern (C++) static int fp(Dsymbol s, void* ctxt)
                 {
                     auto f = s.isCtorDeclaration();
-                    if (f && f.semanticRun == PASS.init)
+                    if (f && f.semanticRun == PASS.initial)
                         f.dsymbolSemantic(null);
                     return 0;
                 }
index 458e821..2771071 100644 (file)
@@ -100,9 +100,9 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
 
             if (tthis && ad.aliasthis.sym.needThis())
             {
-                if (e.op == EXP.variable)
+                if (auto ve = e.isVarExp())
                 {
-                    if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
+                    if (auto fd = ve.var.isFuncDeclaration())
                     {
                         // https://issues.dlang.org/show_bug.cgi?id=13009
                         // Support better match for the overloaded alias this.
index e82413f..52f39d3 100644 (file)
@@ -52,16 +52,16 @@ bool isArrayOpValid(Expression e)
     {
         if (isUnaArrayOp(e.op))
         {
-            return isArrayOpValid((cast(UnaExp)e).e1);
+            return isArrayOpValid(e.isUnaExp().e1);
         }
         if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign)
         {
-            BinExp be = cast(BinExp)e;
+            BinExp be = e.isBinExp();
             return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
         }
         if (e.op == EXP.construct)
         {
-            BinExp be = cast(BinExp)e;
+            BinExp be = e.isBinExp();
             return be.e1.op == EXP.slice && isArrayOpValid(be.e2);
         }
         // if (e.op == EXP.call)
@@ -76,7 +76,7 @@ bool isArrayOpValid(Expression e)
 bool isNonAssignmentArrayOp(Expression e)
 {
     if (e.op == EXP.slice)
-        return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
+        return isNonAssignmentArrayOp(e.isSliceExp().e1);
 
     Type tb = e.type.toBasetype();
     if (tb.ty == Tarray || tb.ty == Tsarray)
@@ -176,7 +176,7 @@ Expression arrayOp(BinAssignExp e, Scope* sc)
         return e.e1.modifiableLvalue(sc, e.e1);
     }
 
-    return arrayOp(cast(BinExp)e, sc);
+    return arrayOp(e.isBinExp(), sc);
 }
 
 /******************************************
index ffbaf95..29b3a3d 100644 (file)
@@ -54,4 +54,3 @@ alias TemplateInstances = Array!(TemplateInstance);
 alias Ensures = Array!(Ensure);
 alias Designators = Array!(Designator);
 alias DesigInits = Array!(DesigInit);
-
index d7dfa0b..ca2051c 100644 (file)
@@ -67,4 +67,3 @@ typedef Array<struct Ensure> Ensures;
 typedef Array<struct Designator> Designators;
 
 typedef Array<struct DesigInit> DesigInits;
-
index 5c01204..afd7ac0 100644 (file)
@@ -99,9 +99,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
                     result = BE.halt;
                     return;
                 }
-                if (s.exp.op == EXP.assert_)
+                if (AssertExp a = s.exp.isAssertExp())
                 {
-                    AssertExp a = cast(AssertExp)s.exp;
                     if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
                     {
                         result = BE.halt;
@@ -505,7 +504,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
             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");
+                    s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
                 else
                     result |= BE.throw_;
             }
index a6dbd8e..2ed0dc7 100644 (file)
@@ -301,7 +301,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
     auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
     auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
     fop.storage_class |= STC.inference;
-    fop.generated = true;
+    fop.flags  |= FUNCFLAG.generated;
     Expression e;
     if (stc & STC.disable)
     {
@@ -575,7 +575,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
     tf = tf.addSTC(STC.const_).toTypeFunction();
     Identifier id = Id.xopEquals;
     auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
-    fop.generated = true;
+    fop.flags |= FUNCFLAG.generated;
     fop.parent = sd;
     Expression e1 = new IdentifierExp(loc, Id.This);
     Expression e2 = new IdentifierExp(loc, Id.p);
@@ -644,13 +644,13 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
                 switch (e.op)
                 {
                 case EXP.overloadSet:
-                    s = (cast(OverExp)e).vars;
+                    s = e.isOverExp().vars;
                     break;
                 case EXP.scope_:
-                    s = (cast(ScopeExp)e).sds;
+                    s = e.isScopeExp().sds;
                     break;
                 case EXP.variable:
-                    s = (cast(VarExp)e).var;
+                    s = e.isVarExp().var;
                     break;
                 default:
                     break;
@@ -696,7 +696,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
     tf = tf.addSTC(STC.const_).toTypeFunction();
     Identifier id = Id.xopCmp;
     auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
-    fop.generated = true;
+    fop.flags |= FUNCFLAG.generated;
     fop.parent = sd;
     Expression e1 = new IdentifierExp(loc, Id.This);
     Expression e2 = new IdentifierExp(loc, Id.p);
@@ -814,7 +814,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
     auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
     Identifier id = Id.xtoHash;
     auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
-    fop.generated = true;
+    fop.flags |= FUNCFLAG.generated;
 
     /* Do memberwise hashing.
      *
@@ -937,13 +937,13 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
                 if (stc & STC.safe)
                     stc = (stc & ~STC.safe) | STC.trusted;
 
-                ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+                SliceExp se = 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;
+                se.upperIsInBounds = true;
+                se.lowerIsLessThanUpper = true;
 
-                ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex);
+                ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
             }
             e = Expression.combine(ex, e); // combine in reverse order
         }
@@ -952,7 +952,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
         {
             //printf("Building __fieldDtor(), %s\n", e.toChars());
             auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor);
-            dd.generated = true;
+            dd.flags |= FUNCFLAG.generated;
             dd.storage_class |= STC.inference;
             dd.fbody = new ExpStatement(loc, e);
             ad.members.push(dd);
@@ -1008,7 +1008,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
             e = Expression.combine(e, ce);
         }
         auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
-        dd.generated = true;
+        dd.flags |= FUNCFLAG.generated;
         dd.storage_class |= STC.inference;
         dd.fbody = new ExpStatement(loc, e);
         ad.members.push(dd);
@@ -1079,7 +1079,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
     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;
+    func.flags |= FUNCFLAG.generated;
 
     auto sc2 = sc.push();
     sc2.stc &= ~STC.static_; // not a static destructor
@@ -1127,7 +1127,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
     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.flags |= FUNCFLAG.generated;
     func.storage_class |= STC.inference;
 
     auto sc2 = sc.push();
@@ -1403,7 +1403,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
         //printf("Building __fieldPostBlit()\n");
         checkShared();
         auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
-        dd.generated = true;
+        dd.flags |= FUNCFLAG.generated;
         dd.storage_class |= STC.inference | STC.scope_;
         dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
         sd.postblits.shift(dd);
@@ -1441,7 +1441,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
 
         checkShared();
         auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
-        dd.generated = true;
+        dd.flags |= FUNCFLAG.generated;
         dd.storage_class |= STC.inference;
         dd.fbody = new ExpStatement(loc, e);
         sd.members.push(dd);
@@ -1504,7 +1504,7 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const
     auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
     ccd.storage_class |= funcStc;
     ccd.storage_class |= STC.inference;
-    ccd.generated = true;
+    ccd.flags |= FUNCFLAG.generated;
     return ccd;
 }
 
@@ -1691,5 +1691,3 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc)
     }
     return true;
 }
-
-
index 9941c16..75ba9ea 100644 (file)
@@ -217,15 +217,13 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
         }
         emplaceExp!(ComplexExp)(&ue, loc, v, type);
     }
-    else if (e1.op == EXP.symbolOffset)
+    else if (SymOffExp soe = e1.isSymOffExp())
     {
-        SymOffExp soe = cast(SymOffExp)e1;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
         ue.exp().type = type;
     }
-    else if (e2.op == EXP.symbolOffset)
+    else if (SymOffExp soe = e2.isSymOffExp())
     {
-        SymOffExp soe = cast(SymOffExp)e2;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
         ue.exp().type = type;
     }
@@ -320,9 +318,8 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
         }
         emplaceExp!(ComplexExp)(&ue, loc, v, type);
     }
-    else if (e1.op == EXP.symbolOffset)
+    else if (SymOffExp soe = e1.isSymOffExp())
     {
-        SymOffExp soe = cast(SymOffExp)e1;
         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
         ue.exp().type = type;
     }
@@ -731,14 +728,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     {
         if (e2.op == EXP.null_)
             cmp = 1;
-        else if (e2.op == EXP.string_)
+        else if (StringExp es2 = e2.isStringExp())
         {
-            StringExp es2 = cast(StringExp)e2;
             cmp = (0 == es2.len);
         }
-        else if (e2.op == EXP.arrayLiteral)
+        else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
         {
-            ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
             cmp = !es2.elements || (0 == es2.elements.dim);
         }
         else
@@ -749,14 +744,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     }
     else if (e2.op == EXP.null_)
     {
-        if (e1.op == EXP.string_)
+        if (StringExp es1 = e1.isStringExp())
         {
-            StringExp es1 = cast(StringExp)e1;
             cmp = (0 == es1.len);
         }
-        else if (e1.op == EXP.arrayLiteral)
+        else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
         {
-            ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
             cmp = !es1.elements || (0 == es1.elements.dim);
         }
         else
@@ -767,8 +760,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     }
     else if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
-        StringExp es1 = cast(StringExp)e1;
-        StringExp es2 = cast(StringExp)e2;
+        StringExp es1 = e1.isStringExp();
+        StringExp es2 = e2.isStringExp();
         if (es1.sz != es2.sz)
         {
             assert(global.errors);
@@ -784,8 +777,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     }
     else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
     {
-        ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
-        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+        ArrayLiteralExp es1 = e1.isArrayLiteralExp();
+        ArrayLiteralExp es2 = e2.isArrayLiteralExp();
         if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
             cmp = 1; // both arrays are empty
         else if (!es1.elements || !es2.elements)
@@ -818,8 +811,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
     {
     Lsa:
-        StringExp es1 = cast(StringExp)e1;
-        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+        StringExp es1 = e1.isStringExp();
+        ArrayLiteralExp es2 = e2.isArrayLiteralExp();
         size_t dim1 = es1.len;
         size_t dim2 = es2.elements ? es2.elements.dim : 0;
         if (dim1 != dim2)
@@ -844,8 +837,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
     }
     else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
     {
-        StructLiteralExp es1 = cast(StructLiteralExp)e1;
-        StructLiteralExp es2 = cast(StructLiteralExp)e2;
+        StructLiteralExp es1 = e1.isStructLiteralExp();
+        StructLiteralExp es2 = e2.isStructLiteralExp();
         if (es1.sd != es2.sd)
             cmp = 0;
         else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
@@ -935,8 +928,8 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
     }
     else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
     {
-        SymOffExp es1 = cast(SymOffExp)e1;
-        SymOffExp es2 = cast(SymOffExp)e2;
+        SymOffExp es1 = e1.isSymOffExp();
+        SymOffExp es2 = e2.isSymOffExp();
         cmp = (es1.var == es2.var && es1.offset == es2.offset);
     }
     else
@@ -976,8 +969,8 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
     //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
     if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
-        StringExp es1 = cast(StringExp)e1;
-        StringExp es2 = cast(StringExp)e2;
+        StringExp es1 = e1.isStringExp();
+        StringExp es2 = e2.isStringExp();
         size_t sz = es1.sz;
         assert(sz == es2.sz);
         size_t len = es1.len;
@@ -1045,7 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
     }
     if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
     {
-        Expression ex = (cast(VectorExp)e1).e1;
+        Expression ex = e1.isVectorExp().e1;
         emplaceExp!(UnionExp)(&ue, ex);
         return ue;
     }
@@ -1201,20 +1194,17 @@ UnionExp ArrayLength(Type type, Expression e1)
 {
     UnionExp ue = void;
     Loc loc = e1.loc;
-    if (e1.op == EXP.string_)
+    if (StringExp es1 = e1.isStringExp())
     {
-        StringExp es1 = cast(StringExp)e1;
         emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
     }
-    else if (e1.op == EXP.arrayLiteral)
+    else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
     {
-        ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
         size_t dim = ale.elements ? ale.elements.dim : 0;
         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
     }
-    else if (e1.op == EXP.assocArrayLiteral)
+    else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
     {
-        AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
         size_t dim = ale.keys.dim;
         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
     }
@@ -1238,7 +1228,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
     assert(e1.type);
     if (e1.op == EXP.string_ && e2.op == EXP.int64)
     {
-        StringExp es1 = cast(StringExp)e1;
+        StringExp es1 = e1.isStringExp();
         uinteger_t i = e2.toInteger();
         if (i >= es1.len)
         {
@@ -1261,9 +1251,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
             e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
             emplaceExp!(ErrorExp)(&ue);
         }
-        else if (e1.op == EXP.arrayLiteral)
+        else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
         {
-            ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
             auto e = ale[cast(size_t)i];
             e.type = type;
             e.loc = loc;
@@ -1278,9 +1267,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
     else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
     {
         uinteger_t i = e2.toInteger();
-        if (e1.op == EXP.arrayLiteral)
+        if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
         {
-            ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
             if (i >= ale.elements.dim)
             {
                 e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim);
@@ -1300,9 +1288,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
         else
             cantExp(ue);
     }
-    else if (e1.op == EXP.assocArrayLiteral)
+    else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
     {
-        AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
         /* Search the keys backwards, in case there are duplicate keys
          */
         for (size_t i = ae.keys.dim; i;)
@@ -1350,7 +1337,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
 
     if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
     {
-        StringExp es1 = cast(StringExp)e1;
+        StringExp es1 = e1.isStringExp();
         const uinteger_t ilwr = lwr.toInteger();
         const uinteger_t iupr = upr.toInteger();
         if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
@@ -1363,14 +1350,14 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
             const data1 = es1.peekData();
             memcpy(s, data1.ptr + ilwr * sz, len * sz);
             emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
-            StringExp es = cast(StringExp)ue.exp();
+            StringExp es = ue.exp().isStringExp();
             es.committed = es1.committed;
             es.type = type;
         }
     }
     else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
     {
-        ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+        ArrayLiteralExp es1 = e1.isArrayLiteralExp();
         const uinteger_t ilwr = lwr.toInteger();
         const uinteger_t iupr = upr.toInteger();
         if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr))
@@ -1491,15 +1478,15 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
         }
     }
 
-    if (e1.op == EXP.arrayLiteral)
-        append(cast(ArrayLiteralExp)e1);
+    if (auto ale = e1.isArrayLiteralExp())
+        append(ale);
     else
         elems.push(e1);
 
     if (e2)
     {
-        if (e2.op == EXP.arrayLiteral)
-            append(cast(ArrayLiteralExp)e2);
+        if (auto ale = e2.isArrayLiteralExp())
+            append(ale);
         else
             elems.push(e2);
     }
@@ -1544,7 +1531,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
             else
                 utf_encode(sz, s, cast(dchar)v);
             emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-            StringExp es = cast(StringExp)ue.exp();
+            StringExp es = ue.exp().isStringExp();
             es.type = type;
             es.committed = 1;
         }
@@ -1589,8 +1576,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
     else if (e1.op == EXP.string_ && e2.op == EXP.string_)
     {
         // Concatenate the strings
-        StringExp es1 = cast(StringExp)e1;
-        StringExp es2 = cast(StringExp)e2;
+        StringExp es1 = e1.isStringExp();
+        StringExp es2 = e2.isStringExp();
         size_t len = es1.len + es2.len;
         ubyte sz = es1.sz;
         if (sz != es2.sz)
@@ -1609,7 +1596,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         memcpy(cast(char*)s, data1.ptr, es1.len * sz);
         memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-        StringExp es = cast(StringExp)ue.exp();
+        StringExp es = ue.exp().isStringExp();
         es.committed = es1.committed | es2.committed;
         es.type = type;
         assert(ue.exp().type);
@@ -1618,8 +1605,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
     else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
     {
         // [chars] ~ string --> [chars]
-        StringExp es = cast(StringExp)e2;
-        ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
+        StringExp es = e2.isStringExp();
+        ArrayLiteralExp ea = e1.isArrayLiteralExp();
         size_t len = es.len + ea.elements.dim;
         auto elems = new Expressions(len);
         for (size_t i = 0; i < ea.elements.dim; ++i)
@@ -1627,7 +1614,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
             (*elems)[i] = ea[i];
         }
         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
-        ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+        ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
         sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
         assert(ue.exp().type);
         return ue;
@@ -1635,8 +1622,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
     else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
     {
         // string ~ [chars] --> [chars]
-        StringExp es = cast(StringExp)e1;
-        ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
+        StringExp es = e1.isStringExp();
+        ArrayLiteralExp ea = e2.isArrayLiteralExp();
         size_t len = es.len + ea.elements.dim;
         auto elems = new Expressions(len);
         for (size_t i = 0; i < ea.elements.dim; ++i)
@@ -1644,7 +1631,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
             (*elems)[es.len + i] = ea[i];
         }
         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
-        ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+        ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
         sliceAssignArrayLiteralFromString(dest, es, 0);
         assert(ue.exp().type);
         return ue;
@@ -1652,7 +1639,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
     else if (e1.op == EXP.string_ && e2.op == EXP.int64)
     {
         // string ~ char --> string
-        StringExp es1 = cast(StringExp)e1;
+        StringExp es1 = e1.isStringExp();
         StringExp es;
         const sz = es1.sz;
         dinteger_t v = e2.toInteger();
@@ -1668,7 +1655,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         else
             utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-        es = cast(StringExp)ue.exp();
+        es = ue.exp().isStringExp();
         es.committed = es1.committed;
         es.type = type;
         assert(ue.exp().type);
@@ -1679,7 +1666,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         // [w|d]?char ~ string --> string
         // We assume that we only ever prepend one char of the same type
         // (wchar,dchar) as the string's characters.
-        StringExp es2 = cast(StringExp)e2;
+        StringExp es2 = e2.isStringExp();
         const len = 1 + es2.len;
         const sz = es2.sz;
         dinteger_t v = e1.toInteger();
@@ -1688,7 +1675,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         const data2 = es2.peekData();
         memcpy(cast(char*)s + sz, data2.ptr, data2.length);
         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-        StringExp es = cast(StringExp)ue.exp();
+        StringExp es = ue.exp().isStringExp();
         es.sz = sz;
         es.committed = es2.committed;
         es.type = type;
@@ -1796,7 +1783,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
         }
         if (!e.type.equals(type))
         {
-            StringExp se = cast(StringExp)e.copy();
+            StringExp se = e.copy().isStringExp();
             e = se.castTo(null, type);
             emplaceExp!(UnionExp)(&ue, e);
             e = ue.exp();
@@ -1812,23 +1799,21 @@ UnionExp Ptr(Type type, Expression e1)
 {
     //printf("Ptr(e1 = %s)\n", e1.toChars());
     UnionExp ue = void;
-    if (e1.op == EXP.add)
+    if (AddExp ae = e1.isAddExp())
     {
-        AddExp ae = cast(AddExp)e1;
-        if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
+        if (AddrExp ade = ae.e1.isAddrExp())
         {
-            AddrExp ade = cast(AddrExp)ae.e1;
-            if (ade.e1.op == EXP.structLiteral)
-            {
-                StructLiteralExp se = cast(StructLiteralExp)ade.e1;
-                uint offset = cast(uint)ae.e2.toInteger();
-                Expression e = se.getField(type, offset);
-                if (e)
+            if (ae.e2.op == EXP.int64)
+                if (StructLiteralExp se = ade.e1.isStructLiteralExp())
                 {
-                    emplaceExp!(UnionExp)(&ue, e);
-                    return ue;
+                    uint offset = cast(uint)ae.e2.toInteger();
+                    Expression e = se.getField(type, offset);
+                    if (e)
+                    {
+                        emplaceExp!(UnionExp)(&ue, e);
+                        return ue;
+                    }
                 }
-            }
         }
     }
     cantExp(ue);
index fb52b63..bb12aa7 100644 (file)
@@ -981,7 +981,12 @@ final class CParser(AST) : Parser!AST
                     e = new AST.DotIdExp(loc, e, Id.__sizeof);
                     break;
                 }
+                // must be an expression
+                e = cparsePrimaryExp();
+                e = new AST.DotIdExp(loc, e, Id.__sizeof);
+                break;
             }
+
             e = cparseUnaryExp();
             e = new AST.DotIdExp(loc, e, Id.__sizeof);
             break;
@@ -1016,10 +1021,16 @@ final class CParser(AST) : Parser!AST
     {
         if (token.value == TOK.leftParenthesis)
         {
+            //printf("cparseCastExp()\n");
             auto tk = peek(&token);
-            if (tk.value == TOK.identifier &&
-                !isTypedef(tk.ident) &&
-                peek(tk).value == TOK.rightParenthesis)
+            bool iscast;
+            bool isexp;
+            if (tk.value == TOK.identifier)
+            {
+                iscast = isTypedef(tk.ident);
+                isexp = !iscast;
+            }
+            if (isexp)
             {
                 // ( identifier ) is an expression
                 return cparseUnaryExp();
@@ -1045,9 +1056,18 @@ final class CParser(AST) : Parser!AST
                     auto ce = new AST.CompoundLiteralExp(loc, t, ci);
                     return cparsePostfixOperators(ce);
                 }
-                else if (t.isTypeIdentifier() &&
-                         token.value == TOK.leftParenthesis &&
-                         !isCastExpression(pt))
+
+                if (iscast)
+                {
+                    // ( type-name ) cast-expression
+                    auto ce = cparseCastExp();
+                    return new AST.CastExp(loc, ce, t);
+                }
+
+                if (t.isTypeIdentifier() &&
+                    isexp &&
+                    token.value == TOK.leftParenthesis &&
+                    !isCastExpression(pt))
                 {
                     /* (t)(...)... might be a cast expression or a function call,
                      * with different grammars: a cast would be cparseCastExp(),
@@ -1061,12 +1081,10 @@ final class CParser(AST) : Parser!AST
                     AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
                     return cparsePostfixOperators(e);
                 }
-                else
-                {
-                    // ( type-name ) cast-expression
-                    auto ce = cparseCastExp();
-                    return new AST.CastExp(loc, ce, t);
-                }
+
+                // ( type-name ) cast-expression
+                auto ce = cparseCastExp();
+                return new AST.CastExp(loc, ce, t);
             }
         }
         return cparseUnaryExp();
@@ -1764,8 +1782,6 @@ final class CParser(AST) : Parser!AST
                         symbols.push(stag);
                         if (tt.tok == TOK.enum_)
                         {
-                            if (!stag.members)
-                                error(tt.loc, "`enum %s` has no members", stag.toChars());
                             isalias = false;
                             s = new AST.AliasDeclaration(token.loc, id, stag);
                         }
@@ -2382,7 +2398,19 @@ final class CParser(AST) : Parser!AST
                 const idx = previd.toString();
                 if (idx.length > 2 && idx[0] == '_' && idx[1] == '_')  // leading double underscore
                     importBuiltins = true;  // probably one of those compiler extensions
-                t = new AST.TypeIdentifier(loc, previd);
+                t = null;
+                if (scw & SCW.xtypedef)
+                {
+                    /* Punch through to what the typedef is, to support things like:
+                     *  typedef T* T;
+                     */
+                    auto pt = lookupTypedef(previd);
+                    if (pt && *pt)      // if previd is a known typedef
+                        t = *pt;
+                }
+
+                if (!t)
+                    t = new AST.TypeIdentifier(loc, previd);
                 break;
             }
 
@@ -4767,7 +4795,8 @@ final class CParser(AST) : Parser!AST
         scan(&n);
         if (n.value == TOK.identifier && n.ident == Id.pack)
             return pragmaPack(loc);
-        skipToNextLine();
+        if (n.value != TOK.endOfLine)
+            skipToNextLine();
     }
 
     /*********
@@ -4786,7 +4815,8 @@ final class CParser(AST) : Parser!AST
         if (n.value != TOK.leftParenthesis)
         {
             error(loc, "left parenthesis expected to follow `#pragma pack`");
-            skipToNextLine();
+            if (n.value != TOK.endOfLine)
+                skipToNextLine();
             return;
         }
 
@@ -4796,7 +4826,8 @@ final class CParser(AST) : Parser!AST
             {
                 error(loc, "right parenthesis expected to close `#pragma pack(`");
             }
-            skipToNextLine();
+            if (n.value != TOK.endOfLine)
+                skipToNextLine();
         }
 
         void setPackAlign(ref const Token t)
@@ -4923,7 +4954,8 @@ final class CParser(AST) : Parser!AST
         }
 
         error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
-        skipToNextLine();
+        if (n.value != TOK.endOfLine)
+            skipToNextLine();
     }
 
     //}
index 9078f90..32aed16 100644 (file)
@@ -232,11 +232,11 @@ bool needToCopyLiteral(const Expression expr)
         switch (e.op)
         {
         case EXP.arrayLiteral:
-            return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+            return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code;
         case EXP.assocArrayLiteral:
-            return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+            return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code;
         case EXP.structLiteral:
-            return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
+            return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code;
         case EXP.string_:
         case EXP.this_:
         case EXP.variable:
@@ -247,14 +247,14 @@ bool needToCopyLiteral(const Expression expr)
         case EXP.dotVariable:
         case EXP.slice:
         case EXP.cast_:
-            e = (cast(UnaExp)e).e1;
+            e = e.isUnaExp().e1;
             continue;
         case EXP.concatenate:
-            return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
+            return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2);
         case EXP.concatenateAssign:
         case EXP.concatenateElemAssign:
         case EXP.concatenateDcharAssign:
-            e = (cast(BinExp)e).e2;
+            e = e.isBinExp().e2;
             continue;
         default:
             return false;
@@ -286,7 +286,7 @@ UnionExp copyLiteral(Expression e)
         const slice = se.peekData();
         memcpy(s, slice.ptr, slice.length);
         emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
-        StringExp se2 = cast(StringExp)ue.exp();
+        StringExp se2 = ue.exp().isStringExp();
         se2.committed = se.committed;
         se2.postfix = se.postfix;
         se2.type = se.type;
@@ -299,14 +299,14 @@ UnionExp copyLiteral(Expression e)
 
         emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
 
-        ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp();
+        ArrayLiteralExp r = ue.exp().isArrayLiteralExp();
         r.ownedByCtfe = OwnedBy.ctfe;
         return ue;
     }
     if (auto aae = e.isAssocArrayLiteralExp())
     {
         emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
-        AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp();
+        AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
         r.type = e.type;
         r.ownedByCtfe = OwnedBy.ctfe;
         return ue;
@@ -482,7 +482,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
         // 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 = ue.exp().isAssocArrayLiteralExp();
         aae.ownedByCtfe = wasOwned;
     }
     else
@@ -526,7 +526,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null)
  * It's very wasteful to resolve the slice when we only
  * need the length.
  */
-uinteger_t resolveArrayLength(const Expression e)
+uinteger_t resolveArrayLength(Expression e)
 {
     switch (e.op)
     {
@@ -538,7 +538,7 @@ uinteger_t resolveArrayLength(const Expression e)
 
         case EXP.slice:
         {
-            auto se = cast(SliceExp)e;
+            auto se = e.isSliceExp();
             const ilo = se.lwr.toInteger();
             const iup = se.upr.toInteger();
             return iup - ilo;
@@ -720,16 +720,16 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
         *ofs = soe.offset;
     if (auto dve = e.isDotVarExp())
     {
-        const ex = dve.e1;
+        auto ex = dve.e1;
         const v = dve.var.isVarDeclaration();
         assert(v);
         StructLiteralExp se = (ex.op == EXP.classReference)
-            ? (cast(ClassReferenceExp)ex).value
-            : cast(StructLiteralExp)ex;
+            ? ex.isClassReferenceExp().value
+            : ex.isStructLiteralExp();
 
         // We can't use getField, because it makes a copy
         const i = (ex.op == EXP.classReference)
-            ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
+            ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset)
             : se.getFieldIndex(e.type, v.offset);
         e = (*se.elements)[i];
     }
@@ -777,11 +777,11 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
     }
     // Note that type painting can occur with VarExp, so we
     // must compare the variables being pointed to.
-    if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
+    if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)
     {
         return true;
     }
-    if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+    if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var)
     {
         return true;
     }
@@ -801,14 +801,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres
         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
     }
     else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
-             (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
+             agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
     {
         Type pointee = (cast(TypePointer)agg1.type).next;
         const sz = pointee.size();
         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
     }
     else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
-             (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+             agg1.isSymOffExp().var == agg2.isSymOffExp().var)
     {
         emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
     }
@@ -832,12 +832,12 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
         return pue.exp();
     }
     if (eptr.op == EXP.address)
-        eptr = (cast(AddrExp)eptr).e1;
+        eptr = eptr.isAddrExp().e1;
     dinteger_t ofs1;
     Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
     if (agg1.op == EXP.symbolOffset)
     {
-        if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
+        if (agg1.isSymOffExp().var.type.ty != Tsarray)
         {
             error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
             goto Lcant;
@@ -856,7 +856,7 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
     if (agg1.op == EXP.symbolOffset)
     {
         indx = ofs1 / sz;
-        len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
+        len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
     }
     else
     {
@@ -881,8 +881,8 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
     }
     if (agg1.op == EXP.symbolOffset)
     {
-        emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz);
-        SymOffExp se = cast(SymOffExp)pue.exp();
+        emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz);
+        SymOffExp se = pue.exp().isSymOffExp();
         se.type = type;
         return pue.exp();
     }
@@ -1016,7 +1016,7 @@ Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
 bool isCtfeComparable(Expression e)
 {
     if (e.op == EXP.slice)
-        e = (cast(SliceExp)e).e1;
+        e = e.isSliceExp().e1;
     if (e.isConst() != 1)
     {
         if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
@@ -1191,7 +1191,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
     if (e1.op == EXP.classReference || e2.op == EXP.classReference)
     {
         if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
-            (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
+            e1.isClassReferenceExp().value == e2.isClassReferenceExp().value)
             return 0;
         return 1;
     }
@@ -1199,8 +1199,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
     {
         // 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);
+        Type t1 = isType(e1.isTypeidExp().obj);
+        Type t2 = isType(e2.isTypeidExp().obj);
         assert(t1);
         assert(t2);
         return t1 != t2;
@@ -1214,7 +1214,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         dinteger_t ofs1, ofs2;
         Expression agg1 = getAggregateFromPointer(e1, &ofs1);
         Expression agg2 = getAggregateFromPointer(e2, &ofs2);
-        if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+        if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
         {
             if (ofs1 == ofs2)
                 return 0;
@@ -1232,13 +1232,13 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
             return 0;
         assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
         // Same .funcptr. Do they have the same .ptr?
-        Expression ptr1 = (cast(DelegateExp)e1).e1;
-        Expression ptr2 = (cast(DelegateExp)e2).e1;
+        Expression ptr1 = e1.isDelegateExp().e1;
+        Expression ptr2 = e2.isDelegateExp().e1;
         dinteger_t ofs1, ofs2;
         Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
         Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
         // If they are EXP.variable, it means they are FuncDeclarations
-        if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+        if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
         {
             return 0;
         }
@@ -1291,8 +1291,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
     }
     if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
     {
-        StructLiteralExp es1 = cast(StructLiteralExp)e1;
-        StructLiteralExp es2 = cast(StructLiteralExp)e2;
+        StructLiteralExp es1 = e1.isStructLiteralExp();
+        StructLiteralExp es2 = e2.isStructLiteralExp();
         // For structs, we only need to return 0 or 1 (< and > aren't legal).
         if (es1.sd != es2.sd)
             return 1;
@@ -1326,8 +1326,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
     }
     if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
     {
-        AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
-        AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
+        AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp();
+        AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp();
         size_t dim = es1.keys.dim;
         if (es2.keys.dim != dim)
             return 1;
@@ -1394,8 +1394,8 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
     }
     else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
     {
-        SymOffExp es1 = cast(SymOffExp)e1;
-        SymOffExp es2 = cast(SymOffExp)e2;
+        SymOffExp es1 = e1.isSymOffExp();
+        SymOffExp es2 = e2.isSymOffExp();
         cmp = (es1.var == es2.var && es1.offset == es2.offset);
     }
     else if (e1.type.isreal())
@@ -1443,8 +1443,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
     if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
     {
         // [chars] ~ string => string (only valid for CTFE)
-        StringExp es1 = cast(StringExp)e2;
-        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1;
+        StringExp es1 = e2.isStringExp();
+        ArrayLiteralExp es2 = e1.isArrayLiteralExp();
         const len = es1.len + es2.elements.dim;
         const sz = es1.sz;
         void* s = mem.xmalloc((len + 1) * sz);
@@ -1464,7 +1464,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         // Add terminating 0
         memset(cast(char*)s + len * sz, 0, sz);
         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-        StringExp es = cast(StringExp)ue.exp();
+        StringExp es = ue.exp().isStringExp();
         es.committed = 0;
         es.type = type;
         return ue;
@@ -1473,8 +1473,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
     {
         // string ~ [chars] => string (only valid for CTFE)
         // Concatenate the strings
-        StringExp es1 = cast(StringExp)e1;
-        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+        StringExp es1 = e1.isStringExp();
+        ArrayLiteralExp es2 = e2.isArrayLiteralExp();
         const len = es1.len + es2.elements.dim;
         const sz = es1.sz;
         void* s = mem.xmalloc((len + 1) * sz);
@@ -1494,7 +1494,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         // Add terminating 0
         memset(cast(char*)s + len * sz, 0, sz);
         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
-        StringExp es = cast(StringExp)ue.exp();
+        StringExp es = ue.exp().isStringExp();
         es.sz = sz;
         es.committed = 0; //es1.committed;
         es.type = type;
@@ -1503,10 +1503,10 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
     if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
     {
         //  [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
-        ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
-        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+        ArrayLiteralExp es1 = e1.isArrayLiteralExp();
+        ArrayLiteralExp es2 = e2.isArrayLiteralExp();
         emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
-        es1 = cast(ArrayLiteralExp)ue.exp();
+        es1 = ue.exp().isArrayLiteralExp();
         es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
         return ue;
     }
@@ -1594,7 +1594,7 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
         // Disallow reinterpreting class casts. Do this by ensuring that
         // the original class can implicitly convert to the target class.
         // Also do not check 'alias this' for explicit cast expressions.
-        auto tclass = (cast(ClassReferenceExp)e).originalClass().type.isTypeClass();
+        auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass();
         auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf())
                                   : tclass.implicitConvTo(to.mutableOf());
         if (match)
@@ -1665,9 +1665,9 @@ void assignInPlace(Expression dest, Expression src)
     if (dest.op == EXP.structLiteral)
     {
         assert(dest.op == src.op);
-        oldelems = (cast(StructLiteralExp)dest).elements;
-        newelems = (cast(StructLiteralExp)src).elements;
-        auto sd = (cast(StructLiteralExp)dest).sd;
+        oldelems = dest.isStructLiteralExp().elements;
+        newelems = src.isStructLiteralExp().elements;
+        auto sd = dest.isStructLiteralExp().sd;
         const nfields = sd.nonHiddenFields();
         const nvthis = sd.fields.dim - nfields;
         if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
@@ -1676,22 +1676,22 @@ void assignInPlace(Expression dest, Expression src)
     }
     else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
     {
-        oldelems = (cast(ArrayLiteralExp)dest).elements;
-        newelems = (cast(ArrayLiteralExp)src).elements;
+        oldelems = dest.isArrayLiteralExp().elements;
+        newelems = src.isArrayLiteralExp().elements;
     }
     else if (dest.op == EXP.string_ && src.op == EXP.string_)
     {
-        sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
+        sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0);
         return;
     }
     else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
     {
-        sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
+        sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0);
         return;
     }
     else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
     {
-        sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
+        sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
         return;
     }
     else
@@ -1761,13 +1761,13 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
     size_t indxlo = 0;
     if (oldval.op == EXP.slice)
     {
-        indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
-        oldval = (cast(SliceExp)oldval).e1;
+        indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger();
+        oldval = oldval.isSliceExp().e1;
     }
     size_t copylen = oldlen < newlen ? oldlen : newlen;
     if (oldval.op == EXP.string_)
     {
-        StringExp oldse = cast(StringExp)oldval;
+        StringExp oldse = oldval.isStringExp();
         void* s = mem.xcalloc(newlen + 1, oldse.sz);
         const data = oldse.peekData();
         memcpy(s, data.ptr, copylen * oldse.sz);
@@ -1790,7 +1790,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
             }
         }
         emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
-        StringExp se = cast(StringExp)pue.exp();
+        StringExp se = pue.exp().isStringExp();
         se.type = arrayType;
         se.sz = oldse.sz;
         se.committed = oldse.committed;
@@ -1801,7 +1801,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
         if (oldlen != 0)
         {
             assert(oldval.op == EXP.arrayLiteral);
-            ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
+            ArrayLiteralExp ae = oldval.isArrayLiteralExp();
             foreach (size_t i; 0 .. copylen)
                 (*elements)[i] = (*ae.elements)[indxlo + i];
         }
@@ -1819,7 +1819,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray
                 (*elements)[i] = defaultElem;
         }
         emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
-        ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp();
+        ArrayLiteralExp aae = pue.exp().isArrayLiteralExp();
         aae.ownedByCtfe = OwnedBy.ctfe;
     }
     return pue.exp();
@@ -1874,14 +1874,14 @@ bool isCtfeValueValid(Expression newval)
         {
             // &struct.func or &clasinst.func
             // &nestedfunc
-            Expression ethis = (cast(DelegateExp)newval).e1;
-            return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
+            Expression ethis = newval.isDelegateExp().e1;
+            return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func);
         }
 
         case EXP.symbolOffset:
         {
             // function pointer, or pointer to static variable
-            Declaration d = (cast(SymOffExp)newval).var;
+            Declaration d = newval.isSymOffExp().var;
             return d.isFuncDeclaration() || d.isDataseg();
         }
 
@@ -1894,7 +1894,7 @@ bool isCtfeValueValid(Expression newval)
         case EXP.address:
         {
             // e1 should be a CTFE reference
-            Expression e1 = (cast(AddrExp)newval).e1;
+            Expression e1 = newval.isAddrExp().e1;
             return tb.ty == Tpointer &&
             (
                 (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
@@ -1908,7 +1908,7 @@ bool isCtfeValueValid(Expression newval)
         case EXP.slice:
         {
             // e1 should be an array aggregate
-            const SliceExp se = cast(SliceExp)newval;
+            const SliceExp se = newval.isSliceExp();
             assert(se.lwr && se.lwr.op == EXP.int64);
             assert(se.upr && se.upr.op == EXP.int64);
             return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
@@ -1932,7 +1932,7 @@ bool isCtfeReferenceValid(Expression newval)
 
         case EXP.variable:
         {
-            const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
+            const VarDeclaration v = newval.isVarExp().var.isVarDeclaration();
             assert(v);
             // Must not be a reference to a reference
             return true;
@@ -1940,13 +1940,13 @@ bool isCtfeReferenceValid(Expression newval)
 
         case EXP.index:
         {
-            const Expression eagg = (cast(IndexExp)newval).e1;
+            const Expression eagg = newval.isIndexExp().e1;
             return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
         }
 
         case EXP.dotVariable:
         {
-            Expression eagg = (cast(DotVarExp)newval).e1;
+            Expression eagg = newval.isDotVarExp().e1;
             return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
         }
 
@@ -1968,19 +1968,19 @@ void showCtfeExpr(Expression e, int level = 0)
     ClassDeclaration cd = null;
     if (e.op == EXP.structLiteral)
     {
-        elements = (cast(StructLiteralExp)e).elements;
-        sd = (cast(StructLiteralExp)e).sd;
+        elements = e.isStructLiteralExp().elements;
+        sd = e.isStructLiteralExp().sd;
         printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
     }
     else if (e.op == EXP.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);
+        elements = e.isClassReferenceExp().value.elements;
+        cd = e.isClassReferenceExp().originalClass();
+        printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value);
     }
     else if (e.op == EXP.arrayLiteral)
     {
-        elements = (cast(ArrayLiteralExp)e).elements;
+        elements = e.isArrayLiteralExp().elements;
         printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
     }
     else if (e.op == EXP.assocArrayLiteral)
@@ -1994,19 +1994,19 @@ void showCtfeExpr(Expression e, int level = 0)
     else if (e.op == EXP.slice)
     {
         printf("SLICE %p: %s\n", e, e.toChars());
-        showCtfeExpr((cast(SliceExp)e).e1, level + 1);
+        showCtfeExpr(e.isSliceExp().e1, level + 1);
     }
     else if (e.op == EXP.variable)
     {
         printf("VAR %p %s\n", e, e.toChars());
-        VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+        VarDeclaration v = e.isVarExp().var.isVarDeclaration();
         if (v && getValue(v))
             showCtfeExpr(getValue(v), level + 1);
     }
     else if (e.op == EXP.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());
+        printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars());
     }
     else
         printf("VALUE %p: %s\n", e, e.toChars());
@@ -2086,7 +2086,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
             (*elements)[i] = elem;
         }
         emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
-        ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp();
+        ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
         ae.ownedByCtfe = OwnedBy.ctfe;
     }
     else if (t.ty == Tstruct)
@@ -2098,7 +2098,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
             (*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();
+        StructLiteralExp se = ue.exp().isStructLiteralExp();
         se.type = ts;
         se.ownedByCtfe = OwnedBy.ctfe;
     }
index cc251b0..c04793d 100644 (file)
@@ -222,4 +222,3 @@ bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow
     }
     return ok;
 }
-
index 887bb89..685987b 100644 (file)
@@ -3880,4 +3880,3 @@ IntRange getIntRange(Expression e)
         case EXP.negate             : return visitNeg(e.isNegExp());
     }
 }
-
index 82a5f3b..c0e40a5 100644 (file)
@@ -292,7 +292,7 @@ extern (C++) abstract class Declaration : Dsymbol
                  * postblit. Print the first field that has
                  * a disabled postblit.
                  */
-                if (postblit.generated)
+                if (postblit.isGenerated())
                 {
                     auto sd = p.isStructDeclaration();
                     assert(sd);
@@ -334,7 +334,7 @@ extern (C++) abstract class Declaration : Dsymbol
 
         if (auto ctor = isCtorDeclaration())
         {
-            if (ctor.isCpCtor && ctor.generated)
+            if (ctor.isCpCtor && ctor.isGenerated())
             {
                 .error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
                 return true;
@@ -1060,24 +1060,51 @@ extern (C++) class VarDeclaration : Declaration
     enum AdrOnStackNone = ~0u;
     uint ctfeAdrOnStack;
 
-    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 isowner;                   // this is an Owner, despite it being `scope`
-    bool setInCtorOnly;             // field can only be set in a constructor, as it is const or immutable
+    // `bool` fields that are compacted into bit fields in a string mixin
+    private extern (D) static struct BitFields
+    {
+        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 isowner;           /// this is an Owner, despite it being `scope`
+        bool setInCtorOnly;     /// field can only be set in a constructor, as it is const or immutable
+
+        /// It is a class that was allocated on the stack
+        ///
+        /// This means the var is not rebindable once assigned,
+        /// and the destructor gets run when it goes out of scope
+        bool onstack;
 
-    // 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 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
+        bool doNotInferReturn;  /// do not infer 'return' for this variable
+
+        bool isArgDtorVar;      /// temporary created to handle scope destruction of a function argument
+    }
 
+    private ushort bitFields;       // stores multiple booleans for BitFields
     byte 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
-    bool doNotInferReturn;          // do not infer 'return' for this variable
     ubyte isdataseg;                // private data for isDataseg 0 unset, 1 true, 2 false
 
-    bool isArgDtorVar;              // temporary created to handle scope destruction of a function argument
+    // Generate getter and setter functions for `bitFields`
+    extern (D) mixin(() {
+        string result = "extern (C++) pure nothrow @nogc @safe final {";
+        foreach (size_t i, mem; __traits(allMembers, BitFields))
+        {
+            result ~= "
+            /// set or get the corresponding BitFields member
+            bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
+            /// ditto
+            bool "~mem~"(bool v)
+            {
+                v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
+                return v;
+            }";
+        }
+        return result ~ "}";
+    }());
+
 
     final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
     in
@@ -1642,64 +1669,6 @@ extern (C++) class VarDeclaration : Declaration
     {
         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
-    {
-        // VarDeclaration's with these STC's need special treatment
-        enum special = STC.temp | STC.foreach_;
-
-        // Sequence numbers work when there are no special VarDeclaration's involved
-        if (!((this.storage_class | v.storage_class) & special))
-        {
-            assert(this.sequenceNumber != this.sequenceNumber.init);
-            assert(v.sequenceNumber != v.sequenceNumber.init);
-
-            return (this.sequenceNumber < v.sequenceNumber);
-        }
-
-        // Assume that semantic produces temporaries according to their lifetime
-        // (It won't create a temporary before the actual content)
-        if ((this.storage_class & special) && (v.storage_class & special))
-            return this.sequenceNumber < v.sequenceNumber;
-
-        // Fall back to lexical order
-        assert(this.loc != Loc.initial);
-        assert(v.loc != Loc.initial);
-
-        if (this.loc.linnum != v.loc.linnum)
-            return this.loc.linnum < v.loc.linnum;
-
-        if (this.loc.charnum != v.loc.charnum)
-            return this.loc.charnum < v.loc.charnum;
-
-        // Default fallback
-        return this.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);
-    }
 }
 
 /*******************************************************
index 9986ea3..441a966 100644 (file)
@@ -241,22 +241,33 @@ public:
     // When interpreting, these point to the value (NULL if value not determinable)
     // The index of this variable on the CTFE stack, ~0u if not allocated
     unsigned ctfeAdrOnStack;
-
-    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 isowner;               // this is an Owner, despite it being `scope`
-    bool setInCtorOnly;         // field can only be set in a constructor, as it is const or immutable
-    bool onstack;               // it is a class that was allocated on the stack
-    char 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
-    bool doNotInferReturn;      // do not infer 'return' for this variable
-    unsigned char isdataseg;    // private data for isDataseg
-    bool isArgDtorVar;          // temporary created to handle scope destruction of a function argument
-
-public:
+private:
+    uint16_t bitFields;
+public:
+    int8_t canassign; // // it can be assigned to
+    uint8_t isdataseg; // private data for isDataseg
+    bool isargptr() const; // if parameter that _argptr points to
+    bool isargptr(bool v);
+    bool ctorinit() const; // it has been initialized in a ctor
+    bool ctorinit(bool v);
+    bool iscatchvar() const; // this is the exception object variable in catch() clause
+    bool iscatchvar(bool v);
+    bool isowner() const; // this is an Owner, despite it being `scope`
+    bool isowner(bool v);
+    bool setInCtorOnly() const; // field can only be set in a constructor, as it is const or immutable
+    bool setInCtorOnly(bool v);
+    bool onstack() const; // it is a class that was allocated on the stack
+    bool onstack(bool v);
+    bool overlapped() const; // if it is a field and has overlapping
+    bool overlapped(bool v);
+    bool overlapUnsafe() const; // if it is an overlapping field and the overlaps are unsafe
+    bool overlapUnsafe(bool v);
+    bool doNotInferScope() const; // do not infer 'scope' for this variable
+    bool doNotInferScope(bool v);
+    bool doNotInferReturn() const; // do not infer 'return' for this variable
+    bool doNotInferReturn(bool v);
+    bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument
+    bool isArgDtorVar(bool v);
     static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
     VarDeclaration *syntaxCopy(Dsymbol *);
     void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
@@ -273,7 +284,6 @@ public:
     bool hasPointers();
     bool canTakeAddressOf();
     bool needsScopeDtor();
-    bool enclosesLifetimeOf(VarDeclaration *v) const;
     void checkCtorConstInit();
     Dsymbol *toAlias();
     // Eliminate need for dynamic_cast
@@ -541,7 +551,6 @@ public:
     // scopes from having the same name
     DsymbolTable *localsymtab;
     VarDeclaration *vthis;              // 'this' parameter (member and nested)
-    bool isThis2;                       // has a dual-context 'this' parameter
     VarDeclaration *v_arguments;        // '_arguments' parameter
 
     VarDeclaration *v_argptr;           // '_argptr' variable
@@ -551,29 +560,20 @@ public:
     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
-    bool hasAlwaysInlines;              // contains references to functions that must be inlined
-    unsigned char isCrtCtorDtor;        // has attribute pragma(crt_constructor(1)/crt_destructor(2))
-                                        // not set before the glue layer
+
     ILS inlineStatusStmt;
     ILS inlineStatusExp;
     PINLINE inlining;
 
     int inlineNest;                     // !=0 if nested inline
-    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
@@ -585,8 +585,6 @@ public:
     // 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
 
@@ -654,6 +652,19 @@ public:
 
     bool isNogc();
     bool isNogcBypassingInference();
+    bool isNRVO() const;
+    void isNRVO(bool v);
+    bool isNaked() const;
+    bool isGenerated() const;
+    void isGenerated(bool v);
+    bool isIntroducing() const;
+    bool hasSemantic3Errors() const;
+    bool hasNoEH() const;
+    bool inferRetType() const;
+    bool hasDualContext() const;
+    bool hasAlwaysInlines() const;
+    bool isCrtCtor() const;
+    bool isCrtDtor() const;
 
     virtual bool isNested() const;
     AggregateDeclaration *isThis();
index 90e48f8..aba290b 100644 (file)
@@ -96,7 +96,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
 
     override void setScope(Scope* sc)
     {
-        if (semanticRun > PASS.init)
+        if (semanticRun > PASS.initial)
             return;
         ScopeDsymbol.setScope(sc);
     }
@@ -163,6 +163,9 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
         if (defaultval)
             return defaultval;
 
+        if (isCsymbol())
+            return memtype.defaultInit(loc, true);
+
         if (_scope)
             dsymbolSemantic(this, _scope);
         if (errors)
index 30a8a44..3cfc07a 100644 (file)
@@ -535,7 +535,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
     istatex.caller = istate;
     istatex.fd = fd;
 
-    if (fd.isThis2)
+    if (fd.hasDualContext())
     {
         Expression arg0 = thisarg;
         if (arg0 && arg0.type.ty == Tstruct)
@@ -678,7 +678,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
         e = CTFEExp.voidexp;
     if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
         e = thisarg;
-    if (tf.isref && fd.isThis2 && e.op == EXP.index)
+    if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
     {
         auto ie = e.isIndexExp();
         auto pe = ie.e1.isPtrExp();
@@ -944,7 +944,7 @@ public:
             if (auto eaddr = e.isAddrExp())
                 x = eaddr.e1;
             VarDeclaration v;
-            while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
+            while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
             {
                 if (v.storage_class & STC.ref_)
                 {
@@ -1526,7 +1526,7 @@ public:
         }
         while ((*boss.value.elements)[next].op == EXP.classReference)
         {
-            boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
+            boss = (*boss.value.elements)[next].isClassReferenceExp();
         }
         (*boss.value.elements)[next] = collateral;
         return oldest;
@@ -1752,7 +1752,7 @@ public:
             if (istate && istate.fd.vthis)
             {
                 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
-                if (istate.fd.isThis2)
+                if (istate.fd.hasDualContext())
                 {
                     result = ctfeEmplaceExp!PtrExp(e.loc, result);
                     result.type = Type.tvoidptr.sarrayOf(2);
@@ -1768,15 +1768,15 @@ public:
         result = ctfeGlobals.stack.getThis();
         if (result)
         {
-            if (istate && istate.fd.isThis2)
+            if (istate && istate.fd.hasDualContext())
             {
                 assert(result.op == EXP.address);
-                result = (cast(AddrExp)result).e1;
+                result = result.isAddrExp().e1;
                 assert(result.op == EXP.arrayLiteral);
-                result = (*(cast(ArrayLiteralExp)result).elements)[0];
+                result = (*result.isArrayLiteralExp().elements)[0];
                 if (e.type.ty == Tstruct)
                 {
-                    result = (cast(AddrExp)result).e1;
+                    result = result.isAddrExp().e1;
                 }
                 return;
             }
@@ -1873,7 +1873,9 @@ public:
         {
             fromType = (cast(TypeArray)e.var.type).next;
         }
-        if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
+        if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) ||
+                                  (fromType && isSafePointerCast(fromType, pointee)) ||
+                                  (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
         {
             result = e;
             return;
@@ -1980,7 +1982,7 @@ public:
             if (decl.isDataseg()) {
                 // Normally this is already done by optimize()
                 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
-                emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
+                emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
                 result = pue.exp();
                 result.type = e.type;
                 return;
@@ -2399,7 +2401,7 @@ public:
                 return;
             }
 
-            ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
+            ClassDeclaration cd = result.isClassReferenceExp().originalClass();
             assert(cd);
 
             emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
@@ -2487,7 +2489,7 @@ public:
             else
             {
                 // segfault bug 6250
-                assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
+                assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
 
                 ex = interpretRegion(exp, istate);
                 if (exceptionOrCant(ex))
@@ -2521,7 +2523,7 @@ public:
                 return;
             }
             emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
-            auto ale = cast(ArrayLiteralExp)pue.exp();
+            auto ale = pue.exp().isArrayLiteralExp();
             ale.ownedByCtfe = OwnedBy.ctfe;
             result = ale;
         }
@@ -2705,7 +2707,7 @@ public:
                 return;
             }
             emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
-            auto sle = cast(StructLiteralExp)pue.exp();
+            auto sle = pue.exp().isStructLiteralExp();
             sle.type = e.type;
             sle.ownedByCtfe = OwnedBy.ctfe;
             sle.origin = e.origin;
@@ -2737,7 +2739,7 @@ public:
             foreach (ref element; *elements)
                 element = copyLiteral(elem).copy();
             emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
-            auto ae = cast(ArrayLiteralExp)pue.exp();
+            auto ae = pue.exp().isArrayLiteralExp();
             ae.ownedByCtfe = OwnedBy.ctfe;
             return ae;
         }
@@ -2959,7 +2961,7 @@ public:
             result = e; // optimize: reuse this CTFE reference
         else
         {
-            auto edt = cast(DotTypeExp)e.copy();
+            auto edt = e.copy().isDotTypeExp();
             edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
             result = edt;
         }
@@ -3335,7 +3337,7 @@ public:
             if (exceptionOrCant(newval))
                 return;
 
-            VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
+            VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
             setValue(v, newval);
 
             // Get the value to return. Note that 'newval' is an Lvalue,
@@ -3351,7 +3353,7 @@ public:
         {
             while (e1.op == EXP.cast_)
             {
-                CastExp ce = cast(CastExp)e1;
+                CastExp ce = e1.isCastExp();
                 e1 = ce.e1;
             }
         }
@@ -3362,7 +3364,7 @@ public:
         AssocArrayLiteralExp existingAA = null;
         Expression lastIndex = null;
         Expression oldval = null;
-        if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+        if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
         {
             // ---------------------------------------
             //      Deal with AA index assignment
@@ -3374,12 +3376,12 @@ public:
              * (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;
+            IndexExp ie = e1.isIndexExp();
             int depth = 0; // how many nested AA indices are there?
-            while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
+            while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
             {
                 assert(ie.modifiable);
-                ie = cast(IndexExp)ie.e1;
+                ie = ie.e1.isIndexExp();
                 ++depth;
             }
 
@@ -3392,7 +3394,7 @@ public:
                 // 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 = interpretRegion((cast(IndexExp)e1).e2, istate);
+                lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
                 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
                 if (exceptionOrCant(lastIndex))
                     return;
@@ -3400,9 +3402,9 @@ public:
                 while (depth > 0)
                 {
                     // Walk the syntax tree to find the indexExp at this depth
-                    IndexExp xe = cast(IndexExp)e1;
+                    IndexExp xe = e1.isIndexExp();
                     foreach (d; 0 .. depth)
-                        xe = cast(IndexExp)xe.e1;
+                        xe = xe.e1.isIndexExp();
 
                     Expression ekey = interpretRegion(xe.e2, istate);
                     if (exceptionOrCant(ekey))
@@ -3450,9 +3452,9 @@ public:
                 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
 
                 Expression newaae = oldval;
-                while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+                while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
                 {
-                    Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
+                    Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
                     if (exceptionOrCant(ekey))
                         return;
                     ekey = resolveSlice(ekey); // only happens with AA assignment
@@ -3463,7 +3465,7 @@ public:
                     valuesx.push(newaae);
 
                     auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
-                    aae.type = (cast(IndexExp)e1).e1.type;
+                    aae.type = e1.isIndexExp().e1.type;
                     aae.ownedByCtfe = OwnedBy.ctfe;
                     if (!existingAA)
                     {
@@ -3471,7 +3473,7 @@ public:
                         lastIndex = ekey;
                     }
                     newaae = aae;
-                    e1 = (cast(IndexExp)e1).e1;
+                    e1 = e1.isIndexExp().e1;
                 }
 
                 // We must set to aggregate with newaae
@@ -3521,11 +3523,11 @@ public:
             if (exceptionOrCant(e1))
                 return;
 
-            if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+            if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
             {
-                IndexExp ie = cast(IndexExp)e1;
+                IndexExp ie = e1.isIndexExp();
                 assert(ie.e1.op == EXP.assocArrayLiteral);
-                existingAA = cast(AssocArrayLiteralExp)ie.e1;
+                existingAA = ie.e1.isAssocArrayLiteralExp();
                 lastIndex = ie.e2;
             }
         }
@@ -3657,7 +3659,7 @@ public:
 
             // We have changed it into a reference assignment
             // Note that returnValue is still the new length.
-            e1 = (cast(ArrayLengthExp)e1).e1;
+            e1 = e1.isArrayLengthExp().e1;
             Type t = e1.type.toBasetype();
             if (t.ty != Tarray)
             {
@@ -3733,8 +3735,8 @@ public:
                 if (auto dve = e1x.isDotVarExp())
                 {
                     auto ex = dve.e1;
-                    auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
-                             : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
+                    auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
+                             : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
                              : null;
                     auto v = dve.var.isVarDeclaration();
                     if (!sle || !v)
@@ -3792,10 +3794,10 @@ public:
              *  e.v = newval
              */
             auto ex = dve.e1;
-            auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
-                     : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
+            auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
+                     : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
                      : null;
-            auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
+            auto v = e1.isDotVarExp().var.isVarDeclaration();
             if (!sle || !v)
             {
                 e.error("CTFE internal error: dotvar assignment");
@@ -3808,7 +3810,7 @@ public:
             }
 
             int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
-                       : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+                       : ex.isClassReferenceExp().findFieldIndexByName(v);
             if (fieldi == -1)
             {
                 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
@@ -3865,7 +3867,7 @@ public:
                 return CTFEExp.cantexp;
             }
 
-            ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
+            ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
             {
                 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
@@ -3920,8 +3922,8 @@ public:
             assert(oldval.op == EXP.arrayLiteral);
             assert(newval.op == EXP.arrayLiteral);
 
-            Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
-            Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+            Expressions* oldelems = oldval.isArrayLiteralExp().elements;
+            Expressions* newelems = newval.isArrayLiteralExp().elements;
             assert(oldelems.dim == newelems.dim);
 
             Type elemtype = oldval.type.nextOf();
@@ -4124,7 +4126,7 @@ public:
 
             if (newval.op == EXP.slice && !isBlockAssignment)
             {
-                auto se = cast(SliceExp)newval;
+                auto se = newval.isSliceExp();
                 auto aggr2 = se.e1;
                 const srclower = se.lwr.toInteger();
                 const srcupper = se.upr.toInteger();
@@ -4140,7 +4142,7 @@ public:
                     // https://issues.dlang.org/show_bug.cgi?id=14024
                     assert(aggr2.op == EXP.arrayLiteral);
                     Expressions* oldelems = existingAE.elements;
-                    Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
+                    Expressions* newelems = aggr2.isArrayLiteralExp().elements;
 
                     Type elemtype = aggregate.type.nextOf();
                     bool needsPostblit = e.e2.isLvalue();
@@ -4213,13 +4215,13 @@ public:
                 /* 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);
+                sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
                 return newval;
             }
             if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
             {
                 Expressions* oldelems = existingAE.elements;
-                Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+                Expressions* newelems = newval.isArrayLiteralExp().elements;
                 Type elemtype = existingAE.type.nextOf();
                 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
                 foreach (j, newelem; *newelems)
@@ -4264,7 +4266,7 @@ public:
                         if (!directblk && (*w)[k].op == EXP.arrayLiteral)
                         {
                             // Multidimensional array block assign
-                            if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
+                            if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
                                 return ex;
                         }
                         else if (refCopy)
@@ -4420,7 +4422,7 @@ public:
         while (e.op == EXP.not)
         {
             ret *= -1;
-            e = (cast(NotExp)e).e1;
+            e = e.isNotExp().e1;
         }
         switch (e.op)
         {
@@ -4430,8 +4432,8 @@ public:
             goto case; /+ fall through +/
         case EXP.greaterThan:
         case EXP.greaterOrEqual:
-            *p1 = (cast(BinExp)e).e1;
-            *p2 = (cast(BinExp)e).e2;
+            *p1 = e.isBinExp().e1;
+            *p2 = e.isBinExp().e2;
             if (!(isPointer((*p1).type) && isPointer((*p2).type)))
                 ret = 0;
             break;
@@ -4898,7 +4900,7 @@ public:
             }
         }
 
-        if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
+        if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
         {
             e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
             result = CTFEExp.cantexp;
@@ -5201,7 +5203,7 @@ public:
             // Pointer to a non-array variable
             if (agg.op == EXP.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());
+                e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
                 return false;
             }
 
@@ -5285,7 +5287,7 @@ public:
                 e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
                 return false;
             }
-            *pagg = (cast(SliceExp)e1).e1;
+            *pagg = e1.isSliceExp().e1;
             *pidx = index + ilwr;
         }
         else
@@ -5377,7 +5379,7 @@ public:
             assert(e1.op == EXP.assocArrayLiteral);
             UnionExp e2tmp = void;
             e2 = resolveSlice(e2, &e2tmp);
-            result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
+            result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
             if (!result)
             {
                 e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
@@ -5637,7 +5639,7 @@ public:
         }
 
         e1 = resolveSlice(e1);
-        result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1);
+        result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
         if (exceptionOrCant(result))
             return;
         if (!result)
@@ -5742,7 +5744,7 @@ public:
                 return;
             }
 
-            auto cre = cast(ClassReferenceExp)result;
+            auto cre = result.isClassReferenceExp();
             auto cd = cre.originalClass();
 
             // Find dtor(s) in inheritance chain
@@ -5859,10 +5861,10 @@ public:
                 result = pue.exp();
                 return;
             }
-            if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
+            if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
             {
                 // type painting operation
-                IndexExp ie = cast(IndexExp)e1;
+                IndexExp ie = e1.isIndexExp();
                 if (castBackFromVoid)
                 {
                     // get the original type. For strings, it's just the type...
@@ -5870,7 +5872,7 @@ public:
                     // ..but for arrays of type void*, it's the type of the element
                     if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
                     {
-                        ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
+                        ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
                         const indx = cast(size_t)ie.e2.toInteger();
                         if (indx < ale.elements.dim)
                         {
@@ -5912,7 +5914,7 @@ public:
                 {
                     // &val[idx]
                     dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
-                    IndexExp ie = cast(IndexExp)ae.e1;
+                    IndexExp ie = ae.e1.isIndexExp();
                     Expression lwr = ie.e2;
                     Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
 
@@ -5938,7 +5940,7 @@ public:
                 if (auto ve = e1.isVarExp())
                     emplaceExp!(VarExp)(pue, e.loc, ve.var);
                 else
-                    emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
+                    emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
                 result = pue.exp();
                 result.type = e.to;
                 return;
@@ -5966,7 +5968,7 @@ public:
         {
             // 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;
+            SliceExp se = e1.isSliceExp();
             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());
@@ -6086,7 +6088,7 @@ public:
         {
             if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
             {
-                AddrExp ade = cast(AddrExp)ae.e1;
+                AddrExp ade = ae.e1.isAddrExp();
                 Expression ex = interpretRegion(ade.e1, istate);
                 if (exceptionOrCant(ex))
                     return;
@@ -6131,7 +6133,7 @@ public:
         }
 
         // *(&x) ==> x
-        result = (cast(AddrExp)result).e1;
+        result = result.isAddrExp().e1;
 
         if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
         {
@@ -6211,8 +6213,8 @@ public:
         // We can't use getField, because it makes a copy
         if (ex.op == EXP.classReference)
         {
-            se = (cast(ClassReferenceExp)ex).value;
-            i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+            se = ex.isClassReferenceExp().value;
+            i = ex.isClassReferenceExp().findFieldIndexByName(v);
         }
         else if (ex.op == EXP.typeid_)
         {
@@ -6233,7 +6235,7 @@ public:
         }
         else
         {
-            se = cast(StructLiteralExp)ex;
+            se = ex.isStructLiteralExp();
             i = findFieldIndexByName(se.sd, v);
         }
         if (i == -1)
@@ -6540,7 +6542,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
 
     if (e.op == EXP.classReference)
     {
-        StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
+        StructLiteralExp sle = e.isClassReferenceExp().value;
         if (auto ex = scrubSE(sle))
             return ex;
     }
@@ -6620,7 +6622,7 @@ private Expression scrubCacheValue(Expression e)
 
     if (e.op == EXP.classReference)
     {
-        if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
+        if (auto ex = scrubSE(e.isClassReferenceExp().value))
             return ex;
     }
     else if (auto sle = e.isStructLiteralExp())
@@ -6767,14 +6769,14 @@ private Expression copyRegionExp(Expression e)
         case EXP.vector:
         case EXP.dotVariable:
         {
-            UnaExp ue = cast(UnaExp)e;
+            UnaExp ue = e.isUnaExp();
             ue.e1 = copyRegionExp(ue.e1);
             break;
         }
 
         case EXP.index:
         {
-            BinExp be = cast(BinExp)e;
+            BinExp be = e.isBinExp();
             be.e1 = copyRegionExp(be.e1);
             be.e2 = copyRegionExp(be.e2);
             break;
@@ -6939,7 +6941,7 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
 
     Expressions args = Expressions(numParams);
 
-    AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
+    AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
     if (!ae.keys || ae.keys.dim == 0)
         return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
     Expression eresult;
@@ -7298,7 +7300,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const re
         {
             // 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;
+            StructLiteralExp se = pthis.isClassReferenceExp().value;
             assert(arguments.dim <= se.elements.dim);
             foreach (i, arg; *arguments)
             {
index 1e6799f..c3662a7 100644 (file)
@@ -991,10 +991,6 @@ public:
         if (stc & STC.returninferred)
             stc &= ~(STC.return_ | STC.returninferred);
 
-        // 'return inout ref' is the same as 'inout ref'
-        if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild))
-            stc &= ~STC.return_;
-
         // much like hdrgen.stcToBuffer()
         string rrs;
         const isout = (stc & STC.out_) != 0;
@@ -1365,5 +1361,3 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
     }
     return null;
 }
-
-
index 35d2aba..c7e6418 100644 (file)
@@ -662,7 +662,7 @@ extern (C++) final class Module : Package
             return true; // already read
 
         //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
-        if (auto result = FileManager.fileManager.lookup(srcfile))
+        if (auto result = global.fileManager.lookup(srcfile))
         {
             this.src = result.data;
             if (global.params.emitMakeDeps)
index aa30b5d..c3a1d05 100644 (file)
@@ -708,6 +708,31 @@ struct Scope
         return null;
     }
 
+    /********************************************
+     * Find the lexically enclosing function (if any).
+     *
+     * This function skips through generated FuncDeclarations,
+     * e.g. rewritten foreach bodies.
+     *
+     * Returns: the function or null
+     */
+    inout(FuncDeclaration) getEnclosingFunction() inout
+    {
+        if (!this.func)
+            return null;
+
+        auto fd = cast(FuncDeclaration) this.func;
+
+        // Look through foreach bodies rewritten as delegates
+        while (fd.fes)
+        {
+            assert(fd.fes.func);
+            fd = fd.fes.func;
+        }
+
+        return cast(inout(FuncDeclaration)) fd;
+    }
+
     /*******************************************
      * For TemplateDeclarations, we need to remember the Scope
      * where it was declared. So mark the Scope as not
index 9e50bd5..cb6c278 100644 (file)
@@ -190,7 +190,7 @@ struct Visibility
 
 enum PASS : ubyte
 {
-    init,           // initial state
+    initial,        // initial state
     semantic,       // semantic() started
     semanticdone,   // semantic() done
     semantic2,      // semantic2() started
@@ -249,7 +249,7 @@ extern (C++) class Dsymbol : ASTNode
     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 = PASS.init;
+    PASS semanticRun = PASS.initial;
     ushort localNum;        /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
 
     DeprecatedDeclaration depdecl;           // customized deprecation message
@@ -621,7 +621,7 @@ extern (C++) class Dsymbol : ASTNode
         static bool has2This(Dsymbol s)
         {
             if (auto f = s.isFuncDeclaration())
-                return f.isThis2;
+                return f.hasDualContext();
             if (auto ad = s.isAggregateDeclaration())
                 return ad.vthis2 !is null;
             return false;
@@ -2399,6 +2399,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
 {
     enum log = false;
     if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
+    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
     auto sd = s.isScopeDsymbol(); // new declaration
     auto sd2 = s2.isScopeDsymbol(); // existing declaration
 
@@ -2457,6 +2458,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
         sc._module.tagSymTab[cast(void*)s] = s2;
         return s;
     }
+    // neither s2 nor s is a tag
     if (log) printf(" collision\n");
     return null;
 }
@@ -2483,6 +2485,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
 {
     enum log = false;
     if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
+    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
 
     static Dsymbol collision()
     {
@@ -2552,8 +2555,16 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
 
         if (fd.fbody)                   // fd is the definition
         {
+            if (log) printf(" replace existing with new\n");
             sds.symtab.update(fd);      // replace fd2 in symbol table with fd
             fd.overnext = fd2;
+
+            /* If fd2 is covering a tag symbol, then fd has to cover the same one
+             */
+            auto ps = cast(void*)fd2 in sc._module.tagSymTab;
+            if (ps)
+                sc._module.tagSymTab[cast(void*)fd] = *ps;
+
             return fd;
         }
 
index aad0f2d..35500af 100644 (file)
@@ -111,7 +111,7 @@ struct Visibility
  */
 enum class PASS : uint8_t
 {
-    init,           // initial state
+    initial,        // initial state
     semantic,       // semantic() started
     semanticdone,   // semantic() done
     semantic2,      // semantic2() started
index b31dc9d..c990636 100644 (file)
@@ -231,7 +231,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     override void visit(AliasThis dsym)
     {
-        if (dsym.semanticRun != PASS.init)
+        if (dsym.semanticRun != PASS.initial)
             return;
 
         if (dsym._scope)
@@ -346,7 +346,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             printf("linkage = %d\n", dsym.linkage);
             //if (strcmp(toChars(), "mul") == 0) assert(0);
         }
-        //if (semanticRun > PASS.init)
+        //if (semanticRun > PASS.initial)
         //    return;
         //semanticRun = PSSsemantic;
 
@@ -417,7 +417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
             //printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
             dsym._init = dsym._init.inferType(sc);
-            dsym.type = dsym._init.initializerToExpression().type;
+            dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type;
             if (needctfe)
                 sc = sc.endCTFE();
 
@@ -527,7 +527,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
              * and add those.
              */
             size_t nelems = Parameter.dim(tt.arguments);
-            Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null;
+            Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null;
             if (ie)
                 ie = ie.expressionSemantic(sc);
             if (nelems > 0 && ie)
@@ -987,12 +987,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         if (ai && tb.ty == Taarray)
                             e = ai.toAssocArrayLiteral();
                         else
-                            e = dsym._init.initializerToExpression();
+                            e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
                         if (!e)
                         {
                             // Run semantic, but don't need to interpret
                             dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
-                            e = dsym._init.initializerToExpression();
+                            e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
                             if (!e)
                             {
                                 dsym.error("is not a static and cannot have static initializer");
@@ -1162,23 +1162,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         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.useDIP1000 == FeatureState.enabled &&
-                !(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 &&
-                    tv.isTypeStruct().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
@@ -1256,7 +1239,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
     override void visit(Import imp)
     {
         //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars());
-        if (imp.semanticRun > PASS.init)
+        if (imp.semanticRun > PASS.initial)
             return;
 
         if (imp._scope)
@@ -1433,7 +1416,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     void attribSemantic(AttribDeclaration ad)
     {
-        if (ad.semanticRun != PASS.init)
+        if (ad.semanticRun != PASS.initial)
             return;
         ad.semanticRun = PASS.semantic;
         Dsymbols* d = ad.include(sc);
@@ -1776,7 +1759,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     }
                     else if (auto f = s.isFuncDeclaration())
                     {
-                        f.isCrtCtorDtor |= isCtor ? 1 : 2;
+                        f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor;
                         return 1;
                     }
                     else
@@ -1990,7 +1973,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     override void visit(Module m)
     {
-        if (m.semanticRun != PASS.init)
+        if (m.semanticRun != PASS.initial)
             return;
         //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
         m.semanticRun = PASS.semantic;
@@ -2099,7 +2082,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     deferDsymbolSemantic(ed, scx);
                     Module.dprogress = dprogress_save;
                     //printf("\tdeferring %s\n", toChars());
-                    ed.semanticRun = PASS.init;
+                    ed.semanticRun = PASS.initial;
                     return;
                 }
                 else
@@ -2503,7 +2486,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             printf("sc.stc = %llx\n", sc.stc);
             printf("sc.module = %s\n", sc._module.toChars());
         }
-        if (tempdecl.semanticRun != PASS.init)
+        if (tempdecl.semanticRun != PASS.initial)
             return; // semantic() already run
 
         if (tempdecl._scope)
@@ -2648,11 +2631,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm);
             fflush(stdout);
         }
-        if (tm.semanticRun != PASS.init)
+        if (tm.semanticRun != PASS.initial)
         {
             // 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.
+            // has been reset to PASS.initial.
             static if (LOG)
             {
                 printf("\tsemantic done\n");
@@ -2678,7 +2661,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
          */
         if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null))
         {
-            if (tm.semanticRun == PASS.init) // forward reference had occurred
+            if (tm.semanticRun == PASS.initial) // forward reference had occurred
             {
                 //printf("forward reference - deferring\n");
                 return deferDsymbolSemantic(tm, scx);
@@ -2865,7 +2848,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     override void visit(Nspace ns)
     {
-        if (ns.semanticRun != PASS.init)
+        if (ns.semanticRun != PASS.initial)
             return;
         static if (LOG)
         {
@@ -2989,7 +2972,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars());
         }
 
-        if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration())
+        if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration())
         {
             /* Member functions that have return types that are
              * forward references can have semantic() run more than
@@ -3023,7 +3006,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         AggregateDeclaration 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)
+        if (ad && !funcdecl.isGenerated())
         {
             funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_);
             ad.makeNested();
@@ -3061,12 +3044,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
 
         // check pragma(crt_constructor)
-        if (funcdecl.isCrtCtorDtor)
+        if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor))
         {
             if (funcdecl.linkage != LINK.c)
             {
                 funcdecl.error("must be `extern(C)` for `pragma(%s)`",
-                    funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr);
+                    (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor".ptr : "crt_destructor".ptr);
             }
         }
 
@@ -3293,7 +3276,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             if (sc.scopesym && sc.scopesym.isAggregateDeclaration())
                 funcdecl.error("`static` member has no `this` to which `return` can apply");
             else
-                error(funcdecl.loc, "Top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
+                error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
         }
 
         if (funcdecl.isAbstract() && !funcdecl.isVirtual())
@@ -3524,7 +3507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 else
                 {
                     //printf("\tintroducing function %s\n", funcdecl.toChars());
-                    funcdecl.introducing = 1;
+                    funcdecl.flags |= FUNCFLAG.introducing;
                     if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads)
                     {
                         /* Overloaded functions with same name are grouped and in reverse order.
@@ -3916,8 +3899,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
-        if (funcdecl.isMain())
-            funcdecl.checkDmain();       // Check main() parameters and return type
+        funcdecl.checkMain();       // Check main() parameters and return type
 
         /* Purity and safety can be inferred for some functions by examining
          * the function body.
@@ -4525,7 +4507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (sd.errors)
             sd.type = Type.terror;
-        if (sd.semanticRun == PASS.init)
+        if (sd.semanticRun == PASS.initial)
             sd.type = sd.type.addSTC(sc.stc | sd.storage_class);
         sd.type = sd.type.typeSemantic(sd.loc, sc);
         if (auto ts = sd.type.isTypeStruct())
@@ -4539,7 +4521,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         // Ungag errors when not speculative
         Ungag ungag = sd.ungagSpeculative();
 
-        if (sd.semanticRun == PASS.init)
+        if (sd.semanticRun == PASS.initial)
         {
             sd.visibility = sc.visibility;
 
@@ -4747,7 +4729,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (cldec.errors)
             cldec.type = Type.terror;
-        if (cldec.semanticRun == PASS.init)
+        if (cldec.semanticRun == PASS.initial)
             cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class);
         cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
         if (auto tc = cldec.type.isTypeClass())
@@ -4761,7 +4743,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         // Ungag errors when not speculative
         Ungag ungag = cldec.ungagSpeculative();
 
-        if (cldec.semanticRun == PASS.init)
+        if (cldec.semanticRun == PASS.initial)
         {
             cldec.visibility = sc.visibility;
 
@@ -5259,7 +5241,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
                 auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
                 ctor.storage_class |= STC.inference;
-                ctor.generated = true;
+                ctor.flags |= FUNCFLAG.generated;
                 ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
 
                 cldec.members.push(ctor);
@@ -5416,7 +5398,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         // Ungag errors when not speculative
         Ungag ungag = idec.ungagSpeculative();
 
-        if (idec.semanticRun == PASS.init)
+        if (idec.semanticRun == PASS.initial)
         {
             idec.visibility = sc.visibility;
 
@@ -5750,7 +5732,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
         }
         return;
     }
-    if (tempinst.semanticRun != PASS.init)
+    if (tempinst.semanticRun != PASS.initial)
     {
         static if (LOG)
         {
@@ -5761,7 +5743,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
             global.gag = 0;
         tempinst.error(tempinst.loc, "recursive template expansion");
         if (tempinst.gagged)
-            tempinst.semanticRun = PASS.init;
+            tempinst.semanticRun = PASS.initial;
         else
             tempinst.inst = tempinst;
         tempinst.errors = true;
@@ -5800,7 +5782,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
         {
             // https://issues.dlang.org/show_bug.cgi?id=13220
             // Roll back status for later semantic re-running
-            tempinst.semanticRun = PASS.init;
+            tempinst.semanticRun = PASS.initial;
         }
         else
             tempinst.inst = tempinst;
@@ -6034,7 +6016,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
 
     // Create our own scope for the template parameters
     Scope* _scope = tempdecl._scope;
-    if (tempdecl.semanticRun == PASS.init)
+    if (tempdecl.semanticRun == PASS.initial)
     {
         tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars());
         return;
@@ -6332,7 +6314,7 @@ Laftersemantic:
                 target_symbol_list.remove(target_symbol_list_idx);
                 tempinst.memberOf = null;                    // no longer a member
             }
-            tempinst.semanticRun = PASS.init;
+            tempinst.semanticRun = PASS.initial;
             tempinst.inst = null;
             tempinst.symtab = null;
         }
@@ -6495,10 +6477,10 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
 
     // 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 parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null);
+    if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst))
     {
-        //printf("%s type = %s\n", toPrettyChars(), type.toChars());
+        //printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars());
         global.gag = 0;
     }
 
@@ -6572,13 +6554,13 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
     }
     if (s) // it's a symbolic alias
     {
-        //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
+        //printf("alias %s resolved to %s %s\n", ds.toChars(), s.kind(), s.toChars());
         ds.type = null;
         ds.aliassym = s;
     }
     else    // it's a type alias
     {
-        //printf("alias %s resolved to type %s\n", toChars(), type.toChars());
+        //printf("alias %s resolved to type %s\n", ds.toChars(), ds.type.toChars());
         ds.type = ds.type.typeSemantic(ds.loc, sc);
         ds.aliassym = null;
     }
index 366ed60..a5ec63c 100644 (file)
@@ -1173,7 +1173,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
                 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
                 fd.parent = ti;
-                fd.inferRetType = true;
+                fd.flags |= FUNCFLAG.inferRetType;
 
                 // Shouldn't run semantic on default arguments and return type.
                 foreach (ref param; *tf.parameterList.parameters)
@@ -2827,13 +2827,13 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
         if (!sc)
             sc = td._scope; // workaround for Type.aliasthisOf
 
-        if (td.semanticRun == PASS.init && td._scope)
+        if (td.semanticRun == PASS.initial && 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)
+        if (td.semanticRun == PASS.initial)
         {
             .error(loc, "forward reference to template `%s`", td.toChars());
         Lerror:
@@ -2851,7 +2851,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
                 tiargs = new Objects();
             auto ti = new TemplateInstance(loc, td, tiargs);
             Objects dedtypes = Objects(td.parameters.dim);
-            assert(td.semanticRun != PASS.init);
+            assert(td.semanticRun != PASS.initial);
             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
@@ -6425,7 +6425,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                 if (!td)
                     return 0;
 
-                if (td.semanticRun == PASS.init)
+                if (td.semanticRun == PASS.initial)
                 {
                     if (td._scope)
                     {
@@ -6433,7 +6433,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                         Ungag ungag = td.ungagSpeculative();
                         td.dsymbolSemantic(td._scope);
                     }
-                    if (td.semanticRun == PASS.init)
+                    if (td.semanticRun == PASS.initial)
                     {
                         error("`%s` forward references template declaration `%s`",
                             toChars(), td.toChars());
@@ -6786,7 +6786,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                 (*tiargs)[j] = sa;
 
                 TemplateDeclaration td = sa.isTemplateDeclaration();
-                if (td && td.semanticRun == PASS.init && td.literal)
+                if (td && td.semanticRun == PASS.initial && td.literal)
                 {
                     td.dsymbolSemantic(sc);
                 }
@@ -6915,7 +6915,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
 
                 dedtypes.setDim(td.parameters.dim);
                 dedtypes.zero();
-                assert(td.semanticRun != PASS.init);
+                assert(td.semanticRun != PASS.initial);
 
                 MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
                 //printf("matchWithInstance = %d\n", m);
@@ -7093,7 +7093,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
     extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
     {
         //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
-        if (semanticRun != PASS.init)
+        if (semanticRun != PASS.initial)
             return false;
 
         uint olderrs = global.errors;
@@ -7174,7 +7174,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                      */
                     dedtypes.setDim(td.parameters.dim);
                     dedtypes.zero();
-                    if (td.semanticRun == PASS.init)
+                    if (td.semanticRun == PASS.initial)
                     {
                         if (td._scope)
                         {
@@ -7182,7 +7182,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                             Ungag ungag = td.ungagSpeculative();
                             td.dsymbolSemantic(td._scope);
                         }
-                        if (td.semanticRun == PASS.init)
+                        if (td.semanticRun == PASS.initial)
                         {
                             error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
                             return 1;
@@ -7740,13 +7740,13 @@ extern (C++) final class TemplateMixin : TemplateInstance
                 if (!td)
                     return 0;
 
-                if (td.semanticRun == PASS.init)
+                if (td.semanticRun == PASS.initial)
                 {
                     if (td._scope)
                         td.dsymbolSemantic(td._scope);
                     else
                     {
-                        semanticRun = PASS.init;
+                        semanticRun = PASS.initial;
                         return 1;
                     }
                 }
index 46982e3..41fb82b 100644 (file)
@@ -445,6 +445,9 @@ public:
      */
     private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false)
     {
+        if (const mn = getMangleOverride(s))
+            return buf.writestring(mn);
+
         writeIdentifier(s.ident, s.loc, s.kind(), canFix);
     }
 
@@ -719,15 +722,20 @@ public:
         visited[cast(void*)fd] = true;
 
         // silently ignore non-user-defined destructors
-        if (fd.generated && fd.isDtorDeclaration())
+        if (fd.isGenerated && fd.isDtorDeclaration())
             return;
 
         // Note that tf might be null for templated (member) functions
         auto tf = cast(AST.TypeFunction)fd.type;
-        if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
+        if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
         {
             ignored("function %s because of linkage", fd.toPrettyChars());
-            return checkVirtualFunction(fd);
+            return checkFunctionNeedsPlaceholder(fd);
+        }
+        if (fd.mangleOverride && tf && tf.linkage != LINK.c)
+        {
+            ignored("function %s because C++ doesn't support explicit mangling", fd.toPrettyChars());
+            return checkFunctionNeedsPlaceholder(fd);
         }
         if (!adparent && !fd.fbody)
         {
@@ -742,7 +750,7 @@ public:
         if (tf && !isSupportedType(tf.next))
         {
             ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
-            return checkVirtualFunction(fd);
+            return checkFunctionNeedsPlaceholder(fd);
         }
         if (tf) foreach (i, fparam; tf.parameterList)
         {
@@ -750,7 +758,7 @@ public:
             {
                 ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
                         fd.toPrettyChars(), fparam.type.toChars());
-                return checkVirtualFunction(fd);
+                return checkFunctionNeedsPlaceholder(fd);
             }
         }
 
@@ -822,13 +830,19 @@ public:
 
     }
 
-    /// Checks whether `fd` is a virtual function and emits a dummy declaration
-    /// if required to ensure proper vtable layout
-    private void checkVirtualFunction(AST.FuncDeclaration fd)
+    /++
+     + Checks whether `fd` is a function that requires a dummy declaration
+     + instead of simply emitting the declaration (because it would cause
+     + ABI / behaviour issues). This includes:
+     +
+     + - virtual functions to ensure proper vtable layout
+     + - destructors that would break RAII
+     +/
+    private void checkFunctionNeedsPlaceholder(AST.FuncDeclaration fd)
     {
         // Omit redundant declarations - the slot was already
         // reserved in the base class
-        if (fd.isVirtual() && fd.introducing)
+        if (fd.isVirtual() && fd.isIntroducing())
         {
             // Hide placeholders because they are not ABI compatible
             writeProtection(AST.Visibility.Kind.private_);
@@ -837,6 +851,15 @@ public:
             buf.printf("virtual void __vtable_slot_%u();", counter++);
             buf.writenl();
         }
+        else if (fd.isDtorDeclaration())
+        {
+            // Create inaccessible dtor to prevent code from keeping instances that
+            // need to be destroyed on the C++ side (but cannot call the dtor)
+            writeProtection(AST.Visibility.Kind.private_);
+            buf.writeByte('~');
+            buf.writestring(adparent.ident.toString());
+            buf.writestringln("();");
+        }
     }
 
     override void visit(AST.UnitTestDeclaration utd)
@@ -948,6 +971,11 @@ public:
                 ignored("variable %s because of linkage", vd.toPrettyChars());
                 return;
             }
+            if (vd.mangleOverride && vd.linkage != LINK.c)
+            {
+                ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars());
+                return;
+            }
             if (!isSupportedType(type))
             {
                 ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
@@ -1073,7 +1101,7 @@ public:
 
         auto fd = ad.aliassym.isFuncDeclaration();
 
-        if (fd && (fd.generated || fd.isDtorDeclaration()))
+        if (fd && (fd.isGenerated() || fd.isDtorDeclaration()))
         {
             // Ignore. It's taken care of while visiting FuncDeclaration
             return;
@@ -1106,7 +1134,7 @@ public:
                 // Print prefix of the base class if this function originates from a superclass
                 // because alias might be resolved through multiple classes, e.g.
                 // e.g. for alias visit = typeof(super).visit in the visitors
-                if (!fd.introducing)
+                if (!fd.isIntroducing())
                     printPrefix(ad.toParent().isClassDeclaration().baseClass);
                 else
                     printPrefix(pd);
@@ -1655,7 +1683,16 @@ public:
             scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars());
         }
 
-        this.ident = s.ident;
+        // The context pointer (represented as `ThisDeclaration`) is named
+        // `this` but accessible via `outer`
+        if (auto td = s.isThisDeclaration())
+        {
+            import dmd.id;
+            this.ident = Id.outer;
+        }
+        else
+            this.ident = s.ident;
+
         auto type = origType !is null ? origType : t;
         AST.Dsymbol customLength;
 
@@ -1702,7 +1739,12 @@ public:
         if (this.ident)
         {
             buf.writeByte(' ');
-            writeIdentifier(s, canFixup);
+            // Custom identifier doesn't need further checks
+            if (this.ident !is s.ident)
+                buf.writestring(this.ident.toString());
+            else
+                writeIdentifier(s, canFixup);
+
         }
         this.ident = null;
 
@@ -2922,6 +2964,10 @@ public:
             scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars());
         }
 
+        // Explicit `pragma(mangle, "<some string>` overrides the declared name
+        if (auto mn = getMangleOverride(sym))
+            return buf.writestring(mn);
+
         /// Checks whether `sym` is nested in `par` and hence doesn't need the FQN
         static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par)
         {
@@ -2970,6 +3016,15 @@ public:
         else
             buf.writestring(sym.ident.toString());
     }
+
+    /// Returns: Explicit mangling for `sym` if present
+    extern(D) static const(char)[] getMangleOverride(const AST.Dsymbol sym)
+    {
+        if (auto decl = sym.isDeclaration())
+            return decl.mangleOverride;
+
+        return null;
+    }
 }
 
 /// Namespace for identifiers used to represent special enums in C++
@@ -3037,7 +3092,7 @@ void hashEndIf(ref OutBuffer buf)
 /// Writes `#define <content>` into the supplied buffer
 void hashDefine(ref OutBuffer buf, string content)
 {
-    buf.writestring("# define ");
+    buf.writestring("#define ");
     buf.writestringln(content);
 }
 
index e9dcdc0..4196c05 100644 (file)
@@ -692,9 +692,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
             // If va's lifetime encloses v's, then error
             if (va && !va.isDataseg() &&
-                (va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp) ||
-                 vaIsRef ||
-                 va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
+                ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef) &&
                 fd.setUnsafe())
             {
                 if (!gag)
@@ -793,7 +791,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
         // If va's lifetime encloses v's, then error
         if (va &&
-            (va.enclosesLifetimeOf(v) || (va.isRef() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
+            (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
             fd.setUnsafe())
         {
             if (!gag)
@@ -1284,27 +1282,24 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         {
             if (!gag)
             {
-                const(char)* msg, supplemental;
-                if (v.storage_class & STC.parameter &&
-                    (v.type.hasPointers() || v.storage_class & STC.ref_))
-                {
-                    msg = "returning `%s` escapes a reference to parameter `%s`";
-                    supplemental = vsr == ScopeRef.Ref_ReturnScope
-                                              ? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
-                                              : v.ident is Id.This
-                                                    ? "perhaps annotate the function with `return`"
-                                                    : "perhaps annotate the parameter with `return`";
-                }
-                else
+                const(char)* varKind = v.isParameter() ? "parameter" : "local variable";
+                previewErrorFunc(sc.isDeprecated(), featureState)(e.loc,
+                    "returning `%s` escapes a reference to %s `%s`", e.toChars(), varKind, v.toChars());
+
+                if (v.isParameter() && v.isReference())
                 {
-                    msg = "returning `%s` escapes a reference to local variable `%s`";
-                    if (v.ident is Id.This)
-                        supplemental = "perhaps annotate the function with `return`";
+                    if (v.storage_class & STC.returnScope)
+                    {
+                        previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
+                            "perhaps change the `return scope` into `scope return`");
+                    }
+                    else
+                    {
+                        const(char)* annotateKind = (v.ident is Id.This) ? "function" : "parameter";
+                        previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
+                            "perhaps annotate the %s with `return`", annotateKind);
+                    }
                 }
-
-                previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
-                if (supplemental)
-                    previewSupplementalFunc(sc.isDeprecated(), featureState)(e.loc, supplemental);
             }
             result = true;
         }
@@ -1897,7 +1892,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
 
         override void visit(ThisExp e)
         {
-            if (e.var && e.var.toParent2().isFuncDeclaration().isThis2)
+            if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
                 escapeByValue(e, er, live);
             else if (e.var)
                 er.byref.push(e.var);
@@ -2297,3 +2292,37 @@ bool isReferenceToMutable(Parameter p, Type t)
     }
     return isReferenceToMutable(p.type);
 }
+
+/**********************************
+* Determine if `va` has a lifetime that lasts past
+* the destruction of `v`
+* Params:
+*     va = variable assigned to
+*     v = variable being assigned
+* Returns:
+*     true if it does
+*/
+private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) pure
+{
+    assert(va.sequenceNumber != va.sequenceNumber.init);
+    assert(v.sequenceNumber != v.sequenceNumber.init);
+    return va.sequenceNumber < v.sequenceNumber;
+}
+
+/***************************************
+ * Add variable `v` to maybes[]
+ *
+ * When a maybescope variable `v` is assigned to a maybescope variable `va`,
+ * 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`
+ */
+private void addMaybe(VarDeclaration va, VarDeclaration v)
+{
+    //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
+    if (!va.maybes)
+        va.maybes = new VarDeclarations();
+    va.maybes.push(v);
+}
index 7abfe7f..07d885b 100644 (file)
@@ -170,7 +170,7 @@ FuncDeclaration hasThis(Scope* sc)
         {
             return null;
         }
-        if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
+        if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
             break;
 
         Dsymbol parent = fd.parent;
@@ -187,7 +187,7 @@ FuncDeclaration hasThis(Scope* sc)
         fd = parent.isFuncDeclaration();
     }
 
-    if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
+    if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
     {
         return null;
     }
@@ -1210,7 +1210,7 @@ extern (C++) abstract class Expression : ASTNode
                 scope bool function(DtorDeclaration) check, const string checkName
     ) {
         auto dd = f.isDtorDeclaration();
-        if (!dd || !dd.generated)
+        if (!dd || !dd.isGenerated())
             return;
 
         // DtorDeclaration without parents should fail at an earlier stage
@@ -1227,7 +1227,7 @@ extern (C++) abstract class Expression : ASTNode
         }
 
         dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
-                            dd.generated ? "generated " : "".ptr,
+                            dd.isGenerated() ? "generated " : "".ptr,
                             ad.toChars,
                             cast(int) checkName.length, checkName.ptr);
 
@@ -1258,7 +1258,7 @@ extern (C++) abstract class Expression : ASTNode
             {
                 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
 
-                if (fieldSd.dtor.generated)
+                if (fieldSd.dtor.isGenerated())
                     checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
                 else
                     fieldSd.dtor.loc.errorSupplemental("   %.*s `%s.~this` is declared here",
@@ -1288,7 +1288,7 @@ extern (C++) abstract class Expression : ASTNode
             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()))
+        if (v.isConst() && !v.isReference() && (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
@@ -3461,7 +3461,7 @@ extern (C++) final class ScopeExp : Expression
             //assert(ti.needsTypeInference(sc));
             if (ti.tempdecl &&
                 ti.semantictiargsdone &&
-                ti.semanticRun == PASS.init)
+                ti.semanticRun == PASS.initial)
             {
                 error("partial %s `%s` has no type", sds.kind(), toChars());
                 return true;
@@ -3859,7 +3859,7 @@ extern (C++) final class FuncExp : Expression
     {
         if (td)
             return new FuncExp(loc, td.syntaxCopy(null));
-        else if (fd.semanticRun == PASS.init)
+        else if (fd.semanticRun == PASS.initial)
             return new FuncExp(loc, fd.syntaxCopy(null));
         else // https://issues.dlang.org/show_bug.cgi?id=13481
              // Prevent multiple semantic analysis of lambda body.
@@ -4950,7 +4950,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
         // Same logic as ScopeExp.checkType()
         if (ti.tempdecl &&
             ti.semantictiargsdone &&
-            ti.semanticRun == PASS.init)
+            ti.semanticRun == PASS.initial)
         {
             error("partial %s `%s` has no type", ti.kind(), toChars());
             return true;
@@ -4962,7 +4962,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
     {
         if (ti.tempdecl &&
             ti.semantictiargsdone &&
-            ti.semanticRun == PASS.init)
+            ti.semanticRun == PASS.initial)
 
             error("partial %s `%s` has no value", ti.kind(), toChars());
         else
index 5802816..7b7c489 100644 (file)
@@ -1046,7 +1046,7 @@ L1:
     if (e1.op == EXP.this_)
     {
         FuncDeclaration f = hasThis(sc);
-        if (f && f.isThis2)
+        if (f && f.hasDualContext())
         {
             if (f.followInstantiationContext(ad))
             {
@@ -1444,13 +1444,6 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
             Expression ex = condexp.expressionSemantic(sc);
             if (ex.op == EXP.error)
                 e = ex;
-            else if (e.op == EXP.function_ || e.op == EXP.delegate_)
-            {
-                // https://issues.dlang.org/show_bug.cgi?id=21285
-                // Functions and delegates don't convert correctly with castTo below
-                exps[i] = condexp.e1;
-                e = condexp.e2;
-            }
             else
             {
                 // Convert to common type
@@ -1723,7 +1716,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
         if (sc._module)
             sc._module.hasAlwaysInlines = true;
         if (sc.func)
-            sc.func.hasAlwaysInlines = true;
+            sc.func.flags |= FUNCFLAG.hasAlwaysInline;
     }
 
     const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
@@ -3743,7 +3736,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
 
-            if (sd.hasRegularCtor() && nargs)
+            // https://issues.dlang.org/show_bug.cgi?id=22639
+            // If the new expression has arguments, we either should call a
+            // regular constructor of a copy constructor if the first argument
+            // is the same type as the struct
+            if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
             {
                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
                 if (!f || f.errors)
@@ -4201,30 +4198,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         Type tthis = null;
         Expression e1org = exp.e1;
 
-        if (exp.e1.op == EXP.comma)
+        if (auto ce = exp.e1.isCommaExp())
         {
             /* 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 == EXP.delegate_)
+        if (DelegateExp de = exp.e1.isDelegateExp())
         {
-            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 == EXP.function_)
+        if (FuncExp fe = exp.e1.isFuncExp())
         {
             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 == EXP.error)
             {
@@ -4252,9 +4246,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         /* This recognizes:
          *  foo!(tiargs)(funcargs)
          */
-        if (exp.e1.op == EXP.scope_)
+        if (ScopeExp se = exp.e1.isScopeExp())
         {
-            ScopeExp se = cast(ScopeExp)exp.e1;
             TemplateInstance ti = se.sds.isTemplateInstance();
             if (ti)
             {
@@ -4300,9 +4293,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          *  expr.foo!(tiargs)(funcargs)
          */
     Ldotti:
-        if (exp.e1.op == EXP.dotTemplateInstance)
+        if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
         {
-            DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
             TemplateInstance ti = se.ti;
             {
                 /* Attempt to instantiate ti. If that works, go with it.
@@ -4347,9 +4339,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else
         {
-            if (exp.e1.op == EXP.dotIdentifier)
+            if (DotIdExp die = exp.e1.isDotIdExp())
             {
-                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.
@@ -4380,9 +4371,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             /* Look for e1 being a lazy parameter
              */
-            if (exp.e1.op == EXP.variable)
+            if (VarExp ve = exp.e1.isVarExp())
             {
-                VarExp ve = cast(VarExp)exp.e1;
                 if (ve.var.storage_class & STC.lazy_)
                 {
                     // lazy parameters can be called without violating purity and safety
@@ -4404,10 +4394,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.e1 = new VarExp(se.loc, se.var, true);
                 exp.e1 = exp.e1.expressionSemantic(sc);
             }
-            else if (exp.e1.op == EXP.dot)
+            else if (DotExp de = exp.e1.isDotExp())
             {
-                DotExp de = cast(DotExp)exp.e1;
-
                 if (de.e2.op == EXP.overloadSet)
                 {
                     ethis = de.e1;
@@ -4490,7 +4478,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 if (sd.ctor)
                 {
                     auto ctor = sd.ctor.isCtorDeclaration();
-                    if (ctor && ctor.isCpCtor && ctor.generated)
+                    if (ctor && ctor.isCpCtor && ctor.isGenerated())
                         sd.ctor = null;
                 }
 
@@ -4504,7 +4492,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                        If all constructors are copy constructors, then
                        try default construction.
                      */
-                    if (!sd.hasRegularCtor)
+                    if (!sd.hasRegularCtor &&
+                        // https://issues.dlang.org/show_bug.cgi?id=22639
+                        // we might still have a copy constructor that could be called
+                        (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
                         goto Lx;
 
                     auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
@@ -4850,10 +4841,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
         }
-        else if (exp.e1.op == EXP.overloadSet)
+        else if (auto oe = exp.e1.isOverExp())
         {
-            auto os = (cast(OverExp)exp.e1).vars;
-            exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
+            exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
             if (!exp.f)
                 return setError();
             if (ethis)
@@ -4877,11 +4867,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             const(char)* p;
             Dsymbol s;
             exp.f = null;
-            if (exp.e1.op == EXP.function_)
+            if (auto fe = exp.e1.isFuncExp())
             {
                 // function literal that direct called is always inferred.
-                assert((cast(FuncExp)exp.e1).fd);
-                exp.f = (cast(FuncExp)exp.e1).fd;
+                assert(fe.fd);
+                exp.f = fe.fd;
                 tf = cast(TypeFunction)exp.f.type;
                 p = "function literal";
             }
@@ -5011,11 +5001,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             t1 = tf;
         }
-        else if (exp.e1.op == EXP.variable)
+        else if (VarExp ve = exp.e1.isVarExp())
         {
             // Do overload resolution
-            VarExp ve = cast(VarExp)exp.e1;
-
             exp.f = ve.var.isFuncDeclaration();
             assert(exp.f);
             tiargs = null;
@@ -5162,7 +5150,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // declare dual-context container
-        if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func)
+        if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
         {
             // check access to second `this`
             if (AggregateDeclaration ad2 = exp.f.isMember2())
@@ -6042,13 +6030,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         {
             auto fileName = FileName(name.toDString);
-            if (auto fmResult = FileManager.fileManager.lookup(fileName))
+            if (auto fmResult = global.fileManager.lookup(fileName))
             {
                 se = new StringExp(e.loc, fmResult.data);
             }
             else
             {
-                auto readResult = File.read(name);
+                auto readResult = File.read(name.toDString);
                 if (!readResult.success)
                 {
                     e.error("cannot read file `%s`", name);
@@ -6060,9 +6048,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     auto data = readResult.extractSlice();
                     se = new StringExp(e.loc, data);
 
-                    FileBuffer* fileBuffer = FileBuffer.create();
-                    fileBuffer.data = data;
-                    FileManager.fileManager.add(fileName, fileBuffer);
+                    FileBuffer* fileBuffer = new FileBuffer(data);
+                    global.fileManager.add(fileName, fileBuffer);
                 }
             }
         }
@@ -6200,10 +6187,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             const op = exp.e1.op;
             bool isEqualsCallExpression;
-            if (op == EXP.call)
+            if (const callExp = exp.e1.isCallExp())
             {
-                const callExp = cast(CallExp) exp.e1;
-
                 // https://issues.dlang.org/show_bug.cgi?id=20331
                 // callExp.f may be null if the assert contains a call to
                 // a function pointer or literal
@@ -6436,7 +6421,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
                 else if (t)
                 {
-                    result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t);
+                    // Note similarity to getProperty() implementation of __xalignof
+                    const explicitAlignment = t.alignment();
+                    const naturalAlignment = t.alignsize();
+                    const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
+                    result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
                 }
                 else if (s)
                 {
@@ -6643,7 +6632,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
 
             if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
-                      (!v.needThis() && v.semanticRun > PASS.init)))  // fix https://issues.dlang.org/show_bug.cgi?id=17258
+                      (!v.needThis() && v.semanticRun > PASS.initial)))  // fix https://issues.dlang.org/show_bug.cgi?id=17258
             {
                 // (e1, v)
                 checkAccess(exp.loc, sc, exp.e1, v);
@@ -6736,7 +6725,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         result = e;
         // declare dual-context container
-        if (f.isThis2 && !sc.intypeof && sc.func)
+        if (f.hasDualContext() && !sc.intypeof && sc.func)
         {
             // check access to second `this`
             if (AggregateDeclaration ad2 = f.isMember2())
@@ -7311,7 +7300,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (checkNonAssignmentArrayOp(e.e1))
             return setError();
 
-        e.type = Type.tbool;
+        e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
         result = e;
     }
 
@@ -7323,7 +7312,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // 3. Removal of keyword, "delete" can be used for other identities
         if (!exp.isRAII)
         {
-            error(exp.loc, "The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
+            error(exp.loc, "the `delete` keyword is obsolete");
+            errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
             return setError();
         }
 
@@ -7847,9 +7837,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  */
                 if (VarDeclaration v = expToVariable(exp.e1))
                 {
-                    if (exp.e1.op == EXP.dotVariable)
+                    if (DotVarExp dve = exp.e1.isDotVarExp())
                     {
-                        DotVarExp dve = cast(DotVarExp)exp.e1;
+
                         if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
                             !(v.storage_class & STC.ref_))
                         {
@@ -8140,10 +8130,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = exp.e2;
             return;
         }
-        if (exp.e2.op == EXP.template_)
+        if (auto te = exp.e2.isTemplateExp())
         {
-            auto td = (cast(TemplateExp)exp.e2).td;
-            Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
+            Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
             result = e.expressionSemantic(sc);
             return;
         }
@@ -8182,11 +8171,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         e.e2 = e.e2.arrayFuncConv(sc);
 
         e.type = e.e2.type;
+        result = e;
+
+        if (sc.flags & SCOPE.Cfile)
+            return;
+
         if (e.type is Type.tvoid)
             discardValue(e.e1);
-        else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile))
+        else if (!e.allowCommaExp && !e.isGenerated)
             e.error("Using the result of a comma expression is not allowed");
-        result = e;
     }
 
     override void visit(IntervalExp e)
@@ -8472,6 +8465,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // OR it in, because it might already be set for C array indexing
                     exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
                 }
+                else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
+                {
+                    if (auto ve = exp.e1.isVarExp())
+                    {
+                        /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
+                         */
+                        auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
+                        auto e = new AddExp(exp.loc, vp, exp.e2);
+                        auto pe = new PtrExp(exp.loc, e);
+                        result = pe.expressionSemantic(sc).optimize(WANTvalue);
+                        return;
+                    }
+                }
             }
         }
 
@@ -10024,9 +10030,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.e1.op == EXP.slice)
+        if (SliceExp se = exp.e1.isSliceExp())
         {
-            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());
@@ -11270,7 +11275,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             e1x = e1x.optimize(WANTvalue);
             if (e1x.toBool().hasValue(exp.op == EXP.orOr))
             {
-                result = IntegerExp.createBool(exp.op == EXP.orOr);
+                if (sc.flags & SCOPE.Cfile)
+                    result = new IntegerExp(exp.op == EXP.orOr);
+                else
+                    result = IntegerExp.createBool(exp.op == EXP.orOr);
                 return;
             }
         }
@@ -11315,7 +11323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (e2x.type.ty == Tvoid)
             exp.type = Type.tvoid;
         else
-            exp.type = Type.tbool;
+            exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
 
         exp.e1 = e1x;
         exp.e2 = e2x;
@@ -11412,7 +11420,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        exp.type = Type.tbool;
+        exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
 
         // Special handling for array comparisons
         Expression arrayLowering = null;
@@ -11690,7 +11698,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        exp.type = Type.tbool;
+        exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
 
         if (!isArrayComparison)
         {
@@ -11825,8 +11833,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (exp.econd.op == EXP.dotIdentifier)
-            (cast(DotIdExp)exp.econd).noderef = true;
+        if (auto die = exp.econd.isDotIdExp())
+            die.noderef = true;
 
         Expression ec = exp.econd.expressionSemantic(sc);
         ec = resolveProperties(sc, ec);
@@ -12654,9 +12662,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
 
     if (e.op == EXP.error)
         return e;
-    if (e.op == EXP.dotVariable)
+    if (DotVarExp dve = e.isDotVarExp())
     {
-        DotVarExp dve = cast(DotVarExp)e;
         if (FuncDeclaration fd = dve.var.isFuncDeclaration())
         {
             if (TemplateDeclaration td = fd.findTemplateDeclRoot())
@@ -12707,9 +12714,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
         }
     }
 
-    if (e.op == EXP.dotTemplateDeclaration)
+    if (DotTemplateExp dte = e.isDotTemplateExp())
     {
-        DotTemplateExp dte = cast(DotTemplateExp)e;
         exp.e1 = dte.e1; // pull semantic() result
 
         exp.ti.tempdecl = dte.td;
@@ -12738,10 +12744,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
         return new ScopeExp(exp.loc, exp.ti)
                .expressionSemantic(sc);
     }
-    else if (e.op == EXP.dot)
+    else if (DotExp de = e.isDotExp())
     {
-        DotExp de = cast(DotExp)e;
-
         if (de.e2.op == EXP.overloadSet)
         {
             if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
@@ -12765,9 +12769,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
                    .expressionSemantic(sc);
         }
     }
-    else if (e.op == EXP.overloadSet)
+    else if (OverExp oe = e.isOverExp())
     {
-        OverExp oe = cast(OverExp)e;
         exp.ti.tempdecl = oe.vars;
         return new ScopeExp(exp.loc, exp.ti)
                .expressionSemantic(sc);
@@ -13055,7 +13058,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre
         {
             n++;
             e1 = new VarExp(loc, f.vthis);
-            if (f.isThis2)
+            if (f.hasDualContext())
             {
                 // (*__this)[i]
                 if (n > 1)
@@ -13355,8 +13358,8 @@ Expression toBoolean(Expression exp, Scope* sc)
 
         default:
             // Default is 'yes' - do nothing
-            Expression e = exp;
-            Type t = exp.type;
+            Expression e = arrayFuncConv(exp, sc);
+            Type t = e.type;
             Type tb = t.toBasetype();
             Type att = null;
 
index 9ba3807..b86c799 100644 (file)
@@ -20,10 +20,15 @@ import dmd.identifier;
 enum package_d  = "package." ~ mars_ext;
 enum package_di = "package." ~ hdr_ext;
 
-struct FileManager
+final class FileManager
 {
     private StringTable!(FileBuffer*) files;
-    private __gshared bool initialized = false;
+
+    ///
+    public this () nothrow
+    {
+        this.files._init();
+    }
 
 nothrow:
     /********************************************
@@ -143,9 +148,6 @@ nothrow:
      */
     const(FileBuffer)* lookup(FileName filename)
     {
-        if (!initialized)
-            FileManager._init();
-
         const name = filename.toString;
         if (auto val = files.lookup(name))
             return val.value;
@@ -182,9 +184,6 @@ nothrow:
      */
     const(char)[][] getLines(FileName file)
     {
-        if (!initialized)
-            FileManager._init();
-
         const(char)[][] lines;
         if (const buffer = lookup(file))
         {
@@ -241,29 +240,9 @@ nothrow:
      */
     FileBuffer* add(FileName filename, FileBuffer* filebuffer)
     {
-        if (!initialized)
-            FileManager._init();
-
         auto val = files.insert(filename.toString, filebuffer);
         return val == null ? null : val.value;
     }
-
-    __gshared fileManager = FileManager();
-
-    // Initialize the global FileManager singleton
-    private void _init()
-    {
-        if (!initialized)
-        {
-            fileManager.initialize();
-            initialized = true;
-        }
-    }
-
-    void initialize()
-    {
-        files._init();
-    }
 }
 
 private FileBuffer readFromStdin() nothrow
index b779eae..53ed62e 100644 (file)
@@ -320,4 +320,3 @@ void foreachExpAndVar(Statement s,
 
     visit(s);
 }
-
index afc0ebb..8d83951 100644 (file)
@@ -140,7 +140,7 @@ public:
     override void visit(TryFinallyStatement s)
     {
         DtorExpStatement des;
-        if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
+        if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
             fd.nrvo_var == des.var)
         {
             if (!(global.params.useExceptions && ClassDeclaration.throwable))
@@ -182,7 +182,7 @@ public:
             catches.push(ctch);
 
             Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
-            fd.eh_none = false;
+            fd.flags &= ~FUNCFLAG.noEH;
             replaceCurrent(s2);
             s2.accept(this);
         }
@@ -205,6 +205,17 @@ enum FUNCFLAG : uint
     printf           = 0x200,  /// is a printf-like function
     scanf            = 0x400,  /// is a scanf-like function
     noreturn         = 0x800,  /// the function does not return
+    NRVO             = 0x1000, /// Support for named return value optimization
+    naked            = 0x2000, /// The function is 'naked' (see inline ASM)
+    generated        = 0x4000, /// The function is compiler generated (e.g. `opCmp`)
+    introducing      = 0x8000, /// If this function introduces the overload set
+    semantic3Errors  = 0x10000, /// If errors in semantic3 this function's frame ptr
+    noEH             = 0x20000, /// No exception unwinding is needed
+    inferRetType     = 0x40000, /// Return type is to be inferred
+    dualContext      = 0x80000, /// has a dual-context 'this' parameter
+    hasAlwaysInline  = 0x100000, /// Contains references to functions that must be inlined
+    CRTCtor          = 0x200000, /// Has attribute pragma(crt_constructor)
+    CRTDtor          = 0x400000, /// Has attribute pragma(crt_destructor)
 }
 
 /***********************************************************
@@ -268,7 +279,6 @@ extern (C++) class FuncDeclaration : Declaration
     // scopes from having the same name
     DsymbolTable localsymtab;
     VarDeclaration vthis;               /// 'this' parameter (member and nested)
-    bool isThis2;                       /// has a dual-context 'this' parameter
     VarDeclaration v_arguments;         /// '_arguments' parameter
 
     VarDeclaration v_argptr;            /// '_argptr' variable
@@ -278,31 +288,21 @@ extern (C++) class FuncDeclaration : Declaration
     FuncDeclaration overnext0;          /// next in overload list (only used during IFTI)
     Loc endloc;                         /// location of closing curly bracket
     int vtblIndex = -1;                 /// for member functions, index into vtbl[]
-    bool naked;                         /// true if naked
-    bool generated;                     /// true if function was generated by the compiler rather than
-                                        /// supplied by the user
-    bool hasAlwaysInlines;              /// contains references to functions that must be inlined
-    ubyte isCrtCtorDtor;                /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
-                                        /// not set before the glue layer
 
     ILS inlineStatusStmt = ILS.uninitialized;
     ILS inlineStatusExp = ILS.uninitialized;
     PINLINE inlining = PINLINE.default_;
 
     int inlineNest;                     /// !=0 if nested inline
-    bool eh_none;                       /// true if no exception unwinding is needed
 
-    bool semantic3Errors;               /// true if errors in semantic3 this function's frame ptr
     ForeachStatement fes;               /// if foreach body, this is the foreach
     BaseClass* interfaceVirtual;        /// if virtual, but only appears in base interface vtbl[]
-    bool introducing;                   /// true if 'introducing' function
     /** if !=NULL, then this is the type
     of the 'introducing' function
     this one is overriding
     */
     Type tintro;
 
-    bool inferRetType;                  /// true if return type is to be inferred
     StorageClass storage_class2;        /// storage class for template onemember's
 
     // Things that should really go into Scope
@@ -314,8 +314,6 @@ extern (C++) class FuncDeclaration : Declaration
     /// 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
 
@@ -346,7 +344,9 @@ extern (C++) class FuncDeclaration : Declaration
 
     FuncDeclarations *inlinedNestedCallees;
 
-    uint flags;                        /// FUNCFLAG.xxxxx
+    /// Function flags: A collection of boolean packed for memory efficiency
+    /// See the `FUNCFLAG` enum
+    uint flags = FUNCFLAG.NRVO;
 
     /**
      * Data for a function declaration that is needed for the Objective-C
@@ -374,7 +374,8 @@ extern (C++) class FuncDeclaration : Declaration
         /* The type given for "infer the return type" is a TypeFunction with
          * NULL for the return type.
          */
-        inferRetType = (type && type.nextOf() is null);
+        if (type && type.nextOf() is null)
+            this.flags |= FUNCFLAG.inferRetType;
     }
 
     static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
@@ -480,7 +481,7 @@ extern (C++) class FuncDeclaration : Declaration
                 return false;
         }
 
-        return !errors && !semantic3Errors;
+        return !errors && !this.hasSemantic3Errors();
     }
 
     /****************************************************
@@ -515,9 +516,11 @@ extern (C++) class FuncDeclaration : Declaration
      */
     extern (D) final void declareThis(Scope* sc)
     {
-        isThis2 = toParent2() != toParentLocal();
+        const bool dualCtx = (toParent2() != toParentLocal());
+        if (dualCtx)
+            this.flags |= FUNCFLAG.dualContext;
         auto ad = isThis();
-        if (!isThis2 && !ad && !isNested())
+        if (!dualCtx && !ad && !isNested())
         {
             vthis = null;
             objc.selectorParameter = null;
@@ -529,16 +532,16 @@ extern (C++) class FuncDeclaration : Declaration
             return t.addMod(type.mod).addStorageClass(storage_class);
         }
 
-        if (isThis2 || isNested())
+        if (dualCtx || 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.
              */
-            Type tthis = addModStc(isThis2 ?
+            Type tthis = addModStc(dualCtx ?
                                    Type.tvoidptr.sarrayOf(2).pointerTo() :
                                    Type.tvoid.pointerTo());
-            vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
+            vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
             vthis.storage_class |= STC.parameter | STC.nodtor;
         }
         else if (ad)
@@ -549,22 +552,6 @@ extern (C++) class FuncDeclaration : Declaration
             if (thandle.ty == Tstruct)
             {
                 vthis.storage_class |= STC.ref_;
-
-                /* if member function is marked 'inout', then 'this' is 'return ref'
-                 * The same thing is done for `ref inout` parameters in TypeFunction's semantic routine.
-                 */
-                if (auto tf = type.isTypeFunction())
-                {
-                    /* This feature was a mistake, but existing code relies on it.
-                     * So only disable it in @safe code and DIP1000 code
-                     */
-                    if (!(global.params.useDIP1000 == FeatureState.enabled &&
-                          tf.trust == TRUST.safe))
-                    {
-                        if (tf.isInOutQual())
-                            vthis.storage_class |= STC.return_;
-                    }
-                }
             }
         }
 
@@ -574,19 +561,8 @@ extern (C++) class FuncDeclaration : Declaration
                 vthis.storage_class |= STC.return_;
             if (tf.isScopeQual)
                 vthis.storage_class |= STC.scope_;
-
-            /* Add STC.returnScope like typesem.d does for TypeFunction parameters,
-             * at least it should be the same. At the moment, we'll just
-             * do existing practice. But we should examine how TypeFunction does
-             * it, for consistency.
-             */
-            if (global.params.useDIP1000 != FeatureState.enabled &&
-                !tf.isref && isRefReturnScope(vthis.storage_class))
-            {
-                /* if `ref return scope`, evaluate to `ref` `return scope`
-                 */
+            if (tf.isreturnscope)
                 vthis.storage_class |= STC.returnScope;
-            }
         }
         if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
             vthis.storage_class |= STC.maybescope;
@@ -1369,7 +1345,7 @@ extern (C++) class FuncDeclaration : Declaration
         if (!tf.isnogc)
             flags |= FUNCFLAG.nogcInprocess;
 
-        if (!isVirtual() || introducing)
+        if (!isVirtual() || this.isIntroducing())
             flags |= FUNCFLAG.returnInprocess;
 
         // Initialize for inferring STC.scope_
@@ -1482,6 +1458,73 @@ extern (C++) class FuncDeclaration : Declaration
         return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
     }
 
+    final bool isNRVO() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.NRVO);
+    }
+
+    final void isNRVO(bool v) pure nothrow @safe @nogc
+    {
+        if (v) this.flags |= FUNCFLAG.NRVO;
+        else this.flags &= ~FUNCFLAG.NRVO;
+    }
+
+    final bool isNaked() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.naked);
+    }
+
+    final bool isGenerated() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.generated);
+    }
+
+    final void isGenerated(bool v) pure nothrow @safe @nogc
+    {
+        if (v) this.flags |= FUNCFLAG.generated;
+        else this.flags &= ~FUNCFLAG.generated;
+    }
+
+    final bool isIntroducing() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.introducing);
+    }
+
+    final bool hasSemantic3Errors() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.semantic3Errors);
+    }
+
+    final bool hasNoEH() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.noEH);
+    }
+
+    final bool inferRetType() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.inferRetType);
+    }
+
+    final bool hasDualContext() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.dualContext);
+    }
+
+    final bool hasAlwaysInlines() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.hasAlwaysInline);
+    }
+
+    final bool isCrtCtor() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.CRTCtor);
+    }
+
+    final bool isCrtDtor() const scope @safe pure nothrow @nogc
+    {
+        return !!(this.flags & FUNCFLAG.CRTDtor);
+    }
+
     /**************************************
      * The function is doing something that may allocate with the GC,
      * so mark it as not nogc (not no-how).
@@ -1809,19 +1852,19 @@ extern (C++) class FuncDeclaration : Declaration
     {
         auto ad = isThis();
         ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
-        return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+        return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
     }
 
     bool addPostInvariant()
     {
         auto ad = isThis();
         ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
-        return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+        return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
     }
 
     override const(char)* kind() const
     {
-        return generated ? "generated function" : "function";
+        return this.isGenerated() ? "generated function" : "function";
     }
 
     /********************************************
@@ -2163,7 +2206,7 @@ extern (C++) class FuncDeclaration : Declaration
             vresult.parent = this;
         }
 
-        if (sc && vresult.semanticRun == PASS.init)
+        if (sc && vresult.semanticRun == PASS.initial)
         {
             TypeFunction tf = type.toTypeFunction();
             if (tf.isref)
@@ -2609,35 +2652,124 @@ extern (C++) class FuncDeclaration : Declaration
         return fd;
     }
 
-    /******************
-     * Check parameters and return type of D main() function.
-     * Issue error messages.
-     */
-    extern (D) final void checkDmain()
-    {
+    /+
+     + Checks the parameter and return types iff this is a `main` function.
+     +
+     + The following signatures are allowed for a `D main`:
+     + - Either no or a single parameter of type `string[]`
+     + - Return type is either `void`, `int` or `noreturn`
+     +
+     + The following signatures are standard C:
+     + - `int main()`
+     + - `int main(int, char**)`
+     +
+     + This function accepts the following non-standard extensions:
+     + - `char** envp` as a third parameter
+     + - `void` / `noreturn` as return type
+     +
+     + This function will issue errors for unexpected arguments / return types.
+     +/
+    extern (D) final void checkMain()
+    {
+        if (ident != Id.main || isMember() || isNested())
+            return; // Not a main function
+
         TypeFunction tf = type.toTypeFunction();
+
+        Type retType = tf.nextOf();
+        if (!retType)
+        {
+            // auto main(), check after semantic
+            assert(this.inferRetType);
+            return;
+        }
+
+        /// Checks whether `t` is equivalent to `char**`
+        /// Ignores qualifiers and treats enums according to their base type
+        static bool isCharPtrPtr(Type t)
+        {
+            auto tp = t.toBasetype().isTypePointer();
+            if (!tp)
+                return false;
+
+            tp = tp.next.toBasetype().isTypePointer();
+            if (!tp)
+                return false;
+
+            return tp.next.toBasetype().ty == Tchar;
+        }
+
+        // Neither of these qualifiers is allowed because they affect the ABI
+        enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
+
         const nparams = tf.parameterList.length;
         bool argerr;
-        if (nparams == 1)
+
+        if (linkage == LINK.d)
         {
-            auto fparam0 = tf.parameterList[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_))
+            if (nparams == 1)
             {
-                argerr = true;
+                auto fparam0 = tf.parameterList[0];
+                auto t = fparam0.type.toBasetype();
+                if (t.ty != Tarray ||
+                    t.nextOf().ty != Tarray ||
+                    t.nextOf().nextOf().ty != Tchar ||
+                    fparam0.storageClass & invalidSTC)
+                {
+                    argerr = true;
+                }
             }
+
+            if (tf.parameterList.varargs || nparams >= 2 || argerr)
+                error("parameter list must be empty or accept one parameter of type `string[]`");
         }
 
-        if (!tf.nextOf())
-            // auto main(), check after semantic
-            assert(this.inferRetType);
-        else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
+        else if (linkage == LINK.c)
+        {
+            if (nparams == 2 || nparams == 3)
+            {
+                // Argument count must be int
+                auto argCount = tf.parameterList[0];
+                argerr |= !!(argCount.storageClass & invalidSTC);
+                argerr |= argCount.type.toBasetype().ty != Tint32;
+
+                // Argument pointer must be char**
+                auto argPtr = tf.parameterList[1];
+                argerr |= !!(argPtr.storageClass & invalidSTC);
+                argerr |= !isCharPtrPtr(argPtr.type);
+
+                // `char** environ` is a common extension, see J.5.1 of the C standard
+                if (nparams == 3)
+                {
+                    auto envPtr = tf.parameterList[2];
+                    argerr |= !!(envPtr.storageClass & invalidSTC);
+                    argerr |= !isCharPtrPtr(envPtr.type);
+                }
+            }
+            else
+                argerr = nparams != 0;
+
+            // Disallow variadic main() - except for K&R declarations in C files.
+            // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
+            if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
+                argerr |= true;
+
+            if (argerr)
+            {
+                error("parameters must match one of the following signatures");
+                loc.errorSupplemental("`main()`");
+                loc.errorSupplemental("`main(int argc, char** argv)`");
+                loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
+            }
+        }
+        else
+            return; // Neither C nor D main, ignore (should probably be an error)
+
+        // Allow enums with appropriate base types (same ABI)
+        retType = retType.toBasetype();
+
+        if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
             error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
-        else if (tf.parameterList.varargs || nparams >= 2 || argerr)
-            error("parameters must be `main()` or `main(string[] args)`");
     }
 
     /***********************************************
@@ -2649,7 +2781,7 @@ extern (C++) class FuncDeclaration : Declaration
      */
     final bool checkNRVO()
     {
-        if (!nrvo_can || returns is null)
+        if (!isNRVO() || returns is null)
             return false;
 
         auto tf = type.toTypeFunction();
@@ -2661,7 +2793,7 @@ extern (C++) class FuncDeclaration : Declaration
             if (auto ve = rs.exp.isVarExp())
             {
                 auto v = ve.var.isVarDeclaration();
-                if (!v || v.isOut() || v.isRef())
+                if (!v || v.isReference())
                     return false;
                 else if (nrvo_var is null)
                 {
@@ -2669,6 +2801,8 @@ extern (C++) class FuncDeclaration : Declaration
                     // parameters and closure variables cannot be NRVOed.
                     if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
                         return false;
+                    if (v.nestedrefs.length && needsClosure())
+                        return false;
                     // The variable type needs to be equivalent to the return type.
                     if (!v.type.equivalent(tf.next))
                         return false;
index 6697a05..6b6655c 100644 (file)
@@ -15,6 +15,7 @@ import core.stdc.stdint;
 import dmd.root.array;
 import dmd.root.filename;
 import dmd.common.outbuffer;
+import dmd.file_manager;
 import dmd.identifier;
 
 /// Defines a setting for how compiler warnings and deprecations are handled
@@ -329,6 +330,9 @@ extern (C++) struct Global
     bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
     uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
 
+    /// Cache files read from disk
+    FileManager fileManager;
+
     enum recursionLimit = 500; /// number of recursive template expansions before abort
 
   nothrow:
@@ -383,6 +387,7 @@ extern (C++) struct Global
 
     extern (C++) void _init()
     {
+        this.fileManager = new FileManager();
         version (MARS)
         {
             vendor = "Digital Mars D";
index 9bbe0c9..2a33692 100644 (file)
@@ -19,6 +19,8 @@
 // Can't include arraytypes.h here, need to declare these directly.
 template <typename TYPE> struct Array;
 
+class FileManager;
+
 typedef unsigned char Diagnostic;
 enum
 {
@@ -292,6 +294,8 @@ struct Global
     bool hasMainFunction;
     unsigned varSequenceNumber;
 
+    FileManager* fileManager;
+
     /* Start gagging. Return the current number of gagged errors
      */
     unsigned startGagging();
index f2552d4..a3afbe5 100644 (file)
@@ -1836,25 +1836,12 @@ public:
                     t = te.sym.memtype;
                     goto L1;
                 }
+            case Tchar:
             case Twchar:
-                // BUG: need to cast(wchar)
             case Tdchar:
-                // BUG: need to cast(dchar)
-                if (cast(uinteger_t)v > 0xFF)
-                {
-                    buf.printf("'\\U%08llx'", cast(long)v);
-                    break;
-                }
-                goto case;
-            case Tchar:
                 {
-                    size_t o = buf.length;
-                    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);
+                    const o = buf.length;
+                    writeSingleCharLiteral(*buf, cast(dchar) v);
                     if (hgs.ddoc)
                         escapeDdocString(buf, o);
                     break;
@@ -2761,9 +2748,15 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
     bool result = false;
 
     if (stc & STC.scopeinferred)
+    {
+        //buf.writestring("scope-inferred ");
         stc &= ~(STC.scope_ | STC.scopeinferred);
+    }
     if (stc & STC.returninferred)
+    {
+        //buf.writestring("return-inferred ");
         stc &= ~(STC.return_ | STC.returninferred);
+    }
 
     /* Put scope ref return into a standard order
      */
index ec44ee0..bcfbd9a 100644 (file)
@@ -285,7 +285,7 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
     if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
         return true;
 
-    if (!tf1.nextOf().equals(tf2.nextOf()))
+    if (!cTypeEquivalence(tf1.next, tf2.next))
         return false;   // function return types don't match
 
     if (tf1.parameterList.length != tf2.parameterList.length)
@@ -318,3 +318,40 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
     //printf("t2: %s\n", tf2.toChars());
     return true;
 }
+
+/*******************************
+ * Types haven't been merged yet, because we haven't done
+ * semantic() yet.
+ * But we still need to see if t1 and t2 are the same type.
+ * Params:
+ *      t1 = first type
+ *      t2 = second type
+ * Returns:
+ *      true if they are equivalent types
+ */
+bool cTypeEquivalence(Type t1, Type t2)
+{
+    if (t1.equals(t2))
+        return true;    // that was easy
+
+    if (t1.ty != t2.ty || t1.mod != t2.mod)
+        return false;
+
+    if (auto tp = t1.isTypePointer())
+        return cTypeEquivalence(tp.next, t2.nextOf());
+
+    if (auto ta = t1.isTypeSArray())
+        // Bug: should check array dimension
+        return cTypeEquivalence(ta.next, t2.nextOf());
+
+    if (auto ts = t1.isTypeStruct())
+        return ts.sym is t2.isTypeStruct().sym;
+
+    if (auto te = t1.isTypeEnum())
+        return te.sym is t2.isTypeEnum().sym;
+
+    if (auto tf = t1.isTypeFunction())
+        return cFuncEquivalence(tf, tf.isTypeFunction());
+
+    return false;
+}
index c6c8c62..73dc4bb 100644 (file)
@@ -114,4 +114,4 @@ public:
     void accept(Visitor *v) { v->visit(this); }
 };
 
-Expression *initializerToExpression(Initializer *init, Type *t = NULL);
+Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
index bc02bf9..649d88e 100644 (file)
@@ -1080,10 +1080,11 @@ Initializer inferType(Initializer init, Scope* sc)
  * Params:
  *      init = `Initializer` AST node
  *      itype = if not `null`, type to coerce expression to
+ *      isCfile = default initializers are different with C
  * Returns:
  *      `Expression` created, `null` if cannot, `ErrorExp` for other errors
  */
-extern (C++) Expression initializerToExpression(Initializer init, Type itype = null)
+extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
 {
     Expression visitVoid(VoidInitializer)
     {
@@ -1204,7 +1205,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
                 if (!init.type) // don't know what type to use
                     return null;
                 if (!defaultInit)
-                    defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial);
+                    defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile);
                 element = defaultInit;
             }
         }
index 3ff2eae..7cd4bfd 100644 (file)
@@ -77,6 +77,7 @@ class Lexer
         bool doDocComment;      // collect doc comment information
         bool anyToken;          // seen at least one token
         bool commentToken;      // comments are TOK.comment's
+        bool tokenizeNewlines;  // newlines are turned into TOK.endOfLine's
 
         version (DMDLIB)
         {
@@ -116,6 +117,7 @@ class Lexer
         line = p;
         this.doDocComment = doDocComment;
         this.commentToken = commentToken;
+        this.tokenizeNewlines = false;
         this.inTokenStringConstant = 0;
         this.lastDocLine = 0;
         //initKeywords();
@@ -227,6 +229,8 @@ class Lexer
 
     /****************************
      * Turn next token in buffer into a token.
+     * Params:
+     *  t = the token to set the resulting Token to
      */
     final void scan(Token* t)
     {
@@ -286,7 +290,15 @@ class Lexer
             case '\r':
                 p++;
                 if (*p != '\n') // if CR stands by itself
+                {
                     endOfLine();
+                    if (tokenizeNewlines)
+                    {
+                        t.value = TOK.endOfLine;
+                        tokenizeNewlines = false;
+                        return;
+                    }
+                }
                 version (DMDLIB)
                 {
                     if (whitespaceToken)
@@ -299,6 +311,12 @@ class Lexer
             case '\n':
                 p++;
                 endOfLine();
+                if (tokenizeNewlines)
+                {
+                    t.value = TOK.endOfLine;
+                    tokenizeNewlines = false;
+                    return;
+                }
                 version (DMDLIB)
                 {
                     if (whitespaceToken)
@@ -1045,6 +1063,10 @@ class Lexer
                 return;
             case '#':
                 {
+                    // https://issues.dlang.org/show_bug.cgi?id=22825
+                    // Special token sequences are terminated by newlines,
+                    // and should not be skipped over.
+                    this.tokenizeNewlines = true;
                     p++;
                     if (parseSpecialTokenSequence())
                         continue;
@@ -1064,6 +1086,12 @@ class Lexer
                         {
                             endOfLine();
                             p++;
+                            if (tokenizeNewlines)
+                            {
+                                t.value = TOK.endOfLine;
+                                tokenizeNewlines = false;
+                                return;
+                            }
                             continue;
                         }
                     }
@@ -2607,16 +2635,19 @@ class Lexer
     {
         auto linnum = this.scanloc.linnum;
         const(char)* filespec = null;
-        const loc = this.loc();
         bool flags;
 
         if (!linemarker)
             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);
+            const lin = cast(int)(tok.unsvalue);
+            if (lin != tok.unsvalue)
+            {
+                error(tok.loc, "line number `%lld` out of range", cast(ulong)tok.unsvalue);
+                skipToNextLine();
+                return;
+            }
             else
                 linnum = lin;
         }
@@ -2624,15 +2655,19 @@ class Lexer
         {
         }
         else
-            goto Lerr;
+        {
+            error(tok.loc, "positive integer argument expected following `#line`");
+            if (tok.value != TOK.endOfLine)
+                skipToNextLine();
+            return;
+        }
         while (1)
         {
-            switch (*p)
+            scan(&tok);
+            switch (tok.value)
             {
-            case 0:
-            case 0x1A:
-            case '\n':
-            Lnewline:
+            case TOK.endOfFile:
+            case TOK.endOfLine:
                 if (!inTokenStringConstant)
                 {
                     this.scanloc.linnum = linnum;
@@ -2640,93 +2675,40 @@ class Lexer
                         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 '_':
+            case TOK.file:
                 if (filespec || flags)
                     goto Lerr;
-                if (memcmp(p, "__FILE__".ptr, 8) == 0)
-                {
-                    p += 8;
-                    filespec = mem.xstrdup(scanloc.filename);
-                    continue;
-                }
-                goto Lerr;
-            case '"':
+                filespec = mem.xstrdup(scanloc.filename);
+                continue;
+            case TOK.string_:
                 if (filespec || flags)
                     goto Lerr;
-                stringbuffer.setsize(0);
-                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[].ptr);
-                        p++;
-                        break;
-                    default:
-                        if (c & 0x80)
-                        {
-                            uint u = decodeUTF();
-                            if (u == PS || u == LS)
-                                goto Lerr;
-                        }
-                        stringbuffer.writeByte(c);
-                        p++;
-                        continue;
-                    }
-                    break;
-                }
-                continue;
-
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-                if (!linemarker)
+                if (tok.ptr[0] != '"' || tok.postfix != 0)
                     goto Lerr;
-                flags = true;   // linemarker flags seen
-                ++p;
-                if ('0' <= *p && *p <= '9')
-                    goto Lerr;  // only one digit allowed
+                filespec = tok.ustring;
                 continue;
-
-            default:
-                if (*p & 0x80)
+            case TOK.int32Literal:
+                if (!filespec)
+                    goto Lerr;
+                if (linemarker && tok.unsvalue >= 1 && tok.unsvalue <= 4)
                 {
-                    uint u = decodeUTF();
-                    if (u == PS || u == LS)
-                        goto Lnewline;
+                    flags = true;   // linemarker flags seen
+                    continue;
                 }
                 goto Lerr;
+            default:
+                goto Lerr;
             }
         }
     Lerr:
-        if (linemarker)
-            error(loc, "# integer [\"filespec\"] { 1 | 2 | 3 | 4 }\\n expected");
-        else
-            error(loc, "#line integer [\"filespec\"]\\n expected");
+        if (filespec is null)
+            error(tok.loc, "invalid filename for `#line` directive");
+        else if (linemarker)
+            error(tok.loc, "invalid flag for line marker directive");
+        else if (!Ccompile)
+            error(tok.loc, "found `%s` when expecting new line following `#line` directive", tok.toChars());
+        if (tok.value != TOK.endOfLine)
+            skipToNextLine();
     }
 
     /***************************************
@@ -2768,6 +2750,7 @@ class Lexer
             break;
         }
         endOfLine();
+        tokenizeNewlines = false;
     }
 
     /********************************************
@@ -3004,7 +2987,7 @@ private struct TimeStampInfo
         if (auto p = getenv("SOURCE_DATE_EPOCH"))
         {
             if (!ct.parseDigits(p.toDString()))
-                error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
+                error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
         }
         else
             .time(&ct);
index 1494044..b2c7aa4 100644 (file)
@@ -4198,6 +4198,8 @@ extern (C++) final class TypeFunction : TypeNext
 
     ParameterList parameterList;   // function parameters
 
+    // These flags can be accessed like `bool` properties,
+    // getters and setters are generated for them
     private enum FunctionFlag : uint
     {
         none            = 0,
@@ -4206,13 +4208,13 @@ extern (C++) final class TypeFunction : TypeNext
         isproperty      = 0x0004, // can be called without parentheses
         isref           = 0x0008, // returns a reference
         isreturn        = 0x0010, // 'this' is returned by ref
-        isscope         = 0x0020, // 'this' is scope
+        isScopeQual     = 0x0020, // 'this' is scope
         isreturninferred= 0x0040, // 'this' is return from inference
         isscopeinferred = 0x0080, // 'this' is scope from inference
         islive          = 0x0100, // is @live
         incomplete      = 0x0200, // return type or default arguments removed
-        inoutParam      = 0x0400, // inout on the parameters
-        inoutQual       = 0x0800, // inout on the qualifier
+        isInOutParam    = 0x0400, // inout on the parameters
+        isInOutQual     = 0x0800, // inout on the qualifier
         isctor          = 0x1000, // the function is a constructor
         isreturnscope   = 0x2000, // `this` is returned by value
     }
@@ -4480,7 +4482,7 @@ extern (C++) final class TypeFunction : TypeNext
         {
             // Check escaping through return value
             Type tret = nextOf().toBasetype();
-            if (isref || tret.hasPointers())
+            if (isref || tret.hasPointers() || !isnothrow())
             {
                 return stc;
             }
@@ -5084,177 +5086,29 @@ extern (C++) final class TypeFunction : TypeNext
         return false;
     }
 
-    /// set or get if the function has the `nothrow` attribute
-    bool isnothrow() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isnothrow) != 0;
-    }
-    /// ditto
-    void isnothrow(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isnothrow;
-        else funcFlags &= ~FunctionFlag.isnothrow;
-    }
-
-    /// set or get if the function has the `@nogc` attribute
-    bool isnogc() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isnogc) != 0;
-    }
-    /// ditto
-    void isnogc(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isnogc;
-        else funcFlags &= ~FunctionFlag.isnogc;
-    }
-
-    /// set or get if the function has the `@property` attribute
-    bool isproperty() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isproperty) != 0;
-    }
-    /// ditto
-    void isproperty(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isproperty;
-        else funcFlags &= ~FunctionFlag.isproperty;
-    }
-
-    /// set or get if the function has the `ref` attribute
-    bool isref() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isref) != 0;
-    }
-    /// ditto
-    void isref(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isref;
-        else funcFlags &= ~FunctionFlag.isref;
-    }
-
-    /// set or get if the function has the `return` attribute
-    bool isreturn() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isreturn) != 0;
-    }
-    /// ditto
-    void isreturn(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isreturn;
-        else funcFlags &= ~FunctionFlag.isreturn;
-    }
-
-    /// set or get if the function has the `returnscope` attribute
-    bool isreturnscope() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isreturnscope) != 0;
-    }
-    /// ditto
-    void isreturnscope(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isreturnscope;
-        else funcFlags &= ~FunctionFlag.isreturnscope;
-    }
-
-    /// set or get if the function has the `scope` attribute
-    bool isScopeQual() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isscope) != 0;
-    }
-    /// ditto
-    void isScopeQual(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isscope;
-        else funcFlags &= ~FunctionFlag.isscope;
-    }
-
-    /// set or get if the function has the `return` attribute inferred
-    bool isreturninferred() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isreturninferred) != 0;
-    }
-    /// ditto
-    void isreturninferred(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isreturninferred;
-        else funcFlags &= ~FunctionFlag.isreturninferred;
-    }
-
-    /// set or get if the function has the `scope` attribute inferred
-    bool isscopeinferred() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isscopeinferred) != 0;
-    }
-    /// ditoo
-    void isscopeinferred(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isscopeinferred;
-        else funcFlags &= ~FunctionFlag.isscopeinferred;
-    }
-
-    /// set or get if the function has the `@live` attribute
-    bool islive() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.islive) != 0;
-    }
-    /// ditto
-    void islive(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.islive;
-        else funcFlags &= ~FunctionFlag.islive;
-    }
-
-    /// set or get if the return type or the default arguments are removed
-    bool incomplete() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.incomplete) != 0;
-    }
-    /// ditto
-    void incomplete(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.incomplete;
-        else funcFlags &= ~FunctionFlag.incomplete;
-    }
-
-    /// set or get if the function has the `inout` on the parameters
-    bool isInOutParam() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.inoutParam) != 0;
-    }
-    /// ditto
-    void isInOutParam(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.inoutParam;
-        else funcFlags &= ~FunctionFlag.inoutParam;
-    }
+    // Generate getter / setter functions for `FunctionFlag` members so they can be
+    // treated like regular `bool` fields, instead of requiring bit twiddling to read/write
+    extern (D) mixin(() {
+        string result = "extern(C++) pure nothrow @safe @nogc {";
+        foreach (string mem; __traits(allMembers, FunctionFlag))
+        {
+            result ~= "
+            /// set or get if the function has the FunctionFlag attribute of the same name
+            bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
+            /// ditto
+            void "~mem~"(bool v)
+            {
+                if (v) funcFlags |= FunctionFlag."~mem~";
+                else funcFlags &= ~FunctionFlag."~mem~";
+            }";
+        }
+        return result ~ "}\n";
+    }());
 
-    /// set or get if the function has the `inout` on the parameters
-    bool isInOutQual() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.inoutQual) != 0;
-    }
-    /// ditto
-    void isInOutQual(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.inoutQual;
-        else funcFlags &= ~FunctionFlag.inoutQual;
-    }
     /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
     bool iswild() const pure nothrow @safe @nogc
     {
-        return (funcFlags & (FunctionFlag.inoutParam | FunctionFlag.inoutQual)) != 0;
-    }
-
-    /// set or get if the function is a constructor
-    bool isctor() const pure nothrow @safe @nogc
-    {
-        return (funcFlags & FunctionFlag.isctor) != 0;
-    }
-    /// ditto
-    void isctor(bool v) pure nothrow @safe @nogc
-    {
-        if (v) funcFlags |= FunctionFlag.isctor;
-        else funcFlags &= ~FunctionFlag.isctor;
+        return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
     }
 
     /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
@@ -6418,9 +6272,6 @@ extern (C++) final class TypeClass : Type
 
     override MOD deduceWild(Type t, bool isRef)
     {
-        // If sym is forward referenced:
-        if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
-            sym.dsymbolSemantic(null);
         ClassDeclaration cd = t.isClassHandle();
         if (cd && (sym == cd || cd.isBaseOf(sym, null)))
             return Type.deduceWild(t, isRef);
@@ -7176,6 +7027,17 @@ extern (C++) final class Parameter : ASTNode
 
     extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
     {
+        // Workaround for failing covariance when finding a common type of delegates,
+        // some of which have parameters with inferred scope
+        // https://issues.dlang.org/show_bug.cgi?id=21285
+        // The root cause is that scopeinferred is not part of the mangle, and mangle
+        // is used for type equality checks
+        if (to & STC.returninferred)
+            to &= ~STC.return_;
+        // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
+        if (to & STC.scopeinferred && !(to & STC.return_))
+            to &= ~STC.scope_;
+
         if (from == to)
             return true;
 
index d6735d4..2957b3a 100644 (file)
@@ -137,9 +137,9 @@ public:
 
     override void visit(DeleteExp e)
     {
-        if (e.e1.op == EXP.variable)
+        if (VarExp ve = e.e1.isVarExp())
         {
-            VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+            VarDeclaration v = ve.var.isVarDeclaration();
             if (v && v.onstack)
                 return; // delete for scope allocated class object
         }
index c2594fe..121a266 100644 (file)
@@ -1747,7 +1747,7 @@ PtrState toPtrState(VarDeclaration v)
      */
 
     auto t = v.type;
-    if (v.isRef())
+    if (v.isReference())
     {
         return t.hasMutableFields() ? PtrState.Borrowed : PtrState.Readonly;
     }
@@ -1775,7 +1775,7 @@ bool hasPointersToMutableFields(Type t)
     {
         foreach (v; ts.sym.fields)
         {
-            if (v.isRef())
+            if (v.isReference())
             {
                 if (v.type.hasMutableFields())
                     return true;
@@ -1977,7 +1977,12 @@ void checkObErrors(ref ObState obstate)
             else if (isReadonlyPtr(v))
                 pvs.state = PtrState.Readonly;
             else
+            {
+                if (pvs.state == PtrState.Owner && v.type.hasPointersToMutableFields())
+                    v.error(e.loc, "assigning to Owner without disposing of owned value");
+
                 pvs.state = PtrState.Owner;
+            }
             pvs.deps.zero();
 
             EscapeByResults er;
index fc64377..dbd761f 100644 (file)
@@ -711,7 +711,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 if (s)
                 {
                     functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
-                    if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+                    if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                     {
                         return ErrorExp.get();
                     }
@@ -720,7 +720,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 if (s_r)
                 {
                     functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
-                    if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+                    if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                     {
                         return ErrorExp.get();
                     }
@@ -793,7 +793,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (s_r)
                         {
                             functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
-                            if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+                            if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                             {
                                 return ErrorExp.get();
                             }
@@ -802,7 +802,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (s)
                         {
                             functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
-                            if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+                            if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                             {
                                 return ErrorExp.get();
                             }
@@ -1250,7 +1250,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 if (s)
                 {
                     functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
-                    if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+                    if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                     {
                         return ErrorExp.get();
                     }
@@ -1344,7 +1344,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
         if (s)
         {
             functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
-            if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+            if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                 return ErrorExp.get();
         }
         FuncDeclaration lastf = m.lastf;
@@ -1352,7 +1352,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop
         if (s_r)
         {
             functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
-            if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+            if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
                 return ErrorExp.get();
         }
         if (m.count > 1)
index 5a86931..3745a15 100644 (file)
@@ -504,6 +504,16 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     {
                         eint = ei;
                     }
+                    else if (auto se = ep.e1.isSymOffExp())
+                    {
+                        if (!se.var.isReference() &&
+                            !se.var.isImportedSymbol() &&
+                            se.var.isDataseg())
+                        {
+                            var = se.var.isVarDeclaration();
+                            offset += se.offset;
+                        }
+                    }
                 }
                 return false;
             }
@@ -531,7 +541,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         if (auto ae = e.e1.isIndexExp())
         {
             // Convert &array[n] to &array+n
-            if (ae.e2.op == EXP.int64 && ae.e1.isVarExp())
+            if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
             {
                 sinteger_t index = ae.e2.toInteger();
                 VarExp ve = ae.e1.isVarExp();
@@ -541,8 +551,13 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     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();
+                        /* 0 for C static arrays means size is unknown, no need to check
+                         */
+                        if (!(dim == 0 && ve.var.isCsymbol()))
+                        {
+                            e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+                            return error();
+                        }
                     }
 
                     import core.checkedint : mulu;
@@ -559,6 +574,33 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     return;
                 }
             }
+            // Convert &((a.b)[n]) to (&a.b)+n
+            else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
+            {
+                sinteger_t index = ae.e2.toInteger();
+                DotVarExp ve = ae.e1.isDotVarExp();
+                if (ve.type.isTypeSArray() && ve.var.isField() && ve.e1.isPtrExp())
+                {
+                    TypeSArray ts = ve.type.isTypeSArray();
+                    sinteger_t dim = ts.dim.toInteger();
+                    if (index < 0 || index >= dim)
+                    {
+                        /* 0 for C static arrays means size is unknown, no need to check
+                         */
+                        if (!(dim == 0 && ve.var.isCsymbol()))
+                        {
+                            e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+                            return error();
+                        }
+                    }
+
+                    auto pe = new AddrExp(e.loc, ve);
+                    pe.type = e.type;
+                    ret = new AddExp(e.loc, pe, ae.e2);
+                    ret.type = e.type;
+                    return;
+                }
+            }
         }
     }
 
index f6472bf..7b1b63c 100644 (file)
@@ -3651,7 +3651,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
         case TOK.traits:
             if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
-                if (te.ident && te.args)
+                if (te.ident)
                 {
                     t = new AST.TypeTraits(token.loc, te);
                     break;
index 571c3fc..bba3481 100644 (file)
@@ -209,5 +209,3 @@ extern (C++) final class PrintASTVisitor : Visitor
             putc(' ', stdout);
     }
 }
-
-
index 5b8cc82..ba5d331 100644 (file)
@@ -20,7 +20,7 @@ private size_t hash(size_t a) pure nothrow @nogc @safe
     return a ^ (a >> 7) ^ (a >> 4);
 }
 
-struct KeyValueTemplate(K,V)
+private struct KeyValueTemplate(K,V)
 {
     K key;
     V value;
@@ -31,15 +31,17 @@ alias Value = void*;
 
 alias KeyValue = KeyValueTemplate!(Key, Value);
 
-struct aaA
+private struct aaA
 {
+private:
     aaA* next;
     KeyValue keyValue;
     alias keyValue this;
 }
 
-struct AA
+private struct AA
 {
+private:
     aaA** b;
     size_t b_length;
     size_t nodes; // total number of aaA nodes
index 866b952..52bed5e 100644 (file)
@@ -205,4 +205,3 @@ struct Array
         return data.ptr[--length];
     }
 };
-
index 42c09fa..90cbaed 100644 (file)
@@ -187,6 +187,3 @@ nothrow pure unittest
     a = b;
     assert(a == b);
 }
-
-
-
index 1f33c18..a01cfdc 100644 (file)
@@ -45,11 +45,6 @@ struct FileBuffer
         data = null;
         return result;
     }
-
-    extern (C++) static FileBuffer* create() pure nothrow @safe
-    {
-        return new FileBuffer();
-    }
 }
 
 ///
@@ -78,12 +73,6 @@ struct File
 
 nothrow:
     /// Read the full content of a file.
-    extern (C++) static ReadResult read(const(char)* name)
-    {
-        return read(name.toDString());
-    }
-
-    /// Ditto
     static ReadResult read(const(char)[] name)
     {
         ReadResult result;
@@ -179,24 +168,18 @@ nothrow:
     }
 
     /// Write a file, returning `true` on success.
-    extern (D) static bool write(const(char)* name, const void[] data)
+    static bool write(const(char)* name, const void[] data)
     {
         import dmd.common.file : writeFile;
         return writeFile(name, data);
     }
 
     ///ditto
-    extern(D) static bool write(const(char)[] name, const void[] data)
+    static bool write(const(char)[] name, const void[] data)
     {
         return name.toCStringThen!((fname) => write(fname.ptr, data));
     }
 
-    /// ditto
-    extern (C++) static bool write(const(char)* name, const(void)* data, size_t size)
-    {
-        return write(name, data[0 .. size]);
-    }
-
     /// Delete a file.
     extern (C++) static void remove(const(char)* name)
     {
@@ -229,7 +212,7 @@ nothrow:
      * Returns:
      *  `true` on success
      */
-    extern (D) static bool update(const(char)* namez, const void[] data)
+    static bool update(const(char)* namez, const void[] data)
     {
         enum log = false;
         if (log) printf("update %s\n", namez);
@@ -252,17 +235,11 @@ nothrow:
     }
 
     ///ditto
-    extern(D) static bool update(const(char)[] name, const void[] data)
+    static bool update(const(char)[] name, const void[] data)
     {
         return name.toCStringThen!(fname => update(fname.ptr, data));
     }
 
-    /// ditto
-    extern (C++) static bool update(const(char)* name, const(void)* data, size_t size)
-    {
-        return update(name, data[0 .. size]);
-    }
-
     /// Size of a file in bytes.
     /// Params: namez = null-terminated filename
     /// Returns: `ulong.max` on any error, the length otherwise.
index 884a9f1..20316fa 100644 (file)
@@ -224,7 +224,7 @@ public:
     }
 
     /// ditto
-    extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
+    int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
     {
         foreach (const se; table)
         {
index 7314d5b..26fba8f 100644 (file)
@@ -177,4 +177,3 @@ public:
         doCond(s.statement) || applyTo(s);
     }
 }
-
index d237caf..5119576 100644 (file)
@@ -275,7 +275,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     // 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;
+                    funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
                 }
                 return;
             }
@@ -285,7 +285,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
         if (funcdecl.semanticRun >= PASS.semantic3)
             return;
         funcdecl.semanticRun = PASS.semantic3;
-        funcdecl.semantic3Errors = false;
+        funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
 
         if (!funcdecl.type || funcdecl.type.ty != Tfunction)
             return;
@@ -386,7 +386,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
             // functions may be widely used by dmd-compiled projects.
             // It also gives more time for the implementation of dual-context
             // functions to be reworked as a frontend-only feature.
-            if (funcdecl.isThis2)
+            if (funcdecl.hasDualContext())
             {
                 funcdecl.deprecation("function requires a dual-context, which is deprecated");
                 if (auto ti = sc2.parent ? sc2.parent.isInstantiated() : null)
@@ -603,7 +603,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 if (!funcdecl.fbody)
                     funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
 
-                if (funcdecl.naked)
+                if (funcdecl.isNaked())
                 {
                     fpreinv = null;         // can't accommodate with no stack frame
                     fpostinv = null;
@@ -619,8 +619,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
                         f.next = Type.tvoid;
                     if (f.checkRetType(funcdecl.loc))
                         funcdecl.fbody = new ErrorStatement();
-                    else if (funcdecl.isMain())
-                        funcdecl.checkDmain();       // Check main() parameters and return type
+                    else
+                        funcdecl.checkMain(); // Check main() parameters and return type
                 }
 
                 if (f.next !is null)
@@ -654,7 +654,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
 
                 // handle NRVO
                 if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
-                    funcdecl.nrvo_can = 0;
+                    funcdecl.flags &= ~FUNCFLAG.NRVO;
 
                 if (funcdecl.fbody.isErrorStatement())
                 {
@@ -762,7 +762,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     /* Don't generate unwind tables for this function
                      * https://issues.dlang.org/show_bug.cgi?id=17997
                      */
-                    funcdecl.eh_none = true;
+                    funcdecl.flags |= FUNCFLAG.noEH;
                 }
 
                 if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
@@ -927,7 +927,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                             /* 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)
+                            if (!funcdecl.isNRVO())
                                 exp = doCopyOrMove(sc2, exp, f.next);
 
                             if (tret.hasPointers())
@@ -996,7 +996,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 freq = freq.statementSemantic(sc2);
                 freq.blockExit(funcdecl, false);
 
-                funcdecl.eh_none = false;
+                funcdecl.flags &= ~FUNCFLAG.noEH;
 
                 sc2 = sc2.pop();
 
@@ -1030,7 +1030,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 fens = fens.statementSemantic(sc2);
                 fens.blockExit(funcdecl, false);
 
-                funcdecl.eh_none = false;
+                funcdecl.flags &= ~FUNCFLAG.noEH;
 
                 sc2 = sc2.pop();
 
@@ -1159,7 +1159,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                             const blockexit = s.blockExit(funcdecl, isnothrow);
                             if (blockexit & BE.throw_)
                             {
-                                funcdecl.eh_none = false;
+                                funcdecl.flags &= ~FUNCFLAG.noEH;
                                 if (isnothrow)
                                     error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
                                 else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
@@ -1195,7 +1195,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                             {
                                 // 'this' is the monitor
                                 vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
-                                if (funcdecl.isThis2)
+                                if (funcdecl.hasDualContext())
                                 {
                                     vsync = new PtrExp(funcdecl.loc, vsync);
                                     vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
@@ -1230,7 +1230,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 }
 
             // Fix up forward-referenced gotos
-            if (funcdecl.gotos)
+            if (funcdecl.gotos && !funcdecl.isCsymbol())
             {
                 for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
                 {
@@ -1238,7 +1238,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 }
             }
 
-            if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
+            if (funcdecl.isNaked() && (funcdecl.fensures || funcdecl.frequires))
                 funcdecl.error("naked assembly functions with contracts are not supported");
 
             sc2.ctorflow.callSuper = CSX.none;
@@ -1370,7 +1370,10 @@ private extern(C++) final class Semantic3Visitor : Visitor
          * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
          */
         funcdecl.semanticRun = PASS.semantic3done;
-        funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
+        if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()))
+            funcdecl.flags |= FUNCFLAG.semantic3Errors;
+        else
+            funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
         if (funcdecl.type.ty == Terror)
             funcdecl.errors = true;
         //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
index 8b271f8..ae03b8a 100644 (file)
@@ -1761,6 +1761,9 @@ extern (C++) final class GotoStatement : Statement
         return new GotoStatement(loc, ident);
     }
 
+    /**************
+     * Returns: true for error
+     */
     extern (D) bool checkLabel()
     {
         if (!label.statement)
index 6ffba68..c2967d6 100644 (file)
@@ -211,7 +211,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             if (f.checkForwardRef(s.exp.loc))
                 s.exp = ErrorExp.get();
         }
-        if (discardValue(s.exp))
+
+        if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
             s.exp = ErrorExp.get();
 
         s.exp = s.exp.optimize(WANTvalue);
@@ -728,12 +729,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
         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);
+            assert(oaggr.type);
+
+            fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars());
+            if (isAggregate(fs.aggr.type))
+                fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`");
+
             return setError();
         }
 
@@ -2310,12 +2311,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
                 needswitcherror = true;
         }
 
-        if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) &&
+        if (!sc.sw.sdefault &&
             (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
         {
             ss.hasNoDefault = 1;
 
-            if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()))
+            if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile))
                 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
@@ -2323,7 +2324,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             CompoundStatement cs;
             Statement s;
 
-            if (global.params.useSwitchError == CHECKENABLE.on &&
+            if (sc.flags & SCOPE.Cfile)
+            {
+                s = new BreakStatement(ss.loc, null);   // default for C is `default: break;`
+            }
+            else if (global.params.useSwitchError == CHECKENABLE.on &&
                 global.params.checkAction != CHECKACTION.halt)
             {
                 if (global.params.checkAction == CHECKACTION.C)
@@ -2365,7 +2370,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             ss._body = cs;
         }
 
-        if (ss.checkLabel())
+        if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel())
         {
             sc.pop();
             return setError();
@@ -3840,7 +3845,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
                 fd.gotos = new GotoStatements();
             fd.gotos.push(gs);
         }
-        else if (gs.checkLabel())
+        else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel())
             return setError();
 
         result = gs;
@@ -3916,12 +3921,10 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
         }
 
         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.pure_) && sc.func.setImpure())
+            cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
+        if (!(cas.stc & STC.nogc) && sc.func.setGC())
+            cas.error("`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");
 
index 1790996..43feab1 100644 (file)
@@ -245,6 +245,7 @@ enum TOK : ubyte
     arrow,      // ->
     colonColon, // ::
     wchar_tLiteral,
+    endOfLine,  // \n, \r, \u2028, \u2029
     whitespace,
 
     // C only keywords
@@ -851,6 +852,7 @@ extern (C++) struct Token
         TOK.wcharLiteral: "wcharv",
         TOK.dcharLiteral: "dcharv",
         TOK.wchar_tLiteral: "wchar_tv",
+        TOK.endOfLine: "\\n",
         TOK.whitespace: "whitespace",
 
         // C only keywords
@@ -945,20 +947,19 @@ nothrow:
             sprintf(&buffer[0], "%d", cast(int)intvalue);
             break;
         case TOK.uns32Literal:
-        case TOK.wcharLiteral:
-        case TOK.dcharLiteral:
         case TOK.wchar_tLiteral:
             sprintf(&buffer[0], "%uU", cast(uint)unsvalue);
             break;
+        case TOK.wcharLiteral:
+        case TOK.dcharLiteral:
         case TOK.charLiteral:
-        {
-            const v = cast(int)intvalue;
-            if (v >= ' ' && v <= '~')
-                sprintf(&buffer[0], "'%c'", v);
-            else
-                sprintf(&buffer[0], "'\\x%02x'", v);
+            {
+                OutBuffer buf;
+                buf.writeSingleCharLiteral(cast(dchar) intvalue);
+                buf.writeByte('\0');
+                p = buf.extractSlice().ptr;
+            }
             break;
-        }
         case TOK.int64Literal:
             sprintf(&buffer[0], "%lldL", cast(long)intvalue);
             break;
@@ -1090,7 +1091,7 @@ void writeCharLiteral(ref OutBuffer buf, dchar c)
             buf.writeByte('\\');
             goto default;
         default:
-            if (c <= 0x7F)
+            if (c <= 0xFF)
             {
                 if (isprint(c))
                     buf.writeByte(c);
@@ -1114,3 +1115,40 @@ unittest
     }
     assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
 }
+
+/**
+ * Write a single-quoted character literal
+ *
+ * Useful for printing '' char literals in e.g. error messages, ddoc, or the `.stringof` property
+ *
+ * Params:
+ *   buf = buffer to append character in
+ *   c = code point to write
+ */
+nothrow
+void writeSingleCharLiteral(ref OutBuffer buf, dchar c)
+{
+    buf.writeByte('\'');
+    if (c == '\'')
+        buf.writeByte('\\');
+
+    if (c == '"')
+        buf.writeByte('"');
+    else
+        writeCharLiteral(buf, c);
+
+    buf.writeByte('\'');
+}
+
+unittest
+{
+    OutBuffer buf;
+    writeSingleCharLiteral(buf, '\'');
+    assert(buf.extractSlice() == `'\''`);
+    buf.reset();
+    writeSingleCharLiteral(buf, '"');
+    assert(buf.extractSlice() == `'"'`);
+    buf.reset();
+    writeSingleCharLiteral(buf, '\n');
+    assert(buf.extractSlice() == `'\n'`);
+}
index c404cab..f9b6062 100644 (file)
@@ -254,6 +254,7 @@ enum class TOK : unsigned char
     arrow,      // ->
     colonColon, // ::
     wchar_tLiteral,
+    endOfLine,  // \n, \r, \u2028, \u2029
     whitespace,
 
     // C only keywords
index dbdcfd4..4b15e8c 100644 (file)
@@ -80,10 +80,10 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
 {
     if (auto e = isExpression(oarg))
     {
-        if (e.op == EXP.dotVariable)
-            return (cast(DotVarExp)e).var;
-        if (e.op == EXP.dotTemplateDeclaration)
-            return (cast(DotTemplateExp)e).td;
+        if (auto dve = e.isDotVarExp())
+            return dve.var;
+        if (auto dte = e.isDotTemplateExp())
+            return dte.td;
     }
     return getDsymbol(oarg);
 }
@@ -833,7 +833,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                 e.error("argument `%s` has no visibility", o.toChars());
             return ErrorExp.get();
         }
-        if (s.semanticRun == PASS.init)
+        if (s.semanticRun == PASS.initial)
             s.dsymbolSemantic(null);
 
         auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names)
@@ -1053,9 +1053,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
         }
         else if (e.ident == Id.getMember)
         {
-            if (ex.op == EXP.dotIdentifier)
+            if (auto die = ex.isDotIdExp())
                 // Prevent semantic() from replacing Symbol with its initializer
-                (cast(DotIdExp)ex).wantsym = true;
+                die.wantsym = true;
             ex = ex.expressionSemantic(scx);
             return ex;
         }
@@ -2101,13 +2101,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             return ErrorExp.get();
         }
 
-        if (sc.func is null)
+        auto fd = sc.getEnclosingFunction();
+        if (!fd)
         {
             e.error("`__traits(parameters)` may only be used inside a function");
             return ErrorExp.get();
         }
-        assert(sc.func && sc.parent.isFuncDeclaration());
-        auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction();
+
+        auto tf = fd.type.isTypeFunction();
         assert(tf);
         auto exps = new Expressions(0);
         int addParameterDG(size_t idx, Parameter x)
@@ -2162,7 +2163,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc)
         {
             if (ea.op == EXP.function_)
             {
-                if (auto fe = cast(FuncExp)ea)
+                if (auto fe = ea.isFuncExp())
                     return fe.fd;
             }
         }
index e5f839b..bcdbec5 100644 (file)
@@ -978,7 +978,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             // 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.generated && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
+            if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
             {
                 uint errors = global.startGagging();
                 sd.xeq.semantic3(sd.xeq._scope);
@@ -1431,12 +1431,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                     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.isReference())
@@ -1799,6 +1793,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             mtype.exp.ident != Id.derivedMembers &&
             mtype.exp.ident != Id.getMember &&
             mtype.exp.ident != Id.parent &&
+            mtype.exp.ident != Id.parameters &&
             mtype.exp.ident != Id.child &&
             mtype.exp.ident != Id.toType &&
             mtype.exp.ident != Id.getOverloads &&
@@ -3088,7 +3083,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
         //static int nest; if (++nest == 50) *(char*)0=0;
         if (sc is null)
         {
-            error(loc, "Invalid scope.");
+            error(loc, "invalid scope");
             return returnError();
         }
         if (mt.inuse)
@@ -4076,7 +4071,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                     return e.expressionSemantic(sc);
                 }
             }
-            if (d.semanticRun == PASS.init)
+            if (d.semanticRun == PASS.initial)
                 d.dsymbolSemantic(null);
             checkAccess(e.loc, sc, e, d);
             auto ve = new VarExp(e.loc, d);
@@ -4307,7 +4302,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
 
             if (ident == Id.outer && mt.sym.vthis)
             {
-                if (mt.sym.vthis.semanticRun == PASS.init)
+                if (mt.sym.vthis.semanticRun == PASS.initial)
                     mt.sym.vthis.dsymbolSemantic(null);
 
                 if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
@@ -4503,7 +4498,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                     Expression e1;
                     Type t;
                     /* returns: true to continue, false to return */
-                    if (f.isThis2)
+                    if (f.hasDualContext())
                     {
                         if (f.followInstantiationContext(ad))
                         {
@@ -4560,7 +4555,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                 }
             }
             //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
-            if (d.semanticRun == PASS.init)
+            if (d.semanticRun == PASS.initial)
                 d.dsymbolSemantic(null);
 
             // If static function, get the most visible overload.
index f8e7e48..67e4d86 100644 (file)
@@ -63,7 +63,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename)
     auto result = File.read(filename);
     if (!result.success)
     {
-        error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr);
+        error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
         fatal();
     }
     return FileBuffer(result.extractSlice());
index 2a7fb69..61a2b50 100644 (file)
@@ -1441,7 +1441,7 @@ public:
        gcc_assert (e->e1->op == EXP::variable);
 
        VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration ();
-       gcc_assert (v && v->onstack);
+       gcc_assert (v && v->onstack ());
 
        libcall_fn libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
          ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
index 899648f..edc7912 100644 (file)
@@ -141,7 +141,7 @@ get_internal_fn (tree ident, const Visibility &visibility)
 
   FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
                                                   Identifier::idPool (name));
-  fd->generated = true;
+  fd->isGenerated (true);
   fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
   fd->parent = mod;
   fd->visibility = visibility;
index a25f7a5..d20c5c3 100644 (file)
@@ -958,7 +958,7 @@ public:
        /* If returning via NRVO, 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.  */
-       if (this->func_->nrvo_can && this->func_->nrvo_var)
+       if (this->func_->isNRVO () && this->func_->nrvo_var)
          {
            add_stmt (return_expr (decl));
            return;
diff --git a/gcc/testsuite/gdc.dg/nrvo1.d b/gcc/testsuite/gdc.dg/nrvo1.d
new file mode 100644 (file)
index 0000000..d93edfb
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-additional-options "-fpreview=dip1000" }
+ThreadInfo* ptr;
+
+ThreadInfo receiveOnly()
+{
+    ThreadInfo ret;
+
+    get({ptr = &ret;});
+    return ret;
+}
+
+struct ThreadInfo
+{
+    ThreadInfo* next;
+}
+
+bool get(T)(T)
+{
+    return false;
+}
+
+void main()
+{
+    auto t = receiveOnly();
+    assert(&t == ptr);
+}
index 0b9ccf3..c52c710 100644 (file)
@@ -25,4 +25,4 @@ static assert(S.foo!([]) == 0);
 
 alias fooFuns = AliasSeq!(__traits(getOverloads, S, "foo"));
 static assert(fooFuns.length == 1);
-static assert(fooFuns[0]("") == 2);
\ No newline at end of file
+static assert(fooFuns[0]("") == 2);
index e355e49..a29836e 100644 (file)
@@ -38,4 +38,3 @@ alias TK2 = reverse!(int, const uint, X2);
 static assert(TK2[0] == 3);
 static assert(is(TK2[1] == const(uint)));
 static assert(is(TK2[2] == int));
-
index 482faa7..fb14fee 100644 (file)
@@ -1,4 +1,5 @@
 // REQUIRED_ARGS: -unittest
+// PERMUTE_ARGS: -preview=dip1000
 // Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
 unittest
 {
@@ -25,3 +26,36 @@ unittest
     static assert(is(typeof(a[0]) == dg));
     static assert(is(typeof(ab[0]) == fn));
 }
+
+int f(string s) { throw new Exception(""); }
+void main()
+{
+    string path;
+    int bank, preset;
+    void delegate(string value)[string] aa = [
+        "path": (string arg) {
+            path = arg;
+        },
+        "bank": (string arg) {
+            bank = f(arg);
+        },
+        "preset": (string arg) {
+            preset = f(arg);
+        },
+    ];
+
+    string delegate(string value)[string] aa2 = [
+        "path": (string arg) {
+            path = arg;
+            return arg;
+        },
+        "bank": (string arg) {
+            bank = f(arg);
+            return arg;
+        },
+        "preset": (string arg) {
+            preset = f(arg);
+            return arg;
+        },
+    ];
+}
index 94f4bc3..3910ffa 100644 (file)
@@ -22,4 +22,3 @@ void applyNoRemoveRegex()
     auto a = find!((a){return match(e);})(map!regex(noRemoveStr));
   }
 }
-
index d0148b1..433163d 100644 (file)
@@ -36,4 +36,3 @@ void main()
     f(s1.s.tupleof); // OK
     f((s1.s).tupleof); // Error: need 'this' to access member s
 }
-
index 3f48b04..3e9a881 100644 (file)
@@ -4,7 +4,8 @@
 
 import core.stdc.stdio;
 
-extern (C) int main(char** argv, int argc) {
+extern (C) int main()
+{
     printf("hello world\n");
     int[3] a;
     foo(a[], 3);
index ab0fb0a..a140ea9 100644 (file)
@@ -1,6 +1,7 @@
 import core.stdc.stdio;
 
-extern (C) int main(char** argv, int argc) {
+extern (C) int main()
+{
     printf("hello world\n");
     foo(3);
     return 0;
index 4248818..305f097 100644 (file)
@@ -145,4 +145,3 @@ bool test_eq(double x, double y) { return x == y; }
 bool test_ne(double x, double y) { return x != y; }
 bool test_ge(double x, double y) { return x >= y; }
 bool test_gt(double x, double y) { return x >  y; }
-
index 9b97037..dc3d471 100644 (file)
@@ -37,5 +37,3 @@ 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);
-
-
index 23e721d..0a27eda 100644 (file)
@@ -47,7 +47,7 @@ wchar YY;     /// ditto
  *     argulid = the argument
  *     u = the other argument
  */
-int foo(char c, int argulid, char u);
+int foo(char c, int argulid, char u = '\'', wchar v = '\u7233', dchar y = '\U00017233');
 
 int barr() { return 3; } /// doc for barr()
 
index a2cf74b..c4bd7fb 100644 (file)
@@ -22,4 +22,4 @@ $(BR)
 1__a $(BR)
 2__b
 */
-int i;
\ No newline at end of file
+int i;
index fae99d4..ed71d05 100644 (file)
@@ -92,6 +92,3 @@ pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7
 auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9
 pure nothrow:
 V mColon(lazy P p) {} /// 10
-
-
-
index 2a7e457..5a56141 100644 (file)
@@ -39,4 +39,3 @@ class StreamException: Exception {
     /********** stars ***************/
     int stars;
 }
-
index ec3b74a..4a1b075 100644 (file)
@@ -34,4 +34,3 @@ template staticIndexOf(T, TList...) { alias int staticIndexOf; }
 alias staticIndexOf IndexOf;
 
 void main() { }
-
index 3b47497..ad4c214 100644 (file)
@@ -68,4 +68,3 @@ class StreamException: Exception {
     /********** stars ***************/
     int stars;
 }
-
index 69bd64a..a229dc5 100644 (file)
@@ -22,4 +22,3 @@ void main()
 C:\code\d\bugs>dmd -D -o- 148_1.d
 148_1.d(6): Error: static if conditional cannot be at global scope
 +/
-
index 5fe37a3..cf93399 100644 (file)
@@ -10,5 +10,3 @@ enum int c6491 = 4;
 
 /// test
 void bug6491a(int a = ddoc6491.c6491, string b = core.cpuid.vendor);
-
-
index 9c28d1b..eba3680 100644 (file)
@@ -56,4 +56,3 @@ class C
     /// Some doc
     abstract void foo();
 }
-
index bcf5558..9d68631 100644 (file)
@@ -50,7 +50,6 @@ struct S final
     {
         int32_t y;
         double z;
-        extern "C" void foo();
         void bar();
     };
     struct
index 6274e9f..4f13d2b 100644 (file)
@@ -82,7 +82,9 @@ public:
     int32_t a;
     C* c;
     virtual void foo();
-    extern "C" virtual void bar();
+private:
+    virtual void __vtable_slot_0();
+public:
     virtual void baz(int32_t x = 42);
     struct
     {
@@ -116,7 +118,7 @@ public:
     {
     public:
         int32_t x;
-        A* this;
+        A* outer;
     };
 
     typedef Inner I;
@@ -146,8 +148,8 @@ public:
 
 class Parent
 {
-    virtual void __vtable_slot_0();
     virtual void __vtable_slot_1();
+    virtual void __vtable_slot_2();
 public:
     virtual void foo();
 };
index 2d48999..4d56c7c 100644 (file)
@@ -45,6 +45,9 @@ struct S final
     int32_t b;
     int64_t c;
     _d_dynamicArray< int32_t > arr;
+private:
+    ~S();
+public:
     S() :
         a(),
         b(),
@@ -81,7 +84,6 @@ struct S3 final
     int32_t a;
     int32_t b;
     int64_t c;
-    extern "C" S3(int32_t a);
     S3() :
         a(42),
         b(),
@@ -143,7 +145,6 @@ struct A final
 {
     int32_t a;
     S s;
-    extern "C" void bar();
     void baz(int32_t x = 42);
     struct
     {
@@ -232,6 +233,7 @@ extern (C++) struct S
     int b;
     long c;
     int[] arr;
+    extern(D) ~this() {}
 }
 
 extern (C++) struct S2
index f9e57f9..7356ba3 100644 (file)
@@ -39,7 +39,7 @@ struct _d_dynamicArray final
 };
 #endif
 #if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
 #endif
 
 extern "C" int32_t z;
index 91641a6..0426a5e 100644 (file)
@@ -40,7 +40,7 @@ struct _d_dynamicArray final
 };
 #endif
 #if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
 #endif
 
 class ClassFromStruct final
index 1e1b887..d687673 100644 (file)
@@ -39,7 +39,7 @@ struct _d_dynamicArray final
 };
 #endif
 #if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
 #endif
 
 class WithImaginary
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d
new file mode 100644 (file)
index 0000000..44d0dd5
--- /dev/null
@@ -0,0 +1,118 @@
+/++
+REQUIRED_ARGS: -HC=verbose
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+    size_t length;
+    T *ptr;
+
+    _d_dynamicArray() : length(0), ptr(NULL) { }
+
+    _d_dynamicArray(size_t length_in, T *ptr_in)
+        : length(length_in), ptr(ptr_in) { }
+
+    T& operator[](const size_t idx) {
+        assert(idx < length);
+        return ptr[idx];
+    }
+
+    const T& operator[](const size_t idx) const {
+        assert(idx < length);
+        return ptr[idx];
+    }
+};
+#endif
+
+extern "C" int32_t freeC();
+
+// Ignored function dtoh_mangling.bar because C++ doesn't support explicit mangling
+struct Data final
+{
+    // Ignored function dtoh_mangling.Data.foo because of linkage
+    // Ignored function dtoh_mangling.Data.bar because C++ doesn't support explicit mangling
+    Data()
+    {
+    }
+};
+
+extern void accept(Data data);
+
+extern "C" void hasDefault(int32_t i = freeC());
+
+extern "C" void hasDefaultMember(int32_t i = memberC());
+
+extern "C" int32_t someVarC;
+
+// Ignored variable dtoh_mangling.var2 because C++ doesn't support explicit mangling
+struct HasMangleMember final
+{
+    int32_t someAttrC;
+    int32_t someAttrCpp;
+    void hasDefaultVar(int32_t i = someAttrC);
+    HasMangleMember()
+    {
+    }
+};
+
+extern "C" void hasDefaultVar(int32_t i = someVarC);
+---
+++/
+
+extern(C):
+
+pragma(mangle, "freeC")
+int foo() { return 0; }
+
+pragma(mangle, "freeCpp")
+extern (C++) void bar() {}
+
+pragma(mangle, "Aggregate")
+struct Data
+{
+    pragma(mangle, "memberC")
+    static int foo() { return 0; }
+
+    pragma(mangle, "memberCpp")
+    extern (C++) void bar() {}
+}
+
+extern(C++)
+void accept(Data data) {}
+
+void hasDefault(int i = foo()) {}
+
+void hasDefaultMember(int i = Data.foo()) {}
+
+pragma(mangle, "someVarC")
+__gshared int var;
+
+pragma(mangle, "someVarCpp")
+extern(C++) __gshared int var2;
+
+struct HasMangleMember
+{
+    pragma(mangle, "someAttrC")
+    int var;
+
+    pragma(mangle, "someAttrCpp")
+    extern(C++) int var2;
+
+    extern(C++) void hasDefaultVar(int i = var) {}
+}
+
+void hasDefaultVar(int i = var) {}
index 01cf889..3c2e90a 100644 (file)
@@ -577,7 +577,8 @@ struct SafeS
 
     ref SafeS foo3() return scope
     {
-        return this;
+        static SafeS s;
+        return s;
     }
 
     int* p;
index c6876d1..1d49be6 100644 (file)
@@ -23,4 +23,3 @@ void main()
     TypeTuple!(int, long) T;
     printf( "%u\n", cast(uint)IndexOf!(long, T) );
 }
-
index db82252..76730ed 100644 (file)
@@ -42,4 +42,3 @@ void main()
 {
        alias aaa = DOMImplementation!string;
 }
-
index c1e1c48..58f1440 100644 (file)
@@ -35,4 +35,3 @@ pragma(msg, V);
 struct G {}
 struct F(T) { void f(ref T) {} }
 pragma(msg, F!G().f(G.init));
-
index 4090c5e..36baef5 100644 (file)
@@ -20,6 +20,33 @@ int echoPlusOne(int x)
     return x;
 }
 static assert(echoPlusOne(1) == 2);
+
+void nesting(double d, int i)
+{
+    alias EXP = AliasSeq!(d, i);
+
+    if (d)
+    {
+        static assert(__traits(isSame, __traits(parameters), EXP));
+
+        while (d)
+        {
+            static assert(__traits(isSame, __traits(parameters), EXP));
+            switch (i)
+            {
+                static assert(__traits(isSame, __traits(parameters), EXP));
+                case 1:
+                    static assert(__traits(isSame, __traits(parameters), EXP));
+                    break;
+
+                default:
+                    static assert(__traits(isSame, __traits(parameters), EXP));
+                    break;
+            }
+        }
+    }
+}
+
 class Tree {
     int opApply(int delegate(size_t, Tree) dg) {
         if (dg(0, this)) return 1;
@@ -34,7 +61,22 @@ void useOpApply(Tree top, int x)
     }
     foreach(idx, elem; top)
     {
-        static assert(is(typeof(__traits(parameters)) == AliasSeq!(size_t, Tree)));
+        static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
+    }
+
+    foreach(idx, elem; top)
+    {
+        foreach (idx2, elem2; elem)
+            static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
+    }
+
+    foreach(idx, elem; top)
+    {
+        static void foo(char[] text)
+        {
+            foreach (const char c; text)
+                static assert(is(typeof(__traits(parameters)) == AliasSeq!(char[])));
+        }
     }
 }
 class Test
@@ -132,3 +174,64 @@ T testTemplate(T)(scope T input)
 
 static assert(testTemplate!long(420) == 0);
 
+void qualifiers(immutable int a, const bool b)
+{
+    static assert(is(typeof(__traits(parameters)) == AliasSeq!(immutable int, const bool)));
+}
+
+int makeAggregate(int a, bool b)
+{
+    struct S
+    {
+        typeof(__traits(parameters)) members;
+    }
+
+    S s = S(__traits(parameters));
+    assert(s.members[0] == a);
+    assert(s.members[1] == b);
+    return 1;
+}
+
+static assert(makeAggregate(5, true));
+
+int makeAlias(int a, bool b)
+{
+    alias Params = __traits(parameters);
+    assert(Params[0] == 3);
+    assert(Params[1] == true);
+    return 1;
+}
+
+static assert(makeAlias(3, true));
+
+
+mixin template nestedCheckParameters(int unique)
+{
+    alias NestedNames = __traits(parameters);
+    version (Fixed)
+    alias Types = typeof(Names);
+}
+
+mixin template checkParameters(int unique)
+{
+    mixin nestedCheckParameters!unique;
+
+    alias Names = __traits(parameters);
+    alias Types = typeof(Names);
+}
+
+int makeAggregateMixin(immutable int a, const bool b)
+{
+    mixin checkParameters!0;
+
+    struct S
+    {
+        mixin checkParameters!1;
+        typeof(Names) members;
+    }
+
+    S s = S(Names);
+    assert(s.members[0] == a);
+    assert(s.members[1] == b);
+    return 1;
+}
index ff2be37..5deef96 100644 (file)
@@ -7,4 +7,3 @@ void front(T)(T[] a)
 {
     static assert(is(T == void));
 }
-
index bd8fd0c..dc5f094 100644 (file)
@@ -23,6 +23,3 @@ template find()
         return find_!(char).fn( buf );
     }
 }
-
-
-
index 920f0ec..d41f123 100644 (file)
@@ -5,4 +5,3 @@ S test2();
 
 static assert(__traits(isReturnOnStack, test1) == false);
 static assert(__traits(isReturnOnStack, test2) == true);
-
index ad24e7f..7bc16c8 100644 (file)
@@ -52,4 +52,3 @@ void test15478_3()
     enum foo_bug = foo.bug;
     Foo15478!int[foo_bug] baz; // OK
 }
-
index 0af986b..cdc9077 100644 (file)
@@ -10,4 +10,3 @@ struct Target
     OS os = defaultTargetOS();
     @property isPOSIX() scope @nogc { }
 }
-
index f79639d..73d3101 100644 (file)
@@ -191,7 +191,7 @@ struct SafeS
 
     ref SafeS foo3() return scope
     {
-        return this;
+        static SafeS s; return s;
     }
 
        int* p;
index 14e1789..419447d 100644 (file)
@@ -26,5 +26,3 @@ static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d");
 static assert(__LINE__ == 201);
 static assert(__FILE__ == "newfile.d");
 static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d");
-
-
index abbf85a..a53805b 100644 (file)
@@ -52,4 +52,3 @@ void test4()
     enum getStuff = q{ __traits(getMember,sb,"fieldb") };
     auto b = Foo4!(mixin(getStuff));
 }
-
index b476c17..d99c69b 100644 (file)
@@ -5,4 +5,3 @@
     static assert(Fun.stringof == "void function() @safe");
     alias Del = void delegate() @safe;
     static assert(Del.stringof == "void delegate() @safe");
-
index 58cb617..e4451b8 100644 (file)
@@ -123,4 +123,3 @@ void bindFunc() {ssllib.getSymbol();}
     bindFunc();
     bindFunc(); /* 100 */
 }
-
index 41444ce..d676d61 100644 (file)
@@ -72,4 +72,3 @@ struct Vector(T, int N)
             assert(false);
     }
 }
-
index 81dd76a..78cb420 100644 (file)
@@ -7,4 +7,3 @@ void f()
     j = 0; // works as expected
     k = 0; // Error: variable foo.ns.k is private
 }
-
index 0fb0293..0271c0f 100644 (file)
@@ -10,4 +10,3 @@ void main() @safe {
        auto d = cast(const(ubyte)[]) c;
        auto e = cast(const(Windows1252Char)[]) c;
 }
-
index 01c325e..8649efa 100644 (file)
@@ -24,4 +24,3 @@ void mulKaratsuba(int[] result, const(int)[] x, const(int)[] y, int[] )
 
     addAssignSimple(resultHigh[1..$], newscratchbuff[0..y1.length]);
 }
-
index fe0f128..5d5d4da 100644 (file)
@@ -11,4 +11,3 @@ it's a dessert topping
 
 import its.a.floorwax.wax16798;
 import its.a.dessert.topping;
-
index 677fe38..0e615c8 100644 (file)
@@ -9,4 +9,3 @@ void main()
 {
     static assert([__traits(allMembers, LeClass)] == ["toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]);
 }
-
index e5075fb..8188422 100644 (file)
@@ -16,4 +16,3 @@ static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe");
 
 static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe");
 static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg");
-
index d599920..6a7a36a 100644 (file)
@@ -5,4 +5,4 @@ void bug(T)(T t)
     t.opCmp(t);
 }
 
-alias bugi = bug!(typeof(new class{}));
\ No newline at end of file
+alias bugi = bug!(typeof(new class{}));
index e447cc2..2007c83 100644 (file)
@@ -8,4 +8,3 @@ struct S {
 struct tmp(alias fns) {
     alias fun = fns!int;
 }
-
index 206d662..4cbe6b8 100644 (file)
@@ -24,4 +24,3 @@ void test()
     static assert(!hasPopBack!Bar);
     static assert( hasPopBack!Foo && !hasPopBack!Bar);
 }
-
index 27dab9e..6ff5349 100644 (file)
@@ -26,4 +26,3 @@ void main()
     static assert(T.init is T.init);
     static assert(T.init != T.init);
 }
-
index cd059c9..4d7854e 100644 (file)
@@ -27,5 +27,3 @@ void test3032() @nogc
     scope fp = (){ n = 10; };       // no closure
     fp();
 }
-
-
diff --git a/gcc/testsuite/gdc.test/compilable/test20717.d b/gcc/testsuite/gdc.test/compilable/test20717.d
new file mode 100644 (file)
index 0000000..d45801e
--- /dev/null
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=20717
+
+/*
+TEST_OUTPUT:
+---
+false
+---
+*/
+
+pragma(msg, is(typeof({
+    struct S
+    {
+        struct Foo {}
+        struct Bar() {}
+        alias Bar = Foo;
+    }
+})));
index 86ffeda..e542631 100644 (file)
@@ -12,4 +12,3 @@ int test12()
     int d = !x ? 1 : 1 / x;
     return a | b | c;
 }
-
diff --git a/gcc/testsuite/gdc.test/compilable/test22639.d b/gcc/testsuite/gdc.test/compilable/test22639.d
new file mode 100644 (file)
index 0000000..a889aa9
--- /dev/null
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=22639
+
+struct A
+{
+    this(ref return scope A rhs) inout {}
+    this(ref return scope const A rhs, int b = 7) inout
+    {
+        if (b != 7) {
+            this.b = b;
+        }
+    }
+
+    this(this) @disable;
+
+    int a=4;
+    int b=3;
+}
+
+void main()
+{
+    A a = A();
+    A c = A(a, 10);
+    A d = void;
+    d.__ctor(a, 200);
+    A* b = new A(a, 10);
+}
index 9d55dbb..4da6fd1 100644 (file)
@@ -18,5 +18,3 @@ E foo3(E e)
 {
     return E.A; // with qualification, it is an enum
 }
-
-
diff --git a/gcc/testsuite/gdc.test/compilable/test22825.d b/gcc/testsuite/gdc.test/compilable/test22825.d
new file mode 100644 (file)
index 0000000..7820eae
--- /dev/null
@@ -0,0 +1,4 @@
+// https://issues.dlang.org/show_bug.cgi?id=22825
+#line /*
+         multi-line comment
+*/ 42
diff --git a/gcc/testsuite/gdc.test/compilable/test22859.d b/gcc/testsuite/gdc.test/compilable/test22859.d
new file mode 100644 (file)
index 0000000..b5b318c
--- /dev/null
@@ -0,0 +1,40 @@
+// https://issues.dlang.org/show_bug.cgi?id=22859
+private struct __InoutWorkaroundStruct {}
+@property T rvalueOf(T)(T val) { return val; }
+@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
+@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
+
+// taken from std.traits.isAssignable
+template isAssignable(Lhs, Rhs = Lhs)
+{
+    enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);
+}
+
+// taken from std.meta.allSatisfy
+template allSatisfy(alias F, T...)
+{
+    static foreach (Ti; T)
+    {
+        static if (!is(typeof(allSatisfy) == bool) && // not yet defined
+                   !F!(Ti))
+        {
+            enum allSatisfy = false;
+        }
+    }
+    static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
+    {
+        enum allSatisfy = true;
+    }
+}
+
+struct None{}
+
+class C1
+{
+    static if(allSatisfy!(isAssignable, None, C2)) {}
+}
+
+class C2
+{
+    static if(allSatisfy!(isAssignable, None, C1, C2)) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22860.d b/gcc/testsuite/gdc.test/compilable/test22860.d
new file mode 100644 (file)
index 0000000..543dd88
--- /dev/null
@@ -0,0 +1,62 @@
+// https://issues.dlang.org/show_bug.cgi?id=22860
+class C1
+{
+    SumType!(C1, C2) field;
+}
+
+class C2
+{
+    SumType!(SumType!(C1, C2)) field;
+}
+
+alias AliasSeq(TList...) = TList;
+
+template allSatisfy(alias F, T...)
+{
+    static foreach (Ti; T)
+    {
+        static if (!F!Ti)
+            enum allSatisfy = false;
+    }
+}
+
+struct This {}
+
+enum isAssignableTo(T) = isAssignable!T;
+enum isHashable(T) = __traits(compiles, { T.init; });
+
+struct SumType(Types...)
+{
+    alias Types = AliasSeq!(ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType));
+
+    static foreach (T; Types)
+    {
+        static if (isAssignableTo!T)
+        {
+        }
+    }
+
+    static if (allSatisfy!(isAssignableTo, Types))
+    {
+    }
+
+    static if (allSatisfy!(isHashable, Types))
+        size_t toHash;
+}
+
+bool isSumTypeInstance;
+
+alias TemplateArgsOf(T : Base!Args, alias Base, Args...) = Args;
+enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) ;
+enum isRvalueAssignable(Lhs, Rhs ) = __traits(compiles, { lvalueOf!Lhs = Rhs; });
+
+struct __InoutWorkaroundStruct{}
+T lvalueOf(T)(__InoutWorkaroundStruct );
+
+template ReplaceTypeUnless(alias pred, From, To, T...)
+{
+    static if (T.length == 1)
+        alias ReplaceTypeUnless = T;
+    static if (T.length > 1)
+        alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[1 ]));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22919.d b/gcc/testsuite/gdc.test/compilable/test22919.d
new file mode 100644 (file)
index 0000000..8844ed0
--- /dev/null
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -checkaction=context -preview=dip1000
+
+// Issue 22919 - [dip1000] -checkaction=context gives "assigned to `__assertOp2` with longer lifetime" (
+// https://issues.dlang.org/show_bug.cgi?id=22919
+
+@safe:
+struct S
+{
+    int* p;
+    ref S get() scope return {return this;}
+}
+
+void main()
+{
+    scope S arr = S();
+    assert(arr == arr.get());
+}
index a34b329..da05dc5 100644 (file)
@@ -5,5 +5,3 @@ struct Bug3775 {
 }
 
 static assert(cast(int)Bug3775.byLine == 1);
-
-
index a5dfac0..356b353 100644 (file)
@@ -6,5 +6,3 @@ import imports.test50a;
 class Bar : Foo {
         alias typeof(Foo.tupleof) Bleh;
 }
-
-
index b713191..befb947 100644 (file)
@@ -128,5 +128,3 @@ 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);
-
-
index dba0741..8961ba1 100644 (file)
@@ -3,4 +3,3 @@ 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;})));
-
index cd175b5..d29c9ed 100644 (file)
@@ -30,4 +30,4 @@ class Foo
 void main(string[] args)
 {
   auto foo = new Foo();
-}
\ No newline at end of file
+}
index 007f9b6..408c6e9 100644 (file)
@@ -7,4 +7,3 @@ void test()
     enum x = __traits(parent, imports.bug8922).stringof;
     static assert(x == "package imports");
 }
-
index 4898cf6..87ec51a 100644 (file)
@@ -8,4 +8,3 @@ void test()
     enum x = __traits(parent, imports.bug8922).stringof;
     static assert(x == "package imports");
 }
-
index 3594a04..ca2acb6 100644 (file)
@@ -16,5 +16,3 @@ void test9507_2() {
     import imp9057_2;
     Bug9057!(BugInt) xxx;
 }
-
-
index 5b650bd..2b3f8dc 100644 (file)
@@ -1,4 +1,3 @@
 // EXTRA_SOURCES: imports/test9436interp.d
 // EXTRA_FILES: imports/test9436aggr.d imports/test9436node.d imports/test9436type.d
 // this is a dummy module for test 9436.
-
index 2f7beeb..6b0f775 100644 (file)
@@ -20,4 +20,3 @@ void main() {
                 "lala", "lala", "lala", "lala");
 
 }
-
index b2292bf..a0aa052 100644 (file)
@@ -11,4 +11,3 @@ class Tiger : Panzer {}
 static assert (() {
     Panzer p = new Tiger(); return classname(p);
 } () == "Tiger");
-
index 00c5c80..86d06cb 100644 (file)
@@ -20,4 +20,4 @@ version (D_TypeInfo)
 else
 {
     static assert(0);
-}
\ No newline at end of file
+}
index 8ba5717..487f22e 100644 (file)
@@ -8,4 +8,3 @@ fail_compilation/bug5b.d(8): Error: function `bug5b.test1` has no `return` state
 int test1()
 {
 }
-
index 76a7764..176295f 100644 (file)
@@ -9,4 +9,3 @@ fail_compilation/circ10280.d(10):        called from here: `foo10280()`
 
 const int q10280 = foo10280();
 int foo10280() { return q10280; }
-
index 2ce3795..553a0c6 100644 (file)
@@ -7,4 +7,3 @@ fail_compilation/dephexstrings.d(9): Error: declaration expected, not `"60"`
 ---
 */
 enum xstr = x"60";
-
index 4e803be..4f8ea23 100644 (file)
@@ -3,8 +3,8 @@ REQUIRED_ARGS: -de
 TEST_OUTPUT:
 ---
 fail_compilation/dip25.d(17): Deprecation: returning `this.buffer[]` escapes a reference to parameter `this`
-fail_compilation/dip25.d(17):        perhaps annotate the function with `return`
-fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to local variable `x`
+fail_compilation/dip25.d(15):        perhaps annotate the function with `return`
+fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to parameter `x`
 fail_compilation/dip25.d(23): Deprecation: returning `identity(x)` escapes a reference to parameter `x`
 fail_compilation/dip25.d(23):        perhaps annotate the parameter with `return`
 ---
index 263570a..3df797d 100644 (file)
@@ -1,8 +1,15 @@
 /*
 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`
+fail_compilation/fail118.d(43): Error: invalid `foreach` aggregate `Iter` of type `Iter`
+fail_compilation/fail118.d(43):        maybe define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(44): Error: invalid `foreach` aggregate `Iter` of type `Iter`
+fail_compilation/fail118.d(44):        maybe define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(47): Error: invalid `foreach` aggregate `s` of type `S*`
+fail_compilation/fail118.d(49): Error: undefined identifier `unknown`
+fail_compilation/fail118.d(37): Error: undefined identifier `doesNotExist`
+fail_compilation/fail118.d(51): Error: template instance `fail118.error!()` error instantiating
+fail_compilation/fail118.d(51): Error: invalid `foreach` aggregate `error()` of type `void`
 ---
 */
 
@@ -20,9 +27,26 @@ class Foo
     mixin opHackedApply!() oldIterMix;
 }
 
+struct S
+{
+    int opApply(scope int delegate(const int) dg);
+}
+
+auto error()()
+{
+    doesNotExist();
+}
+
 void main()
 {
     Foo f = new Foo;
     foreach (int i; f.oldIterMix.Iter) {}
     foreach (    i; f.oldIterMix.Iter) {}
+
+    S* s;
+    foreach (const i; s) {}
+
+    foreach(const i; unknown) {}
+
+    foreach (const i; error()) {}
 }
index 15b6dc9..78176e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail131.d(8): Error: function `D main` parameters must be `main()` or `main(string[] args)`
+fail_compilation/fail131.d(8): Error: function `D main` parameter list must be empty or accept one parameter of type `string[]`
 ---
 */
 
index 5e3b637..12a6b6e 100644 (file)
@@ -54,14 +54,14 @@ int* testEscape1()
 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 local variable `x`
-fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2`
-fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to local variable `y`
+fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2`
+fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y`
 ---
 */
 int* testEscape2(
@@ -134,9 +134,9 @@ int* testEscape3(
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to parameter `sa1`
 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`
@@ -223,14 +223,14 @@ ref int testEscapeRef1()
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to local variable `sa2`
-fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to local variable `s1`
+fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to parameter `sa2`
+fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to parameter `s1`
 ---
 */
 ref int testEscapeRef2(
@@ -324,8 +324,8 @@ int[] testSlice2() { int[3] sa; int n; return sa[n..2][1..2]; }
 TEST_OUTPUT:
 ---
 fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`
-fail_compilation/fail13902.d(324):        perhaps annotate the parameter with `return`
 ---
+
 */
 ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; }
 @safe int[]   testDynamicArrayVariadic2(int[] vda...) { return vda[]; }
@@ -334,7 +334,7 @@ int[3]  testDynamicArrayVariadic3(int[] vda...) { return vda[0..3]; }   // no er
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to local variable `vsa`
+fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to parameter `vsa`
 fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa`
 ---
 */
index c7a2b89..3531245 100644 (file)
@@ -3,18 +3,30 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail14486.d(35): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(36): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(41): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(42): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(47): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(48): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(53): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(54): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(59): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(60): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(65): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(66): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(47): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(47):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(48): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(48):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(53): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(53):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(54): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(54):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(59): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(59):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(60): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(60):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(65): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(65):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(66): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(66):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(71): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(71):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(72): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(72):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(77): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(77):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(78): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(78):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
 */
 
index ef5fc7b..dc480cf 100644 (file)
@@ -10,4 +10,3 @@ void main() {
        auto fail = () => {};
        auto ok = () => () {};
 }
-
index 82d4160..97ee362 100644 (file)
@@ -9,4 +9,3 @@ fail_compilation/fail17419.d(11): Error: expected 1 arguments for `getLinkage` b
 
 enum s = __traits(getLinkage, 8 * 8);
 enum t = __traits(getLinkage, 8, 8);
-
index c308ad5..f181937 100644 (file)
@@ -13,4 +13,3 @@ alias int* x;
 
 static assert(__traits(getFunctionVariadicStyle, 1) == "none");
 static assert(__traits(getFunctionVariadicStyle, x) == "none");
-
index ef66858..734f8d7 100644 (file)
@@ -25,5 +25,3 @@ Object testobj(scope Object obj) @safe
     array ~= arr;
     return array[0];
 }
-
-
index 689dd48..41f7465 100644 (file)
@@ -1,7 +1,8 @@
 // REQUIRED_ARGS: -de
 /* TEST_OUTPUT:
 ---
-fail_compilation/fail17906.d(11): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail17906.d(12): Error: the `delete` keyword is obsolete
+fail_compilation/fail17906.d(12):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=18647
index 5f371da..410f307 100644 (file)
@@ -11,8 +11,8 @@ fail_compilation/fail17927.d(23): Error: scope variable `ptr` may not be returne
 
 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`
+    // https://issues.dlang.org/show_bug.cgi?id=22027
+    inout(char)* mem2() inout scope @safe { return ptr; }
 
     char* ptr;
 }
@@ -21,4 +21,3 @@ struct String {
 const(char)* foo1(scope const(char)* ptr) @safe { return ptr; }
 
 inout(char)* foo2(scope inout(char)* ptr) @safe { return ptr; }
-
index 9115b4e..abc4fea 100644 (file)
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail19744.d(8): Error: Top-level function `test` has no `this` to which `return` can apply
+fail_compilation/fail19744.d(8): Error: top-level function `test` has no `this` to which `return` can apply
 ---
 */
 
index f4aa848..ccdbb57 100644 (file)
@@ -10,4 +10,3 @@ void f (__vector(int[4]) n)
     foreach (i; 0 .. n)
         cast(void)n;
 }
-
index 82d92eb..254c2ca 100644 (file)
@@ -17,4 +17,3 @@ void f (__vector(int[4]) n, S m)
     foreach (i; m .. n)
         cast(void)n;
 }
-
index dcc73a9..22f6433 100644 (file)
@@ -1,7 +1,7 @@
 /* REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
-fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to local variable `v`
+fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to parameter `v`
 ---
 */
 
index 6ef3a4a..916ee8b 100644 (file)
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail20448.d(16): Error: returning `p.x` escapes a reference to local variable `p`
+fail_compilation/fail20448.d(16): Error: returning `p.x` escapes a reference to parameter `p`
 fail_compilation/fail20448.d(22): Error: template instance `fail20448.member!"x"` error instantiating
 ---
 */
index 63ed0a0..11ad76f 100644 (file)
@@ -22,4 +22,3 @@ main()
     auto m2 = new immutable(Message)(2);
     m2.notifier = 3;
   }
-
index 6f34029..687a727 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail21868b.d(19): Error: returning `&s.x` escapes a reference to parameter `s`
-fail_compilation/fail21868b.d(19):        perhaps remove `scope` parameter annotation so `return` applies to `ref`
+fail_compilation/fail21868b.d(17):        perhaps change the `return scope` into `scope return`
 ---
 */
 
@@ -18,5 +18,3 @@ int* test(ref return scope S s)
 {
     return &s.x;
 }
-
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22825a.d b/gcc/testsuite/gdc.test/fail_compilation/fail22825a.d
new file mode 100644 (file)
index 0000000..d8d1093
--- /dev/null
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22825
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22825a.d(10): Error: positive integer argument expected following `#line`
+fail_compilation/fail22825a.d(11): Error: declaration expected, not `42`
+---
+*/
+#line /*
+         multi-line comment
+*/
+42
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22825b.d b/gcc/testsuite/gdc.test/fail_compilation/fail22825b.d
new file mode 100644 (file)
index 0000000..faac8b4
--- /dev/null
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=22825
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22825b.d(7): Error: declaration expected, not `#`
+---
+*/
+#
+                 line
+
+
+
+
+12
index 57edd3a..ffc12f1 100644 (file)
@@ -1,7 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail2361.d(13): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail2361.d(14): Error: the `delete` keyword is obsolete
+fail_compilation/fail2361.d(14):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
 */
 
index 82b291f..a0d1940 100644 (file)
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()`
+fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()` of type `void`
 ---
 */
 
index 73e062c..85da957 100644 (file)
@@ -1,7 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail261.d(18): Error: invalid `foreach` aggregate `range`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail261.d(19): Error: invalid `foreach` aggregate `range` of type `MyRange`
+fail_compilation/fail261.d(19):        maybe define `opApply()`, range primitives, or use `.tupleof`
 ---
 */
 
index c6a23ad..71e9143 100644 (file)
@@ -1,10 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail359.d(8): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail359.d(9): Error: no identifier for declarator `_BOOM`
+fail_compilation/fail359.d(7): Error: invalid filename for `#line` directive
 ---
 */
 #line 5 _BOOM
 void main() { }
-
index 3111623..28dc991 100644 (file)
@@ -17,4 +17,3 @@ static if (true)
                     void G10(){}
 else
     void G11(){}
-
index 8540249..38c4b00 100644 (file)
@@ -10,4 +10,3 @@ template populate(overloads...)
     mixin populate!(.contents);
 }
 public mixin populate!int;
-
index 220c995..f13ba14 100644 (file)
@@ -9,4 +9,3 @@ struct S7424c
     @property int g()() { return 0; }
     void test() immutable { int f = g; }
 }
-
index 669c9ff..38f47ba 100644 (file)
@@ -9,4 +9,3 @@ struct S7424d
     @property int g()() immutable { return 0; }
     void test() const { int f = g; }
 }
-
index 18bf414..e92b469 100644 (file)
@@ -9,4 +9,3 @@ struct S7424e
     @property int g()() immutable { return 0; }
     void test() { int f = g; }
 }
-
index 29e0ecc..1af14f8 100644 (file)
@@ -9,4 +9,3 @@ struct S7424f
     @property int g()() shared { return 0; }
     void test() { int f = g; }
 }
-
index b4670de..4499b97 100644 (file)
@@ -9,4 +9,3 @@ struct S7424g
     @property int g()() { return 0; }
     void test() shared { int f = g; }
 }
-
index b76f5b3..e48408c 100644 (file)
@@ -9,4 +9,3 @@ struct S7424g
     @property int g()() { return 0; }
     void test() inout { int f = g; }
 }
-
index 887c859..6352166 100644 (file)
@@ -9,4 +9,3 @@ struct S7424g
     @property int g()() immutable { return 0; }
     void test() inout { int f = g; }
 }
-
index 834c315..237b313 100644 (file)
@@ -2,8 +2,7 @@
 REQUIRED_ARGS: -o-
 TEST_OUTPUT:
 ----
-fail_compilation/fail7524a.d(10): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail7524a.d(10): Error: declaration expected, not `"$r:\w+ +\d+ \d+$"`
+fail_compilation/fail7524a.d(9): Error: invalid filename for `#line` directive
 ----
 */
 
index f462746..feee61b 100644 (file)
@@ -2,8 +2,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7524b.d(10): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail7524b.d(10): Error: declaration expected, not `$n$L`
+fail_compilation/fail7524b.d(9): Error: invalid filename for `#line` directive
 ---
 */
 
index 687b0ad..2d291fc 100644 (file)
@@ -11,4 +11,3 @@ void test()
     ub[] = cast(ubyte[4]) &i;
     //ub[] = (cast(ubyte*) &i)[0..4];
 }
-
index 1fb2424..99572c4 100644 (file)
@@ -7,4 +7,3 @@ fail_compilation/fail78.d(9): Error: undefined identifier `inch`
 
 auto yd = ft * 3;
 auto ft = inch * 12;
-
index 235e480..96489d9 100644 (file)
@@ -7,4 +7,3 @@ fail_compilation/fail8009.d(8):        Candidate is: `filter(R)(scope bool deleg
 */
 void filter(R)(scope bool delegate(ref BAD!R) func) { }
 void main() { filter(r => r); }
-
index 2fb478d..6f6337d 100644 (file)
@@ -20,4 +20,3 @@ template fun2(a...) { auto fun2(T...)(T args){ return 1; } }
 
 enum x1 = fun1(0);
 enum x2 = fun2(0);
-
index 2a5cd01..6f181ed 100644 (file)
@@ -37,4 +37,3 @@ class C
     static void fsc() shared const {}
     static void fsw() shared inout {}
 }
-
index 8e34199..ba4655e 100644 (file)
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t`
+fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t` of type `typeof(null)`
 fail_compilation/fail92.d(23): Error: template instance `fail92.crash!(typeof(null))` error instantiating
 ---
 */
index abfe914..3d1b07e 100644 (file)
@@ -148,4 +148,3 @@ struct S4
         static assert(__traits(compiles, v = 1)); // multiple initialization
     }
 }
-
index 42dbfdc..631468b 100644 (file)
@@ -9,4 +9,3 @@ fail_compilation/fail9735.d(10): Deprecation: casting from void delegate() to vo
 void* dg2ptr(void delegate() dg) {
     return cast(void*) dg;
 }
-
index 7087b0c..e76a779 100644 (file)
@@ -209,7 +209,8 @@ fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'`
 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): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete
+fail_compilation/fail_arrayop2.d(281):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 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
@@ -234,7 +235,6 @@ fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without
 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()
 {
index 0a29997..ed640fb 100644 (file)
@@ -1,7 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/faildeleteaa.d(11): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/faildeleteaa.d(12): Error: the `delete` keyword is obsolete
+fail_compilation/faildeleteaa.d(12):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
 */
 
index 7b8f287..49c0707 100644 (file)
@@ -1,10 +1,10 @@
 /* REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
-fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to local variable `t`
+fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to parameter `t`
 ---
 */
 
@@ -38,4 +38,3 @@ auto h(S s) {
 auto j(S s, S t) {
     return s.ghi(t);
 }
-
index 48c74cb..7000f39 100644 (file)
@@ -16,4 +16,3 @@ alias T1 = Type!(__traits(toType));
 alias T2 = Type!(__traits(toType, int));
 alias T3 = Type!(__traits(toType, 1));
 alias T4 = Type!(__traits(toType, "hello betty"));
-
index 1f23122..9dfcc4d 100644 (file)
@@ -17,6 +17,7 @@ fail_compilation/fob1.d(104): Error: variable `fob1.foo1.p` is returned but is U
 
 /* TEST_OUTPUT:
 ---
+fail_compilation/fob1.d(204): Error: variable `fob1.foo2.p` assigning to Owner without disposing of owned value
 fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at return
 ---
 */
index 175ade3..6f100ee 100644 (file)
@@ -176,3 +176,20 @@ void free7(int*);
     free7(p);
 }
 
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(807): Error: variable `fob2.test8.p` assigning to Owner without disposing of owned value
+---
+*/
+
+#line 800
+
+int* malloc8();
+void free8(int*);
+
+@live void test8()
+{
+    int* p = malloc8();
+    p = malloc8();  // error here
+    free8(p);
+}
index 3a24227..bc40d9a 100644 (file)
@@ -41,4 +41,3 @@ pragma(printf) extern (C) int vprintf4(const(char)*, int, va_list);
 pragma(printf) extern (C) int vprintf5(const(char)*, va_list);
 pragma(printf) extern (C) int vprintf6(immutable(char)*, va_list);
 pragma(printf) extern (C) int vprintf7(char*, va_list);
-
index 6d3b223..ebefe33 100644 (file)
@@ -4,8 +4,6 @@
 TEST_OUTPUT:
 ---
 fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop`
-fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating
-fail_compilation/imports/foo10727a.d(31):        instantiated from here: `Bar!(Foo)`
 ---
 */
 
index 4a59d5c..125ac12 100644 (file)
@@ -4,8 +4,6 @@
 TEST_OUTPUT:
 ---
 fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop`
-fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating
-fail_compilation/imports/foo10727b.d(22):        instantiated from here: `Bar!(Foo)`
 ---
 */
 
index ea44eae..1d50b66 100644 (file)
@@ -1,7 +1,8 @@
 /*
 TEST_OUTPUT:
 ----
-fail_compilation/ice11968.d(8): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/ice11968.d(9): Error: the `delete` keyword is obsolete
+fail_compilation/ice11968.d(9):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ----
 */
 
index 6b8f2f3..d7086b4 100644 (file)
@@ -6,7 +6,7 @@ fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression i
 fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254a.d(15): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254a.d(15): Error: invalid `foreach` aggregate `false` of type `bool`
 ---
 */
 
index a430fbf..5484abd 100644 (file)
@@ -6,7 +6,7 @@ fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression i
 fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254b.d(17): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254b.d(17): Error: invalid `foreach` aggregate `false` of type `bool`
 ---
 */
 
index b58cfe5..23eeecc 100644 (file)
@@ -6,7 +6,7 @@ fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression i
 fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
 fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254c.d(15): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254c.d(15): Error: invalid `foreach` aggregate `false` of type `bool`
 ---
 */
 
index 8d2e1db..a12ef10 100644 (file)
@@ -3,4 +3,3 @@ private enum { b = "asdfgh" }
 
 struct S { private enum string c = "qwerty"; }
 class  C { private enum string d = "qwerty"; }
-
index c9a7682..1270584 100644 (file)
@@ -47,5 +47,3 @@ private struct FilterResult(alias pred, Range)
         return _input[0];
     }
 }
-
-
index d2b6cb9..2ab5a12 100644 (file)
@@ -4,4 +4,4 @@ struct SomeThing(T...)
 {
 }
 
-class SomeClass {}
\ No newline at end of file
+class SomeClass {}
index 72ebce7..915aade 100644 (file)
@@ -52,4 +52,3 @@ void put(R, E)(ref R r, E e)
                 "Cannot put a "~E.stringof~" into a "~R.stringof);
     }
 }
-
index ee1802a..eb49d23 100644 (file)
@@ -1,7 +1,6 @@
 /* TEST_OUTPUT:
 ---
-fail_compilation/issue22826.d(7): Error: #line integer ["filespec"]\n expected
-fail_compilation/issue22826.d(7): Error: declaration expected, not `3`
+fail_compilation/issue22826.d(6): Error: found `3` when expecting new line following `#line` directive
 ---
 */
 #line 12 "issue22826.d" 3
index 115f136..e6cabf2 100644 (file)
@@ -11,8 +11,8 @@ 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 `' '`
-fail_compilation/lexer1.d(39): Error: declaration expected, not `55295U`
-fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U`
+fail_compilation/lexer1.d(39): Error: declaration expected, not `'\ud7ff'`
+fail_compilation/lexer1.d(40): Error: declaration expected, not `'\U00010000'`
 fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a\0ab"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
index ecc7208..c9db264 100644 (file)
@@ -13,12 +13,12 @@ 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"`
+fail_compilation/lexer4.d(36): Error: positive integer argument expected following `#line`
+fail_compilation/lexer4.d(19): Error: found `"file"` when expecting new line following `#line` directive
 ---
 */
 
+
 static c1 = '
 ;
 static c2 = '';
index 415e719..69e148f 100644 (file)
@@ -39,4 +39,3 @@ __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;
-
index 8f18ec5..859bd40 100644 (file)
@@ -63,9 +63,12 @@ fail_compilation/nogc1.d(55): Error: cannot use `new` in `@nogc` function `nogc1
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/nogc1.d(73): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/nogc1.d(74): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/nogc1.d(75): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/nogc1.d(76): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(76):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/nogc1.d(77): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(77):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/nogc1.d(78): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(78):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
 */
 @nogc void testDelete(int* p, Object o, S1* s)
index 6d935a0..5d43277 100644 (file)
@@ -7,4 +7,3 @@ fail_compilation/pragmainline.d(8): Error: pragma `inline` one boolean expressio
 
 pragma(inline, 1,2,3) void bar();
 pragma(inline, "string") void baz(); // works now
-
index eeea28c..6e7e909 100644 (file)
@@ -116,6 +116,7 @@ fail_compilation/reserved_version.d(217): Error: version identifier `AVR` is res
 fail_compilation/reserved_version.d(218): Error: version identifier `D_PreConditions` is reserved and cannot be set
 fail_compilation/reserved_version.d(219): Error: version identifier `D_PostConditions` is reserved and cannot be set
 fail_compilation/reserved_version.d(220): Error: version identifier `D_ProfileGC` is reserved and cannot be set
+fail_compilation/reserved_version.d(221): Error: version identifier `D_Invariants` is reserved and cannot be set
 ---
 */
 
@@ -238,6 +239,7 @@ version = AVR;
 version = D_PreConditions;
 version = D_PostConditions;
 version = D_ProfileGC;
+version = D_Invariants;
 
 // This should work though
 debug = DigitalMars;
index 792ea0a..cd85b41 100644 (file)
 // REQUIRED_ARGS: -version=D_PreConditions
 // REQUIRED_ARGS: -version=D_PostConditions
 // REQUIRED_ARGS: -version=D_ProfileGC
+// REQUIRED_ARGS: -version=D_Invariants
 // REQUIRED_ARGS: -debug=DigitalMars
 // REQUIRED_ARGS: -debug=GNU
 // REQUIRED_ARGS: -debug=LDC
 // REQUIRED_ARGS: -debug=D_PreConditions
 // REQUIRED_ARGS: -debug=D_PostConditions
 // REQUIRED_ARGS: -debug=D_ProfileGC
+// REQUIRED_ARGS: -debug=D_Invariants
 /*
 TEST_OUTPUT:
 ---
@@ -318,5 +320,6 @@ Error: version identifier `none` is reserved and cannot be set
 Error: version identifier `D_PreConditions` is reserved and cannot be set
 Error: version identifier `D_PostConditions` is reserved and cannot be set
 Error: version identifier `D_ProfileGC` is reserved and cannot be set
+Error: version identifier `D_Invariants` is reserved and cannot be set
 ---
 */
index 130d49b..951ad59 100644 (file)
@@ -53,47 +53,6 @@ void bar4()
 /*
 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
index 0625d8e..a4c8d58 100644 (file)
@@ -23,4 +23,3 @@ void test() @safe
             p = &t.a; // should not compile
     }
 }
-
index 47f216f..7e68bfc 100644 (file)
@@ -231,3 +231,23 @@ const(int)* f_c_20150() @safe
     int x = 42;
     return escape_c_20150(&x);
 }
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(13010): Error: reference to local variable `str` assigned to non-scope parameter `x` calling retscope6.f_throw
+---
+*/
+
+#line 13000
+// https://issues.dlang.org/show_bug.cgi?id=22221
+
+void f_throw(string x) @safe pure
+{
+    throw new Exception(x);
+}
+
+void escape_throw_20150() @safe
+{
+    immutable(char)[4] str;
+    f_throw(str[]);
+}
index 6011d17..ab6f540 100644 (file)
@@ -91,7 +91,6 @@ fail_compilation/shared.d(2194): Error: direct access to shared `(new shared(K2)
 fail_compilation/shared.d(2202): Error: direct access to shared `c` is not allowed, see `core.atomic`
 fail_compilation/shared.d(2206): Error: function `shared.test_inference_2` function returns `shared` but cannot be inferred `ref`
 fail_compilation/shared.d(2208): Error: returning `c` escapes a reference to parameter `c`
-fail_compilation/shared.d(2208):        perhaps annotate the parameter with `return`
 fail_compilation/shared.d(2214): Error: function `shared.test_inference_3` function returns `shared` but cannot be inferred `ref`
 fail_compilation/shared.d(2216):        return value `getSharedObject()` is not an lvalue
 fail_compilation/shared.d(2222): Error: direct access to shared `a` is not allowed, see `core.atomic`
@@ -100,6 +99,7 @@ fail_compilation/shared.d(2222):        cannot implicitly convert `a` of type `s
 fail_compilation/shared.d(2222): Error: cannot implicitly convert expression `a` of type `shared(const(Object))` to `object.Object`
 ---
  */
+
 #line 2100
 // Derived from https://issues.dlang.org/show_bug.cgi?id=20908
 ref shared(int) test20908()
index 2cbc9c6..6f4f644 100644 (file)
@@ -15,5 +15,3 @@ int x;
     __traits(getAttributes, foo);
     __traits(getAttributes, foo)[0];
 }
-
-
index 6c94b40..cf60b80 100644 (file)
@@ -15,4 +15,3 @@ fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code,
 @safe ubyte oops(ubyte[3] b) {
     return *b.ptr;
 }
-
index a92a7c1..8e9811c 100644 (file)
@@ -57,4 +57,3 @@ void gun() @system
 @safe:
 void abc(ref int x) { }
 void def(const ref int x) { }
-
index 00ec33a..fe9934a 100644 (file)
@@ -44,4 +44,3 @@ struct S2
 @safe void bar(ref int*);
 @safe void cbar(ref const int*);
 @safe void sinister(out int*);
-
index eeb4492..91ac675 100644 (file)
@@ -46,5 +46,3 @@ void testClosure1()
     dg = &bar;               // Error
     auto dg2 = &bar;
 }
-
-
index 1665e85..dd07857 100644 (file)
@@ -28,4 +28,3 @@ void test2() @safe
     const(ubyte)[] a;
     auto b = cast(const(uint[])) a;
 }
-
index d818033..2be9d30 100644 (file)
@@ -14,4 +14,3 @@ void main() @safe {
 
     arr1[] = arr2[];  // overwrites pointers with arbitrary ints
 }
-
index 6d6c51e..018ab0d 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * TEST_OUTPUT:
 ---
-fail_compilation/test16195.d(13): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/test16195.d(14): Error: the `delete` keyword is obsolete
+fail_compilation/test16195.d(14):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 ---
  */
 
index 0e86081..dc4c593 100644 (file)
@@ -3,15 +3,15 @@ REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
 fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`
-fail_compilation/test16589.d(26):        perhaps annotate the function with `return`
+fail_compilation/test16589.d(24):        perhaps annotate the function with `return`
 fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`
-fail_compilation/test16589.d(31):        perhaps annotate the function with `return`
+fail_compilation/test16589.d(29):        perhaps annotate the function with `return`
 fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`
-fail_compilation/test16589.d(37):        perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(35):        perhaps annotate the parameter with `return`
 fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`
-fail_compilation/test16589.d(42):        perhaps annotate the parameter with `return`
-fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to local variable `s`
-fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to local variable `s`
+fail_compilation/test16589.d(40):        perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to parameter `s`
+fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to parameter `s`
 ---
 */
 
index 77c4956..7140615 100644 (file)
@@ -29,4 +29,3 @@ enum a2 = __traits(getParameterStorageClasses, i, 4);
 enum a3 = __traits(getParameterStorageClasses, foo, int);
 
 enum a4 = __traits(getParameterStorageClasses, foo, 0, 1);
-
index f350cbd..098adaa 100644 (file)
@@ -3,9 +3,9 @@ REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
 fail_compilation/test17450.d(17): Error: returning `&s.bar` escapes a reference to parameter `s`
-fail_compilation/test17450.d(17):        perhaps annotate the parameter with `return`
+fail_compilation/test17450.d(16):        perhaps annotate the parameter with `return`
 fail_compilation/test17450.d(20): Error: returning `&this.bar` escapes a reference to parameter `this`
-fail_compilation/test17450.d(20):        perhaps annotate the function with `return`
+fail_compilation/test17450.d(19):        perhaps annotate the function with `return`
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=17450
index 20743ea..430967e 100644 (file)
@@ -21,5 +21,3 @@ fail_compilation/test18644.d(22): Error: escaping reference to stack allocated v
     ref int foo() { return i; }
     return foo();
 }
-
-
index 0f22fe7..55c84f9 100644 (file)
@@ -23,4 +23,3 @@ void main()
     imports.imp21353.P();
     with (imports.imp21353) { P(); } // fixed
 }
-
index fa23285..4791409 100644 (file)
@@ -2,8 +2,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test21927.d(17): Error: invalid `foreach` aggregate `this.T2(Args2...)`
-fail_compilation/test21927.d(18): Error: invalid `foreach` aggregate `this.T2!()`
+fail_compilation/test21927.d(17): Error: invalid `foreach` aggregate `this.T2(Args2...)` of type `void`
+fail_compilation/test21927.d(18): Error: invalid `foreach` aggregate `this.T2!()` of type `void`
 ---
 */
 
index cb755ef..8f30bac 100644 (file)
@@ -2,7 +2,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test21939.d(9): Error: invalid `foreach` aggregate `Object`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/test21939.d(10): Error: invalid `foreach` aggregate `Object` of type `Object`
+fail_compilation/test21939.d(10):        maybe define `opApply()`, range primitives, or use `.tupleof`
 ---
 */
 
index 910db0a..6152f44 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/test22541.d(104): Error: returning `i` escapes a reference to parameter `i`
-fail_compilation/test22541.d(104):        perhaps annotate the parameter with `return`
+fail_compilation/test22541.d(102):        perhaps annotate the parameter with `return`
 ---
  */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22840.d b/gcc/testsuite/gdc.test/fail_compilation/test22840.d
new file mode 100644 (file)
index 0000000..f7be64a
--- /dev/null
@@ -0,0 +1,26 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/test22840.d(25): Error: returning `sb.slice()` escapes a reference to local variable `sb`
+---
+*/
+
+// inout method with inferred @safe escapes local data
+// https://issues.dlang.org/show_bug.cgi?id=22840
+
+// See also: https://issues.dlang.org/show_bug.cgi?id=20149
+
+struct S
+{
+    int buf;
+    auto slice() inout
+    {
+        return &buf;
+    }
+}
+
+int* fun() @safe
+{
+    S sb;
+    return sb.slice(); // should error
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22910.d b/gcc/testsuite/gdc.test/fail_compilation/test22910.d
new file mode 100644 (file)
index 0000000..581c693
--- /dev/null
@@ -0,0 +1,19 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test22910.d(17): Error: returning `&this.val` escapes a reference to parameter `this`
+fail_compilation/test22910.d(15):        perhaps change the `return scope` into `scope return`
+---
+*/
+@safe:
+
+struct S
+{
+    int  val;
+    int* ptr;
+
+    int* retScope() return scope
+    {
+        return &this.val;
+    }
+}
index 674455b..e040574 100644 (file)
@@ -8,4 +8,3 @@ fail_compilation/varargsstc.d(102): Error: variadic parameter cannot have attrib
 
 int printf(const(char)*, const scope shared return ...);
 int printf(const(char)*, ref out scope immutable shared return ...);
-
index 71beb85..732168e 100644 (file)
@@ -8,4 +8,3 @@ void main()
     auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } );
     assert(num == 5);
 }
-
index 55864a0..23681d9 100644 (file)
@@ -35,4 +35,3 @@ void foo()
         assert(i == 1);  // this fails
     }
 }
-
index 444f00a..cbec56c 100644 (file)
@@ -25,4 +25,3 @@ class Container(T) : IContainer!(int)
            return new Enumerator!(int)();
        }
 }
-
index d83805d..49102af 100644 (file)
@@ -36,4 +36,3 @@ template removeIf( Buf, Pred )
         return removeIf_!(ElemTypeOf!(Buf), Pred).fn( buf, pred );
     }
 }
-
index 0596933..af0c044 100644 (file)
@@ -3,4 +3,3 @@ module imports.c22b;
 public import imports.c22a : afn1;
 
 void bfn1() {}
-
index 2782782..f97230f 100644 (file)
@@ -3,5 +3,3 @@ struct C { auto asdfg() {} }
 
 // extreme test of bug 4820
 void nextis(W)(void delegate() dg = {}) {}
-
-
index 7a56f8a..c14ed40 100644 (file)
@@ -4,4 +4,3 @@ module imports.test11039b;
 import test11039;
 
 static anotherGlobalField = SomeStruct!string("Hello Again!");
-
index 4512e41..a840fab 100644 (file)
@@ -52,4 +52,3 @@ unittest {
     assert(pairA == pairB);
     printf("Pair tests passed!\r\n");
 }
-
index fe3ab97..9e834e2 100644 (file)
@@ -3,4 +3,3 @@ module imports.test29a;
 private import imports.test29b;
 
 deprecated alias imports.test29b.qwert qwert;
-
index 3d88280..150f92b 100644 (file)
@@ -3,4 +3,3 @@ module imports.test31a;
 template Baz() {
     private void privfunc(){ }
 }
-
index b011934..e49ea80 100644 (file)
@@ -36,4 +36,3 @@ template removeIf( Buf, Pred )
        return removeIf_!(ElemTypeOf!(Buf), Pred).fn( buf, pred );
     }
 }
-
index e73122a..ab562c9 100644 (file)
@@ -7,4 +7,3 @@ class B
     private C!(char) c;
     this() { c = new C!(char); }
 }
-
index 8e53307..6f353e9 100644 (file)
@@ -17,4 +17,3 @@ int main()
     assert(a(10, 1, -1, -1, 1, 0) == -67);
     return 0;
 }
-
diff --git a/gcc/testsuite/gdc.test/runnable/nrvo.d b/gcc/testsuite/gdc.test/runnable/nrvo.d
new file mode 100644 (file)
index 0000000..5c653fe
--- /dev/null
@@ -0,0 +1,30 @@
+/***************************************************/
+
+struct S1
+{
+    int x;
+    ~this() {}
+}
+
+__gshared S1* s1ptr;
+
+S1 test1a()
+{
+    auto result = S1(123);
+    (() @trusted { result.x++; s1ptr = &result; })();
+    return result;
+}
+
+void test1()
+{
+    auto r = test1a();
+    assert(r.x == 124);
+    assert(&r == s1ptr);
+}
+
+/***************************************************/
+
+void main()
+{
+    test1();
+}
index bb5f0d0..73c5919 100644 (file)
@@ -169,6 +169,3 @@ int tiszero()
                         return false;
         return true;
 }
-
-
-
index 3993e81..a229230 100644 (file)
@@ -27,4 +27,3 @@ void bug2962comment36()(int p)
     int inner()() { return p; }
     alias inner!() finner;
 }
-
index 8c45c20..0c19dad 100644 (file)
@@ -30,4 +30,3 @@ string getEnum(size_t count)
 mixin(getEnum(1087));
 
 void main() { }
-
index abaae37..6735a81 100644 (file)
@@ -1389,5 +1389,3 @@ int main(string[] argv)
     printf("Success\n");
     return 0;
 }
-
-
index cc5cdba..0900609 100644 (file)
@@ -20,4 +20,3 @@ void main()
     globalField.getInnerField();
     anotherGlobalField.getInnerField();
 }
-
index 01c7486..22f4b84 100644 (file)
@@ -1246,4 +1246,3 @@ int main(string[] argv)
     printf("Success\n");
     return 0;
 }
-
index 3004945..6ea66a3 100644 (file)
@@ -29,4 +29,3 @@ void main()
         res ~= value;
     assert(res == [1, 2, 3]);
 }
-
index 4b17ede..b09cfb3 100644 (file)
@@ -40,4 +40,3 @@ int main()
     ulog("point(1.2)\n");
     return 0;
 }
-
index 2d51720..778d62d 100644 (file)
@@ -47,4 +47,3 @@ int main(string[] args)
     auto bar = genBar(args.length == 0);
     return 0;
 }
-
index 640de19..f22c1f7 100644 (file)
@@ -7,4 +7,3 @@ void main()
        foreach(p; px)
                assert(p && *p == 7);
 }
-
index 47a8db3..df4a226 100644 (file)
@@ -15,4 +15,3 @@ void main()
         assert(temp!int() == 5);
     }
 }
-
index 66e3cf2..c532339 100644 (file)
@@ -7,4 +7,3 @@ int main()
     TA!(int) variable;
     return 0;
 }
-
diff --git a/gcc/testsuite/gdc.test/runnable/test22175.d b/gcc/testsuite/gdc.test/runnable/test22175.d
new file mode 100644 (file)
index 0000000..195001b
--- /dev/null
@@ -0,0 +1,32 @@
+// https://issues.dlang.org/show_bug.cgi?id=22175
+
+struct Struct
+{
+    short a = 24, b = 25, c = 26, d = 27;
+    ubyte e = 28;
+}
+
+Struct foo() { Struct s; s.a = 60; s.b = 61; s.c = 62, s.d = 63; s.e = 64; return s; }
+
+Struct test(int i) {
+    Struct var = i ? Struct() : foo();
+    Struct nest() { return var; }
+    return nest();
+}
+
+int main()
+{
+    auto s = test(0);
+    assert(s.a == 60);
+    assert(s.b == 61);
+    assert(s.c == 62);
+    assert(s.d == 63);
+    assert(s.e == 64);
+    s = test(1);
+    assert(s.a == 24);
+    assert(s.b == 25);
+    assert(s.c == 26);
+    assert(s.d == 27);
+    assert(s.e == 28);
+    return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test22945.d b/gcc/testsuite/gdc.test/runnable/test22945.d
new file mode 100644 (file)
index 0000000..a8b968d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+REQUIRED_ARGS: -release -check=assert=on
+PERMUTE_ARGS:  -check=invariant=on
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=22945
+
+bool hitStruct;
+bool hitClass;
+
+struct S
+{
+    this(int) {}
+    invariant { hitStruct = true; }
+}
+
+class C
+{
+    this() {}
+    invariant { hitClass = true; }
+}
+
+int main()
+{
+    cast(void) S(0);
+    cast(void) new C();
+
+    version(D_Invariants)
+    {
+        assert(hitStruct && hitClass);
+    }
+    else
+    {
+        assert(!hitStruct && !hitClass);
+    }
+
+    return 0;
+}
index 4c6b9de..36c1aa3 100644 (file)
@@ -38,4 +38,3 @@ int main(string[] args)
     assert(a.bar == "lolobetty");
     return 0;
 }
-
index d98d468..31f0cc7 100644 (file)
@@ -8,4 +8,3 @@ void main()
 {
     assert(S.sizeof == int.sizeof);
 }
-
index 2c1069d..497b0be 100644 (file)
@@ -13,4 +13,3 @@ class Foo {
 void main() {
         Bar.foobar();
 }
-
index 54cf672..c79b3f8 100644 (file)
@@ -7,4 +7,3 @@ module test57;
 import imports.test57a;
 
 void main() {}
-
index e8eaad8..309f0e3 100644 (file)
@@ -28,4 +28,4 @@ void main(string[] args)
 {
   test9495a();
   test9495b();
-}
\ No newline at end of file
+}
index 111696a..1af9fbb 100644 (file)
@@ -9,4 +9,3 @@ void main()
     void whatever() {}
     foo!(whatever)();
 }
-
index 4de1eba..a1164dc 100644 (file)
@@ -4,7 +4,7 @@ TEST_OUTPUT:
 ---
 foo1 ulong function(return ref int* delegate() return p) ref return
 foo2 int function(return ref int delegate() p) ref
-foo3 int function(return ref inout(int*) p) ref
+foo3 int function(ref inout(int*) p) ref
 foo4 int function(return ref inout(int*) p) ref
 ---
 */
@@ -47,13 +47,13 @@ void test3()
         // Test scope mangling
         assert(SS.foo1.mangleof == "_D10testscope22SS4foo1MFNcNjNkKDFNjZPiZm");
         assert(SS.foo2.mangleof == "_D10testscope22SS4foo2MFNcNkKDFZiZi");
-        assert(SS.foo3.mangleof == "_D10testscope22SS4foo3MFNcNkKNgPiZi");
+        assert(SS.foo3.mangleof == "_D10testscope22SS4foo3MFNcKNgPiZi");
         assert(SS.foo4.mangleof == "_D10testscope22SS4foo4MFNcNkKNgPiZi");
 
         // Test scope pretty-printing
         assert(typeof(SS.foo1).stringof == "ref ulong(return ref int* delegate() return p) return");
         assert(typeof(SS.foo2).stringof == "ref int(return ref int delegate() p)");
-        assert(typeof(SS.foo3).stringof == "ref int(return ref inout(int*) p)");
+        assert(typeof(SS.foo3).stringof == "ref int(ref inout(int*) p)");
         assert(typeof(SS.foo4).stringof == "ref int(return ref inout(int*) p)");
     }
 }
index 7b59509..04bbbd1 100644 (file)
@@ -96,4 +96,3 @@ int main()
     printf("Success\n");
     return 0;
 }
-
index 6acffb4..8e171de 100644 (file)
@@ -101,4 +101,3 @@ int main()
     printf("Success\n");
     return 0;
 }
-
index f976520..b7d1266 100644 (file)
@@ -21,4 +21,3 @@ int main()
     assert(stuff1.num == 1);
     return 0;
 }
-
index edda423..6aeb25d 100644 (file)
@@ -17,4 +17,4 @@ extern(C++) int test6716(int magic)
 {
     assert(magic == 12345);
     return 0;
-}
\ No newline at end of file
+}
index 77b6ad0..b1da32e 100644 (file)
@@ -1,4 +1,4 @@
-26b581670ef6e2643d74078f200d1cd21fa40e90
+c52e28b723ccfbe845a95e8e7b528e3cc0b9d790
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
index ba64131..6ca4012 100644 (file)
@@ -294,13 +294,13 @@ DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
 
 DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
        core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
-       core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
-       core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
-       core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
-       core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
-       core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
-       core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
-       core/sys/openbsd/unistd.d
+       core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+       core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+       core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+       core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+       core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+       core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+       core/sys/openbsd/time.d core/sys/openbsd/unistd.d
 
 DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
        core/sys/posix/arpa/inet.d core/sys/posix/config.d \
index 1c64d35..f7f78d7 100644 (file)
@@ -344,9 +344,10 @@ am__objects_14 = core/sys/netbsd/dlfcn.lo core/sys/netbsd/err.lo \
 @DRUNTIME_OS_NETBSD_TRUE@am__objects_15 = $(am__objects_14)
 am__objects_16 = core/sys/openbsd/dlfcn.lo core/sys/openbsd/err.lo \
        core/sys/openbsd/execinfo.lo core/sys/openbsd/pthread_np.lo \
-       core/sys/openbsd/stdlib.lo core/sys/openbsd/string.lo \
-       core/sys/openbsd/sys/cdefs.lo core/sys/openbsd/sys/elf.lo \
-       core/sys/openbsd/sys/elf32.lo core/sys/openbsd/sys/elf64.lo \
+       core/sys/openbsd/pwd.lo core/sys/openbsd/stdlib.lo \
+       core/sys/openbsd/string.lo core/sys/openbsd/sys/cdefs.lo \
+       core/sys/openbsd/sys/elf.lo core/sys/openbsd/sys/elf32.lo \
+       core/sys/openbsd/sys/elf64.lo \
        core/sys/openbsd/sys/elf_common.lo \
        core/sys/openbsd/sys/link_elf.lo core/sys/openbsd/sys/mman.lo \
        core/sys/openbsd/sys/sysctl.lo core/sys/openbsd/time.lo \
@@ -958,13 +959,13 @@ DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
 
 DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
        core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
-       core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
-       core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
-       core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
-       core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
-       core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
-       core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
-       core/sys/openbsd/unistd.d
+       core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+       core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+       core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+       core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+       core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+       core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+       core/sys/openbsd/time.d core/sys/openbsd/unistd.d
 
 DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
        core/sys/posix/arpa/inet.d core/sys/posix/config.d \
@@ -1619,6 +1620,7 @@ core/sys/openbsd/dlfcn.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/err.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/execinfo.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/pthread_np.lo: core/sys/openbsd/$(am__dirstamp)
+core/sys/openbsd/pwd.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/stdlib.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/string.lo: core/sys/openbsd/$(am__dirstamp)
 core/sys/openbsd/sys/$(am__dirstamp):
index e6a82e5..4af3fdf 100644 (file)
@@ -292,7 +292,7 @@ template cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.
     in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
     {
         // resolve implicit conversions
-        T arg1 = ifThis;
+        const T arg1 = ifThis;
         T arg2 = writeThis;
 
         static if (__traits(isFloating, T))
@@ -1276,4 +1276,13 @@ version (CoreUnittest)
         shared NoIndirections n;
         static assert(is(typeof(atomicLoad(n)) == NoIndirections));
     }
+
+    unittest // Issue 21631
+    {
+        shared uint si1 = 45;
+        shared uint si2 = 38;
+        shared uint* psi = &si1;
+
+        assert((&psi).cas(cast(const) psi, &si2));
+    }
 }
index 930e0cd..cb8d433 100644 (file)
@@ -1339,7 +1339,7 @@ pure @safe:
         TypeFunction:
             CallConvention FuncAttrs Arguments ArgClose Type
     */
-    char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return
+    char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
     {
         debug(trace) printf( "parseTypeFunction+\n" );
         debug(trace) scope(success) printf( "parseTypeFunction-\n" );
index e862f8e..4366da8 100644 (file)
@@ -17,12 +17,13 @@ builds.  It is separate from `__ArrayCast` to minimize code
 bloat.
 
 Params:
-    fromType = name of the type being cast from
-    fromSize = total size in bytes of the array being cast from
-    toType   = name of the type being cast o
-    toSize   = total size in bytes of the array being cast to
+    fromType   = name of the type being cast from
+    fromSize   = total size in bytes of the array being cast from
+    fromLength = length of array being cast from
+    toType     = name of the type being cast to
+    toElemSize = element size of array being cast to
  */
-private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
+private void onArrayCastError()(string fromType, size_t fromSize, size_t fromLength, string toType, size_t toElemSize) @trusted
 {
     import core.internal.string : unsignedToTempString;
     import core.memory : pureMalloc;
@@ -45,17 +46,22 @@ private void onArrayCastError()(string fromType, size_t fromSize, string toType,
         index += N;
     }
 
-    add("An array of size ");
-    auto s = unsignedToTempString(fromSize);
+    add("`");
+    add(fromType);
+    add("[]` of length ");
+    auto s = unsignedToTempString(fromLength);
     add(s[]);
-    add(" does not align on an array of size ");
-    s = unsignedToTempString(toSize);
+    add(" cannot be cast to `");
+    add(toType);
+    add("[]` as its length in bytes (");
+    s = unsignedToTempString(fromSize);
     add(s[]);
-    add(", so `");
-    add(fromType);
-    add("` cannot be cast to `");
+    add(") is not a multiple of `");
     add(toType);
-    add("`");
+    add(".sizeof` (");
+    s = unsignedToTempString(toElemSize);
+    add(s[]);
+    add(").");
     msg[index] = '\0'; // null-termination
 
     // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
@@ -64,7 +70,7 @@ private void onArrayCastError()(string fromType, size_t fromSize, string toType,
 
 /**
 The compiler lowers expressions of `cast(TTo[])TFrom[]` to
-this implementation.
+this implementation. Note that this does not detect alignment problems.
 
 Params:
     from = the array to reinterpret-cast
@@ -79,7 +85,7 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
 
     if ((fromSize % TTo.sizeof) != 0)
     {
-        onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
+        onArrayCastError(TFrom.stringof, fromSize, from.length, TTo.stringof, TTo.sizeof);
     }
 
     struct Array
@@ -113,3 +119,26 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
     foreach (v; s)
         assert(v == cast(short) 0xabab);
 }
+
+@system nothrow unittest
+{
+    string msg;
+    try
+    {
+        auto str = "hello";
+        auto wstr = cast(wstring) str;
+    }
+    catch (Throwable t)
+        msg = t.msg;
+
+    static immutable expected = "`immutable(char)[]` of length 5 cannot be cast to `immutable(wchar)[]` as " ~
+                            "its length in bytes (5) is not a multiple of `immutable(wchar).sizeof` (2).";
+
+    if (msg != expected)
+    {
+        import core.stdc.stdio;
+        printf("Expected: |%.*s|\n", cast(int) expected.length, expected.ptr);
+        printf("Actual  : |%.*s|\n", cast(int) msg.length, msg.ptr);
+        assert(false);
+    }
+}
index aa51867..e29e426 100644 (file)
@@ -2935,19 +2935,18 @@ struct Gcx
         else version (linux)
         {
             // clone() fits better as we don't want to do anything but scanning in the child process.
-            // no fork-handlera are called, so we can avoid deadlocks due to malloc locks. Probably related:
+            // no fork-handlers are called, so we can avoid deadlocks due to malloc locks. Probably related:
             //  https://sourceware.org/bugzilla/show_bug.cgi?id=4737
             import core.sys.linux.sched : clone;
             import core.sys.posix.signal : SIGCHLD;
-            enum CLONE_CHILD_CLEARTID = 0x00200000; /* Register exit futex and memory */
-            const flags = CLONE_CHILD_CLEARTID | SIGCHLD; // child thread id not needed
+            const flags = SIGCHLD; // exit signal
             scope int delegate() scope dg = &child_mark;
             extern(C) static int wrap_delegate(void* arg)
             {
                 auto dg = cast(int delegate() scope*)arg;
                 return (*dg)();
             }
-            char[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
+            ubyte[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
             auto stack = stackbuf.ptr + (isStackGrowingDown ? stackbuf.length : 0);
             auto pid = clone(&wrap_delegate, stack, flags, &dg);
         }
@@ -2957,7 +2956,6 @@ struct Gcx
             auto pid = fork();
             fork_needs_lock = true;
         }
-        assert(pid != -1);
         switch (pid)
         {
             case -1: // fork() failed, retry without forking
@@ -3028,7 +3026,7 @@ struct Gcx
         //printf("\tpool address range = %p .. %p\n", minAddr, maxAddr);
 
         version (COLLECT_FORK)
-            bool doFork = shouldFork;
+            alias doFork = shouldFork;
         else
             enum doFork = false;
 
@@ -3083,6 +3081,7 @@ Lmark:
                     final switch (forkResult)
                     {
                         case ChildStatus.error:
+                            // fork() failed, retry without forking
                             disableFork();
                             goto Lmark;
                         case ChildStatus.running:
index 92f8f70..dbe55a4 100644 (file)
@@ -69,8 +69,8 @@ struct div_t
 ///
 struct ldiv_t
 {
-    int quot,
-        rem;
+    c_long quot,
+           rem;
 }
 
 ///
index dfec1ec..defbd83 100644 (file)
@@ -343,7 +343,7 @@ extern(D):
         ///
         inout(T)* data() inout @safe                                        { return _Get_data()._Myptr; }
         ///
-        inout(T)[] as_array() return scope inout nothrow @trusted           { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
+        inout(T)[] as_array() scope return inout nothrow @trusted           { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
         ///
         ref inout(T) at(size_type i) inout nothrow @trusted                 { return _Get_data()._Myptr[0 .. _Get_data()._Mysize][i]; }
 
@@ -1920,7 +1920,7 @@ extern(D):
         ///
         inout(T)* data() inout @safe                                        { return __get_pointer(); }
         ///
-        inout(T)[] as_array() return scope inout nothrow @trusted           { return __get_pointer()[0 .. size()]; }
+        inout(T)[] as_array() scope return inout nothrow @trusted           { return __get_pointer()[0 .. size()]; }
         ///
         ref inout(T) at(size_type i) inout nothrow @trusted                 { return __get_pointer()[0 .. size()][i]; }
 
diff --git a/libphobos/libdruntime/core/sys/openbsd/pwd.d b/libphobos/libdruntime/core/sys/openbsd/pwd.d
new file mode 100644 (file)
index 0000000..f6a35a8
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+  * D header file for OpenBSD pwd.h.
+  *
+  * Copyright: Copyright Â© 2022, The D Language Foundation
+  * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+  * Authors: Brian Callahan
+  */
+module core.sys.openbsd.pwd;
+
+version (OpenBSD):
+extern (C):
+nothrow:
+@nogc:
+
+public import core.sys.posix.pwd;
+import core.sys.posix.sys.types : uid_t;
+
+passwd* getpwnam_shadow(scope const char*);
+passwd* getpwuid_shadow(uid_t);
index 1b3c0ca..e477269 100644 (file)
@@ -6,7 +6,7 @@
  *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
  *    (See accompanying file LICENSE)
  * Authors:   Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source:    $(DRUNTIMESRC core/thread/package.d)
+ * Source:    $(DRUNTIMESRC core/thread/context.d)
  */
 
 module core.thread.context;
index 47b67f1..5ef2695 100644 (file)
@@ -669,7 +669,7 @@ extern (C) void _d_print_throwable(Throwable t)
 
     void sink(in char[] buf) scope nothrow
     {
-        fprintf(stderr, "%.*s", cast(int)buf.length, buf.ptr);
+        fwrite(buf.ptr, char.sizeof, buf.length, stderr);
     }
     formatThrowable(t, &sink);
 }
index 6eb555e..7306c10 100644 (file)
@@ -1,4 +1,4 @@
-a74fa63e6775d626850d8ebd854d9803c7ffb97d
+99e9c1b7741e0f4e6f2a8c14883c4828d092701d
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
index 06b3797..8f6c3bf 100644 (file)
@@ -2850,7 +2850,7 @@ do
     static if (isNarrowString!Source)
     {
         import std.string : representation;
-        auto s = source.representation;
+        scope s = source.representation;
     }
     else
     {
@@ -2898,7 +2898,7 @@ do
     }
 
     static if (isNarrowString!Source)
-        source = cast(Source) s;
+        source = source[$ - s.length .. $];
 
     static if (doCount)
     {
@@ -3105,7 +3105,7 @@ if (isSomeString!Source && !is(Source == enum) &&
  *     A $(LREF ConvException) if `source` is empty, if no number could be
  *     parsed, or if an overflow occurred.
  */
-auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source source)
+auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
 if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
     isFloatingPoint!Target && !is(Target == enum))
 {
@@ -3115,18 +3115,17 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
     static if (isNarrowString!Source)
     {
         import std.string : representation;
-        auto p = source.representation;
+        scope p = source.representation;
     }
     else
     {
         alias p = source;
     }
 
-    void advanceSource() @trusted
+    void advanceSource()
     {
-        // p is assigned from source.representation above so the cast is valid
         static if (isNarrowString!Source)
-            source = cast(Source) p;
+            source = source[$ - p.length .. $];
     }
 
     static immutable real[14] negtab =
@@ -5983,3 +5982,14 @@ if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
         }
     }
 }
+
+// Converts an unsigned integer to a compile-time string constant.
+package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
+
+// Check that .stringof does what we expect, since it's not guaranteed by the
+// language spec.
+@safe /*@betterC*/ unittest
+{
+    assert(toCtString!0 == "0");
+    assert(toCtString!123456 == "123456");
+}
index 949ad7d..e80f122 100644 (file)
@@ -390,6 +390,33 @@ public:
                            hnsecsToUnixEpoch;
                 }
             }
+            else version (Hurd)
+            {
+                static if (clockType == ClockType.second)
+                    return unixTimeToStdTime(core.stdc.time.time(null));
+                else
+                {
+                    import core.sys.hurd.time : CLOCK_REALTIME_COARSE;
+                    import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
+                    static if (clockType == ClockType.coarse)       alias clockArg = CLOCK_REALTIME_COARSE;
+                    else static if (clockType == ClockType.normal)  alias clockArg = CLOCK_REALTIME;
+                    else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
+                    else static assert(0, "Previous static if is wrong.");
+                    timespec ts = void;
+                    immutable error = clock_gettime(clockArg, &ts);
+                    // Posix clock_gettime called with a valid address and valid clock_id is only
+                    // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+                    // is long or larger overflow won't happen before 292 billion years A.D.
+                    static if (ts.tv_sec.max < long.max)
+                    {
+                        if (error)
+                            throw new TimeException("Call to clock_gettime() failed");
+                    }
+                    return convert!("seconds", "hnsecs")(ts.tv_sec) +
+                           ts.tv_nsec / 100 +
+                           hnsecsToUnixEpoch;
+                }
+            }
             else static assert(0, "Unsupported OS");
         }
         else static assert(0, "Unsupported OS");
@@ -693,7 +720,7 @@ public:
 
         Returns: The `this` of this `SysTime`.
       +/
-    ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow
+    ref SysTime opAssign()(auto ref const(SysTime) rhs) scope return @safe pure nothrow
     {
         _stdTime = rhs._stdTime;
         _timezone = rhs._timezone;
index afd98ad..6a28de5 100644 (file)
@@ -1633,14 +1633,14 @@ private @property Logger defaultSharedLoggerImpl() @trusted
     import std.concurrency : initOnce;
     initOnce!stdSharedDefaultLogger({
         auto buffer = cast(ubyte[]) _buffer;
-        return emplace!FileLogger(buffer, stderr, LogLevel.warning);
+        return emplace!FileLogger(buffer, stderr, LogLevel.info);
     }());
 
     return stdSharedDefaultLogger;
 }
 
 /** This property sets and gets the default `Logger`. Unless set to another
-logger by the user, the default logger's log level is LogLevel.warning.
+logger by the user, the default logger's log level is LogLevel.info.
 
 Example:
 -------------
@@ -2008,7 +2008,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
 
     auto oldunspecificLogger = sharedLog;
 
-    assert(oldunspecificLogger.logLevel == LogLevel.warning,
+    assert(oldunspecificLogger.logLevel == LogLevel.info,
          to!string(oldunspecificLogger.logLevel));
 
     assert(l.logLevel == LogLevel.all);
@@ -3064,7 +3064,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
 {
     auto dl = cast(FileLogger) sharedLog;
     assert(dl !is null);
-    assert(dl.logLevel == LogLevel.warning);
+    assert(dl.logLevel == LogLevel.info);
     assert(globalLogLevel == LogLevel.all);
 
     auto tl = cast(StdForwardLogger) stdThreadLocalLog;
index a0bea77..5112e52 100644 (file)
@@ -263,7 +263,7 @@ class FileLogger : Logger
 {
     auto dl = cast(FileLogger) sharedLog;
     assert(dl !is null);
-    assert(dl.logLevel == LogLevel.warning);
+    assert(dl.logLevel == LogLevel.info);
     assert(globalLogLevel == LogLevel.all);
 
     auto tl = cast(StdForwardLogger) stdThreadLocalLog;
index 90bfb58..9acd23a 100644 (file)
@@ -191,7 +191,7 @@ class MultiLogger : Logger
 {
     auto dl = cast(FileLogger) sharedLog;
     assert(dl !is null);
-    assert(dl.logLevel == LogLevel.warning);
+    assert(dl.logLevel == LogLevel.info);
     assert(globalLogLevel == LogLevel.all);
 
     auto tl = cast(StdForwardLogger) stdThreadLocalLog;
index b09b82a..6bc7d4d 100644 (file)
@@ -214,7 +214,7 @@ class FileException : Exception
                           string file = __FILE__,
                           size_t line = __LINE__) @safe
     {
-        this(name, sysErrorString(errno), file, line, errno);
+        this(name, generateSysErrorMsg(errno), file, line, errno);
     }
     else version (Posix) this(scope const(char)[] name,
                              uint errno = .errno,
@@ -3471,7 +3471,7 @@ else version (Posix) string getcwd() @trusted
         while (true)
         {
             auto len = GetModuleFileNameW(null, buffer.ptr, cast(DWORD) buffer.length);
-            enforce(len, sysErrorString(GetLastError()));
+            wenforce(len);
             if (len != buffer.length)
                 return to!(string)(buffer[0 .. len]);
             buffer.length *= 2;
@@ -3574,6 +3574,10 @@ else version (Posix) string getcwd() @trusted
         // Only Solaris 10 and later
         return readLink(format("/proc/%d/path/a.out", getpid()));
     }
+    else version (Hurd)
+    {
+        return readLink("/proc/self/exe");
+    }
     else
         static assert(0, "thisExePath is not supported on this platform");
 }
index 68b9e4d..f1d6964 100644 (file)
@@ -2000,8 +2000,7 @@ template hasToString(T, Char)
         enum hasToString = HasToStringResult.none;
     }
     else static if (is(typeof(
-        {
-            T val = void;
+        (T val) {
             const FormatSpec!Char f;
             static struct S {void put(scope Char s){}}
             S s;
@@ -2015,8 +2014,7 @@ template hasToString(T, Char)
         enum hasToString = HasToStringResult.customPutWriterFormatSpec;
     }
     else static if (is(typeof(
-        {
-            T val = void;
+        (T val) {
             static struct S {void put(scope Char s){}}
             S s;
             val.toString(s);
@@ -2026,36 +2024,36 @@ template hasToString(T, Char)
     {
         enum hasToString = HasToStringResult.customPutWriter;
     }
-    else static if (is(typeof({ T val = void; FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
+    else static if (is(typeof((T val) { FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
     {
         enum hasToString = HasToStringResult.constCharSinkFormatSpec;
     }
-    else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}, "%s"); })))
+    else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}, "%s"); })))
     {
         enum hasToString = HasToStringResult.constCharSinkFormatString;
     }
-    else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}); })))
+    else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}); })))
     {
         enum hasToString = HasToStringResult.constCharSink;
     }
 
     else static if (hasPreviewIn &&
-                    is(typeof({ T val = void; FormatSpec!Char f; val.toString((in char[] s){}, f); })))
+                    is(typeof((T val) { FormatSpec!Char f; val.toString((in char[] s){}, f); })))
     {
         enum hasToString = HasToStringResult.inCharSinkFormatSpec;
     }
     else static if (hasPreviewIn &&
-                    is(typeof({ T val = void; val.toString((in char[] s){}, "%s"); })))
+                    is(typeof((T val) { val.toString((in char[] s){}, "%s"); })))
     {
         enum hasToString = HasToStringResult.inCharSinkFormatString;
     }
     else static if (hasPreviewIn &&
-                    is(typeof({ T val = void; val.toString((in char[] s){}); })))
+                    is(typeof((T val) { val.toString((in char[] s){}); })))
     {
         enum hasToString = HasToStringResult.inCharSink;
     }
 
-    else static if (is(typeof({ T val = void; return val.toString(); }()) S) && isSomeString!S)
+    else static if (is(ReturnType!((T val) { return val.toString(); }) S) && isSomeString!S)
     {
         enum hasToString = HasToStringResult.hasSomeToString;
     }
@@ -2171,6 +2169,133 @@ template hasToString(T, Char)
     }
 }
 
+// const toString methods
+@safe unittest
+{
+    import std.range.primitives : isOutputRange;
+
+    static struct A
+    {
+        void toString(Writer)(ref Writer w) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct B
+    {
+        void toString(scope void delegate(scope const(char)[]) sink, scope FormatSpec!char fmt) const {}
+    }
+    static struct C
+    {
+        void toString(scope void delegate(scope const(char)[]) sink, string fmt) const {}
+    }
+    static struct D
+    {
+        void toString(scope void delegate(scope const(char)[]) sink) const {}
+    }
+    static struct E
+    {
+        string toString() const {return "";}
+    }
+    static struct F
+    {
+        void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct G
+    {
+        string toString() const {return "";}
+        void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+    }
+    static struct H
+    {
+        string toString() const {return "";}
+        void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct I
+    {
+        void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+        void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct J
+    {
+        string toString() const {return "";}
+        void toString(Writer)(ref Writer w, scope ref FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct K
+    {
+        void toString(Writer)(Writer w, scope const ref FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct L
+    {
+        void toString(Writer)(ref Writer w, scope const FormatSpec!char fmt) const
+        if (isOutputRange!(Writer, string))
+        {}
+    }
+    static struct M
+    {
+        void toString(scope void delegate(in char[]) sink, in FormatSpec!char fmt) const {}
+    }
+    static struct N
+    {
+        void toString(scope void delegate(in char[]) sink, string fmt) const {}
+    }
+    static struct O
+    {
+        void toString(scope void delegate(in char[]) sink) const {}
+    }
+
+    with(HasToStringResult)
+    {
+        static assert(hasToString!(A, char) == customPutWriter);
+        static assert(hasToString!(B, char) == constCharSinkFormatSpec);
+        static assert(hasToString!(C, char) == constCharSinkFormatString);
+        static assert(hasToString!(D, char) == constCharSink);
+        static assert(hasToString!(E, char) == hasSomeToString);
+        static assert(hasToString!(F, char) == customPutWriterFormatSpec);
+        static assert(hasToString!(G, char) == customPutWriter);
+        static assert(hasToString!(H, char) == customPutWriterFormatSpec);
+        static assert(hasToString!(I, char) == customPutWriterFormatSpec);
+        static assert(hasToString!(J, char) == hasSomeToString);
+        static assert(hasToString!(K, char) == constCharSinkFormatSpec);
+        static assert(hasToString!(L, char) == none);
+        static if (hasPreviewIn)
+        {
+            static assert(hasToString!(M, char) == inCharSinkFormatSpec);
+            static assert(hasToString!(N, char) == inCharSinkFormatString);
+            static assert(hasToString!(O, char) == inCharSink);
+        }
+
+        // https://issues.dlang.org/show_bug.cgi?id=22873
+        static assert(hasToString!(inout(A), char) == customPutWriter);
+        static assert(hasToString!(inout(B), char) == constCharSinkFormatSpec);
+        static assert(hasToString!(inout(C), char) == constCharSinkFormatString);
+        static assert(hasToString!(inout(D), char) == constCharSink);
+        static assert(hasToString!(inout(E), char) == hasSomeToString);
+        static assert(hasToString!(inout(F), char) == customPutWriterFormatSpec);
+        static assert(hasToString!(inout(G), char) == customPutWriter);
+        static assert(hasToString!(inout(H), char) == customPutWriterFormatSpec);
+        static assert(hasToString!(inout(I), char) == customPutWriterFormatSpec);
+        static assert(hasToString!(inout(J), char) == hasSomeToString);
+        static assert(hasToString!(inout(K), char) == constCharSinkFormatSpec);
+        static assert(hasToString!(inout(L), char) == none);
+        static if (hasPreviewIn)
+        {
+            static assert(hasToString!(inout(M), char) == inCharSinkFormatSpec);
+            static assert(hasToString!(inout(N), char) == inCharSinkFormatString);
+            static assert(hasToString!(inout(O), char) == inCharSink);
+        }
+    }
+}
+
 // object formatting with toString
 private void formatObject(Writer, T, Char)(ref Writer w, ref T val, scope const ref FormatSpec!Char f)
 if (hasToString!(T, Char))
index 6c9e9ae..76d68f6 100644 (file)
@@ -1589,7 +1589,7 @@ char[] sformat(alias fmt, Args...)(char[] buf, Args args)
 if (isSomeString!(typeof(fmt)))
 {
     alias e = checkFormatException!(fmt, Args);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .sformat(buf, fmt, args);
 }
 
index b3d8d1f..144fa8c 100644 (file)
@@ -305,7 +305,7 @@ if (isSomeString!(typeof(fmt)))
     import std.format : checkFormatException;
 
     alias e = checkFormatException!(fmt, Args);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .formattedRead(r, fmt, args);
 }
 
index e67d95c..cbab512 100644 (file)
@@ -677,7 +677,7 @@ if (isSomeString!(typeof(fmt)))
     import std.format : checkFormatException;
 
     alias e = checkFormatException!(fmt, Args);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .formattedWrite(w, fmt, args);
 }
 
index 90b0f91..70aaee3 100644 (file)
@@ -65,6 +65,7 @@ module std.functional;
 
 import std.meta : AliasSeq, Reverse;
 import std.traits : isCallable, Parameters;
+import std.conv : toCtString;
 
 import std.internal.attributes : betterC;
 
@@ -1848,17 +1849,6 @@ if (isCallable!(F))
     }
 }
 
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
-    assert(toCtString!0 == "0");
-    assert(toCtString!123456 == "123456");
-}
-
 /**
  * Passes the fields of a struct as arguments to a function.
  *
index 89def0f..c6e746a 100644 (file)
@@ -321,7 +321,7 @@ struct JSONValue
        (*a)[0] = "world";  // segmentation fault
        ---
      */
-    @property ref inout(JSONValue[]) array() return scope inout pure @system
+    @property ref inout(JSONValue[]) array() scope return inout pure @system
     {
         enforce!JSONException(type == JSONType.array,
                                 "JSONValue is not an array");
index 9590238..c434481 100644 (file)
@@ -331,7 +331,7 @@ class OutBuffer
         import std.format : checkFormatException;
 
         alias e = checkFormatException!(fmt, A);
-        static assert(!e, e.msg);
+        static assert(!e, e);
         return this.writef(fmt, args);
     }
 
@@ -377,7 +377,7 @@ class OutBuffer
         import std.format : checkFormatException;
 
         alias e = checkFormatException!(fmt, A);
-        static assert(!e, e.msg);
+        static assert(!e, e);
         return this.writefln(fmt, args);
     }
 
index 971cfa0..2c97638 100644 (file)
@@ -1039,6 +1039,11 @@ uint totalCPUsImpl() @nogc nothrow @trusted
         import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
         return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
     }
+    else version (Hurd)
+    {
+        import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+        return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+    }
     else
     {
         static assert(0, "Don't know how to get N CPUs on this OS.");
index 2c68f36..28bfb04 100644 (file)
@@ -299,10 +299,9 @@ static:
         }
         else version (Windows)
         {
-            import std.exception : enforce;
-            enforce(
+            import std.windows.syserror : wenforce;
+            wenforce(
                 SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
-                sysErrorString(GetLastError())
             );
             return value;
         }
@@ -1330,7 +1329,7 @@ private Pid spawnProcessWin(scope const(char)[] commandLine,
                 {
                     throw new StdioException(
                         "Failed to make "~which~" stream inheritable by child process ("
-                        ~sysErrorString(GetLastError()) ~ ')',
+                        ~generateSysErrorMsg() ~ ')',
                         0);
                 }
             }
@@ -2775,7 +2774,7 @@ Pipe pipe() @trusted //TODO: @safe
     if (!CreatePipe(&readHandle, &writeHandle, null, 0))
     {
         throw new StdioException(
-            "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
+            "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
             0);
     }
 
@@ -3475,7 +3474,7 @@ class ProcessException : Exception
                                              string file = __FILE__,
                                              size_t line = __LINE__)
     {
-        auto lastMsg = sysErrorString(GetLastError());
+        auto lastMsg = generateSysErrorMsg();
         auto msg = customMsg.empty ? lastMsg
                                    : customMsg ~ " (" ~ lastMsg ~ ')';
         return new ProcessException(msg, file, line);
index cd23232..915159f 100644 (file)
@@ -169,7 +169,7 @@ string formatSocketError(int err) @trusted
     else
     version (Windows)
     {
-        return sysErrorString(err);
+        return generateSysErrorMsg(err);
     }
     else
         return "Socket error " ~ to!string(err);
@@ -842,7 +842,7 @@ private string formatGaiError(int err) @trusted
 {
     version (Windows)
     {
-        return sysErrorString(err);
+        return generateSysErrorMsg(err);
     }
     else
     {
index bc2d3fe..1bde73d 100644 (file)
@@ -1458,6 +1458,7 @@ Throws: `Exception` if the file is not opened.
     {
         import core.sys.windows.winbase : OVERLAPPED;
         import core.sys.windows.winnt : BOOL, ULARGE_INTEGER;
+        import std.windows.syserror : wenforce;
 
         private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length,
             Flags flags)
@@ -1474,15 +1475,6 @@ Throws: `Exception` if the file is not opened.
             return F(windowsHandle, flags, 0, liLength.LowPart,
                 liLength.HighPart, &overlapped);
         }
-
-        private static T wenforce(T)(T cond, lazy string str)
-        {
-            import core.sys.windows.winbase : GetLastError;
-            import std.windows.syserror : sysErrorString;
-
-            if (cond) return cond;
-            throw new Exception(str ~ ": " ~ sysErrorString(GetLastError()));
-        }
     }
     version (Posix)
     {
@@ -1783,7 +1775,7 @@ Throws: `Exception` if the file is not opened.
         import std.format : checkFormatException;
 
         alias e = checkFormatException!(fmt, A);
-        static assert(!e, e.msg);
+        static assert(!e, e);
         return this.writef(fmt, args);
     }
 
@@ -1802,7 +1794,7 @@ Throws: `Exception` if the file is not opened.
         import std.format : checkFormatException;
 
         alias e = checkFormatException!(fmt, A);
-        static assert(!e, e.msg);
+        static assert(!e, e);
         return this.writefln(fmt, args);
     }
 
@@ -2151,7 +2143,7 @@ $(CONSOLE
         import std.format : checkFormatException;
 
         alias e = checkFormatException!(format, Data);
-        static assert(!e, e.msg);
+        static assert(!e, e);
         return this.readf(format, data);
     }
 
@@ -4388,7 +4380,7 @@ if (isSomeString!(typeof(fmt)))
     import std.format : checkFormatException;
 
     alias e = checkFormatException!(fmt, A);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .writef(fmt, args);
 }
 
@@ -4429,7 +4421,7 @@ if (isSomeString!(typeof(fmt)))
     import std.format : checkFormatException;
 
     alias e = checkFormatException!(fmt, A);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .writefln(fmt, args);
 }
 
@@ -4510,7 +4502,7 @@ if (isSomeString!(typeof(format)))
     import std.format : checkFormatException;
 
     alias e = checkFormatException!(format, A);
-    static assert(!e, e.msg);
+    static assert(!e, e);
     return .readf(format, args);
 }
 
index f4f4216..dac531f 100644 (file)
@@ -237,21 +237,11 @@ import std.traits : ConstOf, ImmutableOf, InoutOf, TemplateArgsOf;
 import std.traits : CommonType, DeducedParameterType;
 import std.typecons : ReplaceTypeUnless;
 import std.typecons : Flag;
+import std.conv : toCtString;
 
 /// Placeholder used to refer to the enclosing [SumType].
 struct This {}
 
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
-    assert(toCtString!0 == "0");
-    assert(toCtString!123456 == "123456");
-}
-
 // True if a variable of type T can appear on the lhs of an assignment
 private enum isAssignableTo(T) =
     isAssignable!T || (!isCopyable!T && isRvalueAssignable!T);
index ea8f8bd..1ee7faa 100644 (file)
@@ -3109,6 +3109,64 @@ struct Nullable(T)
     {
         return isNull ? fallback : _value.payload;
     }
+
+    /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
+    alias empty = isNull;
+
+    /// ditto
+    alias popFront = nullify;
+
+    /// ditto
+    alias popBack = nullify;
+
+    /// ditto
+    @property ref inout(T) front() inout @safe pure nothrow
+    {
+        return get();
+    }
+
+    /// ditto
+    alias back = front;
+
+    /// ditto
+    @property inout(typeof(this)) save() inout
+    {
+        return this;
+    }
+
+    /// ditto
+    inout(typeof(this)) opIndex() inout
+    {
+        return this;
+    }
+
+    /// ditto
+    inout(typeof(this)) opIndex(size_t[2] dim) inout
+    in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
+    {
+        return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
+    }
+    /// ditto
+    size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
+    {
+        return [from, to];
+    }
+
+    /// ditto
+    @property size_t length() const @safe pure nothrow
+    {
+        return !empty;
+    }
+
+    /// ditto
+    alias opDollar(size_t dim : 0) = length;
+
+    /// ditto
+    ref inout(T) opIndex(size_t index) inout @safe pure nothrow
+    in (index < length)
+    {
+        return get();
+    }
 }
 
 /// ditto
@@ -3162,6 +3220,23 @@ auto nullable(T)(T t)
     assert(a.isNull);
     assertThrown!Throwable(a.get);
 }
+///
+@safe unittest
+{
+    import std.algorithm.iteration : each, joiner;
+    Nullable!int a = 42;
+    Nullable!int b;
+    // Add each value to an array
+    int[] arr;
+    a.each!((n) => arr ~= n);
+    assert(arr == [42]);
+    b.each!((n) => arr ~= n);
+    assert(arr == [42]);
+    // Take first value from an array of Nullables
+    Nullable!int[] c = new Nullable!int[](10);
+    c[7] = Nullable!int(42);
+    assert(c.joiner.front == 42);
+}
 @safe unittest
 {
     auto k = Nullable!int(74);
@@ -3638,6 +3713,42 @@ auto nullable(T)(T t)
     a = b = c = nullable(5);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=18374
+@safe pure nothrow unittest
+{
+    import std.algorithm.comparison : equal;
+    import std.range : only, takeNone;
+    import std.range.primitives : hasAssignableElements, hasLength,
+        hasLvalueElements, hasSlicing, hasSwappableElements,
+        isRandomAccessRange;
+    Nullable!int a = 42;
+    assert(!a.empty);
+    assert(a.front == 42);
+    assert(a.back == 42);
+    assert(a[0] == 42);
+    assert(a.equal(only(42)));
+    assert(a[0 .. $].equal(only(42)));
+    a[0] = 43;
+    assert(a.equal(only(43)));
+    --a[0];
+    assert(a.equal(only(42)));
+    Nullable!int b;
+    assert(b.empty);
+    assert(b.equal(takeNone(b)));
+    Nullable!int c = a.save();
+    assert(!c.empty);
+    c.popFront();
+    assert(!a.empty);
+    assert(c.empty);
+
+    assert(isRandomAccessRange!(Nullable!int));
+    assert(hasLength!(Nullable!int));
+    assert(hasSlicing!(Nullable!int));
+    assert(hasAssignableElements!(Nullable!int));
+    assert(hasSwappableElements!(Nullable!int));
+    assert(hasLvalueElements!(Nullable!int));
+}
+
 /**
 Just like `Nullable!T`, except that the null state is defined as a
 particular value. For example, $(D Nullable!(uint, uint.max)) is an
@@ -8793,19 +8904,6 @@ private:
     enum isBaseEnumType(T) = is(E == T);
     alias Base = OriginalType!E;
     Base mValue;
-    static struct Negation
-    {
-    @safe @nogc pure nothrow:
-    private:
-        Base mValue;
-
-        // Prevent non-copy construction outside the module.
-        @disable this();
-        this(Base value)
-        {
-            mValue = value;
-        }
-    }
 
 public:
     this(E flag)
@@ -8830,10 +8928,10 @@ public:
         return mValue;
     }
 
-    Negation opUnary(string op)() const
+    auto opUnary(string op)() const
         if (op == "~")
     {
-        return Negation(~mValue);
+        return BitFlags(cast(E) cast(Base) ~mValue);
     }
 
     auto ref opAssign(T...)(T flags)
@@ -8877,12 +8975,6 @@ public:
         return this;
     }
 
-    auto ref opOpAssign(string op: "&")(Negation negatedFlags)
-    {
-        mValue &= negatedFlags.mValue;
-        return this;
-    }
-
     auto opBinary(string op)(BitFlags flags) const
         if (op == "|" || op == "&")
     {
@@ -8899,13 +8991,6 @@ public:
         return result;
     }
 
-    auto opBinary(string op: "&")(Negation negatedFlags) const
-    {
-        BitFlags result = this;
-        result.opOpAssign!op(negatedFlags);
-        return result;
-    }
-
     auto opBinaryRight(string op)(E flag) const
         if (op == "|" || op == "&")
     {
@@ -9104,6 +9189,34 @@ public:
     assert(flags.A && !flags.B && !flags.C);
 }
 
+// Negation of BitFlags should work with any base type.
+// Double-negation of BitFlags should work.
+@safe @nogc pure nothrow unittest
+{
+    static foreach (alias Base; AliasSeq!(
+        byte,
+        ubyte,
+        short,
+        ushort,
+        int,
+        uint,
+        long,
+        ulong,
+    ))
+    {{
+        enum Enum : Base
+        {
+            A = 1 << 0,
+            B = 1 << 1,
+            C = 1 << 2,
+        }
+
+        auto flags = BitFlags!Enum(Enum.A);
+
+        assert(flags == ~~flags);
+    }}
+}
+
 private enum false_(T) = false;
 
 // ReplaceType
index eeeda72..98735ac 100644 (file)
@@ -9834,25 +9834,29 @@ dchar toLower(dchar c)
     Returns:
         An array with the same element type as `s`.
 +/
-ElementEncodingType!S[] toLower(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toLower(S)(return scope S s) @trusted
+if (isSomeString!S)
 {
     static import std.ascii;
+    return toCase!(LowerTriple, std.ascii.toLower)(s);
+}
 
-    static if (isSomeString!S)
-        return () @trusted { return toCase!(LowerTriple, std.ascii.toLower)(s); } ();
-    else
-        return toCase!(LowerTriple, std.ascii.toLower)(s);
+/// ditto
+ElementEncodingType!S[] toLower(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+    static import std.ascii;
+    return toCase!(LowerTriple, std.ascii.toLower)(s);
 }
 
 // overloads for the most common cases to reduce compile time
 @safe pure /*TODO nothrow*/
 {
-    string toLower(string s)
+    string toLower(return scope string s)
     { return toLower!string(s); }
-    wstring toLower(wstring s)
+    wstring toLower(return scope wstring s)
     { return toLower!wstring(s); }
-    dstring toLower(dstring s)
+    dstring toLower(return scope dstring s)
     { return toLower!dstring(s); }
 
     @safe unittest
@@ -10038,25 +10042,29 @@ dchar toUpper(dchar c)
     Returns:
         An new array with the same element type as `s`.
 +/
-ElementEncodingType!S[] toUpper(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toUpper(S)(return scope S s) @trusted
+if (isSomeString!S)
 {
     static import std.ascii;
+    return toCase!(UpperTriple, std.ascii.toUpper)(s);
+}
 
-    static if (isSomeString!S)
-        return () @trusted { return toCase!(UpperTriple, std.ascii.toUpper)(s); } ();
-    else
-        return toCase!(UpperTriple, std.ascii.toUpper)(s);
+/// ditto
+ElementEncodingType!S[] toUpper(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+    static import std.ascii;
+    return toCase!(UpperTriple, std.ascii.toUpper)(s);
 }
 
 // overloads for the most common cases to reduce compile time
 @safe pure /*TODO nothrow*/
 {
-    string toUpper(string s)
+    string toUpper(return scope string s)
     { return toUpper!string(s); }
-    wstring toUpper(wstring s)
+    wstring toUpper(return scope wstring s)
     { return toUpper!wstring(s); }
-    dstring toUpper(dstring s)
+    dstring toUpper(return scope dstring s)
     { return toUpper!dstring(s); }
 
     @safe unittest
index 69626b5..ce33616 100644 (file)
@@ -76,12 +76,7 @@ const(char)* toMBSz(scope const(char)[] s, uint codePage = 0)
                         to!int(result.length), null, null);
             }
 
-            if (!readLen || readLen != result.length)
-            {
-                throw new Exception("Couldn't convert string: " ~
-                        sysErrorString(GetLastError()));
-            }
-
+            wenforce(readLen && readLen == result.length, "Couldn't convert string");
             return result.ptr;
         }
     }
@@ -107,16 +102,10 @@ string fromMBSz(return scope immutable(char)* s, int codePage = 0)
                         to!int(result.length));
             }
 
-            if (!readLen || readLen != result.length)
-            {
-                throw new Exception("Couldn't convert string: " ~
-                    sysErrorString(GetLastError()));
-            }
+            wenforce(readLen && readLen == result.length, "Couldn't convert string");
 
             return result[0 .. result.length-1].to!string; // omit trailing null
         }
     }
     return s[0 .. c-s];         // string is ASCII, no conversion necessary
 }
-
-
index 94f8ee5..3d8c5e7 100644 (file)
@@ -43,7 +43,7 @@ version (StdDdoc)
     {
         private alias DWORD = int;
         final @property DWORD code(); /// `GetLastError`'s return value.
-        this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted;
+        this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted;
     }
 
     /++
@@ -66,9 +66,9 @@ else:
 version (Windows):
 
 import core.sys.windows.winbase, core.sys.windows.winnt;
-import std.array : appender;
-import std.conv : to;
-import std.format.write : formattedWrite;
+import std.array : appender, Appender;
+import std.conv : to, toTextRange, text;
+import std.exception;
 import std.windows.charset;
 
 string sysErrorString(
@@ -79,16 +79,25 @@ string sysErrorString(
 {
     auto buf = appender!string();
 
-    if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId)))
-    {
-        throw new Exception(
-            "failed getting error string for WinAPI error code: " ~
-            sysErrorString(GetLastError()));
-    }
+    wenforce(
+        // Ignore unlikely UTF decoding errors, always report the actual error (`errCode`)
+        putSysError(errCode, buf, MAKELANGID(langId, subLangId)).ifThrown(false),
+        text("Could not fetch error string for WinAPI code ", errCode)
+    );
 
     return buf.data;
 }
 
+@safe unittest
+{
+    import std.algorithm.searching;
+
+    assert(sysErrorString(ERROR_PATH_NOT_FOUND) !is null);
+
+    const msg = collectExceptionMsg!WindowsException(sysErrorString(DWORD.max));
+    assert(msg.startsWith(`Could not fetch error string for WinAPI code 4294967295: `));
+}
+
 bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0)
 {
     wchar *lpMsgBuf = null;
@@ -114,7 +123,6 @@ bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0)
         return false;
 }
 
-
 class WindowsException : Exception
 {
     import core.sys.windows.windef : DWORD;
@@ -122,11 +130,11 @@ class WindowsException : Exception
     final @property DWORD code() { return _code; } /// `GetLastError`'s return value.
     private DWORD _code;
 
-    this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted
+    this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted
     {
         _code = code;
 
-        auto buf = appender!string();
+        auto buf = appender!(char[]);
 
         if (str != null)
         {
@@ -135,18 +143,43 @@ class WindowsException : Exception
                 buf.put(": ");
         }
 
-        if (code)
+        if (code && writeErrorMessage(code, buf))
         {
-            auto success = putSysError(code, buf);
-            formattedWrite(buf, success ? " (error %d)" : "Error %d", code);
+            buf.put(" (error ");
+            toTextRange(code, buf);
+            buf.put(')');
         }
 
-        super(buf.data, file, line);
+        super(cast(immutable) buf.data, file, line);
     }
 }
 
+/// Writes the error string associated to `code` into `buf`.
+/// Writes `Error <code>` when the error message lookup fails
+private bool writeErrorMessage(DWORD code, ref Appender!(char[]) buf) nothrow
+{
+    bool success;
+    try
+    {
+        // Reset the buffer to undo partial changes
+        const len = buf[].length;
+        scope (failure) buf.shrinkTo(len);
 
-T wenforce(T, S)(T value, lazy S msg = null,
+        success = putSysError(code, buf);
+    }
+    catch (Exception) {}
+
+    // Write the error code instead if we couldn't find the string
+    if (!success)
+    {
+        buf.put("Error ");
+        toTextRange(code, buf);
+    }
+
+    return success;
+}
+
+T wenforce(T, S = string)(T value, lazy S msg = null,
 string file = __FILE__, size_t line = __LINE__)
 if (isSomeString!S)
 {
@@ -177,11 +210,9 @@ T wenforce(T)(T condition, const(char)[] name, const(wchar)* namez, string file
     throw new WindowsException(GetLastError(), names, file, line);
 }
 
-version (Windows)
 @system unittest
 {
     import std.algorithm.searching : startsWith, endsWith;
-    import std.exception;
     import std.string;
 
     auto e = collectException!WindowsException(
@@ -199,3 +230,29 @@ version (Windows)
     e = new WindowsException(0, "Test");
     assert(e.msg == "Test");
 }
+
+@safe nothrow unittest
+{
+    import std.algorithm.searching : endsWith;
+
+    auto e = new WindowsException(ERROR_FILE_NOT_FOUND);
+    assert(e.msg.endsWith("(error 2)"));
+
+    e = new WindowsException(DWORD.max);
+    assert(e.msg == "Error 4294967295");
+}
+
+/// Tries to translate an error code from the Windows API to the corresponding
+/// error message. Returns `Error <code>` on failure
+package (std) string generateSysErrorMsg(DWORD errCode = GetLastError()) nothrow @trusted
+{
+    auto buf = appender!(char[]);
+    cast(void) writeErrorMessage(errCode, buf);
+    return cast(immutable) buf[];
+}
+
+nothrow @safe unittest
+{
+    assert(generateSysErrorMsg(ERROR_PATH_NOT_FOUND) !is null);
+    assert(generateSysErrorMsg(DWORD.max) == "Error 4294967295");
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/message_with_null.d b/libphobos/testsuite/libphobos.exceptions/message_with_null.d
new file mode 100644 (file)
index 0000000..64092f0
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-shouldfail " world!" }
+// { dg-output "object.Exception@.*: hello.*world!" }
+module message_with_null;
+
+void main()
+{
+    throw new Exception("hello\0 world!");
+}