public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/ibuclaw/heads/gdc)] Import dmd v2.097.0: dmd 2a48c54ad, druntime c3a4c517, phobos 61c00065a
@ 2021-07-30  8:44 Iain Buclaw
  0 siblings, 0 replies; only message in thread
From: Iain Buclaw @ 2021-07-30  8:44 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:7881f57cd49ca75ac8da796be150e65474a76e3c

commit 7881f57cd49ca75ac8da796be150e65474a76e3c
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Sat Apr 24 01:35:50 2021 +0200

    Import dmd v2.097.0: dmd 2a48c54ad, druntime c3a4c517, phobos 61c00065a

Diff:
---
 gcc/d/Make-lang.in                                 |     4 +-
 gcc/d/d-attribs.cc                                 |     1 +
 gcc/d/d-builtins.cc                                |    21 +-
 gcc/d/d-codegen.cc                                 |    42 +-
 gcc/d/d-compiler.cc                                |    14 +-
 gcc/d/d-convert.cc                                 |    71 +-
 gcc/d/d-frontend.cc                                |     2 +-
 gcc/d/d-lang.cc                                    |    59 +-
 gcc/d/d-target.cc                                  |    97 +-
 gcc/d/d-target.def                                 |    17 -
 gcc/d/decl.cc                                      |    67 +-
 gcc/d/dmd/MERGE                                    |     2 +-
 gcc/d/dmd/README.md                                |     8 +-
 gcc/d/dmd/VERSION                                  |     2 +-
 gcc/d/dmd/access.d                                 |    79 +-
 gcc/d/dmd/aggregate.d                              |    63 +-
 gcc/d/dmd/aggregate.h                              |    74 +-
 gcc/d/dmd/aliasthis.d                              |    53 +-
 gcc/d/dmd/aliasthis.h                              |     2 +-
 gcc/d/dmd/apply.d                                  |    82 +-
 gcc/d/dmd/arrayop.d                                |     3 +-
 gcc/d/dmd/arraytypes.d                             |     5 +-
 gcc/d/dmd/arraytypes.h                             |     5 +
 gcc/d/dmd/ast_node.d                               |     2 +-
 gcc/d/dmd/astcodegen.d                             |    17 +-
 gcc/d/dmd/astenums.d                               |   347 +
 gcc/d/dmd/attrib.d                                 |   212 +-
 gcc/d/dmd/attrib.h                                 |    39 +-
 gcc/d/dmd/blockexit.d                              |     5 +-
 gcc/d/dmd/builtin.d                                |     2 +-
 gcc/d/dmd/canthrow.d                               |     3 +-
 gcc/d/dmd/chkformat.d                              |   210 +-
 gcc/d/dmd/clone.d                                  |   510 +-
 gcc/d/dmd/compiler.d                               |     5 +-
 gcc/d/dmd/compiler.h                               |     3 -
 gcc/d/dmd/complex.d                                |     2 +-
 gcc/d/dmd/cond.d                                   |    63 +-
 gcc/d/dmd/cond.h                                   |     4 +-
 gcc/d/dmd/constfold.d                              |    10 +-
 gcc/d/dmd/cparse.d                                 |  4052 +++++++
 gcc/d/dmd/cppmangle.d                              |   598 +-
 gcc/d/dmd/ctfeexpr.d                               |    11 +-
 gcc/d/dmd/ctorflow.d                               |     2 +-
 gcc/d/dmd/dcast.d                                  |   599 +-
 gcc/d/dmd/dclass.d                                 |    38 +-
 gcc/d/dmd/declaration.d                            |   300 +-
 gcc/d/dmd/declaration.h                            |    76 +-
 gcc/d/dmd/delegatize.d                             |     3 +-
 gcc/d/dmd/denum.d                                  |    81 +-
 gcc/d/dmd/dimport.d                                |    73 +-
 gcc/d/dmd/dinterpret.d                             |   235 +-
 gcc/d/dmd/dmacro.d                                 |     2 +-
 gcc/d/dmd/dmangle.d                                |   292 +-
 gcc/d/dmd/dmodule.d                                |   317 +-
 gcc/d/dmd/doc.d                                    |    67 +-
 gcc/d/dmd/dscope.d                                 |   127 +-
 gcc/d/dmd/dstruct.d                                |    88 +-
 gcc/d/dmd/dsymbol.d                                |   350 +-
 gcc/d/dmd/dsymbol.h                                |    29 +-
 gcc/d/dmd/dsymbolsem.d                             |  1709 ++-
 gcc/d/dmd/dtemplate.d                              |   553 +-
 gcc/d/dmd/dtoh.d                                   |  2528 +++--
 gcc/d/dmd/dversion.d                               |     6 +-
 gcc/d/dmd/entity.d                                 |     2 +-
 gcc/d/dmd/enum.h                                   |     8 +-
 gcc/d/dmd/errors.d                                 |    94 +-
 gcc/d/dmd/errors.h                                 |     4 +-
 gcc/d/dmd/escape.d                                 |   117 +-
 gcc/d/dmd/expression.d                             |   179 +-
 gcc/d/dmd/expression.h                             |    59 +-
 gcc/d/dmd/expressionsem.d                          |   715 +-
 gcc/d/dmd/foreachvar.d                             |     3 +-
 gcc/d/dmd/func.d                                   |   186 +-
 gcc/d/dmd/globals.d                                |   341 +-
 gcc/d/dmd/globals.h                                |   130 +-
 gcc/d/dmd/gluelayer.d                              |     2 +-
 gcc/d/dmd/hdrgen.d                                 |   393 +-
 gcc/d/dmd/iasm.d                                   |     2 +-
 gcc/d/dmd/iasmgcc.d                                |    35 +-
 gcc/d/dmd/id.d                                     |    21 +-
 gcc/d/dmd/id.h                                     |     2 +-
 gcc/d/dmd/identifier.d                             |     2 +-
 gcc/d/dmd/impcnvtab.d                              |    63 +-
 gcc/d/dmd/imphint.d                                |     2 +-
 gcc/d/dmd/import.h                                 |     8 +-
 gcc/d/dmd/init.d                                   |   151 +-
 gcc/d/dmd/init.h                                   |    24 +
 gcc/d/dmd/initsem.d                                |   615 +-
 gcc/d/dmd/inline.d                                 |     2 +-
 gcc/d/dmd/intrange.d                               |     3 +-
 gcc/d/dmd/json.d                                   |    49 +-
 gcc/d/dmd/lambdacomp.d                             |     3 +-
 gcc/d/dmd/lexer.d                                  |   585 +-
 gcc/d/dmd/module.h                                 |     6 +-
 gcc/d/dmd/mtype.d                                  |   564 +-
 gcc/d/dmd/mtype.h                                  |    82 +-
 gcc/d/dmd/nogc.d                                   |     3 +-
 gcc/d/dmd/nspace.d                                 |    12 +-
 gcc/d/dmd/nspace.h                                 |     2 +-
 gcc/d/dmd/ob.d                                     |     7 +-
 gcc/d/dmd/objc.d                                   |   155 +-
 gcc/d/dmd/objc.h                                   |     7 +-
 gcc/d/dmd/opover.d                                 |    53 +-
 gcc/d/dmd/optimize.d                               |    53 +-
 gcc/d/dmd/parse.d                                  |  1815 ++--
 gcc/d/dmd/parsetimevisitor.d                       |     6 +-
 gcc/d/dmd/printast.d                               |    73 +-
 gcc/d/dmd/root/aav.d                               |     2 +-
 gcc/d/dmd/root/array.d                             |    37 +-
 gcc/d/dmd/root/array.h                             |    28 +-
 gcc/d/dmd/root/bitarray.d                          |    27 +-
 gcc/d/dmd/root/bitarray.h                          |     4 +-
 gcc/d/dmd/root/ctfloat.d                           |     6 +-
 gcc/d/dmd/root/ctfloat.h                           |     2 +-
 gcc/d/dmd/root/dcompat.h                           |    12 +
 gcc/d/dmd/root/file.d                              |   564 +-
 gcc/d/dmd/root/file.h                              |     2 +-
 gcc/d/dmd/root/filename.d                          |   184 +-
 gcc/d/dmd/root/filename.h                          |     3 +-
 gcc/d/dmd/root/hash.d                              |     2 +-
 gcc/d/dmd/root/longdouble.d                        |     2 +-
 gcc/d/dmd/root/object.h                            |     2 +-
 gcc/d/dmd/root/outbuffer.d                         |   145 +-
 gcc/d/dmd/root/outbuffer.h                         |     6 +-
 gcc/d/dmd/root/port.d                              |     2 +-
 gcc/d/dmd/root/port.h                              |     2 +-
 gcc/d/dmd/root/region.d                            |    10 +-
 gcc/d/dmd/root/rmem.d                              |   246 +-
 gcc/d/dmd/root/rmem.h                              |     4 +-
 gcc/d/dmd/root/root.h                              |     2 +-
 gcc/d/dmd/root/rootobject.d                        |     3 +-
 gcc/d/dmd/root/speller.d                           |   273 +-
 gcc/d/dmd/root/string.d                            |     4 +-
 gcc/d/dmd/root/stringtable.d                       |    31 +-
 gcc/d/dmd/safe.d                                   |    15 +-
 gcc/d/dmd/sapply.d                                 |    17 +-
 gcc/d/dmd/scope.h                                  |    80 +-
 gcc/d/dmd/semantic2.d                              |   411 +-
 gcc/d/dmd/semantic3.d                              |   326 +-
 gcc/d/dmd/sideeffect.d                             |    32 +-
 gcc/d/dmd/statement.d                              |   156 +-
 gcc/d/dmd/statement.h                              |    83 +-
 gcc/d/dmd/statement_rewrite_walker.d               |     2 +-
 gcc/d/dmd/statementsem.d                           |  1382 +--
 gcc/d/dmd/staticassert.d                           |     4 +-
 gcc/d/dmd/staticassert.h                           |     2 +-
 gcc/d/dmd/staticcond.d                             |     2 +-
 gcc/d/dmd/stmtstate.d                              |     2 +-
 gcc/d/dmd/target.d                                 |   168 +-
 gcc/d/dmd/target.h                                 |   102 +-
 gcc/d/dmd/template.h                               |    25 +-
 gcc/d/dmd/templateparamsem.d                       |    56 +-
 gcc/d/dmd/tokens.d                                 |   157 +-
 gcc/d/dmd/tokens.h                                 |    33 +-
 gcc/d/dmd/traits.d                                 |   182 +-
 gcc/d/dmd/transitivevisitor.d                      |   101 +-
 gcc/d/dmd/typesem.d                                |   384 +-
 gcc/d/dmd/typinf.d                                 |     2 +-
 gcc/d/dmd/utf.d                                    |     2 +-
 gcc/d/dmd/utils.d                                  |    76 +-
 gcc/d/dmd/version.h                                |     4 +-
 gcc/d/dmd/visitor.d                                |    10 +-
 gcc/d/dmd/visitor.h                                |    13 +-
 gcc/d/expr.cc                                      |   158 +-
 gcc/d/imports.cc                                   |     6 +-
 gcc/d/intrinsics.def                               |    97 +-
 gcc/d/lang.opt                                     |    23 +-
 gcc/d/modules.cc                                   |    13 +-
 gcc/d/toir.cc                                      |    16 +-
 gcc/d/typeinfo.cc                                  |    36 +-
 gcc/d/types.cc                                     |    71 +-
 gcc/doc/tm.texi.in                                 |     4 -
 gcc/testsuite/gdc.dg/Wcastresult2.d                |     2 +-
 gcc/testsuite/gdc.dg/imports/gdc170.d              |     8 +-
 gcc/testsuite/gdc.dg/intrinsics.d                  |    26 +-
 gcc/testsuite/gdc.dg/pr98277.d                     |     2 +-
 gcc/testsuite/gdc.dg/pr98457.d                     |     6 +-
 gcc/testsuite/gdc.dg/torture/gdc309.d              |     1 +
 gcc/testsuite/gdc.dg/torture/pr94777b.d            |    97 -
 gcc/testsuite/gdc.test/compilable/aliasassign.d    |    41 +
 gcc/testsuite/gdc.test/compilable/b12504.d         |    20 +
 gcc/testsuite/gdc.test/compilable/b21285.d         |    27 +
 gcc/testsuite/gdc.test/compilable/callconv.d       |     8 -
 gcc/testsuite/gdc.test/compilable/checkimports3.d  |     6 -
 gcc/testsuite/gdc.test/compilable/compile1.d       |     5 +
 gcc/testsuite/gdc.test/compilable/cppmangle.d      |    46 +-
 gcc/testsuite/gdc.test/compilable/cppmangle3.d     |     8 +-
 gcc/testsuite/gdc.test/compilable/ctfe_math.d      |     8 +-
 gcc/testsuite/gdc.test/compilable/ddoc15475.d      |     3 -
 gcc/testsuite/gdc.test/compilable/depsOutput9948.d |    23 -
 gcc/testsuite/gdc.test/compilable/diag12598.d      |     3 -
 gcc/testsuite/gdc.test/compilable/dip22d.d         |     6 -
 .../gdc.test/compilable/dtoh_AliasDeclaration.d    |   127 +-
 .../gdc.test/compilable/dtoh_AliasDeclaration_98.d |    56 +
 .../gdc.test/compilable/dtoh_AnonDeclaration.d     |    37 +-
 .../compilable/dtoh_CPPNamespaceDeclaration.d      |    28 +
 .../gdc.test/compilable/dtoh_ClassDeclaration.d    |   132 +-
 .../gdc.test/compilable/dtoh_StructDeclaration.d   |    86 +-
 .../gdc.test/compilable/dtoh_TemplateDeclaration.d |   368 +-
 .../gdc.test/compilable/dtoh_UnionDeclaration.d    |    93 +
 .../gdc.test/compilable/dtoh_VarDeclaration.d      |    66 +-
 .../gdc.test/compilable/dtoh_cpp98_compat.d        |   142 +
 gcc/testsuite/gdc.test/compilable/dtoh_enum.d      |   104 +-
 .../gdc.test/compilable/dtoh_enum_cpp98.d          |    78 +-
 .../gdc.test/compilable/dtoh_expressions.d         |   127 +
 .../gdc.test/compilable/dtoh_extern_type.d         |   115 +-
 .../gdc.test/compilable/dtoh_forwarding.d          |   257 +
 gcc/testsuite/gdc.test/compilable/dtoh_functions.d |   199 +-
 gcc/testsuite/gdc.test/compilable/dtoh_ignored.d   |   147 +
 .../gdc.test/compilable/dtoh_invalid_identifiers.d |   170 +
 gcc/testsuite/gdc.test/compilable/dtoh_names.d     |   260 +
 .../gdc.test/compilable/dtoh_protection.d          |   218 +
 .../gdc.test/compilable/dtoh_required_symbols.d    |   225 +
 .../gdc.test/compilable/dtoh_special_enum.d        |    90 +
 .../gdc.test/compilable/dtoh_unittest_block.d      |    29 +
 gcc/testsuite/gdc.test/compilable/dtoh_verbose.d   |   141 +-
 gcc/testsuite/gdc.test/compilable/dtorfields.d     |     3 +
 .../gdc.test/compilable/dtorfields_deprecation.d   |    49 +
 .../gdc.test/compilable/extra-files/dtoh_imports.d |    13 +
 .../compilable/extra-files/dtoh_imports2.d         |     3 +
 .../gdc.test/compilable/extra-files/header1.d      |    17 -
 .../gdc.test/compilable/extra-files/header2.d      |    24 +-
 gcc/testsuite/gdc.test/compilable/fix21647.d       |    10 +-
 gcc/testsuite/gdc.test/compilable/ice20415.d       |    16 +
 .../gdc.test/compilable/imports/cstuff3.c          |     6 +
 .../gdc.test/compilable/imports/depsOutput9948a.d  |     6 -
 .../gdc.test/compilable/imports/depsOutput9948b.d  |     6 -
 gcc/testsuite/gdc.test/compilable/interpret3.d     |    46 -
 gcc/testsuite/gdc.test/compilable/isZeroInit.d     |     7 -
 .../gdc.test/compilable/isreturnonstack.d          |     1 +
 gcc/testsuite/gdc.test/compilable/issue15478.d     |    36 +-
 gcc/testsuite/gdc.test/compilable/issue21726.d     |     1 +
 gcc/testsuite/gdc.test/compilable/json.d           |    29 +-
 gcc/testsuite/gdc.test/compilable/mixintype2.d     |     9 -
 gcc/testsuite/gdc.test/compilable/noreturn1.d      |    49 +-
 gcc/testsuite/gdc.test/compilable/ob1.d            |     4 +-
 gcc/testsuite/gdc.test/compilable/previewin.d      |    53 +-
 .../gdc.test/compilable/readmodify_structclass.d   |     7 +-
 gcc/testsuite/gdc.test/compilable/riia_ctor.d      |     1 +
 gcc/testsuite/gdc.test/compilable/scope.d          |   139 +
 gcc/testsuite/gdc.test/compilable/shared.d         |    16 +
 .../gdc.test/compilable/sw_transition_complex.d    |     6 +-
 gcc/testsuite/gdc.test/compilable/test11292.d      |     5 -
 gcc/testsuite/gdc.test/compilable/test1170.d       |     6 -
 gcc/testsuite/gdc.test/compilable/test15019.d      |     4 +-
 gcc/testsuite/gdc.test/compilable/test1537.d       |     8 +-
 gcc/testsuite/gdc.test/compilable/test15371.d      |    10 -
 gcc/testsuite/gdc.test/compilable/test1547.d       |     5 -
 gcc/testsuite/gdc.test/compilable/test15856.d      |     6 -
 gcc/testsuite/gdc.test/compilable/test16002.d      |     3 -
 gcc/testsuite/gdc.test/compilable/test17419.d      |     5 -
 gcc/testsuite/gdc.test/compilable/test17752.d      |     5 -
 gcc/testsuite/gdc.test/compilable/test17791.d      |     9 -
 gcc/testsuite/gdc.test/compilable/test19227.d      |     8 +
 gcc/testsuite/gdc.test/compilable/test19731.d      |    78 +
 gcc/testsuite/gdc.test/compilable/test19754.d      |     2 +-
 gcc/testsuite/gdc.test/compilable/test19809.d      |     7 +-
 gcc/testsuite/gdc.test/compilable/test20051.d      |     7 -
 gcc/testsuite/gdc.test/compilable/test20063.d      |    15 -
 gcc/testsuite/gdc.test/compilable/test20100.d      |    13 +-
 gcc/testsuite/gdc.test/compilable/test20136.d      |     6 -
 gcc/testsuite/gdc.test/compilable/test20406.d      |     5 -
 gcc/testsuite/gdc.test/compilable/test20835.d      |    15 +
 gcc/testsuite/gdc.test/compilable/test21217.d      |    54 -
 gcc/testsuite/gdc.test/compilable/test324.d        |    11 -
 gcc/testsuite/gdc.test/compilable/test9029.d       |     7 -
 gcc/testsuite/gdc.test/compilable/test9278a.d      |     2 +-
 gcc/testsuite/gdc.test/compilable/test9278b.d      |     2 +-
 gcc/testsuite/gdc.test/compilable/test930.d        |     6 -
 gcc/testsuite/gdc.test/compilable/test9613.d       |     2 +-
 gcc/testsuite/gdc.test/compilable/test9701.d       |     6 -
 gcc/testsuite/gdc.test/compilable/testCpCtor.d     |     5 +-
 gcc/testsuite/gdc.test/compilable/testInference.d  |     6 -
 .../gdc.test/compilable/testcheckimports.d         |     8 -
 gcc/testsuite/gdc.test/compilable/testcstuff1.c    |   499 +
 gcc/testsuite/gdc.test/compilable/testcstuff2.c    |   313 +
 gcc/testsuite/gdc.test/compilable/testcstuff3.d    |     4 +
 gcc/testsuite/gdc.test/compilable/testexpression.d |    24 -
 .../gdc.test/compilable/testheaderudamodule.d      |     4 -
 gcc/testsuite/gdc.test/compilable/testparse.d      |    12 +
 gcc/testsuite/gdc.test/compilable/traits.d         |   119 +-
 gcc/testsuite/gdc.test/compilable/vcg-ast.d        |    17 +
 gcc/testsuite/gdc.test/compilable/vtemplates.d     |     6 +-
 .../gdc.test/compilable/vtemplates_list.d          |    17 +-
 .../gdc.test/fail_compilation/aliasassign.d        |    21 +
 .../gdc.test/fail_compilation/aliasassign1.d       |    34 +
 gcc/testsuite/gdc.test/fail_compilation/b15909.d   |    15 +
 gcc/testsuite/gdc.test/fail_compilation/b19523.d   |     3 +-
 gcc/testsuite/gdc.test/fail_compilation/b20780.d   |     8 +-
 gcc/testsuite/gdc.test/fail_compilation/b3841.d    |    42 +-
 gcc/testsuite/gdc.test/fail_compilation/b6227.d    |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/bug15613.d |     3 -
 gcc/testsuite/gdc.test/fail_compilation/bug16165.d |     6 -
 gcc/testsuite/gdc.test/fail_compilation/bug18743.d |     6 +-
 gcc/testsuite/gdc.test/fail_compilation/bug9631.d  |    28 +-
 gcc/testsuite/gdc.test/fail_compilation/cconst1.c  |    21 +
 .../gdc.test/fail_compilation/checkimports2a.d     |    32 -
 .../gdc.test/fail_compilation/checkimports2b.d     |    29 -
 .../gdc.test/fail_compilation/checkimports2c.d     |    29 -
 .../gdc.test/fail_compilation/chkformat.d          |     7 -
 .../gdc.test/fail_compilation/cppmangle.d          |    12 +-
 gcc/testsuite/gdc.test/fail_compilation/dassert.d  |    43 +
 .../gdc.test/fail_compilation/ddoc_18083.d         |     6 +-
 .../fail_compilation/debugCaseDeclaration.d        |    39 +
 .../fail_compilation/deprecate_objc_interface.d    |    13 -
 .../gdc.test/fail_compilation/deprecations.d       |    11 +-
 .../gdc.test/fail_compilation/diag10169.d          |     4 -
 .../gdc.test/fail_compilation/diag12380.d          |     2 +-
 .../gdc.test/fail_compilation/diag12829.d          |     2 +-
 .../gdc.test/fail_compilation/diag13215.d          |    12 +
 .../gdc.test/fail_compilation/diag14145.d          |    38 +
 .../gdc.test/fail_compilation/diag14875.d          |    15 +-
 .../gdc.test/fail_compilation/diag15411.d          |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/diag1730.d |    26 +-
 .../gdc.test/fail_compilation/diag21883.d          |    16 +
 gcc/testsuite/gdc.test/fail_compilation/diag4596.d |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/diag5385.d |    11 -
 gcc/testsuite/gdc.test/fail_compilation/diag6707.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/diag8044.d |    19 +
 gcc/testsuite/gdc.test/fail_compilation/diag8101.d |    13 -
 .../gdc.test/fail_compilation/diag8101b.d          |    14 +-
 gcc/testsuite/gdc.test/fail_compilation/diag8178.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/diag8318.d |    27 +-
 gcc/testsuite/gdc.test/fail_compilation/diag9831.d |     2 +-
 .../fail_compilation/diag_debug_conditional.d      |    11 +
 .../fail_compilation/diag_template_alias.d         |    11 +
 .../gdc.test/fail_compilation/diag_template_this.d |    11 +
 gcc/testsuite/gdc.test/fail_compilation/diagin.d   |     8 +-
 gcc/testsuite/gdc.test/fail_compilation/dip22a.d   |     9 -
 gcc/testsuite/gdc.test/fail_compilation/dip22b.d   |     4 -
 gcc/testsuite/gdc.test/fail_compilation/dip22e.d   |     4 -
 .../gdc.test/fail_compilation/extra-files/a14446.d |     6 -
 gcc/testsuite/gdc.test/fail_compilation/fail101.d  |     3 +-
 .../gdc.test/fail_compilation/fail10528.d          |    11 -
 gcc/testsuite/gdc.test/fail_compilation/fail109.d  |     7 -
 .../gdc.test/fail_compilation/fail10905.d          |     3 -
 .../gdc.test/fail_compilation/fail10968.d          |    21 +-
 .../gdc.test/fail_compilation/fail11355.d          |     6 +-
 .../gdc.test/fail_compilation/fail11445.d          |     4 -
 .../gdc.test/fail_compilation/fail11552.d          |     2 +-
 .../gdc.test/fail_compilation/fail11717.d          |    14 -
 .../gdc.test/fail_compilation/fail11720.d          |    33 -
 gcc/testsuite/gdc.test/fail_compilation/fail134.d  |     5 +-
 .../gdc.test/fail_compilation/fail15616b.d         |     3 -
 .../gdc.test/fail_compilation/fail16001.d          |    13 +
 .../gdc.test/fail_compilation/fail16206a.d         |    12 -
 .../gdc.test/fail_compilation/fail16206b.d         |    12 -
 .../gdc.test/fail_compilation/fail16689.d          |    14 +
 .../gdc.test/fail_compilation/fail17382.d          |     9 -
 .../gdc.test/fail_compilation/fail17602.d          |     2 +-
 .../gdc.test/fail_compilation/fail17955.d          |     2 +-
 .../gdc.test/fail_compilation/fail18143.d          |    11 -
 .../gdc.test/fail_compilation/fail18266.d          |    28 -
 .../gdc.test/fail_compilation/fail18719.d          |    13 -
 .../gdc.test/fail_compilation/fail18970.d          |    11 +-
 .../gdc.test/fail_compilation/fail18994.d          |     2 +-
 .../gdc.test/fail_compilation/fail19103.d          |    16 +-
 .../gdc.test/fail_compilation/fail19107.d          |    21 -
 gcc/testsuite/gdc.test/fail_compilation/fail196.d  |    34 -
 .../gdc.test/fail_compilation/fail20108.d          |    14 +-
 .../gdc.test/fail_compilation/fail20183.d          |    18 +
 .../gdc.test/fail_compilation/fail20714.d          |    32 +
 .../gdc.test/fail_compilation/fail20965.d          |    27 +
 .../gdc.test/fail_compilation/fail21092.d          |    27 +
 .../gdc.test/fail_compilation/fail21227.d          |    20 -
 .../gdc.test/fail_compilation/fail21508.d          |    18 +
 .../gdc.test/fail_compilation/fail21508_2.d        |    11 +
 .../gdc.test/fail_compilation/fail21547.d          |    34 +
 gcc/testsuite/gdc.test/fail_compilation/fail217.d  |     4 -
 .../gdc.test/fail_compilation/fail21830.d          |    34 +
 .../gdc.test/fail_compilation/fail21831.d          |    29 +
 .../gdc.test/fail_compilation/fail21832.d          |    21 +
 .../gdc.test/fail_compilation/fail21849.d          |    36 +
 .../gdc.test/fail_compilation/fail21885.d          |    25 +
 .../gdc.test/fail_compilation/fail21928.d          |    19 +
 .../gdc.test/fail_compilation/fail21928b.d         |    19 +
 .../gdc.test/fail_compilation/fail22035.d          |    11 +
 .../gdc.test/fail_compilation/fail22084.d          |    23 +
 gcc/testsuite/gdc.test/fail_compilation/fail222.d  |     9 +-
 gcc/testsuite/gdc.test/fail_compilation/fail241.d  |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/fail2450.d |     7 +-
 gcc/testsuite/gdc.test/fail_compilation/fail246.d  |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail247.d  |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail2789.d |    11 +-
 gcc/testsuite/gdc.test/fail_compilation/fail3.d    |     4 -
 gcc/testsuite/gdc.test/fail_compilation/fail303.d  |    15 +-
 gcc/testsuite/gdc.test/fail_compilation/fail313.d  |     6 -
 gcc/testsuite/gdc.test/fail_compilation/fail324.d  |    17 -
 gcc/testsuite/gdc.test/fail_compilation/fail332.d  |     4 -
 gcc/testsuite/gdc.test/fail_compilation/fail341.d  |     6 +-
 gcc/testsuite/gdc.test/fail_compilation/fail347.d  |     6 -
 gcc/testsuite/gdc.test/fail_compilation/fail3753.d |    48 -
 gcc/testsuite/gdc.test/fail_compilation/fail3882.d |     6 +-
 .../gdc.test/fail_compilation/fail4375a.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375b.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375c.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375d.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375e.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375f.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375g.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375h.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375i.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375j.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375k.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375l.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375m.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375o.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375r.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375s.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375t.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375u.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375v.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375w.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375x.d          |     4 +-
 .../gdc.test/fail_compilation/fail4375y.d          |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/fail47.d   |    13 -
 gcc/testsuite/gdc.test/fail_compilation/fail5435.d |    14 -
 gcc/testsuite/gdc.test/fail_compilation/fail5634.d |    10 -
 gcc/testsuite/gdc.test/fail_compilation/fail6334.d |     3 +-
 gcc/testsuite/gdc.test/fail_compilation/fail6795.d |    35 +-
 gcc/testsuite/gdc.test/fail_compilation/fail7173.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail7352.d |    52 +
 gcc/testsuite/gdc.test/fail_compilation/fail79.d   |     4 -
 gcc/testsuite/gdc.test/fail_compilation/fail9346.d |     9 +-
 gcc/testsuite/gdc.test/fail_compilation/fail9613.d |     2 +-
 .../gdc.test/fail_compilation/fail_arrayop2.d      |     6 +-
 .../gdc.test/fail_compilation/fail_contracts3.d    |     8 -
 .../gdc.test/fail_compilation/fail_scope.d         |     4 +-
 .../gdc.test/fail_compilation/failcstuff1.c        |   103 +
 .../gdc.test/fail_compilation/failcstuff2.c        |    86 +
 gcc/testsuite/gdc.test/fail_compilation/failob2.d  |    67 +
 gcc/testsuite/gdc.test/fail_compilation/fob2.d     |    15 +
 gcc/testsuite/gdc.test/fail_compilation/goto2.d    |    93 +
 gcc/testsuite/gdc.test/fail_compilation/ice10212.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/ice10770.d |    13 -
 gcc/testsuite/gdc.test/fail_compilation/ice10938.d |     3 +-
 gcc/testsuite/gdc.test/fail_compilation/ice11552.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/ice11822.d |     7 +-
 gcc/testsuite/gdc.test/fail_compilation/ice11967.d |    10 -
 gcc/testsuite/gdc.test/fail_compilation/ice13385.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/ice14446.d |    13 -
 gcc/testsuite/gdc.test/fail_compilation/ice14907.d |    10 -
 gcc/testsuite/gdc.test/fail_compilation/ice20042.d |     2 +-
 gcc/testsuite/gdc.test/fail_compilation/ice8255.d  |    18 -
 gcc/testsuite/gdc.test/fail_compilation/ice8511.d  |    13 -
 gcc/testsuite/gdc.test/fail_compilation/ice9759.d  |     2 +-
 .../gdc.test/fail_compilation/imports/imp21832.d   |    24 +
 .../fail_compilation/imports/import21508.d         |     2 +
 .../gdc.test/fail_compilation/issue20704.d         |    39 +
 .../gdc.test/fail_compilation/issue21203.d         |    17 +
 .../gdc.test/fail_compilation/issue21378.d         |    16 +
 .../gdc.test/fail_compilation/issue21936.d         |    32 +
 gcc/testsuite/gdc.test/fail_compilation/lookup.d   |     7 -
 .../gdc.test/fail_compilation/mixintype2.d         |     7 -
 .../gdc.test/fail_compilation/nestedtempl1.d       |     4 +-
 .../gdc.test/fail_compilation/nestedtempl2.d       |    12 +-
 gcc/testsuite/gdc.test/fail_compilation/noreturn.d |   118 +
 .../gdc.test/fail_compilation/parseStc2.d          |     4 +-
 .../gdc.test/fail_compilation/pragmainline.d       |     5 +-
 gcc/testsuite/gdc.test/fail_compilation/pragmas.d  |     3 +-
 .../gdc.test/fail_compilation/previewin.d          |    60 +-
 .../gdc.test/fail_compilation/protattr1.d          |     2 +-
 .../gdc.test/fail_compilation/protattr2.d          |     2 +-
 .../gdc.test/fail_compilation/reserved_version.d   |    57 +-
 .../fail_compilation/reserved_version_switch.d     |     3 +
 gcc/testsuite/gdc.test/fail_compilation/retref2.d  |     7 +-
 gcc/testsuite/gdc.test/fail_compilation/retscope.d |     8 +-
 .../gdc.test/fail_compilation/retscope6.d          |    28 +
 .../gdc.test/fail_compilation/test11176.d          |     4 -
 .../gdc.test/fail_compilation/test12385.d          |     2 +-
 .../gdc.test/fail_compilation/test12558.d          |    49 +-
 .../gdc.test/fail_compilation/test13667.d          |   101 +
 gcc/testsuite/gdc.test/fail_compilation/test143.d  |     4 -
 .../gdc.test/fail_compilation/test15117.d          |    30 -
 .../gdc.test/fail_compilation/test15306.d          |     4 +-
 .../gdc.test/fail_compilation/test15785.d          |     4 -
 .../gdc.test/fail_compilation/test15785b.d         |    11 -
 .../gdc.test/fail_compilation/test15897.d          |     4 -
 .../gdc.test/fail_compilation/test15925.d          |     5 -
 .../gdc.test/fail_compilation/test15989.d          |     2 +-
 .../gdc.test/fail_compilation/test16193.d          |     2 +-
 .../gdc.test/fail_compilation/test16228.d          |     3 +-
 .../gdc.test/fail_compilation/test17450.d          |     2 +-
 .../gdc.test/fail_compilation/test17451.d          |     2 +-
 .../gdc.test/fail_compilation/test18385.d          |     2 +-
 .../gdc.test/fail_compilation/test18385b.d         |    47 +
 .../gdc.test/fail_compilation/test19176.d          |     3 +-
 .../gdc.test/fail_compilation/test20324.d          |    16 +
 .../gdc.test/fail_compilation/test20549.d          |     3 +-
 .../gdc.test/fail_compilation/test20565.d          |    19 +
 .../gdc.test/fail_compilation/test21319.d          |    12 +
 .../gdc.test/fail_compilation/test21518.d          |    38 +
 .../gdc.test/fail_compilation/test21665.d          |    31 +
 .../gdc.test/fail_compilation/test21807.d          |    54 +
 .../gdc.test/fail_compilation/test22048.d          |    10 +
 gcc/testsuite/gdc.test/fail_compilation/test314.d  |     4 -
 gcc/testsuite/gdc.test/fail_compilation/test6883.d |    12 +-
 .../gdc.test/fail_compilation/testpull1810.d       |     4 +-
 gcc/testsuite/gdc.test/fail_compilation/traits.d   |    63 +-
 .../gdc.test/fail_compilation/traits_child.d       |     7 -
 .../fail_compilation/union_initialization.d        |    88 +
 .../gdc.test/fail_compilation/warn13679.d          |     4 +-
 gcc/testsuite/gdc.test/runnable/aliasassign.d      |    31 +
 gcc/testsuite/gdc.test/runnable/b10562.d           |     5 -
 gcc/testsuite/gdc.test/runnable/builtin.d          |     6 +-
 gcc/testsuite/gdc.test/runnable/casting.d          |    27 +-
 gcc/testsuite/gdc.test/runnable/complex.d          |  1165 +-
 gcc/testsuite/gdc.test/runnable/constfold.d        |    36 +-
 gcc/testsuite/gdc.test/runnable/cppdtor.d          |   143 +
 gcc/testsuite/gdc.test/runnable/cstuff2.c          |   254 +
 gcc/testsuite/gdc.test/runnable/foreach4.d         |     6 -
 gcc/testsuite/gdc.test/runnable/foreach5.d         |    40 +-
 gcc/testsuite/gdc.test/runnable/funclit.d          |     2 +-
 gcc/testsuite/gdc.test/runnable/ice21696.d         |    23 +
 gcc/testsuite/gdc.test/runnable/ifti.d             |     2 -
 gcc/testsuite/gdc.test/runnable/imports/Other.d    |    11 +-
 .../gdc.test/runnable/imports/std15017variant.d    |     2 +-
 gcc/testsuite/gdc.test/runnable/interpret.d        |    43 +-
 gcc/testsuite/gdc.test/runnable/link15017.d        |     1 +
 gcc/testsuite/gdc.test/runnable/link6574.d         |    16 -
 gcc/testsuite/gdc.test/runnable/mangle.d           |    15 +-
 gcc/testsuite/gdc.test/runnable/mars1.d            |   293 +-
 gcc/testsuite/gdc.test/runnable/mixin1.d           |    13 +-
 gcc/testsuite/gdc.test/runnable/mixin2.d           |     8 -
 gcc/testsuite/gdc.test/runnable/nested.d           |     4 -
 gcc/testsuite/gdc.test/runnable/opover2.d          |     5 +-
 gcc/testsuite/gdc.test/runnable/overload.d         |    36 +
 gcc/testsuite/gdc.test/runnable/previewin.d        |    41 +-
 gcc/testsuite/gdc.test/runnable/property2.d        |     8 -
 gcc/testsuite/gdc.test/runnable/sdtor.d            |    85 +-
 gcc/testsuite/gdc.test/runnable/structlit.d        |    14 +-
 gcc/testsuite/gdc.test/runnable/template10.d       |   754 --
 gcc/testsuite/gdc.test/runnable/template4.d        |    34 -
 gcc/testsuite/gdc.test/runnable/template9.d        |    22 +-
 gcc/testsuite/gdc.test/runnable/test10619.d        |    38 +
 gcc/testsuite/gdc.test/runnable/test14874.d        |    76 +-
 gcc/testsuite/gdc.test/runnable/test15.d           |     7 +-
 gcc/testsuite/gdc.test/runnable/test16140.d        |    32 +
 gcc/testsuite/gdc.test/runnable/test17072.d        |     2 +-
 gcc/testsuite/gdc.test/runnable/test17373.d        |    20 -
 gcc/testsuite/gdc.test/runnable/test17965.d        |    29 +
 gcc/testsuite/gdc.test/runnable/test18772.d        |    94 -
 gcc/testsuite/gdc.test/runnable/test19122.d        |     7 +-
 gcc/testsuite/gdc.test/runnable/test19192.d        |    18 +
 gcc/testsuite/gdc.test/runnable/test19441.d        |     6 +-
 gcc/testsuite/gdc.test/runnable/test19774.d        |     7 +-
 gcc/testsuite/gdc.test/runnable/test19782.d        |     5 +-
 gcc/testsuite/gdc.test/runnable/test19822.d        |     7 +-
 gcc/testsuite/gdc.test/runnable/test20.d           |    53 -
 gcc/testsuite/gdc.test/runnable/test20025.d        |     6 -
 gcc/testsuite/gdc.test/runnable/test20565.d        |    18 +
 gcc/testsuite/gdc.test/runnable/test20855.d        |    26 +
 gcc/testsuite/gdc.test/runnable/test21357.d        |    35 +
 gcc/testsuite/gdc.test/runnable/test21403.d        |    72 +
 gcc/testsuite/gdc.test/runnable/test21424.d        |    12 +
 gcc/testsuite/gdc.test/runnable/test21479.d        |    28 +
 gcc/testsuite/gdc.test/runnable/test21515.d        |    81 +
 gcc/testsuite/gdc.test/runnable/test21586.d        |    31 +
 gcc/testsuite/gdc.test/runnable/test21822.d        |    18 +
 gcc/testsuite/gdc.test/runnable/test21833.d        |    30 +
 gcc/testsuite/gdc.test/runnable/test22.d           |   294 -
 gcc/testsuite/gdc.test/runnable/test23.d           |    22 -
 gcc/testsuite/gdc.test/runnable/test28.d           |    27 -
 gcc/testsuite/gdc.test/runnable/test34.d           |     5 -
 gcc/testsuite/gdc.test/runnable/test4.d            |    44 +-
 gcc/testsuite/gdc.test/runnable/test42.d           |    39 -
 gcc/testsuite/gdc.test/runnable/test6795.d         |    26 +
 gcc/testsuite/gdc.test/runnable/test711.d          |     6 +-
 gcc/testsuite/gdc.test/runnable/test8.d            |    99 +-
 gcc/testsuite/gdc.test/runnable/test809.d          |     5 -
 gcc/testsuite/gdc.test/runnable/testassert.d       |   148 +
 gcc/testsuite/gdc.test/runnable/testassign.d       |     3 -
 gcc/testsuite/gdc.test/runnable/testcgelem.d       |     3 +-
 gcc/testsuite/gdc.test/runnable/testclass.d        |    40 +
 gcc/testsuite/gdc.test/runnable/testconst.d        |     2 +-
 gcc/testsuite/gdc.test/runnable/testcontracts.d    |   106 +-
 gcc/testsuite/gdc.test/runnable/testdstress.d      |    20 -
 gcc/testsuite/gdc.test/runnable/testkeyword.d      |     4 +-
 gcc/testsuite/gdc.test/runnable/testsafe.d         |     6 -
 gcc/testsuite/gdc.test/runnable/testscope2.d       |     6 +-
 gcc/testsuite/gdc.test/runnable/testtypeid.d       |    80 -
 gcc/testsuite/gdc.test/runnable/traits.d           |    55 -
 .../gdc.test/runnable/traits_getPointerBitmap.d    |     2 -
 gcc/testsuite/gdc.test/runnable/uda.d              |     4 -
 gcc/testsuite/gdc.test/runnable/ufcs.d             |     5 -
 gcc/testsuite/gdc.test/runnable/uniformctor.d      |    14 -
 gcc/testsuite/gdc.test/runnable/xtest46.d          |    12 -
 .../gdc.test/runnable_cxx/cpp_abi_tests.d          |    18 +
 gcc/testsuite/gdc.test/runnable_cxx/cppa.d         |    32 +-
 gcc/testsuite/gdc.test/runnable_cxx/externmangle.d |     9 +
 .../runnable_cxx/extra-files/cpp_abi_tests.cpp     |    17 +
 .../gdc.test/runnable_cxx/extra-files/cppb.cpp     |    19 -
 .../runnable_cxx/extra-files/externmangle.cpp      |    11 +
 .../runnable_cxx/extra-files/test20652.cpp         |    34 +
 .../runnable_cxx/extra-files/test21515.cpp         |    18 +-
 gcc/testsuite/gdc.test/runnable_cxx/test20652.d    |    23 +
 gcc/testsuite/gdc.test/runnable_cxx/test21515.d    |     1 +
 gcc/testsuite/lib/gdc-utils.exp                    |     8 +-
 libphobos/configure                                |     4 +-
 libphobos/libdruntime/{LICENSE => LICENSE.txt}     |     3 -
 libphobos/libdruntime/MERGE                        |     2 +-
 libphobos/libdruntime/Makefile.am                  |   180 +-
 libphobos/libdruntime/Makefile.in                  |   584 +-
 libphobos/libdruntime/__entrypoint.di              |    56 -
 libphobos/libdruntime/core/atomic.d                |    76 +-
 libphobos/libdruntime/core/attribute.d             |    72 +
 libphobos/libdruntime/core/bitop.d                 |    87 +-
 libphobos/libdruntime/core/builtins.d              |    19 +
 libphobos/libdruntime/core/checkedint.d            |    91 +-
 libphobos/libdruntime/core/cpuid.d                 |     4 -
 libphobos/libdruntime/core/demangle.d              |    22 +-
 libphobos/libdruntime/core/exception.d             |     8 +-
 libphobos/libdruntime/core/gc/gcinterface.d        |     2 +-
 .../libdruntime/core/internal/array/appending.d    |    77 +-
 .../libdruntime/core/internal/array/casting.d      |     7 +-
 .../libdruntime/core/internal/array/comparison.d   |    10 +-
 .../core/internal/array/concatenation.d            |     2 +-
 .../libdruntime/core/internal/array/construction.d |   109 +-
 libphobos/libdruntime/core/internal/atomic.d       |     8 +
 .../{rt => core/internal}/backtrace/dwarf.d        |   544 +-
 .../{rt => core/internal}/backtrace/elf.d          |     7 +-
 .../libdruntime/core/internal/backtrace/handler.d  |   133 +
 .../core/internal/backtrace/libunwind.d            |   157 +
 .../{rt => core/internal}/backtrace/macho.d        |     2 +-
 .../libdruntime/core/internal/backtrace/unwind.d   |   199 +
 .../{rt/util => core/internal}/container/array.d   |     4 +-
 .../{rt/util => core/internal}/container/common.d  |    11 +-
 .../{rt/util => core/internal}/container/hashtab.d |     6 +-
 .../{rt/util => core/internal}/container/treap.d   |    37 +-
 libphobos/libdruntime/core/internal/convert.d      |    27 +-
 libphobos/libdruntime/core/internal/dassert.d      |   319 +-
 libphobos/libdruntime/core/internal/elf/dl.d       |     8 +-
 libphobos/libdruntime/core/internal/elf/io.d       |     5 +
 .../libdruntime/{ => core/internal}/gc/bits.d      |    10 +-
 .../{ => core/internal}/gc/impl/conservative/gc.d  |   140 +-
 .../{ => core/internal}/gc/impl/manual/gc.d        |    25 +-
 .../{ => core/internal}/gc/impl/proto/gc.d         |    26 +-
 libphobos/libdruntime/{ => core/internal}/gc/os.d  |    14 +-
 .../libdruntime/{ => core/internal}/gc/pooltable.d |     4 +-
 .../libdruntime/{ => core/internal}/gc/proxy.d     |    31 +-
 libphobos/libdruntime/core/internal/lifetime.d     |    86 +-
 .../libdruntime/{rt => core/internal}/qsort.d      |    10 +-
 libphobos/libdruntime/core/internal/string.d       |     2 +-
 libphobos/libdruntime/core/internal/traits.d       |   237 +-
 libphobos/libdruntime/core/internal/util/array.d   |    14 +-
 libphobos/libdruntime/core/internal/util/math.d    |    53 +
 libphobos/libdruntime/core/lifetime.d              |   446 +-
 libphobos/libdruntime/core/math.d                  |    12 -
 libphobos/libdruntime/core/memory.d                |   242 +-
 libphobos/libdruntime/core/runtime.d               |   140 +-
 libphobos/libdruntime/core/simd.d                  |   209 -
 libphobos/libdruntime/core/stdc/complex.d          |    19 -
 libphobos/libdruntime/core/stdc/math.d             |   391 +-
 libphobos/libdruntime/core/stdc/stdarg.d           |    66 -
 libphobos/libdruntime/core/stdc/stdint.d           |    91 +-
 libphobos/libdruntime/core/stdc/stdio.d            |     4 -
 libphobos/libdruntime/core/stdc/time.d             |     4 -
 libphobos/libdruntime/core/stdcpp/allocator.d      |    26 +-
 libphobos/libdruntime/core/stdcpp/exception.d      |    32 +-
 libphobos/libdruntime/core/stdcpp/new_.d           |     5 +-
 libphobos/libdruntime/core/stdcpp/string.d         |    14 +
 libphobos/libdruntime/core/stdcpp/typeinfo.d       |    34 +-
 libphobos/libdruntime/core/stdcpp/vector.d         |    21 +-
 libphobos/libdruntime/core/sync/barrier.d          |     4 +-
 libphobos/libdruntime/core/sync/condition.d        |    18 +-
 libphobos/libdruntime/core/sync/config.d           |     8 +-
 libphobos/libdruntime/core/sync/mutex.d            |    14 +-
 libphobos/libdruntime/core/sync/rwmutex.d          |    40 +-
 libphobos/libdruntime/core/sync/semaphore.d        |    29 +-
 libphobos/libdruntime/core/sys/darwin/dlfcn.d      |     5 +
 libphobos/libdruntime/core/sys/darwin/mach/dyld.d  |     5 -
 libphobos/libdruntime/core/sys/freebsd/sys/event.d |     7 -
 libphobos/libdruntime/core/sys/freebsd/sys/mount.d |    17 -
 libphobos/libdruntime/core/sys/linux/execinfo.d    |     3 -
 libphobos/libdruntime/core/sys/linux/sys/mman.d    |     7 -
 libphobos/libdruntime/core/sys/posix/arpa/inet.d   |    60 +-
 libphobos/libdruntime/core/sys/posix/dirent.d      |    13 -
 libphobos/libdruntime/core/sys/posix/dlfcn.d       |     7 -
 libphobos/libdruntime/core/sys/posix/locale.d      |    58 -
 libphobos/libdruntime/core/sys/posix/pthread.d     |     4 -
 libphobos/libdruntime/core/sys/posix/setjmp.d      |     4 +
 libphobos/libdruntime/core/sys/posix/signal.d      |    28 -
 libphobos/libdruntime/core/sys/posix/stdc/time.d   |     4 -
 libphobos/libdruntime/core/sys/posix/stdio.d       |    21 +-
 libphobos/libdruntime/core/sys/posix/sys/stat.d    |    16 -
 libphobos/libdruntime/core/sys/posix/sys/statvfs.d |   109 -
 libphobos/libdruntime/core/sys/posix/ucontext.d    |     7 -
 libphobos/libdruntime/core/sys/windows/dll.d       |    12 -
 libphobos/libdruntime/core/sys/windows/stdc/time.d |     4 -
 libphobos/libdruntime/core/thread/fiber.d          |    38 -
 libphobos/libdruntime/core/thread/osthread.d       |   179 +-
 libphobos/libdruntime/core/thread/threadbase.d     |    55 +-
 libphobos/libdruntime/core/time.d                  |   156 +-
 libphobos/libdruntime/gcc/deh.d                    |    10 -
 libphobos/libdruntime/gcc/emutls.d                 |     3 +-
 libphobos/libdruntime/gcc/sections/elf.d           |     6 +-
 libphobos/libdruntime/gcc/sections/elf_shared.d    |  1007 --
 libphobos/libdruntime/gcc/sections/macho.d         |     2 +-
 libphobos/libdruntime/gcc/sections/pecoff.d        |     2 +-
 libphobos/libdruntime/gcc/sections/win32.d         |   183 -
 libphobos/libdruntime/gcc/sections/win64.d         |   321 -
 libphobos/libdruntime/object.d                     |   881 +-
 libphobos/libdruntime/rt/aApplyR.d                 |     1 +
 libphobos/libdruntime/rt/aaA.d                     |    58 +-
 libphobos/libdruntime/rt/cast_.d                   |     1 +
 libphobos/libdruntime/rt/critical_.d               |     1 +
 libphobos/libdruntime/rt/dmain2.d                  |   154 +-
 libphobos/libdruntime/rt/ehalloc.d                 |     3 +-
 libphobos/libdruntime/rt/invariant.d               |     1 +
 libphobos/libdruntime/rt/lifetime.d                |    71 +-
 libphobos/libdruntime/rt/minfo.d                   |     4 +-
 libphobos/libdruntime/rt/monitor_.d                |     1 +
 libphobos/libdruntime/rt/profilegc.d               |     2 +-
 libphobos/libdruntime/rt/sections.d                |     9 +
 libphobos/libdruntime/rt/tlsgc.d                   |     1 +
 libphobos/libdruntime/rt/util/random.d             |    36 -
 libphobos/libdruntime/rt/util/typeinfo.d           |   294 +-
 libphobos/libdruntime/rt/util/utility.d            |    17 +
 libphobos/src/MERGE                                |     2 +-
 libphobos/src/Makefile.am                          |    26 +-
 libphobos/src/Makefile.in                          |    93 +-
 libphobos/src/index.d                              |     6 +-
 libphobos/src/std/algorithm/comparison.d           |    28 +-
 libphobos/src/std/algorithm/iteration.d            |   720 +-
 libphobos/src/std/algorithm/mutation.d             |    23 +-
 libphobos/src/std/algorithm/package.d              |     1 +
 libphobos/src/std/algorithm/searching.d            |    59 +-
 libphobos/src/std/algorithm/sorting.d              |   122 +-
 libphobos/src/std/array.d                          |   135 +-
 libphobos/src/std/base64.d                         |   131 +-
 libphobos/src/std/bigint.d                         |   161 +-
 libphobos/src/std/bitmanip.d                       |   545 +-
 libphobos/src/std/complex.d                        |   483 +-
 libphobos/src/std/concurrency.d                    |   103 +-
 libphobos/src/std/container/array.d                |   205 +-
 libphobos/src/std/container/dlist.d                |    12 +-
 libphobos/src/std/container/package.d              |   142 +-
 libphobos/src/std/container/rbtree.d               |     3 -
 libphobos/src/std/conv.d                           |  2395 ++--
 libphobos/src/std/csv.d                            |    37 +-
 libphobos/src/std/datetime/date.d                  |    16 +-
 libphobos/src/std/datetime/package.d               |   581 -
 libphobos/src/std/datetime/systime.d               |    74 +-
 libphobos/src/std/datetime/timezone.d              |    42 +-
 libphobos/src/std/digest/digest.d                  |     2 +-
 libphobos/src/std/digest/hmac.d                    |     6 +-
 libphobos/src/std/digest/md.d                      |    17 +-
 libphobos/src/std/digest/package.d                 |     2 +-
 libphobos/src/std/digest/ripemd.d                  |    49 +-
 libphobos/src/std/encoding.d                       |    14 +-
 libphobos/src/std/exception.d                      |    97 +-
 .../allocator/building_blocks/affix_allocator.d    |     4 +-
 .../allocator/building_blocks/aligned_block_list.d |     4 +-
 .../allocator/building_blocks/allocator_list.d     |    26 +-
 .../allocator/building_blocks/bitmapped_block.d    |     8 +-
 .../allocator/building_blocks/kernighan_ritchie.d  |     3 +-
 .../allocator/building_blocks/region.d             |     7 +-
 libphobos/src/std/experimental/allocator/common.d  |    20 +-
 libphobos/src/std/experimental/allocator/package.d |    57 +-
 libphobos/src/std/experimental/allocator/typed.d   |     2 +-
 libphobos/src/std/experimental/checkedint.d        |   189 +-
 libphobos/src/std/experimental/logger/core.d       |    20 +-
 libphobos/src/std/experimental/logger/filelogger.d |     2 +-
 libphobos/src/std/experimental/logger/nulllogger.d |     4 -
 libphobos/src/std/experimental/typecons.d          |    11 +-
 libphobos/src/std/file.d                           |   254 +-
 libphobos/src/std/format.d                         |  8476 ---------------
 libphobos/src/std/format/internal/floats.d         |  2930 +++++
 libphobos/src/std/format/internal/read.d           |   410 +
 libphobos/src/std/format/internal/write.d          |  3980 +++++++
 libphobos/src/std/format/package.d                 |  1787 +++
 libphobos/src/std/format/read.d                    |   721 ++
 libphobos/src/std/format/spec.d                    |   949 ++
 libphobos/src/std/format/write.d                   |  1289 +++
 libphobos/src/std/functional.d                     |   196 +-
 libphobos/src/std/getopt.d                         |    31 +-
 libphobos/src/std/internal/cstring.d               |    60 +-
 libphobos/src/std/internal/math/biguintcore.d      |    99 +-
 libphobos/src/std/internal/math/errorfunction.d    |     7 +-
 libphobos/src/std/internal/math/gammafunction.d    |    25 +-
 libphobos/src/std/internal/memory.d                |     4 +-
 libphobos/src/std/internal/test/dummyrange.d       |     6 +-
 libphobos/src/std/json.d                           |   124 +-
 libphobos/src/std/math.d                           | 10869 -------------------
 libphobos/src/std/math/algebraic.d                 |  1079 ++
 libphobos/src/std/math/constants.d                 |    38 +
 libphobos/src/std/math/exponential.d               |  3439 ++++++
 libphobos/src/std/math/hardware.d                  |  1212 +++
 libphobos/src/std/math/operations.d                |  2010 ++++
 libphobos/src/std/math/package.d                   |   494 +
 libphobos/src/std/math/remainder.d                 |   155 +
 libphobos/src/std/math/rounding.d                  |  1004 ++
 libphobos/src/std/math/traits.d                    |   853 ++
 libphobos/src/std/math/trigonometry.d              |  1421 +++
 libphobos/src/std/mathspecial.d                    |     6 +-
 libphobos/src/std/meta.d                           |   103 +-
 libphobos/src/std/mmfile.d                         |     7 +-
 libphobos/src/std/net/isemail.d                    |    12 +-
 libphobos/src/std/numeric.d                        |   507 +-
 libphobos/src/std/outbuffer.d                      |     4 +-
 libphobos/src/std/package.d                        |     1 +
 libphobos/src/std/parallelism.d                    |   110 +-
 libphobos/src/std/path.d                           |    22 +-
 libphobos/src/std/process.d                        |   704 +-
 libphobos/src/std/random.d                         |    62 +-
 libphobos/src/std/range/package.d                  |   227 +-
 libphobos/src/std/range/primitives.d               |    42 +-
 libphobos/src/std/regex/internal/backtracking.d    |    24 +-
 libphobos/src/std/regex/internal/generator.d       |     2 +-
 libphobos/src/std/regex/internal/ir.d              |   117 +-
 libphobos/src/std/regex/internal/parser.d          |     2 +-
 libphobos/src/std/regex/internal/tests.d           |     4 -
 libphobos/src/std/regex/internal/tests2.d          |   216 +-
 libphobos/src/std/regex/internal/thompson.d        |     5 +-
 libphobos/src/std/regex/package.d                  |    34 +-
 libphobos/src/std/socket.d                         |    18 +-
 libphobos/src/std/stdio.d                          |   729 +-
 libphobos/src/std/string.d                         |    60 +-
 libphobos/src/std/sumtype.d                        |  2477 +++++
 libphobos/src/std/system.d                         |     5 +-
 libphobos/src/std/traits.d                         |   574 +-
 libphobos/src/std/typecons.d                       |   402 +-
 libphobos/src/std/uni/package.d                    |    31 +-
 libphobos/src/std/uri.d                            |     2 +-
 libphobos/src/std/utf.d                            |    13 +-
 libphobos/src/std/variant.d                        |   271 +-
 libphobos/src/std/windows/syserror.d               |     2 +-
 libphobos/src/std/xml.d                            |   258 +-
 libphobos/testsuite/libphobos.aa/test_aa.d         |    60 +-
 .../libphobos.allocations/alloc_from_assert.d      |    25 +
 .../testsuite/libphobos.exceptions/assert_fail.d   |   295 +-
 libphobos/testsuite/libphobos.gc/attributes.d      |    30 +
 libphobos/testsuite/libphobos.hash/test_hash.d     |    33 +-
 .../testsuite/libphobos.init_fini/custom_gc.d      |     2 +-
 .../large_aggregate_destroy_21097.d                |    78 +
 .../testsuite/libphobos.lifetime/lifetime.exp      |    27 +
 libphobos/testsuite/libphobos.thread/join_detach.d |    20 +
 libphobos/testsuite/libphobos.typeinfo/enum_.d     |    21 +
 838 files changed, 65768 insertions(+), 42715 deletions(-)

diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index cb8c1c394db..320eda7e3ff 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -82,6 +82,7 @@ D_FRONTEND_OBJS = \
 	d/attrib.o \
 	d/ast_node.o \
 	d/astcodegen.o \
+	d/astenums.o \
 	d/bitarray.o \
 	d/blockexit.o \
 	d/builtin.o \
@@ -92,6 +93,7 @@ D_FRONTEND_OBJS = \
 	d/complex.o \
 	d/cond.o \
 	d/constfold.o \
+	d/cparse.o \
 	d/cppmangle.o \
 	d/ctfeexpr.o \
 	d/ctfloat.o \
@@ -215,7 +217,7 @@ d_OBJS = $(D_ALL_OBJS) d/d-spec.o
 
 d21$(exeext): $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS) $(d.prev)
 	@$(call LINK_PROGRESS,$(INDEX.d),start)
-	+$(DLLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	+$(DLLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -static-libphobos -o $@ \
 		$(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
 	@$(call LINK_PROGRESS,$(INDEX.d),end)
 
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 070866020a2..9fd3eaac862 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "dmd/attrib.h"
 #include "dmd/declaration.h"
+#include "dmd/expression.h"
 #include "dmd/module.h"
 #include "dmd/mtype.h"
 #include "dmd/template.h"
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index a2260d971cd..ab3a950689f 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -99,7 +99,7 @@ build_frontend_type (tree type)
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
 	    return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
 
-	  if (dtype->ty == Tfunction)
+	  if (dtype->ty == TY::Tfunction)
 	    return (TypePointer::create (dtype))->addMod (mod);
 
 	  return dtype->pointerTo ()->addMod (mod);
@@ -131,7 +131,7 @@ build_frontend_type (tree type)
 
       /* For now, skip support for cent/ucent until the frontend
 	 has better support for handling it.  */
-      for (size_t i = Tint8; i <= Tuns64; i++)
+      for (size_t i = (size_t) TY::Tint8; i <= (size_t) TY::Tuns64; i++)
 	{
 	  dtype = Type::basic[i];
 
@@ -149,7 +149,7 @@ build_frontend_type (tree type)
     {
       unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
 
-      for (size_t i = Tfloat32; i <= Tfloat80; i++)
+      for (size_t i = (size_t) TY::Tfloat32; i <= (size_t) TY::Tfloat80; i++)
 	{
 	  dtype = Type::basic[i];
 
@@ -165,7 +165,8 @@ build_frontend_type (tree type)
     case COMPLEX_TYPE:
     {
       unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
-      for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
+      for (size_t i = (size_t) TY::Tcomplex32; i <= (size_t) TY::Tcomplex80;
+	   i++)
 	{
 	  dtype = Type::basic[i];
 
@@ -236,7 +237,7 @@ build_frontend_type (tree type)
       sdecl->structsize = int_size_in_bytes (type);
       sdecl->alignsize = TYPE_ALIGN_UNIT (type);
       sdecl->alignment = STRUCTALIGN_DEFAULT;
-      sdecl->sizeok = SIZEOKdone;
+      sdecl->sizeok = Sizeok::done;
       sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
       sdecl->type->ctype = type;
       sdecl->type->merge2 ();
@@ -328,7 +329,7 @@ build_frontend_type (tree type)
 	     have no named parameters, and so can't be represented in D.  */
 	  if (args->length != 0 || varargs_p == VARARGnone)
 	    {
-	      dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
+	      dtype = TypeFunction::create (args, dtype, varargs_p, LINK::c);
 	      return dtype->addMod (mod);
 	    }
 	}
@@ -379,7 +380,7 @@ d_eval_constant_expression (const Loc &loc, tree cst)
       else if (code == STRING_CST)
 	{
 	  const void *string = TREE_STRING_POINTER (cst);
-	  size_t len = TREE_STRING_LENGTH (cst);
+	  size_t len = TREE_STRING_LENGTH (cst) - 1;
 	  return StringExp::create (loc, CONST_CAST (void *, string), len);
 	}
       else if (code == VECTOR_CST)
@@ -461,7 +462,7 @@ d_init_versions (void)
   VersionCondition::addPredefinedGlobalIdent ("GNU_InlineAsm");
 
   /* LP64 only means 64bit pointers in D.  */
-  if (global.params.isLP64)
+  if (POINTER_SIZE == 64)
     VersionCondition::addPredefinedGlobalIdent ("D_LP64");
 
   /* Setting `global.params.cov' forces module info generation which is
@@ -659,7 +660,7 @@ d_build_builtins_module (Module *m)
     members->push (build_alias_declaration ("__builtin_unwind_uint", t));
   }
 
-  m->members->push (LinkDeclaration::create (LINKc, members));
+  m->members->push (LinkDeclaration::create (Loc (), LINK::c, members));
 }
 
 /* Search for any `extern(C)' functions that match any known GCC library builtin
@@ -857,7 +858,7 @@ d_build_d_type_nodes (void)
 
   /* Calling build_ctype() links the front-end Type to the GCC node,
      and sets the TYPE_NAME to the D language type.  */
-  for (unsigned ty = 0; ty < TMAX; ty++)
+  for (unsigned ty = 0; ty < (unsigned) TY::TMAX; ty++)
     {
       if (Type::basic[ty] != NULL)
 	build_ctype (Type::basic[ty]);
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 8494d7ad639..18f8b75a616 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -75,7 +75,7 @@ d_decl_context (Dsymbol *dsym)
 	 but only for extern(D) symbols.  */
       if (parent->isModule ())
 	{
-	  if ((decl != NULL && decl->linkage != LINKd)
+	  if ((decl != NULL && decl->linkage != LINK::d)
 	      || (ad != NULL && ad->classKind != ClassKind::d))
 	    return NULL_TREE;
 
@@ -130,7 +130,7 @@ declaration_reference_p (Declaration *decl)
   Type *tb = decl->type->toBasetype ();
 
   /* Declaration is a reference type.  */
-  if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
+  if (tb->ty == TY::Treference || decl->storage_class & (STCout | STCref))
     return true;
 
   return false;
@@ -145,7 +145,7 @@ declaration_type (Declaration *decl)
   if (decl->storage_class & STClazy)
     {
       TypeFunction *tf = TypeFunction::create (NULL, decl->type,
-					       VARARGnone, LINKd);
+					       VARARGnone, LINK::d);
       TypeDelegate *t = TypeDelegate::create (tf);
       return build_ctype (t->merge2 ());
     }
@@ -180,7 +180,7 @@ parameter_reference_p (Parameter *arg)
   Type *tb = arg->type->toBasetype ();
 
   /* Parameter is a reference type.  */
-  if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
+  if (tb->ty == TY::Treference || arg->storageClass & (STCout | STCref))
     return true;
 
   return false;
@@ -195,7 +195,7 @@ parameter_type (Parameter *arg)
   if (arg->storageClass & STClazy)
     {
       TypeFunction *tf = TypeFunction::create (NULL, arg->type,
-					       VARARGnone, LINKd);
+					       VARARGnone, LINK::d);
       TypeDelegate *t = TypeDelegate::create (tf);
       return build_ctype (t->merge2 ());
     }
@@ -318,10 +318,10 @@ get_array_length (tree exp, Type *type)
 
   switch (tb->ty)
     {
-    case Tsarray:
+    case TY::Tsarray:
       return size_int (tb->isTypeSArray ()->dim->toUInteger ());
 
-    case Tarray:
+    case TY::Tarray:
       return d_array_length (exp);
 
     default:
@@ -410,7 +410,7 @@ build_delegate_cst (tree method, tree object, Type *type)
   tree ctype;
 
   Type *tb = type->toBasetype ();
-  if (tb->ty == Tdelegate)
+  if (tb->ty == TY::Tdelegate)
     ctype = build_ctype (type);
   else
     {
@@ -463,11 +463,11 @@ build_typeof_null_value (Type *type)
   tree value;
 
   /* For dynamic arrays, set length and pointer fields to zero.  */
-  if (tb->ty == Tarray)
+  if (tb->ty == TY::Tarray)
     value = d_array_value (build_ctype (type), size_int (0), null_pointer_node);
 
   /* For associative arrays, set the pointer field to null.  */
-  else if (tb->ty == Taarray)
+  else if (tb->ty == TY::Taarray)
     {
       tree ctype = build_ctype (type);
       gcc_assert (TYPE_ASSOCIATIVE_ARRAY (ctype));
@@ -477,7 +477,7 @@ build_typeof_null_value (Type *type)
     }
 
   /* For delegates, set the frame and function pointer fields to null.  */
-  else if (tb->ty == Tdelegate)
+  else if (tb->ty == TY::Tdelegate)
     value = build_delegate_cst (null_pointer_node, null_pointer_node, type);
 
   /* Simple zero constant for all other types.  */
@@ -881,7 +881,9 @@ identity_compare_p (StructDeclaration *sd)
 	}
 
       /* Check for types that may have padding.  */
-      if ((tb->ty == Tcomplex80 || tb->ty == Tfloat80 || tb->ty == Timaginary80)
+      if ((tb->ty == TY::Tcomplex80
+	   || tb->ty == TY::Tfloat80
+	   || tb->ty == TY::Timaginary80)
 	  && target.realpad != 0)
 	return false;
 
@@ -959,12 +961,12 @@ lower_struct_comparison (tree_code code, StructDeclaration *sd,
 	  /* Compare inner data structures.  */
 	  tcmp = lower_struct_comparison (code, ts->sym, t1ref, t2ref);
 	}
-      else if (type->ty != Tvector && type->isintegral ())
+      else if (type->ty != TY::Tvector && type->isintegral ())
 	{
 	  /* Integer comparison, no special handling required.  */
 	  tcmp = build_boolop (code, t1ref, t2ref);
 	}
-      else if (type->ty != Tvector && type->isfloating ())
+      else if (type->ty != TY::Tvector && type->isfloating ())
 	{
 	  /* Floating-point comparison, don't compare padding in type.  */
 	  if (!type->iscomplex ())
@@ -1894,7 +1896,7 @@ array_bounds_check (void)
     case CHECKENABLEsafeonly:
       /* For D2 safe functions only.  */
       fd = d_function_chain->function;
-      if (fd && fd->type->ty == Tfunction)
+      if (fd && fd->type->ty == TY::Tfunction)
 	{
 	  if (fd->type->isTypeFunction ()->trust == TRUST::safe)
 	    return true;
@@ -1913,11 +1915,11 @@ TypeFunction *
 get_function_type (Type *t)
 {
   TypeFunction *tf = NULL;
-  if (t->ty == Tpointer)
+  if (t->ty == TY::Tpointer)
     t = t->nextOf ()->toBasetype ();
-  if (t->ty == Tfunction)
+  if (t->ty == TY::Tfunction)
     tf = t->isTypeFunction ();
-  else if (t->ty == Tdelegate)
+  else if (t->ty == TY::Tdelegate)
     tf = t->isTypeDelegate ()->next->isTypeFunction ();
   return tf;
 }
@@ -1977,7 +1979,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
 
   gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
   gcc_assert (tf != NULL);
-  gcc_assert (tf->ty == Tfunction);
+  gcc_assert (tf->ty == TY::Tfunction);
 
   if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
     {
@@ -2076,7 +2078,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
   SET_EXPR_LOCATION (result, input_location);
 
   /* Enforce left to right evaluation.  */
-  if (tf->linkage == LINKd)
+  if (tf->linkage == LINK::d)
     CALL_EXPR_ARGS_ORDERED (result) = 1;
 
   result = maybe_expand_intrinsic (result);
diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 44366988ba7..3df40073ac5 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -88,7 +88,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
   /* Encode CST to buffer.  */
   int len = native_encode_expr (cst, buffer, sizeof (buffer));
 
-  if (tb->ty == Tsarray)
+  if (tb->ty == TY::Tsarray)
     {
       /* Interpret value as a vector of the same size,
 	 then return the array literal.  */
@@ -126,22 +126,22 @@ Compiler::onParseModule (Module *m)
 {
   ModuleDeclaration *md = m->md;
 
-  if (!md || !md->id || !md->packages)
+  if (!md || !md->id|| md->packages.length == 0)
     {
       Identifier *id = (md && md->id) ? md->id : m->ident;
       if (!strcmp (id->toChars (), "object"))
 	create_tinfo_types (m);
     }
-  else if (md->packages->length == 1)
+  else if (md->packages.length == 1)
     {
-      if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+      if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
 	  && !strcmp (md->id->toChars (), "builtins"))
 	d_build_builtins_module (m);
     }
-  else if (md->packages->length == 2)
+  else if (md->packages.length == 2)
     {
-      if (!strcmp ((*md->packages)[0]->toChars (), "core")
-	  && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
+      if (!strcmp (md->packages.ptr[0]->toChars (), "core")
+	  && !strcmp (md->packages.ptr[1]->toChars (), "stdc"))
 	d_add_builtin_module (m);
     }
 }
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index ae0b58efe18..0e030eca541 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -361,14 +361,14 @@ convert_expr (tree exp, Type *etype, Type *totype)
 
   switch (ebtype->ty)
     {
-    case Tdelegate:
-      if (tbtype->ty == Tdelegate)
+    case TY::Tdelegate:
+      if (tbtype->ty == TY::Tdelegate)
 	{
 	  exp = d_save_expr (exp);
 	  return build_delegate_cst (delegate_method (exp),
 				     delegate_object (exp), totype);
 	}
-      else if (tbtype->ty == Tpointer)
+      else if (tbtype->ty == TY::Tpointer)
 	{
 	  /* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
 	     Maybe should only allow void* ?  */
@@ -382,8 +382,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	}
       break;
 
-    case Tstruct:
-      if (tbtype->ty == Tstruct)
+    case TY::Tstruct:
+      if (tbtype->ty == TY::Tstruct)
 	{
 	  if (totype->size () == etype->size ())
 	    {
@@ -400,8 +400,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
       /* else, default conversion, which should produce an error.  */
       break;
 
-    case Tclass:
-      if (tbtype->ty == Tclass)
+    case TY::Tclass:
+      if (tbtype->ty == TY::Tclass)
 	{
 	  ClassDeclaration *cdfrom = ebtype->isClassHandle ();
 	  ClassDeclaration *cdto = tbtype->isClassHandle ();
@@ -460,12 +460,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
       /* else default conversion.  */
       break;
 
-    case Tsarray:
-      if (tbtype->ty == Tpointer)
+    case TY::Tsarray:
+      if (tbtype->ty == TY::Tpointer)
 	{
 	  result = build_nop (build_ctype (totype), build_address (exp));
 	}
-      else if (tbtype->ty == Tarray)
+      else if (tbtype->ty == TY::Tarray)
 	{
 	  dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
 	  dinteger_t esize = ebtype->nextOf ()->size ();
@@ -490,12 +490,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	  return d_array_value (build_ctype (totype), size_int (dim),
 				build_nop (ptrtype, build_address (exp)));
 	}
-      else if (tbtype->ty == Tsarray)
+      else if (tbtype->ty == TY::Tsarray)
 	{
 	  /* D allows casting a static array to any static array type.  */
 	  return build_nop (build_ctype (totype), exp);
 	}
-      else if (tbtype->ty == Tstruct)
+      else if (tbtype->ty == TY::Tstruct)
 	{
 	  /* And allows casting a static array to any struct type too.
 	     Type sizes should have already been checked by the frontend.  */
@@ -510,12 +510,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	}
       break;
 
-    case Tarray:
-      if (tbtype->ty == Tpointer)
+    case TY::Tarray:
+      if (tbtype->ty == TY::Tpointer)
 	{
 	  return d_convert (build_ctype (totype), d_array_ptr (exp));
 	}
-      else if (tbtype->ty == Tarray)
+      else if (tbtype->ty == TY::Tarray)
 	{
 	  /* Assume tvoid->size() == 1.  */
 	  d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
@@ -543,7 +543,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	      return build_vconvert (build_ctype (totype), exp);
 	    }
 	}
-      else if (tbtype->ty == Tsarray)
+      else if (tbtype->ty == TY::Tsarray)
 	{
 	  /* Strings are treated as dynamic arrays in D2.  */
 	  if (ebtype->isString () && tbtype->isString ())
@@ -557,23 +557,23 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	}
       break;
 
-    case Taarray:
-      if (tbtype->ty == Taarray)
+    case TY::Taarray:
+      if (tbtype->ty == TY::Taarray)
 	return build_vconvert (build_ctype (totype), exp);
       /* Can convert associative arrays to void pointers.  */
-      else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
+      else if (tbtype->ty == TY::Tpointer && tbtype->nextOf ()->ty == TY::Tvoid)
 	return build_vconvert (build_ctype (totype), exp);
       /* Else, default conversion, which should product an error.  */
       break;
 
-    case Tpointer:
+    case TY::Tpointer:
       /* Can convert void pointers to associative arrays too.  */
-      if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
+      if (tbtype->ty == TY::Taarray && ebtype->nextOf ()->ty == TY::Tvoid)
 	return build_vconvert (build_ctype (totype), exp);
       break;
 
-    case Tnull:
-    case Tnoreturn:
+    case TY::Tnull:
+    case TY::Tnoreturn:
       /* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
 	 for `noreturn' expressions is represented as all zeros.  */
       result = build_typeof_null_value (totype);
@@ -583,8 +583,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	result = compound_expr (exp, result);
       break;
 
-    case Tvector:
-      if (tbtype->ty == Tsarray)
+    case TY::Tvector:
+      if (tbtype->ty == TY::Tsarray)
 	{
 	  if (tbtype->size () == ebtype->size ())
 	    return build_vconvert (build_ctype (totype), exp);
@@ -624,7 +624,7 @@ convert_for_rvalue (tree expr, Type *etype, Type *totype)
 
   switch (ebtype->ty)
     {
-    case Tbool:
+    case TY::Tbool:
       /* If casting from bool, the result is either 0 or 1, any other value
 	 violates @safe code, so enforce that it is never invalid.  */
       if (CONSTANT_CLASS_P (expr))
@@ -662,7 +662,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
 
   /* Assuming this only has to handle converting a non Tsarray type to
      arbitrarily dimensioned Tsarrays.  */
-  if (tbtype->ty == Tsarray)
+  if (tbtype->ty == TY::Tsarray)
     {
       Type *telem = tbtype->nextOf ()->baseElemOf ();
 
@@ -696,7 +696,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
     }
 
   /* D Front end uses IntegerExp(0) to mean zero-init an array or structure.  */
-  if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct)
+  if ((tbtype->ty == TY::Tsarray || tbtype->ty == TY::Tstruct)
       && ebtype->isintegral ())
     {
       if (!integer_zerop (expr))
@@ -747,12 +747,12 @@ convert_for_condition (tree expr, Type *type)
 
   switch (type->toBasetype ()->ty)
     {
-    case Taarray:
+    case TY::Taarray:
       /* Checks that aa.ptr !is null.  */
       result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
       break;
 
-    case Tarray:
+    case TY::Tarray:
       {
 	/* Checks (arr.length || arr.ptr) (i.e arr !is null).  */
 	expr = d_save_expr (expr);
@@ -773,7 +773,7 @@ convert_for_condition (tree expr, Type *type)
 	break;
       }
 
-    case Tdelegate:
+    case TY::Tdelegate:
       {
 	/* Checks (function || object), but what good is it if there is
 	   a null function pointer?  */
@@ -794,7 +794,7 @@ convert_for_condition (tree expr, Type *type)
 	break;
       }
 
-    case Tnoreturn:
+    case TY::Tnoreturn:
       /* Front-end allows conditionals that never return, represent the
 	 conditional result value as all zeros.  */
       result = build_zero_cst (d_bool_type);
@@ -821,10 +821,10 @@ d_array_convert (Expression *exp)
 {
   Type *tb = exp->type->toBasetype ();
 
-  if (tb->ty == Tarray)
+  if (tb->ty == TY::Tarray)
     return build_expr (exp);
 
-  if (tb->ty == Tsarray)
+  if (tb->ty == TY::Tsarray)
     {
       Type *totype = tb->nextOf ()->arrayOf ();
       return convert_expr (build_expr (exp), exp->type, totype);
@@ -843,7 +843,8 @@ d_array_convert (Type *etype, Expression *exp)
 {
   Type *tb = exp->type->toBasetype ();
 
-  if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
+  if ((tb->ty != TY::Tarray && tb->ty != TY::Tsarray)
+      || same_type_p (tb, etype))
     {
       /* Convert single element to an array.  */
       tree expr = build_expr (exp);
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 256faeb6c13..522095f12c5 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -80,7 +80,7 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
 Type *
 getTypeInfoType (Loc loc, Type *type, Scope *sc)
 {
-  gcc_assert (type->ty != Terror);
+  gcc_assert (type->ty != TY::Terror);
   check_typeinfo_type (loc, sc);
   create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
   return type->vtinfo->type;
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 2a56e85158c..c8f9935da30 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -244,9 +244,9 @@ deps_write (Module *module, obstack *buffer)
 		  && m->parent == NULL)
 		continue;
 
-	      if (m->md && m->md->packages)
+	      if (m->md && m->md->packages.length)
 		{
-		  Identifier *package = (*m->md->packages)[0];
+		  Identifier *package = m->md->packages.ptr[0];
 
 		  if (package == Identifier::idPool ("core")
 		      || package == Identifier::idPool ("std")
@@ -504,6 +504,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 	case CppStdRevisionCpp11:
 	case CppStdRevisionCpp14:
 	case CppStdRevisionCpp17:
+	case CppStdRevisionCpp20:
 	  global.params.cplusplus = (CppStdRevision) value;
 	  break;
 
@@ -547,11 +548,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_fpreview_all:
-      global.params.vsafe = value;
       global.params.ehnogc = value;
-      global.params.useDIP25 = value;
+      global.params.useDIP25 = FeatureState::enabled;
+      global.params.useDIP1000 = FeatureState::enabled;
       global.params.useDIP1021 = value;
-      global.params.dtorFields = value;
+      global.params.dtorFields = FeatureState::enabled;
       global.params.fieldwise = value;
       global.params.fixAliasThis = value;
       global.params.previewIn = value;
@@ -559,10 +560,12 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.markdown = value;
       global.params.noSharedAccess = value;
       global.params.rvalueRefParam = value;
+      global.params.inclusiveInContracts = value;
+      global.params.shortenedMethods = value;
       break;
 
     case OPT_fpreview_dip1000:
-      global.params.vsafe = value;
+      global.params.useDIP1000 = FeatureState::enabled;
       break;
 
     case OPT_fpreview_dip1008:
@@ -574,11 +577,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_fpreview_dip25:
-      global.params.useDIP25 = value;
+      global.params.useDIP25 = FeatureState::enabled;
       break;
 
     case OPT_fpreview_dtorfields:
-      global.params.dtorFields = value;
+      global.params.dtorFields = FeatureState::enabled;
       break;
 
     case OPT_fpreview_fieldwise:
@@ -601,10 +604,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.fix16997 = value;
       break;
 
-    case OPT_fpreview_markdown:
-      global.params.markdown = value;
-      break;
-
     case OPT_fpreview_nosharedaccess:
       global.params.noSharedAccess = value;
       break;
@@ -613,16 +612,30 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.rvalueRefParam = value;
       break;
 
+    case OPT_fpreview_shortenedMethods:
+      global.params.shortenedMethods = value;
+      break;
+
     case OPT_frelease:
       global.params.release = value;
       break;
 
     case OPT_frevert_all:
-      global.params.noDIP25 = value;
+      global.params.useDIP25 = FeatureState::disabled;
+      global.params.markdown = !value;
+      global.params.dtorFields = FeatureState::disabled;
       break;
 
     case OPT_frevert_dip25:
-      global.params.noDIP25 = value;
+      global.params.useDIP25 = FeatureState::disabled;
+      break;
+
+    case OPT_frevert_dtorfields:
+      global.params.dtorFields = FeatureState::disabled;
+      break;
+
+    case OPT_frevert_markdown:
+      global.params.markdown = !value;
       break;
 
     case OPT_frtti:
@@ -639,17 +652,12 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_ftransition_all:
-      global.params.vcomplex = value;
       global.params.vfield = value;
       global.params.vgc = value;
       global.params.vmarkdown= value;
       global.params.vtls = value;
       break;
 
-    case OPT_ftransition_complex:
-      global.params.vcomplex = value;
-      break;
-
     case OPT_ftransition_field:
       global.params.vfield = value;
       break;
@@ -881,7 +889,11 @@ d_post_options (const char ** fn)
 
   /* Enabling DIP1021 implies DIP1000.  */
   if (global.params.useDIP1021)
-    global.params.vsafe = true;
+    global.params.useDIP1000 = FeatureState::enabled;
+
+  /* Enabling DIP1000 implies DIP25.  */
+  if (global.params.useDIP1000 == FeatureState::enabled)
+    global.params.useDIP25 = FeatureState::enabled;
 
   /* Keep in sync with existing -fbounds-check flag.  */
   flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon);
@@ -1273,7 +1285,7 @@ d_parse_file (void)
       if (name && (name[0] != '-' || name[1] != '\0'))
 	{
 	  const char *nameext
-	    = FileName::defaultExt (name, global.json_ext.ptr);
+	    = FileName::defaultExt (name, json_ext.ptr);
 	  json_stream = fopen (nameext, "w");
 	  if (!json_stream)
 	    {
@@ -1500,7 +1512,7 @@ d_type_promotes_to (tree type)
   /* Promotions are only applied on unnamed function arguments for declarations
      with `extern(C)' or `extern(C++)' linkage.  */
   if (cfun && DECL_LANG_FRONTEND (cfun->decl)
-      && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINKd)
+      && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINK::d)
     {
       /* In [type/integer-promotions], integer promotions are conversions of the
 	 following types:
@@ -1653,7 +1665,8 @@ d_types_compatible_p (tree x, tree y)
 	return true;
 
       /* Type system allows implicit conversion between.  */
-      if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
+      if (tx->implicitConvTo (ty) != MATCH::nomatch
+	  || ty->implicitConvTo (tx) != MATCH::nomatch)
 	return true;
     }
 
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index 5133d1114b3..21417dddf78 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tm_p.h"
 #include "target.h"
+#include "calls.h"
 
 #include "d-tree.h"
 #include "d-target.h"
@@ -137,19 +138,19 @@ Target::_init (const Param &)
   /* Define what type to use for size_t, ptrdiff_t.  */
   if (this->ptrsize == 8)
     {
-      global.params.isLP64 = true;
-      Type::tsize_t = Type::basic[Tuns64];
-      Type::tptrdiff_t = Type::basic[Tint64];
+      this->isLP64 = true;
+      Type::tsize_t = Type::basic[(int)TY::Tuns64];
+      Type::tptrdiff_t = Type::basic[(int)TY::Tint64];
     }
   else if (this->ptrsize == 4)
     {
-      Type::tsize_t = Type::basic[Tuns32];
-      Type::tptrdiff_t = Type::basic[Tint32];
+      Type::tsize_t = Type::basic[(int)TY::Tuns32];
+      Type::tptrdiff_t = Type::basic[(int)TY::Tint32];
     }
   else if (this->ptrsize == 2)
     {
-      Type::tsize_t = Type::basic[Tuns16];
-      Type::tptrdiff_t = Type::basic[Tint16];
+      Type::tsize_t = Type::basic[(int)TY::Tuns16];
+      Type::tptrdiff_t = Type::basic[(int)TY::Tint16];
     }
   else
     sorry ("D does not support pointers on this target.");
@@ -159,15 +160,7 @@ Target::_init (const Param &)
   /* Set-up target C ABI.  */
   this->c.longsize = int_size_in_bytes (long_integer_type_node);
   this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
-
-  /* Define what type to use for wchar_t.  We don't want to support wide
-     characters less than "short" in D.  */
-  if (WCHAR_TYPE_SIZE == 32)
-    this->c.twchar_t = Type::basic[Tdchar];
-  else if (WCHAR_TYPE_SIZE == 16)
-    this->c.twchar_t = Type::basic[Twchar];
-  else
-    sorry ("D does not support wide characters on this target.");
+  this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
 
   /* Set-up target C++ ABI.  */
   this->cpp.reverseOverloads = false;
@@ -177,6 +170,12 @@ Target::_init (const Param &)
   /* Set-up target Objective-C ABI.  */
   this->objc.supported = false;
 
+  /* Set-up environmental settings.  */
+  this->obj_ext = "o";
+  this->lib_ext = "a";
+  this->dll_ext = "so";
+  this->run_noext = true;
+
   /* Initialize all compile-time properties for floating-point types.
      Should ensure that our real_t type is able to represent real_value.  */
   gcc_assert (sizeof (real_t) >= sizeof (real_value));
@@ -268,7 +267,7 @@ Target::isVectorTypeSupported (int sz, Type *type)
     type = Type::tuns8;
 
   /* No support for non-trivial types, complex types, or booleans.  */
-  if (!type->isTypeBasic () || type->iscomplex () || type->ty == Tbool)
+  if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
     return 2;
 
   /* In [simd/vector extensions], which vector types are supported depends on
@@ -288,9 +287,9 @@ Target::isVectorTypeSupported (int sz, Type *type)
    Returns true if the operation is supported or type is not a vector.  */
 
 bool
-Target::isVectorOpSupported (Type *type, TOK op, Type *)
+Target::isVectorOpSupported (Type *type, unsigned op, Type *)
 {
-  if (type->ty != Tvector)
+  if (type->ty != TY::Tvector)
     return true;
 
   /* Don't support if type is non-scalar, such as __vector(void[]).  */
@@ -366,7 +365,8 @@ TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
 const char *
 TargetCPP::typeMangle (Type *type)
 {
-  if (type->isTypeBasic () || type->ty == Tvector || type->ty == Tstruct)
+  if (type->isTypeBasic () || type->ty == TY::Tvector
+      || type->ty == TY::Tstruct)
     {
       tree ctype = build_ctype (type);
       return targetm.mangle_type (ctype);
@@ -387,14 +387,14 @@ TargetCPP::parameterType (Parameter *arg)
   else if (arg->storageClass & STClazy)
     {
       /* Mangle as delegate.  */
-      Type *td = TypeFunction::create (NULL, t, VARARGnone, LINKd);
-      td = TypeDelegate::create (td);
-      t = t->merge2 ();
+      TypeFunction *tf = TypeFunction::create (NULL, t, VARARGnone, LINK::d);
+      TypeDelegate *td = TypeDelegate::create (tf);
+      t = td->merge2 ();
     }
 
   /* Could be a va_list, which we mangle as a pointer.  */
   Type *tvalist = target.va_listType (Loc (), NULL);
-  if (t->ty == Tsarray && tvalist->ty == Tsarray)
+  if (t->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
     {
       Type *tb = t->toBasetype ()->mutableOf ();
       if (tb == tvalist)
@@ -437,10 +437,10 @@ Target::systemLinkage (void)
       /* In [attribute/linkage], `System' is the same as `Windows' on Windows
 	 platforms, and `C' on other platforms.  */
       if (link_system)
-	return LINKwindows;
+	return LINK::windows;
     }
 
-  return LINKc;
+  return LINK::c;
 }
 
 /* Generate a TypeTuple of the equivalent types used to determine if a
@@ -469,7 +469,7 @@ Target::isReturnOnStack (TypeFunction *tf, bool)
 
   Type *tn = tf->next->toBasetype ();
 
-  return (tn->ty == Tstruct || tn->ty == Tsarray);
+  return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
 }
 
 /* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by
@@ -562,12 +562,49 @@ Target::getTargetInfo (const char *key, const Loc &loc)
   return NULL;
 }
 
-/**
- * Returns true if the implementation for object monitors is always defined
- * in the D runtime library (rt/monitor_.d).  */
+/* Returns true if the callee invokes destructors for arguments.  */
+
+bool
+Target::isCalleeDestroyingArgs (TypeFunction *tf)
+{
+  return tf->linkage == LINK::d;
+}
+
+/* Returns true if the implementation for object monitors is always defined
+   in the D runtime library (rt/monitor_.d).  */
 
 bool
 Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
 {
   return true;
 }
+
+/* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
+   be passed by reference or by valie.  This is used only when compiling with
+   `-fpreview=in' enabled.  */
+
+bool
+Target::preferPassByRef (Type *param_type)
+{
+  if (param_type->size () == SIZE_INVALID)
+    return false;
+
+  tree type = build_ctype (param_type);
+
+  /* Prefer a `ref' if the type is an aggregate, and its size is greater than
+     its alignment.  */
+  if (AGGREGATE_TYPE_P (type)
+      && (!valid_constant_size_p (TYPE_SIZE_UNIT (type))
+	  || compare_tree_int (TYPE_SIZE_UNIT (type), TYPE_ALIGN (type)) > 0))
+    return true;
+
+  /* If the back-end is always going to pass this by invisible reference.  */
+  if (pass_by_reference (NULL, function_arg_info (type, true)))
+    return true;
+
+  /* If returning the parameter means the caller will do RVO.  */
+  if (targetm.calls.return_in_memory (type, NULL_TREE))
+    return true;
+
+  return false;
+}
diff --git a/gcc/d/d-target.def b/gcc/d/d-target.def
index 37764e0df38..67647515cf2 100644
--- a/gcc/d/d-target.def
+++ b/gcc/d/d-target.def
@@ -112,22 +112,5 @@ if they have external linkage.  If this flag is false, then instantiated\n\
 decls will be emitted as weak symbols.  The default is @code{false}.",
  bool, false)
 
-/* The floating point ABI, may be "hard" or "soft".  */
-DEFHOOK
-(d_float_abi_type,
- "Returns a string specifying which floating-point ABI is in use, or whether\n\
-floating-point value types are passed in FPU registers.  For most targets,\n\
-this would be described as either \"hard\" or \"soft\".",
- const char *, (void),
- hook_constcharptr_void_null)
-
-/* The target object format.  */
-DEFHOOK
-(d_object_format,
- "Returns a string specifying the executable object format of the platform\n\
-the compiler is generating code for.",
- const char *, (void),
- hook_constcharptr_void_null)
-
 /* Close the 'struct gcc_targetdm' definition.  */
 HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 0a6f804d55f..ac6161e234e 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -106,9 +106,9 @@ gcc_attribute_p (Dsymbol *decl)
 {
   ModuleDeclaration *md = decl->getModule ()->md;
 
-  if (md && md->packages && md->packages->length == 1)
+  if (md && md->packages.length == 1)
     {
-      if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+      if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
 	  && !strcmp (md->id->toChars (), "attributes"))
 	return true;
     }
@@ -156,7 +156,7 @@ apply_pragma_crt (Dsymbol *sym, bool isctor)
 	  decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
 	}
 
-      if (fd->linkage != LINKc)
+      if (fd->linkage != LINK::c)
 	{
 	  error_at (make_location_t (fd->loc),
 		    "must be %<extern(C)%> for %<pragma(%s)%>",
@@ -376,14 +376,14 @@ public:
        nested members.  Only applies to classes or structs.  */
     Type *tb = fd->type->nextOf ()->baseElemOf ();
 
-    while (tb->ty == Tarray || tb->ty == Tpointer)
+    while (tb->ty == TY::Tarray || tb->ty == TY::Tpointer)
       tb = tb->nextOf ()->baseElemOf ();
 
     TemplateInstance *ti = NULL;
 
-    if (tb->ty == Tstruct)
+    if (tb->ty == TY::Tstruct)
       ti = tb->isTypeStruct ()->sym->isInstantiated ();
-    else if (tb->ty == Tclass)
+    else if (tb->ty == TY::Tclass)
       ti = tb->isTypeClass ()->sym->isInstantiated ();
 
     /* Return type is instantiated from this template declaration, walk over
@@ -425,7 +425,7 @@ public:
     if (d->semanticRun >= PASSobj)
       return;
 
-    if (d->type->ty == Terror)
+    if (d->type->ty == TY::Terror)
       {
 	error_at (make_location_t (d->loc),
 		  "had semantic errors when compiling");
@@ -512,7 +512,8 @@ public:
 	    if (fd2->isFuture ())
 	      continue;
 
-	    if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
+	    if (fd->leastAsSpecialized (fd2) != MATCH::nomatch
+		|| fd2->leastAsSpecialized (fd) != MATCH::nomatch)
 	      {
 		error_at (make_location_t (fd->loc), "use of %qs",
 			  fd->toPrettyChars ());
@@ -539,7 +540,7 @@ public:
     if (d->semanticRun >= PASSobj)
       return;
 
-    if (d->type->ty == Terror)
+    if (d->type->ty == TY::Terror)
       {
 	error_at (make_location_t (d->loc),
 		  "had semantic errors when compiling");
@@ -613,7 +614,7 @@ public:
     if (d->semanticRun >= PASSobj)
       return;
 
-    if (d->type->ty == Terror)
+    if (d->type->ty == TY::Terror)
       {
 	error_at (make_location_t (d->loc),
 		  "had semantic errors when compiling");
@@ -656,7 +657,7 @@ public:
     if (d->semanticRun >= PASSobj)
       return;
 
-    if (d->errors || d->type->ty == Terror)
+    if (d->errors || d->type->ty == TY::Terror)
       {
 	error_at (make_location_t (d->loc),
 		  "had semantic errors when compiling");
@@ -695,7 +696,7 @@ public:
     if (d->semanticRun >= PASSobj)
       return;
 
-    if (d->type->ty == Terror)
+    if (d->type->ty == TY::Terror)
       {
 	error_at (make_location_t (d->loc),
 		  "had semantic errors when compiling");
@@ -713,8 +714,6 @@ public:
 	/* Do not store variables we cannot take the address of,
 	   but keep the values for purposes of debugging.  */
 	if (!d->type->isscalar ())
-	  DECL_INITIAL (decl) = build_expr (ie, false, true);
-	else
 	  {
 	    tree decl = get_symbol_decl (d);
 	    d_pushdecl (decl);
@@ -763,7 +762,7 @@ public:
 
 	/* Frontend should have already caught this.  */
 	gcc_assert (!integer_zerop (size)
-		    || d->type->toBasetype ()->ty == Tsarray);
+		    || d->type->toBasetype ()->ty == TY::Tsarray);
 
 	d_finish_decl (decl);
 
@@ -838,7 +837,7 @@ public:
     /* Check if any errors occurred when running semantic.  */
     if (TypeFunction *tf = d->type->isTypeFunction ())
       {
-	if (tf->next == NULL || tf->next->ty == Terror)
+	if (tf->next == NULL || tf->next->ty == TY::Terror)
 	  return;
       }
 
@@ -1317,9 +1316,9 @@ get_symbol_decl (Declaration *decl)
 
       /* In [pragma/inline], functions decorated with `pragma(inline)' affects
 	 whether they are inlined or not.  */
-      if (fd->inlining == PINLINEalways)
+      if (fd->inlining == PINLINE::always)
 	DECL_DECLARED_INLINE_P (decl->csym) = 1;
-      else if (fd->inlining == PINLINEnever)
+      else if (fd->inlining == PINLINE::never)
 	DECL_UNINLINABLE (decl->csym) = 1;
 
       /* Function was declared `naked'.  */
@@ -1333,13 +1332,6 @@ get_symbol_decl (Declaration *decl)
       if (fd->generated)
 	DECL_ARTIFICIAL (decl->csym) = 1;
 
-      /* Vector array operations are always compiler generated.  */
-      if (fd->isArrayOp)
-	{
-	  DECL_ARTIFICIAL (decl->csym) = 1;
-	  DECL_DECLARED_INLINE_P (decl->csym) = 1;
-	}
-
       /* Ensure and require contracts are lexically nested in the function they
 	 part of, but are always publicly callable.  */
       if (fd->ident == Identifier::idPool ("ensure")
@@ -1350,7 +1342,7 @@ get_symbol_decl (Declaration *decl)
 	DECL_FINAL_P (decl->csym) = 1;
 
       /* Function is of type `noreturn' or `typeof(*null)'.  */
-      if (fd->type->nextOf ()->ty == Tnoreturn)
+      if (fd->type->nextOf ()->ty == TY::Tnoreturn)
 	TREE_THIS_VOLATILE (decl->csym) = 1;
 
       /* Check whether this function is expanded by the frontend.  */
@@ -1377,10 +1369,10 @@ get_symbol_decl (Declaration *decl)
   if (decl->storage_class & STCvolatile)
     TREE_THIS_VOLATILE (decl->csym) = 1;
 
-  /* Protection attributes are used by the debugger.  */
-  if (decl->protection.kind == Prot::private_)
+  /* Visibility attributes are used by the debugger.  */
+  if (decl->visibility.kind == Visibility::private_)
     TREE_PRIVATE (decl->csym) = 1;
-  else if (decl->protection.kind == Prot::protected_)
+  else if (decl->visibility.kind == Visibility::protected_)
     TREE_PROTECTED (decl->csym) = 1;
 
   /* Likewise, so could the deprecated attribute.  */
@@ -1873,7 +1865,7 @@ make_thunk (FuncDeclaration *decl, int offset)
      forcing a D local thunk to be emitted.  */
   const char *ident;
 
-  if (decl->linkage == LINKcpp)
+  if (decl->linkage == LINK::cpp)
     ident = target.cpp.thunkMangle (decl, offset);
   else
     {
@@ -1889,7 +1881,9 @@ make_thunk (FuncDeclaration *decl, int offset)
   SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
 
   d_keep (thunk);
-  free (CONST_CAST (char *, ident));
+
+  if (decl->linkage != LINK::cpp)
+    free (CONST_CAST (char *, ident));
 
   if (!DECL_EXTERNAL (function))
     finish_thunk (thunk, function);
@@ -2389,17 +2383,6 @@ create_field_decl (tree type, const char *name, int artificial, int ignored)
   return decl;
 }
 
-/* Returns the module NAMESPACE_DECL context of DECL or NULL.  */
-
-static tree
-get_module_context (tree decl)
-{
-  while (decl && TREE_CODE (decl) != NAMESPACE_DECL)
-    decl = get_containing_scope (decl);
-
-  return decl;
-}
-
 /* Return the COMDAT group into which DECL should be placed.  */
 
 static tree
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index c93d090a51d..96d2e208f83 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-3a55c54a8e5773c3f56e10365a98f4570f8c6ce6
+2a48c54ad064f60eee50c63a27e28b730775546b
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
index e517db14e4f..720d25683af 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -44,10 +44,11 @@ Note that these groups have no strict meaning, the category assignments are a bi
 
 | File                                                                  | Purpose                                                              |
 |-----------------------------------------------------------------------|----------------------------------------------------------------------|
-| [lexer.d](https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d)   | Convert source code into tokens for the parser                       |
+| [lexer.d](https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d)   | Convert source code into tokens for the D and ImportC parsers        |
 | [entity.d](https://github.com/dlang/dmd/blob/master/src/dmd/entity.d) | Define "\\&Entity;" escape sequence for strings / character literals |
 | [tokens.d](https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d) | Define lexical tokens.                                               |
-| [parse.d](https://github.com/dlang/dmd/blob/master/src/dmd/parse.d)   | Convert tokens into an Abstract Syntax Tree (AST)                    |
+| [parse.d](https://github.com/dlang/dmd/blob/master/src/dmd/parse.d)   | D parser, converting tokens into an Abstract Syntax Tree (AST)       |
+| [cparse.d](https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d) | ImportC parser, converting tokens into an Abstract Syntax Tree (AST) |
 
 ### Semantic analysis
 
@@ -76,6 +77,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
 | [ast_node.d](https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d)         | Define an abstract AST node class                           |
 | [astbase.d](https://github.com/dlang/dmd/blob/master/src/dmd/astbase.d)           | Namespace of AST nodes that can be produced by the parser   |
 | [astcodegen.d](https://github.com/dlang/dmd/blob/master/src/dmd/astcodegen.d)     | Namespace of AST nodes of a AST ready for code generation   |
+| [astenums.d](https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d)         | Enums common to DMD and AST                                 |
 | [expression.d](https://github.com/dlang/dmd/blob/master/src/dmd/expression.d)     | Define expression AST nodes                                 |
 | [statement.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement.d)       | Define statement AST nodes                                  |
 | [staticassert.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d) | Define a `static assert` AST node                           |
@@ -174,7 +176,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
 
 | File                                                                        | Purpose                                                                            |
 |-----------------------------------------------------------------------------|------------------------------------------------------------------------------------|
-| [chkformat.d](https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d) | Validate arguments wiht format specifiers for `printf` / `scanf` etc.              |
+| [chkformat.d](https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d) | Validate arguments with format specifiers for `printf` / `scanf` etc.              |
 | [imphint.d](https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d)     | Give a suggestion to e.g. `import std.stdio` when `writeln` could not be resolved. |
 
 ### Library files
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 18ca570447d..6945fd11783 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.094.0
+v2.097.0
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index 3f5916a36c3..20c162c7fa1 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d)
@@ -14,6 +14,7 @@
 module dmd.access;
 
 import dmd.aggregate;
+import dmd.astenums;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dmodule;
@@ -48,11 +49,19 @@ bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember)
         return false; // for backward compatibility
     }
 
-    if (!symbolIsVisible(sc, smember) && (!(sc.flags & SCOPE.onlysafeaccess) || sc.func.setUnsafe()))
+    if (!symbolIsVisible(sc, smember))
     {
+        // when in @safe code or with -preview=dip1000
+        if (sc.flags & SCOPE.onlysafeaccess)
+        {
+            // if there is a func. ask for it's opinion of safety, and if it considers the access @safe accept it.
+            if (sc.func && !sc.func.setUnsafe())
+                return false;
+        }
+
         ad.error(loc, "member `%s` is not accessible%s", smember.toChars(), (sc.flags & SCOPE.onlysafeaccess) ? " from `@safe` code".ptr : "".ptr);
-        //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
-        //        smember.kind(), smember.toPrettyChars(), smember.prot(), smember.semanticRun);
+        //printf("smember = %s %s, vis = %d, semanticRun = %d\n",
+        //        smember.kind(), smember.toPrettyChars(), smember.visible() smember.semanticRun);
         return true;
     }
     return false;
@@ -70,14 +79,14 @@ private bool hasPackageAccess(Module mod, Dsymbol s)
 {
     static if (LOG)
     {
-        printf("hasPackageAccess(s = '%s', mod = '%s', s.protection.pkg = '%s')\n", s.toChars(), mod.toChars(), s.prot().pkg ? s.prot().pkg.toChars() : "NULL");
+        printf("hasPackageAccess(s = '%s', mod = '%s', s.visibility.pkg = '%s')\n", s.toChars(), mod.toChars(), s.visible().pkg ? s.visible().pkg.toChars() : "NULL");
     }
     Package pkg = null;
-    if (s.prot().pkg)
-        pkg = s.prot().pkg;
+    if (s.visible().pkg)
+        pkg = s.visible().pkg;
     else
     {
-        // no explicit package for protection, inferring most qualified one
+        // no explicit package for visibility, inferring most qualified one
         for (; s; s = s.parent)
         {
             if (auto m = s.isModule())
@@ -163,7 +172,7 @@ private bool hasProtectedAccess(Scope *sc, Dsymbol s)
  * Check access to d for expression e.d
  * Returns true if the declaration is not accessible.
  */
-bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d)
+bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
 {
     if (sc.flags & SCOPE.noaccesscheck)
         return false;
@@ -227,7 +236,7 @@ bool checkAccess(Scope* sc, Package p)
         return false;
     for (; sc; sc = sc.enclosing)
     {
-        if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Prot(Prot.Kind.private_)))
+        if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Visibility(Visibility.Kind.private_)))
             return false;
     }
 
@@ -244,16 +253,16 @@ bool checkAccess(Scope* sc, Package p)
  */
 bool symbolIsVisible(Module mod, Dsymbol s)
 {
-    // should sort overloads by ascending protection instead of iterating here
+    // should sort overloads by ascending visibility instead of iterating here
     s = mostVisibleOverload(s);
-    final switch (s.prot().kind)
+    final switch (s.visible().kind)
     {
-    case Prot.Kind.undefined: return true;
-    case Prot.Kind.none: return false; // no access
-    case Prot.Kind.private_: return s.getAccessModule() == mod;
-    case Prot.Kind.package_: return s.getAccessModule() == mod || hasPackageAccess(mod, s);
-    case Prot.Kind.protected_: return s.getAccessModule() == mod;
-    case Prot.Kind.public_, Prot.Kind.export_: return true;
+    case Visibility.Kind.undefined: return true;
+    case Visibility.Kind.none: return false; // no access
+    case Visibility.Kind.private_: return s.getAccessModule() == mod;
+    case Visibility.Kind.package_: return s.getAccessModule() == mod || hasPackageAccess(mod, s);
+    case Visibility.Kind.protected_: return s.getAccessModule() == mod;
+    case Visibility.Kind.public_, Visibility.Kind.export_: return true;
     }
 }
 
@@ -291,21 +300,21 @@ bool symbolIsVisible(Scope *sc, Dsymbol s)
  */
 bool checkSymbolAccess(Scope *sc, Dsymbol s)
 {
-    final switch (s.prot().kind)
+    final switch (s.visible().kind)
     {
-    case Prot.Kind.undefined: return true;
-    case Prot.Kind.none: return false; // no access
-    case Prot.Kind.private_: return sc._module == s.getAccessModule();
-    case Prot.Kind.package_: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s);
-    case Prot.Kind.protected_: return hasProtectedAccess(sc, s);
-    case Prot.Kind.public_, Prot.Kind.export_: return true;
+    case Visibility.Kind.undefined: return true;
+    case Visibility.Kind.none: return false; // no access
+    case Visibility.Kind.private_: return sc._module == s.getAccessModule();
+    case Visibility.Kind.package_: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s);
+    case Visibility.Kind.protected_: return hasProtectedAccess(sc, s);
+    case Visibility.Kind.public_, Visibility.Kind.export_: return true;
     }
 }
 
 /**
  * Use the most visible overload to check visibility. Later perform an access
  * check on the resolved overload.  This function is similar to overloadApply,
- * but doesn't recurse nor resolve aliases because protection/visibility is an
+ * but doesn't recurse nor resolve aliases because visibility is an
  * attribute of the alias not the aliasee.
  */
 public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null)
@@ -355,7 +364,7 @@ public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null)
                  * Usually aliases should not be resolved for visibility checking
                  * b/c public aliases to private symbols are public. But for the
                  * overloadable alias situation, the Alias (_ad_) has been moved
-                 * into it's own Aliasee, leaving a shell that we peel away here.
+                 * into its own Aliasee, leaving a shell that we peel away here.
                  */
                 auto aliasee = ad.toAlias();
                 if (aliasee.isFuncAliasDeclaration || aliasee.isOverDeclaration)
@@ -378,23 +387,23 @@ public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null)
             break;
 
         /**
-        * Return the "effective" protection attribute of a symbol when accessed in a module.
-        * The effective protection attribute is the same as the regular protection attribute,
+        * Return the "effective" visibility attribute of a symbol when accessed in a module.
+        * The effective visibility attribute is the same as the regular visibility attribute,
         * except package() is "private" if the module is outside the package;
         * otherwise, "public".
         */
-        static Prot protectionSeenFromModule(Dsymbol d, Module mod = null)
+        static Visibility visibilitySeenFromModule(Dsymbol d, Module mod = null)
         {
-            Prot prot = d.prot();
-            if (mod && prot.kind == Prot.Kind.package_)
+            Visibility vis = d.visible();
+            if (mod && vis.kind == Visibility.Kind.package_)
             {
-                return hasPackageAccess(mod, d) ? Prot(Prot.Kind.public_) : Prot(Prot.Kind.private_);
+                return hasPackageAccess(mod, d) ? Visibility(Visibility.Kind.public_) : Visibility(Visibility.Kind.private_);
             }
-            return prot;
+            return vis;
         }
 
         if (next &&
-            protectionSeenFromModule(mostVisible, mod).isMoreRestrictiveThan(protectionSeenFromModule(next, mod)))
+            visibilitySeenFromModule(mostVisible, mod) < visibilitySeenFromModule(next, mod))
             mostVisible = next;
     }
     return mostVisible;
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index f5cfc00d8fa..da54ba2bf9f 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -4,7 +4,7 @@
  * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
  *                $(LINK2 https://dlang.org/spec/class.html, Class).
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d)
@@ -20,7 +20,7 @@ import core.checkedint;
 import dmd.aliasthis;
 import dmd.apply;
 import dmd.arraytypes;
-import dmd.gluelayer : Symbol;
+import dmd.astenums;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dstruct;
@@ -38,29 +38,13 @@ import dmd.tokens;
 import dmd.typesem : defaultInit;
 import dmd.visitor;
 
-enum Sizeok : int
-{
-    none,           /// size of aggregate is not yet able to compute
-    fwd,            /// size of aggregate is ready to compute
-    inProcess,      /// in the midst of computing the size
-    done,           /// size of aggregate is set correctly
-}
-
-enum Baseok : int
-{
-    none,             /// base classes not computed yet
-    start,            /// in process of resolving base classes
-    done,             /// all base classes are resolved
-    semanticdone,     /// all base classes semantic done
-}
-
 /**
  * The ClassKind enum is used in AggregateDeclaration AST nodes to
  * specify the linkage type of the struct/class/interface or if it
  * is an anonymous class. If the class is anonymous it is also
  * considered to be a D class.
  */
-enum ClassKind : int
+enum ClassKind : ubyte
 {
     /// the aggregate is a d(efault) class
     d,
@@ -70,6 +54,16 @@ enum ClassKind : int
     objc,
 }
 
+/**
+ * If an aggregate has a pargma(mangle, ...) this holds the information
+ * to mangle.
+ */
+struct MangleOverride
+{
+    Dsymbol agg;   // The symbol to copy template parameters from (if any)
+    Identifier id; // the name to override the aggregate's with, defaults to agg.ident
+}
+
 /***********************************************************
  * Abstract aggregate as a common ancestor for Class- and StructDeclaration.
  */
@@ -89,6 +83,9 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
     /// Only valid for class and struct. TODO: Merge with ClassKind ?
     CPPMANGLE cppmangle;
 
+    /// overridden symbol with pragma(mangle, "...") if not null
+    MangleOverride* mangleOverride;
+
     /**
      * !=null if is nested
      * pointing to the dsymbol that directly enclosing it.
@@ -125,14 +122,15 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
 
     Expression getRTInfo;   /// pointer to GC info generated by object.RTInfo(this)
 
-    Prot protection;                /// visibility
+    ///
+    Visibility visibility;
     bool noDefaultCtor;             /// no default construction
     Sizeok sizeok = Sizeok.none;    /// set when structsize contains valid data
 
     final extern (D) this(const ref Loc loc, Identifier id)
     {
         super(loc, id);
-        protection = Prot(Prot.Kind.public_);
+        visibility = Visibility(Visibility.Kind.public_);
     }
 
     /***************************************
@@ -145,8 +143,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         sc2.stc &= STCFlowThruAggregate;
         sc2.parent = this;
         sc2.inunion = isUnionDeclaration();
-        sc2.protection = Prot(Prot.Kind.public_);
-        sc2.explicitProtection = 0;
+        sc2.visibility = Visibility(Visibility.Kind.public_);
+        sc2.explicitVisibility = 0;
         sc2.aligndecl = null;
         sc2.userAttribDecl = null;
         sc2.namespace = null;
@@ -723,7 +721,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
             // Emulate vthis.dsymbolSemantic()
             vthis.storage_class |= STC.field;
             vthis.parent = this;
-            vthis.protection = Prot(Prot.Kind.public_);
+            vthis.visibility = Visibility(Visibility.Kind.public_);
             vthis.alignment = t.alignment();
             vthis.semanticRun = PASS.semanticdone;
 
@@ -767,7 +765,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         // Emulate vthis2.dsymbolSemantic()
         vthis2.storage_class |= STC.field;
         vthis2.parent = this;
-        vthis2.protection = Prot(Prot.Kind.public_);
+        vthis2.visibility = Visibility(Visibility.Kind.public_);
         vthis2.alignment = t.alignment();
         vthis2.semanticRun = PASS.semanticdone;
 
@@ -777,7 +775,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
 
     override final bool isExport() const
     {
-        return protection.kind == Prot.Kind.export_;
+        return visibility.kind == Visibility.Kind.export_;
     }
 
     /*******************************************
@@ -822,9 +820,9 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         return s;
     }
 
-    override final Prot prot() pure nothrow @nogc @safe
+    override final Visibility visible() pure nothrow @nogc @safe
     {
-        return protection;
+        return visibility;
     }
 
     // 'this' type
@@ -833,9 +831,14 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         return type;
     }
 
+    // Does this class have an invariant function?
+    final bool hasInvariant()
+    {
+        return invs.length != 0;
+    }
+
     // Back end
-    Symbol* stag;   /// tag symbol for debug data
-    Symbol* sinit;  /// initializer symbol
+    void* sinit;  /// initializer symbol
 
     override final inout(AggregateDeclaration) isAggregateDeclaration() inout
     {
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index cf6bde75d23..41572a82bdb 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -26,20 +26,20 @@ class InterfaceDeclaration;
 class TypeInfoClassDeclaration;
 class VarDeclaration;
 
-enum Sizeok
+enum class Sizeok : uint8_t
 {
-    SIZEOKnone,         // size of aggregate is not yet able to compute
-    SIZEOKfwd,          // size of aggregate is ready to compute
-    SIZEOKinProcess,    // in the midst of computing the size
-    SIZEOKdone          // size of aggregate is set correctly
+    none,         // size of aggregate is not yet able to compute
+    fwd,          // size of aggregate is ready to compute
+    inProcess,    // in the midst of computing the size
+    done          // size of aggregate is set correctly
 };
 
-enum Baseok
+enum class Baseok : uint8_t
 {
-    BASEOKnone,         // base classes not computed yet
-    BASEOKin,           // in process of resolving base classes
-    BASEOKdone,         // all base classes are resolved
-    BASEOKsemanticdone  // all base classes semantic done
+    none,         // base classes not computed yet
+    in,           // in process of resolving base classes
+    done,         // all base classes are resolved
+    semanticdone  // all base classes semantic done
 };
 
 enum StructPOD
@@ -49,26 +49,29 @@ enum StructPOD
     ISPODfwd            // POD not yet computed
 };
 
-enum Abstract
+enum class Abstract : uint8_t
 {
-    ABSfwdref = 0,      // whether an abstract class is not yet computed
-    ABSyes,             // is abstract class
-    ABSno               // is not abstract class
+    fwdref = 0,      // whether an abstract class is not yet computed
+    yes,             // is abstract class
+    no               // is not abstract class
 };
 
 FuncDeclaration *search_toString(StructDeclaration *sd);
 
-struct ClassKind
+enum class ClassKind : uint8_t
 {
-    enum Type
-    {
-        /// the aggregate is a d(efault) struct/class/interface
-        d,
-        /// the aggregate is a C++ struct/class/interface
-        cpp,
-        /// the aggregate is an Objective-C class/interface
-        objc
-    };
+  /// the aggregate is a d(efault) struct/class/interface
+  d,
+  /// the aggregate is a C++ struct/class/interface
+  cpp,
+  /// the aggregate is an Objective-C class/interface
+  objc
+};
+
+struct MangleOverride
+{
+    Dsymbol *agg;
+    Identifier *id;
 };
 
 class AggregateDeclaration : public ScopeDsymbol
@@ -81,9 +84,11 @@ public:
     VarDeclarations fields;     // VarDeclaration fields
     Dsymbol *deferred;          // any deferred semantic2() or semantic3() symbol
 
-    ClassKind::Type classKind;  // specifies the linkage type
+    ClassKind classKind;        // specifies the linkage type
     CPPMANGLE cppmangle;
 
+    // overridden symbol with pragma(mangle, "...")
+    MangleOverride *mangleOverride;
     /* !=NULL if is nested
      * pointing to the dsymbol that directly enclosing it.
      * 1. The function that enclosing it (nested struct and class)
@@ -115,7 +120,7 @@ public:
 
     Expression *getRTInfo;      // pointer to GC info generated by object.RTInfo(this)
 
-    Prot protection;
+    Visibility visibility;
     bool noDefaultCtor;         // no default construction
     Sizeok sizeok;              // set when structsize contains valid data
 
@@ -134,14 +139,15 @@ public:
     bool isExport() const;
     Dsymbol *searchCtor();
 
-    Prot prot();
+    Visibility visible();
 
     // 'this' type
     Type *handleType() { return type; }
 
+    bool hasInvariant();
+
     // Back end
-    Symbol *stag;               // tag symbol for debug data
-    Symbol *sinit;
+    void *sinit;
 
     AggregateDeclaration *isAggregateDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
@@ -186,7 +192,7 @@ public:
     TypeTuple *argTypes;
 
     static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    StructDeclaration *syntaxCopy(Dsymbol *s);
     void semanticTypeInfoMembers();
     Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
     const char *kind() const;
@@ -199,12 +205,13 @@ public:
 
     unsigned numArgTypes() const;
     Type *argType(unsigned index);
+    bool hasRegularCtor(bool checkDisabled = false);
 };
 
 class UnionDeclaration : public StructDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    UnionDeclaration *syntaxCopy(Dsymbol *s);
     const char *kind() const;
 
     UnionDeclaration *isUnionDeclaration() { return this; }
@@ -280,7 +287,8 @@ public:
     Symbol *cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
 
     static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    const char *toPrettyChars(bool QualifyTypes = false);
+    ClassDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     bool isBaseOf2(ClassDeclaration *cd);
 
@@ -317,7 +325,7 @@ public:
 class InterfaceDeclaration : public ClassDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    InterfaceDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     bool isBaseOf(ClassDeclaration *cd, int *poffset);
     bool isBaseOf(BaseClass *bc, int *poffset);
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index 27781ed1cfd..81e0d7e64be 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d)
@@ -43,7 +43,7 @@ extern (C++) final class AliasThis : Dsymbol
         this.ident = ident;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override AliasThis syntaxCopy(Dsymbol s)
     {
         assert(!s);
         auto at = new AliasThis(loc, ident);
@@ -154,26 +154,49 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
  */
 bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
 {
-    import dmd.errors : deprecation;
+    import dmd.errors : deprecation, Classification;
     import dmd.dsymbolsem : getMessage;
 
     if (global.params.useDeprecated != DiagnosticReporting.off
         && at.isDeprecated() && !sc.isDeprecated())
     {
-            const(char)* message = null;
-            for (Dsymbol p = at; p; p = p.parent)
-            {
-                message = p.depdecl ? p.depdecl.getMessage() : null;
-                if (message)
-                    break;
-            }
+        const(char)* message = null;
+        for (Dsymbol p = at; p; p = p.parent)
+        {
+            message = p.depdecl ? p.depdecl.getMessage() : null;
             if (message)
-                deprecation(loc, "`alias %s this` is deprecated - %s",
-                            at.sym.toChars(), message);
-            else
-                deprecation(loc, "`alias %s this` is deprecated",
-                            at.sym.toChars());
+                break;
+        }
+        if (message)
+            deprecation(loc, "`alias %s this` is deprecated - %s",
+                        at.sym.toChars(), message);
+        else
+            deprecation(loc, "`alias %s this` is deprecated",
+                        at.sym.toChars());
+
+        if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
+            ti.printInstantiationTrace(Classification.deprecation);
+
         return true;
     }
     return false;
 }
+
+/**************************************
+ * Check and set 'att' if 't' is a recursive 'alias this' type
+ * Params:
+ *   att = type reference used to detect recursion
+ *   t   = 'alias this' type
+ *
+ * Returns:
+ *   Whether the 'alias this' is recursive or not
+ */
+bool isRecursiveAliasThis(ref Type att, Type t)
+{
+    auto tb = t.toBasetype();
+    if (att && tb.equivalent(att))
+        return true;
+    else if (!att && tb.checkAliasThisRec())
+        att = tb;
+    return false;
+}
diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h
index c4630039d56..de93a8e6ae4 100644
--- a/gcc/d/dmd/aliasthis.h
+++ b/gcc/d/dmd/aliasthis.h
@@ -23,7 +23,7 @@ public:
     Dsymbol    *sym;
     bool       isDeprecated_;
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    AliasThis *syntaxCopy(Dsymbol *);
     const char *kind() const;
     AliasThis *isAliasThis() { return this; }
     void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d
index e989a8f0b79..ab427e885dc 100644
--- a/gcc/d/dmd/apply.d
+++ b/gcc/d/dmd/apply.d
@@ -1,7 +1,7 @@
 /**
  * A depth-first visitor for expressions.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d)
@@ -18,6 +18,46 @@ import dmd.dtemplate;
 import dmd.expression;
 import dmd.visitor;
 
+bool walkPostorder(Expression e, StoppableVisitor v)
+{
+    scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
+    e.accept(pv);
+    return v.stop;
+}
+
+/*********************************
+ * Iterate this dsymbol or members of this scoped dsymbol, then
+ * call `fp` with the found symbol and `params`.
+ * Params:
+ *  symbol = the dsymbol or parent of members to call fp on
+ *  fp = function pointer to process the iterated symbol.
+ *       If it returns nonzero, the iteration will be aborted.
+ *  params = any parameters passed to fp.
+ * Returns:
+ *  nonzero if the iteration is aborted by the return value of fp,
+ *  or 0 if it's completed.
+ */
+int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params)
+{
+    if (auto nd = symbol.isNspace())
+    {
+        return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+    }
+    if (auto ad = symbol.isAttribDeclaration())
+    {
+        return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+    }
+    if (auto tm = symbol.isTemplateMixin())
+    {
+        if (tm._scope) // if fwd reference
+            dsymbolSemantic(tm, null); // try to resolve it
+
+        return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+    }
+
+    return fp(symbol, params);
+}
+
 /**************************************
  * An Expression tree walker that will visit each Expression e in the tree,
  * in depth-first evaluation order, and call fp(e,param) on it.
@@ -147,43 +187,3 @@ public:
         doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
     }
 }
-
-bool walkPostorder(Expression e, StoppableVisitor v)
-{
-    scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
-    e.accept(pv);
-    return v.stop;
-}
-
-/*********************************
- * Iterate this dsymbol or members of this scoped dsymbol, then
- * call `fp` with the found symbol and `params`.
- * Params:
- *  symbol = the dsymbol or parent of members to call fp on
- *  fp = function pointer to process the iterated symbol.
- *       If it returns nonzero, the iteration will be aborted.
- *  params = any parameters passed to fp.
- * Returns:
- *  nonzero if the iteration is aborted by the return value of fp,
- *  or 0 if it's completed.
- */
-int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params)
-{
-    if (auto nd = symbol.isNspace())
-    {
-        return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
-    }
-    if (auto ad = symbol.isAttribDeclaration())
-    {
-        return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } );
-    }
-    if (auto tm = symbol.isTemplateMixin())
-    {
-        if (tm._scope) // if fwd reference
-            dsymbolSemantic(tm, null); // try to resolve it
-
-        return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
-    }
-
-    return fp(symbol, params);
-}
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 9359c26f0ca..66be73ea21f 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d)
@@ -15,6 +15,7 @@ module dmd.arrayop;
 
 import core.stdc.stdio;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d
index b504b179f89..b1f8d86a208 100644
--- a/gcc/d/dmd/arraytypes.d
+++ b/gcc/d/dmd/arraytypes.d
@@ -1,7 +1,7 @@
 /**
  * Provide aliases for arrays of certain declarations or statements.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d)
@@ -52,3 +52,6 @@ alias ReturnStatements = Array!(ReturnStatement);
 alias GotoStatements = Array!(GotoStatement);
 alias TemplateInstances = Array!(TemplateInstance);
 alias Ensures = Array!(Ensure);
+alias Designators = Array!(Designator);
+alias DesigInits = Array!(DesigInit);
+
diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h
index 5fd32e41fdf..602d89059a0 100644
--- a/gcc/d/dmd/arraytypes.h
+++ b/gcc/d/dmd/arraytypes.h
@@ -63,3 +63,8 @@ typedef Array<class GotoStatement *> GotoStatements;
 typedef Array<class TemplateInstance *> TemplateInstances;
 
 typedef Array<struct Ensure> Ensures;
+
+typedef Array<struct Designator> Designators;
+
+typedef Array<struct DesigInit> DesigInits;
+
diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d
index fd11481ea8d..82d62a03657 100644
--- a/gcc/d/dmd/ast_node.d
+++ b/gcc/d/dmd/ast_node.d
@@ -1,7 +1,7 @@
 /**
  * Defines the base class for all nodes which are part of the AST.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d)
diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d
index 364c058acd0..d40f836faae 100644
--- a/gcc/d/dmd/astcodegen.d
+++ b/gcc/d/dmd/astcodegen.d
@@ -34,12 +34,14 @@ struct ASTCodegen
     public import dmd.staticassert;
     public import dmd.typesem;
     public import dmd.ctfeexpr;
+    public import dmd.init : Designator;
 
 
     alias initializerToExpression   = dmd.initsem.initializerToExpression;
     alias typeToExpression          = dmd.typesem.typeToExpression;
     alias UserAttributeDeclaration  = dmd.attrib.UserAttributeDeclaration;
     alias Ensure                    = dmd.func.Ensure; // workaround for bug in older DMD frontends
+    alias ErrorExp                  = dmd.expression.ErrorExp;
 
     alias MODFlags                  = dmd.mtype.MODFlags;
     alias Type                      = dmd.mtype.Type;
@@ -57,6 +59,7 @@ struct ASTCodegen
     alias Tfloat80                  = dmd.mtype.Tfloat80;
     alias Tfunction                 = dmd.mtype.Tfunction;
     alias Tpointer                  = dmd.mtype.Tpointer;
+    alias Treference                = dmd.mtype.Treference;
     alias Tident                    = dmd.mtype.Tident;
     alias Tint8                     = dmd.mtype.Tint8;
     alias Tint16                    = dmd.mtype.Tint16;
@@ -70,20 +73,30 @@ struct ASTCodegen
     alias Tuns64                    = dmd.mtype.Tuns64;
     alias Tvoid                     = dmd.mtype.Tvoid;
     alias Twchar                    = dmd.mtype.Twchar;
+    alias Tnoreturn                 = dmd.mtype.Tnoreturn;
+
+    alias Timaginary32              = dmd.mtype.Timaginary32;
+    alias Timaginary64              = dmd.mtype.Timaginary64;
+    alias Timaginary80              = dmd.mtype.Timaginary80;
+    alias Tcomplex32                = dmd.mtype.Tcomplex32;
+    alias Tcomplex64                = dmd.mtype.Tcomplex64;
+    alias Tcomplex80                = dmd.mtype.Tcomplex80;
 
     alias ParameterList             = dmd.mtype.ParameterList;
     alias VarArg                    = dmd.mtype.VarArg;
     alias STC                       = dmd.declaration.STC;
     alias Dsymbol                   = dmd.dsymbol.Dsymbol;
     alias Dsymbols                  = dmd.dsymbol.Dsymbols;
-    alias Prot                      = dmd.dsymbol.Prot;
+    alias Visibility                = dmd.dsymbol.Visibility;
 
     alias stcToBuffer               = dmd.hdrgen.stcToBuffer;
     alias linkageToChars            = dmd.hdrgen.linkageToChars;
-    alias protectionToChars         = dmd.hdrgen.protectionToChars;
+    alias visibilityToChars         = dmd.hdrgen.visibilityToChars;
 
     alias isType                    = dmd.dtemplate.isType;
     alias isExpression              = dmd.dtemplate.isExpression;
     alias isTuple                   = dmd.dtemplate.isTuple;
 
+    alias IgnoreErrors              = dmd.dsymbol.IgnoreErrors;
+    alias PASS                      = dmd.dsymbol.PASS;
 }
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
new file mode 100644
index 00000000000..0860c55e178
--- /dev/null
+++ b/gcc/d/dmd/astenums.d
@@ -0,0 +1,347 @@
+/**
+ * Defines enums common to dmd and dmd as parse library.
+ *
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d)
+ * Documentation:  https://dlang.org/phobos/dmd_astenums.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astenums.d
+ */
+
+module dmd.astenums;
+
+enum Sizeok : ubyte
+{
+    none,               /// size of aggregate is not yet able to compute
+    fwd,                /// size of aggregate is ready to compute
+    inProcess,          /// in the midst of computing the size
+    done,               /// size of aggregate is set correctly
+}
+
+enum Baseok : ubyte
+{
+    none,               /// base classes not computed yet
+    start,              /// in process of resolving base classes
+    done,               /// all base classes are resolved
+    semanticdone,       /// all base classes semantic done
+}
+
+enum MODFlags : int
+{
+    const_       = 1,    // type is const
+    immutable_   = 4,    // type is immutable
+    shared_      = 2,    // type is shared
+    wild         = 8,    // type is wild
+    wildconst    = (MODFlags.wild | MODFlags.const_), // type is wild const
+    mutable      = 0x10, // type is mutable (only used in wildcard matching)
+}
+
+alias MOD = ubyte;
+
+enum STC : ulong
+{
+    undefined_          = 0L,
+    static_             = (1L << 0),
+    extern_             = (1L << 1),
+    const_              = (1L << 2),
+    final_              = (1L << 3),
+    abstract_           = (1L << 4),
+    parameter           = (1L << 5),
+    field               = (1L << 6),
+    override_           = (1L << 7),
+    auto_               = (1L << 8),
+    synchronized_       = (1L << 9),
+    deprecated_         = (1L << 10),
+    in_                 = (1L << 11),   // in parameter
+    out_                = (1L << 12),   // out parameter
+    lazy_               = (1L << 13),   // lazy parameter
+    foreach_            = (1L << 14),   // variable for foreach loop
+                          //(1L << 15)
+    variadic            = (1L << 16),   // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
+    ctorinit            = (1L << 17),   // can only be set inside constructor
+    templateparameter   = (1L << 18),   // template parameter
+    scope_              = (1L << 19),
+    immutable_          = (1L << 20),
+    ref_                = (1L << 21),
+    init                = (1L << 22),   // has explicit initializer
+    manifest            = (1L << 23),   // manifest constant
+    nodtor              = (1L << 24),   // don't run destructor
+    nothrow_            = (1L << 25),   // never throws exceptions
+    pure_               = (1L << 26),   // pure function
+    tls                 = (1L << 27),   // thread local
+    alias_              = (1L << 28),   // alias parameter
+    shared_             = (1L << 29),   // accessible from multiple threads
+    gshared             = (1L << 30),   // accessible from multiple threads, but not typed as "shared"
+    wild                = (1L << 31),   // for "wild" type constructor
+    property            = (1L << 32),
+    safe                = (1L << 33),
+    trusted             = (1L << 34),
+    system              = (1L << 35),
+    ctfe                = (1L << 36),   // can be used in CTFE, even if it is static
+    disable             = (1L << 37),   // for functions that are not callable
+    result              = (1L << 38),   // for result variables passed to out contracts
+    nodefaultctor       = (1L << 39),   // must be set inside constructor
+    temp                = (1L << 40),   // temporary variable
+    rvalue              = (1L << 41),   // force rvalue for variables
+    nogc                = (1L << 42),   // @nogc
+    volatile_           = (1L << 43),   // destined for volatile in the back end
+    return_             = (1L << 44),   // 'return ref' or 'return scope' for function parameters
+    autoref             = (1L << 45),   // Mark for the already deduced 'auto ref' parameter
+    inference           = (1L << 46),   // do attribute inference
+    exptemp             = (1L << 47),   // temporary variable that has lifetime restricted to an expression
+    maybescope          = (1L << 48),   // parameter might be 'scope'
+    scopeinferred       = (1L << 49),   // 'scope' has been inferred and should not be part of mangling
+    future              = (1L << 50),   // introducing new base class function
+    local               = (1L << 51),   // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
+    returninferred      = (1L << 52),   // 'return' has been inferred and should not be part of mangling
+    live                = (1L << 53),   // function @live attribute
+    register            = (1L << 54),   // `register` storage class
+
+    safeGroup = STC.safe | STC.trusted | STC.system,
+    IOR  = STC.in_ | STC.ref_ | STC.out_,
+    TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild),
+    FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live |
+                safeGroup),
+}
+
+/* This is different from the one in declaration.d, make that fix a separate PR */
+static if (0)
+extern (C++) __gshared const(StorageClass) STCStorageClass =
+    (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ |
+     STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.override_ | STC.lazy_ |
+     STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ |
+     STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls |
+     STC.gshared | STC.property | STC.live |
+     STC.safeGroup | STC.disable);
+
+enum TY : ubyte
+{
+    Tarray,     // slice array, aka T[]
+    Tsarray,    // static array, aka T[dimension]
+    Taarray,    // associative array, aka T[type]
+    Tpointer,
+    Treference,
+    Tfunction,
+    Tident,
+    Tclass,
+    Tstruct,
+    Tenum,
+
+    Tdelegate,
+    Tnone,
+    Tvoid,
+    Tint8,
+    Tuns8,
+    Tint16,
+    Tuns16,
+    Tint32,
+    Tuns32,
+    Tint64,
+
+    Tuns64,
+    Tfloat32,
+    Tfloat64,
+    Tfloat80,
+    Timaginary32,
+    Timaginary64,
+    Timaginary80,
+    Tcomplex32,
+    Tcomplex64,
+    Tcomplex80,
+
+    Tbool,
+    Tchar,
+    Twchar,
+    Tdchar,
+    Terror,
+    Tinstance,
+    Ttypeof,
+    Ttuple,
+    Tslice,
+    Treturn,
+
+    Tnull,
+    Tvector,
+    Tint128,
+    Tuns128,
+    Ttraits,
+    Tmixin,
+    Tnoreturn,
+    Ttag,
+    TMAX
+}
+
+alias Tarray = TY.Tarray;
+alias Tsarray = TY.Tsarray;
+alias Taarray = TY.Taarray;
+alias Tpointer = TY.Tpointer;
+alias Treference = TY.Treference;
+alias Tfunction = TY.Tfunction;
+alias Tident = TY.Tident;
+alias Tclass = TY.Tclass;
+alias Tstruct = TY.Tstruct;
+alias Tenum = TY.Tenum;
+alias Tdelegate = TY.Tdelegate;
+alias Tnone = TY.Tnone;
+alias Tvoid = TY.Tvoid;
+alias Tint8 = TY.Tint8;
+alias Tuns8 = TY.Tuns8;
+alias Tint16 = TY.Tint16;
+alias Tuns16 = TY.Tuns16;
+alias Tint32 = TY.Tint32;
+alias Tuns32 = TY.Tuns32;
+alias Tint64 = TY.Tint64;
+alias Tuns64 = TY.Tuns64;
+alias Tfloat32 = TY.Tfloat32;
+alias Tfloat64 = TY.Tfloat64;
+alias Tfloat80 = TY.Tfloat80;
+alias Timaginary32 = TY.Timaginary32;
+alias Timaginary64 = TY.Timaginary64;
+alias Timaginary80 = TY.Timaginary80;
+alias Tcomplex32 = TY.Tcomplex32;
+alias Tcomplex64 = TY.Tcomplex64;
+alias Tcomplex80 = TY.Tcomplex80;
+alias Tbool = TY.Tbool;
+alias Tchar = TY.Tchar;
+alias Twchar = TY.Twchar;
+alias Tdchar = TY.Tdchar;
+alias Terror = TY.Terror;
+alias Tinstance = TY.Tinstance;
+alias Ttypeof = TY.Ttypeof;
+alias Ttuple = TY.Ttuple;
+alias Tslice = TY.Tslice;
+alias Treturn = TY.Treturn;
+alias Tnull = TY.Tnull;
+alias Tvector = TY.Tvector;
+alias Tint128 = TY.Tint128;
+alias Tuns128 = TY.Tuns128;
+alias Ttraits = TY.Ttraits;
+alias Tmixin = TY.Tmixin;
+alias Tnoreturn = TY.Tnoreturn;
+alias Ttag = TY.Ttag;
+alias TMAX = TY.TMAX;
+
+enum TFlags
+{
+    integral     = 1,
+    floating     = 2,
+    unsigned     = 4,
+    real_        = 8,
+    imaginary    = 0x10,
+    complex      = 0x20,
+}
+
+enum PKG : int
+{
+    unknown,      /// not yet determined whether it's a package.d or not
+    module_,      /// already determined that's an actual package.d
+    package_,     /// already determined that's an actual package
+}
+
+enum StructPOD : int
+{
+    no,    /// struct is not POD
+    yes,   /// struct is POD
+    fwd,   /// POD not yet computed
+}
+
+enum TRUST : ubyte
+{
+    default_   = 0,
+    system     = 1,    // @system (same as TRUST.default)
+    trusted    = 2,    // @trusted
+    safe       = 3,    // @safe
+}
+
+enum PURE : ubyte
+{
+    impure      = 0,    // not pure at all
+    fwdref      = 1,    // it's pure, but not known which level yet
+    weak        = 2,    // no mutable globals are read or written
+    const_      = 3,    // parameters are values or const
+    strong      = 4,    // parameters are values or immutable
+}
+
+// Whether alias this dependency is recursive or not
+enum AliasThisRec : int
+{
+    no           = 0,    // no alias this recursion
+    yes          = 1,    // alias this has recursive dependency
+    fwdref       = 2,    // not yet known
+    typeMask     = 3,    // mask to read no/yes/fwdref
+    tracing      = 0x4,  // mark in progress of implicitConvTo/deduceWild
+    tracingDT    = 0x8,  // mark in progress of deduceType
+}
+
+/***************
+ * Variadic argument lists
+ * https://dlang.org/spec/function.html#variadic
+ */
+enum VarArg : ubyte
+{
+    none     = 0,  /// fixed number of arguments
+    variadic = 1,  /// (T t, ...)  can be C-style (core.stdc.stdarg) or D-style (core.vararg)
+    typesafe = 2,  /// (T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
+                   ///   or https://dlang.org/spec/function.html#typesafe_variadic_functions
+}
+
+/*************************
+ * Identify Statement types with this enum rather than
+ * virtual functions
+ */
+enum STMT : ubyte
+{
+    Error,
+    Peel,
+    Exp, DtorExp,
+    Compile,
+    Compound, CompoundDeclaration, CompoundAsm,
+    UnrolledLoop,
+    Scope,
+    Forwarding,
+    While,
+    Do,
+    For,
+    Foreach,
+    ForeachRange,
+    If,
+    Conditional,
+    StaticForeach,
+    Pragma,
+    StaticAssert,
+    Switch,
+    Case,
+    CaseRange,
+    Default,
+    GotoDefault,
+    GotoCase,
+    SwitchError,
+    Return,
+    Break,
+    Continue,
+    Synchronized,
+    With,
+    TryCatch,
+    TryFinally,
+    ScopeGuard,
+    Throw,
+    Debug,
+    Goto,
+    Label,
+    Asm, InlineAsm, GccAsm,
+    Import,
+}
+
+/**********************
+ * Discriminant for which kind of initializer
+ */
+enum InitKind : ubyte
+{
+    void_,
+    error,
+    struct_,
+    array,
+    exp,
+    C_,
+}
+
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index d4f1f7d9965..646dd3c7a40 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -14,7 +14,7 @@
  * - Protection (`private`, `public`)
  * - Deprecated declarations (`@deprecated`)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
@@ -26,6 +26,7 @@ module dmd.attrib;
 
 import dmd.aggregate;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.cond;
 import dmd.declaration;
 import dmd.dmodule;
@@ -33,10 +34,10 @@ import dmd.dscope;
 import dmd.dsymbol;
 import dmd.dsymbolsem : dsymbolSemantic;
 import dmd.expression;
-import dmd.expressionsem : arrayExpressionSemantic;
+import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
-import dmd.hdrgen : protectionToBuffer;
+import dmd.hdrgen : visibilityToBuffer;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
@@ -81,15 +82,15 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
      * the scope after it used.
      */
     extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
-        CPPMANGLE cppmangle, Prot protection, int explicitProtection,
-        AlignDeclaration aligndecl, PINLINE inlining)
+        CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
+        AlignDeclaration aligndecl, PragmaDeclaration inlining)
     {
         Scope* sc2 = sc;
         if (stc != sc.stc ||
             linkage != sc.linkage ||
             cppmangle != sc.cppmangle ||
-            !protection.isSubsetOf(sc.protection) ||
-            explicitProtection != sc.explicitProtection ||
+            explicitVisibility != sc.explicitVisibility ||
+            visibility != sc.visibility ||
             aligndecl !is sc.aligndecl ||
             inlining != sc.inlining)
         {
@@ -98,8 +99,8 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
             sc2.stc = stc;
             sc2.linkage = linkage;
             sc2.cppmangle = cppmangle;
-            sc2.protection = protection;
-            sc2.explicitProtection = explicitProtection;
+            sc2.visibility = visibility;
+            sc2.explicitVisibility = explicitVisibility;
             sc2.aligndecl = aligndecl;
             sc2.inlining = inlining;
         }
@@ -231,7 +232,7 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
         this.stc = stc;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override StorageClassDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
@@ -256,7 +257,7 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
         scstc |= stc;
         //printf("scstc = x%llx\n", scstc);
         return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
-            sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining);
+            sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
     }
 
     override final bool oneMember(Dsymbol* ps, Identifier ident)
@@ -344,7 +345,7 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
         this.msg = msg;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override DeprecatedDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
@@ -393,27 +394,27 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
 {
     LINK linkage; /// either explicitly set or `default_`
 
-    extern (D) this(LINK linkage, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl)
     {
-        super(decl);
+        super(loc, null, decl);
         //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
         this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
     }
 
-    static LinkDeclaration create(LINK p, Dsymbols* decl)
+    static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
     {
-        return new LinkDeclaration(p, decl);
+        return new LinkDeclaration(loc, p, decl);
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override LinkDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl));
+        return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
     }
 
     override Scope* newScope(Scope* sc)
     {
-        return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection,
+        return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
             sc.aligndecl, sc.inlining);
     }
 
@@ -445,22 +446,22 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration
 {
     CPPMANGLE cppmangle;
 
-    extern (D) this(CPPMANGLE cppmangle, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl)
     {
-        super(decl);
+        super(loc, null, decl);
         //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
         this.cppmangle = cppmangle;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override CPPMangleDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl));
+        return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
     }
 
     override Scope* newScope(Scope* sc)
     {
-        return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.protection, sc.explicitProtection,
+        return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
             sc.aligndecl, sc.inlining);
     }
 
@@ -515,32 +516,30 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
     /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
     Expression exp;
 
-    extern (D) this(Identifier ident, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
     {
-        super(decl);
-        this.ident = ident;
+        super(loc, ident, decl);
     }
 
-    extern (D) this(Expression exp, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
     {
-        super(decl);
+        super(loc, null, decl);
         this.exp = exp;
     }
 
-    extern (D) this(Identifier ident, Expression exp, Dsymbols* decl,
+    extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
                     CPPNamespaceDeclaration parent)
     {
-        super(decl);
-        this.ident = ident;
+        super(loc, ident, decl);
         this.exp = exp;
         this.cppnamespace = parent;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override CPPNamespaceDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new CPPNamespaceDeclaration(
-            this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
+            this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
     }
 
     /**
@@ -576,24 +575,24 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
 /***********************************************************
  * Visibility declaration for Dsymbols, e.g. `public int i;`
  *
- * `<protection> <decl...>` or
+ * `<visibility> <decl...>` or
  * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
  */
-extern (C++) final class ProtDeclaration : AttribDeclaration
+extern (C++) final class VisibilityDeclaration : AttribDeclaration
 {
-    Prot protection;                /// the visibility
-    Identifiers* pkg_identifiers;   /// identifiers for `package(foo.bar)` or null
+    Visibility visibility;          /// the visibility
+    Identifier[] pkg_identifiers;   /// identifiers for `package(foo.bar)` or null
 
     /**
      * Params:
      *  loc = source location of attribute token
-     *  protection = protection attribute data
-     *  decl = declarations which are affected by this protection attribute
+     *  visibility = visibility attribute data
+     *  decl = declarations which are affected by this visibility attribute
      */
-    extern (D) this(const ref Loc loc, Prot protection, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl)
     {
         super(loc, null, decl);
-        this.protection = protection;
+        this.visibility = visibility;
         //printf("decl = %p\n", decl);
     }
 
@@ -601,35 +600,36 @@ extern (C++) final class ProtDeclaration : AttribDeclaration
      * Params:
      *  loc = source location of attribute token
      *  pkg_identifiers = list of identifiers for a qualified package name
-     *  decl = declarations which are affected by this protection attribute
+     *  decl = declarations which are affected by this visibility attribute
      */
-    extern (D) this(const ref Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl)
+    extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
     {
         super(loc, null, decl);
-        this.protection.kind = Prot.Kind.package_;
+        this.visibility.kind = Visibility.Kind.package_;
         this.pkg_identifiers = pkg_identifiers;
-        if (pkg_identifiers !is null && pkg_identifiers.dim > 0)
+        if (pkg_identifiers.length > 0)
         {
             Dsymbol tmp;
             Package.resolve(pkg_identifiers, &tmp, null);
-            protection.pkg = tmp ? tmp.isPackage() : null;
+            visibility.pkg = tmp ? tmp.isPackage() : null;
         }
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override VisibilityDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        if (protection.kind == Prot.Kind.package_)
-            return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
+
+        if (visibility.kind == Visibility.Kind.package_)
+            return new VisibilityDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
         else
-            return new ProtDeclaration(this.loc, protection, Dsymbol.arraySyntaxCopy(decl));
+            return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
     }
 
     override Scope* newScope(Scope* sc)
     {
         if (pkg_identifiers)
             dsymbolSemantic(this, sc);
-        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining);
+        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
     }
 
     override void addMember(Scope* sc, ScopeDsymbol sds)
@@ -638,24 +638,24 @@ extern (C++) final class ProtDeclaration : AttribDeclaration
         {
             Dsymbol tmp;
             Package.resolve(pkg_identifiers, &tmp, null);
-            protection.pkg = tmp ? tmp.isPackage() : null;
+            visibility.pkg = tmp ? tmp.isPackage() : null;
             pkg_identifiers = null;
         }
-        if (protection.kind == Prot.Kind.package_ && protection.pkg && sc._module)
+        if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
         {
             Module m = sc._module;
 
             // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
             // each package's .isModule() properites are equal.
             //
-            // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
+            // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
             // This breaks package declarations of the package in question if they are declared in
             // the same package.d file, which _do_ have a module associated with them, and hence a non-null
             // isModule()
-            if (!m.isPackage() || !protection.pkg.ident.equals(m.isPackage().ident))
+            if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
             {
                 Package pkg = m.parent ? m.parent.isPackage() : null;
-                if (!pkg || !protection.pkg.isAncestorPackageOf(pkg))
+                if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
                     error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true));
             }
         }
@@ -664,18 +664,18 @@ extern (C++) final class ProtDeclaration : AttribDeclaration
 
     override const(char)* kind() const
     {
-        return "protection attribute";
+        return "visibility attribute";
     }
 
     override const(char)* toPrettyChars(bool)
     {
-        assert(protection.kind > Prot.Kind.undefined);
+        assert(visibility.kind > Visibility.Kind.undefined);
         OutBuffer buf;
-        protectionToBuffer(&buf, protection);
+        visibilityToBuffer(&buf, visibility);
         return buf.extractChars();
     }
 
-    override inout(ProtDeclaration) isProtDeclaration() inout
+    override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
     {
         return this;
     }
@@ -709,7 +709,7 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
         this.ealign = ealign;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override AlignDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new AlignDeclaration(loc,
@@ -719,7 +719,7 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
 
     override Scope* newScope(Scope* sc)
     {
-        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining);
+        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
     }
 
     override void accept(Visitor v)
@@ -745,7 +745,7 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
         this.isunion = isunion;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override AnonDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
@@ -865,7 +865,7 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
         this.args = args;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override PragmaDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
         assert(!s);
@@ -876,32 +876,9 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
     {
         if (ident == Id.Pinline)
         {
-            PINLINE inlining = PINLINE.default_;
-            if (!args || args.dim == 0)
-                inlining = PINLINE.default_;
-            else if (args.dim != 1)
-            {
-                error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim);
-                args.setDim(1);
-                (*args)[0] = ErrorExp.get();
-            }
-            else
-            {
-                Expression e = (*args)[0];
-                if (e.op != TOK.int64 || !e.type.equals(Type.tbool))
-                {
-                    if (e.op != TOK.error)
-                    {
-                        error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars());
-                        (*args)[0] = ErrorExp.get();
-                    }
-                }
-                else if (e.isBool(true))
-                    inlining = PINLINE.always;
-                else if (e.isBool(false))
-                    inlining = PINLINE.never;
-            }
-            return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining);
+            // We keep track of this pragma inside scopes,
+            // then it's evaluated on demand in function semantic
+            return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
         }
         if (ident == Id.printf || ident == Id.scanf)
         {
@@ -918,6 +895,34 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
         return sc;
     }
 
+    PINLINE evalPragmaInline(Scope* sc)
+    {
+        if (!args || args.dim == 0)
+            return PINLINE.default_;
+
+        Expression e = (*args)[0];
+        if (!e.type)
+        {
+
+            sc = sc.startCTFE();
+            e = e.expressionSemantic(sc);
+            e = resolveProperties(sc, e);
+            sc = sc.endCTFE();
+            e = e.ctfeInterpret();
+            e = e.toBoolean(sc);
+            if (e.isErrorExp())
+                error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars());
+            (*args)[0] = e;
+        }
+
+        if (e.isBool(true))
+            return PINLINE.always;
+        else if (e.isBool(false))
+            return PINLINE.never;
+        else
+            return PINLINE.default_;
+    }
+
     override const(char)* kind() const
     {
         return "pragma";
@@ -940,18 +945,18 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
     Condition condition;    /// condition deciding whether decl or elsedecl applies
     Dsymbols* elsedecl;     /// array of Dsymbol's for else block
 
-    extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
+    extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
     {
-        super(decl);
+        super(loc, null, decl);
         //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
         this.condition = condition;
         this.elsedecl = elsedecl;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override ConditionalDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
+        return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
     }
 
     override final bool oneMember(Dsymbol* ps, Identifier ident)
@@ -1018,16 +1023,16 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
     private bool addisdone = false; /// true if members have been added to scope
     private bool onStack = false;   /// true if a call to `include` is currently active
 
-    extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
+    extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
     {
-        super(condition, decl, elsedecl);
+        super(loc, condition, decl, elsedecl);
         //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override StaticIfDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
+        return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
     }
 
     /****************************************
@@ -1129,11 +1134,11 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
 
     extern (D) this(StaticForeach sfe, Dsymbols* decl)
     {
-        super(decl);
+        super(sfe.loc, null, decl);
         this.sfe = sfe;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override StaticForeachDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new StaticForeachDeclaration(
@@ -1312,7 +1317,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration
         this.exps = exps;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override CompileDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
         return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
@@ -1357,11 +1362,10 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
     extern (D) this(Expressions* atts, Dsymbols* decl)
     {
         super(decl);
-        //printf("UserAttributeDeclaration()\n");
         this.atts = atts;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override UserAttributeDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
         assert(!s);
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index e68ed284935..e58db84016c 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -47,7 +47,7 @@ class StorageClassDeclaration : public AttribDeclaration
 public:
     StorageClass stc;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    StorageClassDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     bool oneMember(Dsymbol **ps, Identifier *ident);
     void addMember(Scope *sc, ScopeDsymbol *sds);
@@ -62,7 +62,7 @@ public:
     Expression *msg;
     const char *msgstr;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    DeprecatedDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     void setScope(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
@@ -73,8 +73,8 @@ class LinkDeclaration : public AttribDeclaration
 public:
     LINK linkage;
 
-    static LinkDeclaration *create(LINK p, Dsymbols *decl);
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
+    LinkDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     const char *toChars() const;
     void accept(Visitor *v) { v->visit(this); }
@@ -85,7 +85,7 @@ class CPPMangleDeclaration : public AttribDeclaration
 public:
     CPPMANGLE cppmangle;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    CPPMangleDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     void setScope(Scope *sc);
     const char *toChars() const;
@@ -97,24 +97,24 @@ class CPPNamespaceDeclaration : public AttribDeclaration
 public:
     Expression *exp;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     const char *toChars() const;
     void accept(Visitor *v) { v->visit(this); }
 };
 
-class ProtDeclaration : public AttribDeclaration
+class VisibilityDeclaration : public AttribDeclaration
 {
 public:
-    Prot protection;
-    Identifiers* pkg_identifiers;
+    Visibility visibility;
+    DArray<Identifier*> pkg_identifiers;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    VisibilityDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     void addMember(Scope *sc, ScopeDsymbol *sds);
     const char *kind() const;
     const char *toPrettyChars(bool unused);
-    ProtDeclaration *isProtDeclaration() { return this; }
+    VisibilityDeclaration *isVisibilityDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -125,7 +125,7 @@ public:
     structalign_t salign;
 
     AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl);
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    AlignDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -139,7 +139,7 @@ public:
     unsigned anonstructsize;    // size of anonymous struct
     unsigned anonalignsize;     // size of anonymous struct for alignment purposes
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    AnonDeclaration *syntaxCopy(Dsymbol *s);
     void setScope(Scope *sc);
     void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
     const char *kind() const;
@@ -152,8 +152,9 @@ class PragmaDeclaration : public AttribDeclaration
 public:
     Expressions *args;          // array of Expression's
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    PragmaDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
+    PINLINE evalPragmaInline(Scope* sc);
     const char *kind() const;
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -164,7 +165,7 @@ public:
     Condition *condition;
     Dsymbols *elsedecl; // array of Dsymbol's for else block
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    ConditionalDeclaration *syntaxCopy(Dsymbol *s);
     bool oneMember(Dsymbol **ps, Identifier *ident);
     Dsymbols *include(Scope *sc);
     void addComment(const utf8_t *comment);
@@ -179,7 +180,7 @@ public:
     bool addisdone;
     bool onStack;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    StaticIfDeclaration *syntaxCopy(Dsymbol *s);
     Dsymbols *include(Scope *sc);
     void addMember(Scope *sc, ScopeDsymbol *sds);
     void setScope(Scope *sc);
@@ -197,7 +198,7 @@ public:
     bool cached;
     Dsymbols *cache;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    StaticForeachDeclaration *syntaxCopy(Dsymbol *s);
     bool oneMember(Dsymbol **ps, Identifier *ident);
     Dsymbols *include(Scope *sc);
     void addMember(Scope *sc, ScopeDsymbol *sds);
@@ -229,7 +230,7 @@ public:
     ScopeDsymbol *scopesym;
     bool compiled;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    CompileDeclaration *syntaxCopy(Dsymbol *s);
     void addMember(Scope *sc, ScopeDsymbol *sds);
     void setScope(Scope *sc);
     const char *kind() const;
@@ -245,7 +246,7 @@ class UserAttributeDeclaration : public AttribDeclaration
 public:
     Expressions *atts;
 
-    Dsymbol *syntaxCopy(Dsymbol *s);
+    UserAttributeDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
     void setScope(Scope *sc);
     Expressions *getAttributes();
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index ab7cce42fc2..efeb3fac748 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -1,7 +1,7 @@
 /**
  * Find out in what ways control flow can exit a statement block.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d)
@@ -14,6 +14,7 @@ module dmd.blockexit;
 import core.stdc.stdio;
 
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.canthrow;
 import dmd.dclass;
 import dmd.declaration;
@@ -107,6 +108,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
                         return;
                     }
                 }
+                if (s.exp.type.toBasetype().isTypeNoreturn())
+                    result = BE.halt;
                 if (canThrow(s.exp, func, mustNotThrow))
                     result |= BE.throw_;
             }
diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d
index a60a269b602..b99f690e156 100644
--- a/gcc/d/dmd/builtin.d
+++ b/gcc/d/dmd/builtin.d
@@ -3,7 +3,7 @@
  *
  * Currently includes functions from `std.math`, `core.math` and `core.bitop`.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d)
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index 7f2a961c5e1..fcb884df72d 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d)
@@ -17,6 +17,7 @@ import dmd.aggregate;
 import dmd.apply;
 import dmd.arraytypes;
 import dmd.attrib;
+import dmd.astenums;
 import dmd.declaration;
 import dmd.dsymbol;
 import dmd.expression;
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index bd9d47d7815..97adc5ad8ac 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -1,7 +1,7 @@
 /**
  * Check the arguments to `printf` and `scanf` against the `format` string.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d)
@@ -13,9 +13,12 @@ module dmd.chkformat;
 //import core.stdc.stdio : printf, scanf;
 import core.stdc.ctype : isdigit;
 
+import dmd.astenums;
+import dmd.cond;
 import dmd.errors;
 import dmd.expression;
 import dmd.globals;
+import dmd.identifier;
 import dmd.mtype;
 import dmd.target;
 
@@ -59,7 +62,7 @@ import dmd.target;
 bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list)
 {
     //printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr);
-    size_t n = 0;
+    size_t n, gnu_m_count;    // index in args / number of Format.GNU_m
     for (size_t i = 0; i < format.length;)
     {
         if (format[i] != '%')
@@ -85,17 +88,23 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
             continue;
         }
 
-        Expression getNextArg()
+        if (fmt == Format.GNU_m)
+            ++gnu_m_count;
+
+        Expression getNextArg(ref bool skip)
         {
             if (n == args.length)
             {
-                deprecation(loc, "more format specifiers than %d arguments", cast(int)n);
+                if (args.length < (n + 1) - gnu_m_count)
+                    deprecation(loc, "more format specifiers than %d arguments", cast(int)n);
+                else
+                    skip = true;
                 return null;
             }
             return args[n++];
         }
 
-        void errorMsg(const char* prefix, const char[] specifier, Expression arg, const char* texpect, Type tactual)
+        void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual)
         {
             deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
                   prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars());
@@ -103,31 +112,40 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
 
         if (widthStar)
         {
-            auto e = getNextArg();
+            bool skip;
+            auto e = getNextArg(skip);
+            if (skip)
+                continue;
             if (!e)
                 return true;
             auto t = e.type.toBasetype();
             if (t.ty != Tint32 && t.ty != Tuns32)
-                errorMsg("width ", slice, e, "int", t);
+                errorMsg("width ", e, "int", t);
         }
 
         if (precisionStar)
         {
-            auto e = getNextArg();
+            bool skip;
+            auto e = getNextArg(skip);
+            if (skip)
+                continue;
             if (!e)
                 return true;
             auto t = e.type.toBasetype();
             if (t.ty != Tint32 && t.ty != Tuns32)
-                errorMsg("precision ", slice, e, "int", t);
+                errorMsg("precision ", e, "int", t);
         }
 
-        auto e = getNextArg();
+        bool skip;
+        auto e = getNextArg(skip);
+        if (skip)
+            continue;
         if (!e)
             return true;
         auto t = e.type.toBasetype();
         auto tnext = t.nextOf();
         const c_longsize = target.c.longsize;
-        const is64bit = global.params.is64bit;
+        const ptrsize = target.ptrsize;
 
         // Types which are promoted to int are allowed.
         // Spec: C99 6.5.2.2.7
@@ -136,130 +154,143 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
             case Format.u:      // unsigned int
             case Format.d:      // int
                 if (t.ty != Tint32 && t.ty != Tuns32)
-                    errorMsg(null, slice, e, "int", t);
+                    errorMsg(null, e, fmt == Format.u ? "uint" : "int", t);
                 break;
 
             case Format.hhu:    // unsigned char
             case Format.hhd:    // signed char
                 if (t.ty != Tint32 && t.ty != Tuns32 && t.ty != Tint8 && t.ty != Tuns8)
-                    errorMsg(null, slice, e, "byte", t);
+                    errorMsg(null, e, fmt == Format.hhu ? "ubyte" : "byte", t);
                 break;
 
             case Format.hu:     // unsigned short int
             case Format.hd:     // short int
                 if (t.ty != Tint32 && t.ty != Tuns32 && t.ty != Tint16 && t.ty != Tuns16)
-                    errorMsg(null, slice, e, "short", t);
+                    errorMsg(null, e, fmt == Format.hu ? "ushort" : "short", t);
                 break;
 
             case Format.lu:     // unsigned long int
             case Format.ld:     // long int
                 if (!(t.isintegral() && t.size() == c_longsize))
-                    errorMsg(null, slice, e, (c_longsize == 4 ? "int" : "long"), t);
+                {
+                    if (fmt == Format.lu)
+                        errorMsg(null, e, (c_longsize == 4 ? "uint" : "ulong"), t);
+                    else
+                        errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t);
+                }
                 break;
 
             case Format.llu:    // unsigned long long int
             case Format.lld:    // long long int
                 if (t.ty != Tint64 && t.ty != Tuns64)
-                    errorMsg(null, slice, e, "long", t);
+                    errorMsg(null, e, fmt == Format.llu ? "ulong" : "long", t);
                 break;
 
             case Format.ju:     // uintmax_t
             case Format.jd:     // intmax_t
                 if (t.ty != Tint64 && t.ty != Tuns64)
-                    errorMsg(null, slice, e, "core.stdc.stdint.intmax_t", t);
+                {
+                    if (fmt == Format.ju)
+                        errorMsg(null, e, "core.stdc.stdint.uintmax_t", t);
+                    else
+                        errorMsg(null, e, "core.stdc.stdint.intmax_t", t);
+                }
                 break;
 
             case Format.zd:     // size_t
-                if (!(t.isintegral() && t.size() == (is64bit ? 8 : 4)))
-                    errorMsg(null, slice, e, "size_t", t);
+                if (!(t.isintegral() && t.size() == ptrsize))
+                    errorMsg(null, e, "size_t", t);
                 break;
 
             case Format.td:     // ptrdiff_t
-                if (!(t.isintegral() && t.size() == (is64bit ? 8 : 4)))
-                    errorMsg(null, slice, e, "ptrdiff_t", t);
+                if (!(t.isintegral() && t.size() == ptrsize))
+                    errorMsg(null, e, "ptrdiff_t", t);
                 break;
 
+            case Format.GNU_a:  // Format.GNU_a is only for scanf
             case Format.lg:
             case Format.g:      // double
                 if (t.ty != Tfloat64 && t.ty != Timaginary64)
-                    errorMsg(null, slice, e, "double", t);
+                    errorMsg(null, e, "double", t);
                 break;
 
             case Format.Lg:     // long double
                 if (t.ty != Tfloat80 && t.ty != Timaginary80)
-                    errorMsg(null, slice, e, "real", t);
+                    errorMsg(null, e, "real", t);
                 break;
 
             case Format.p:      // pointer
                 if (t.ty != Tpointer && t.ty != Tnull && t.ty != Tclass && t.ty != Tdelegate && t.ty != Taarray)
-                    errorMsg(null, slice, e, "void*", t);
+                    errorMsg(null, e, "void*", t);
                 break;
 
             case Format.n:      // pointer to int
                 if (!(t.ty == Tpointer && tnext.ty == Tint32))
-                    errorMsg(null, slice, e, "int*", t);
+                    errorMsg(null, e, "int*", t);
                 break;
 
             case Format.ln:     // pointer to long int
                 if (!(t.ty == Tpointer && tnext.isintegral() && tnext.size() == c_longsize))
-                    errorMsg(null, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+                    errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
                 break;
 
             case Format.lln:    // pointer to long long int
                 if (!(t.ty == Tpointer && tnext.ty == Tint64))
-                    errorMsg(null, slice, e, "long*", t);
+                    errorMsg(null, e, "long*", t);
                 break;
 
             case Format.hn:     // pointer to short
                 if (!(t.ty == Tpointer && tnext.ty == Tint16))
-                    errorMsg(null, slice, e, "short*", t);
+                    errorMsg(null, e, "short*", t);
                 break;
 
             case Format.hhn:    // pointer to signed char
                 if (!(t.ty == Tpointer && tnext.ty == Tint16))
-                    errorMsg(null, slice, e, "byte*", t);
+                    errorMsg(null, e, "byte*", t);
                 break;
 
             case Format.jn:     // pointer to intmax_t
                 if (!(t.ty == Tpointer && tnext.ty == Tint64))
-                    errorMsg(null, slice, e, "core.stdc.stdint.intmax_t*", t);
+                    errorMsg(null, e, "core.stdc.stdint.intmax_t*", t);
                 break;
 
             case Format.zn:     // pointer to size_t
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tuns64 : Tuns32)))
-                    errorMsg(null, slice, e, "size_t*", t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+                    errorMsg(null, e, "size_t*", t);
                 break;
 
             case Format.tn:     // pointer to ptrdiff_t
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tint64 : Tint32)))
-                    errorMsg(null, slice, e, "ptrdiff_t*", t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+                    errorMsg(null, e, "ptrdiff_t*", t);
                 break;
 
             case Format.c:      // char
                 if (t.ty != Tint32 && t.ty != Tuns32)
-                    errorMsg(null, slice, e, "char", t);
+                    errorMsg(null, e, "char", t);
                 break;
 
             case Format.lc:     // wint_t
                 if (t.ty != Tint32 && t.ty != Tuns32)
-                    errorMsg(null, slice, e, "wchar_t", t);
+                    errorMsg(null, e, "wchar_t", t);
                 break;
 
             case Format.s:      // pointer to char string
                 if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
-                    errorMsg(null, slice, e, "char*", t);
+                    errorMsg(null, e, "char*", t);
                 break;
 
             case Format.ls:     // pointer to wchar_t string
-                const twchar_t = global.params.isWindows ? Twchar : Tdchar;
-                if (!(t.ty == Tpointer && tnext.ty == twchar_t))
-                    errorMsg(null, slice, e, "wchar_t*", t);
+                if (!(t.ty == Tpointer && tnext.ty.isSomeChar && tnext.size() == target.c.wchar_tsize))
+                    errorMsg(null, e, "wchar_t*", t);
                 break;
 
             case Format.error:
                 deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
                 break;
 
+            case Format.GNU_m:
+                break;  // not assert(0) because it may go through it if there are extra arguments
+
             case Format.percent:
                 assert(0);
         }
@@ -340,7 +371,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
             return args[n++];
         }
 
-        void errorMsg(const char* prefix, const char[] specifier, Expression arg, const char* texpect, Type tactual)
+        void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual)
         {
             deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
                   prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars());
@@ -353,117 +384,120 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
         auto t = e.type.toBasetype();
         auto tnext = t.nextOf();
         const c_longsize = target.c.longsize;
-        const is64bit = global.params.is64bit;
+        const ptrsize = target.ptrsize;
 
         final switch (fmt)
         {
             case Format.n:
             case Format.d:      // pointer to int
                 if (!(t.ty == Tpointer && tnext.ty == Tint32))
-                    errorMsg(null, slice, e, "int*", t);
+                    errorMsg(null, e, "int*", t);
                 break;
 
             case Format.hhn:
             case Format.hhd:    // pointer to signed char
                 if (!(t.ty == Tpointer && tnext.ty == Tint16))
-                    errorMsg(null, slice, e, "byte*", t);
+                    errorMsg(null, e, "byte*", t);
                 break;
 
             case Format.hn:
             case Format.hd:     // pointer to short
                 if (!(t.ty == Tpointer && tnext.ty == Tint16))
-                    errorMsg(null, slice, e, "short*", t);
+                    errorMsg(null, e, "short*", t);
                 break;
 
             case Format.ln:
             case Format.ld:     // pointer to long int
-                if (!(t.ty == Tpointer && tnext.isintegral() && tnext.size() == c_longsize))
-                    errorMsg(null, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == c_longsize))
+                    errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
                 break;
 
             case Format.lln:
             case Format.lld:    // pointer to long long int
                 if (!(t.ty == Tpointer && tnext.ty == Tint64))
-                    errorMsg(null, slice, e, "long*", t);
+                    errorMsg(null, e, "long*", t);
                 break;
 
             case Format.jn:
             case Format.jd:     // pointer to intmax_t
                 if (!(t.ty == Tpointer && tnext.ty == Tint64))
-                    errorMsg(null, slice, e, "core.stdc.stdint.intmax_t*", t);
+                    errorMsg(null, e, "core.stdc.stdint.intmax_t*", t);
                 break;
 
             case Format.zn:
             case Format.zd:     // pointer to size_t
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tuns64 : Tuns32)))
-                    errorMsg(null, slice, e, "size_t*", t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+                    errorMsg(null, e, "size_t*", t);
                 break;
 
             case Format.tn:
             case Format.td:     // pointer to ptrdiff_t
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tint64 : Tint32)))
-                    errorMsg(null, slice, e, "ptrdiff_t*", t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+                    errorMsg(null, e, "ptrdiff_t*", t);
                 break;
 
             case Format.u:      // pointer to unsigned int
                 if (!(t.ty == Tpointer && tnext.ty == Tuns32))
-                    errorMsg(null, slice, e, "uint*", t);
+                    errorMsg(null, e, "uint*", t);
                 break;
 
             case Format.hhu:    // pointer to unsigned char
                 if (!(t.ty == Tpointer && tnext.ty == Tuns8))
-                    errorMsg(null, slice, e, "ubyte*", t);
+                    errorMsg(null, e, "ubyte*", t);
                 break;
 
             case Format.hu:     // pointer to unsigned short int
                 if (!(t.ty == Tpointer && tnext.ty == Tuns16))
-                    errorMsg(null, slice, e, "ushort*", t);
+                    errorMsg(null, e, "ushort*", t);
                 break;
 
             case Format.lu:     // pointer to unsigned long int
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tuns64 : Tuns32)))
-                    errorMsg(null, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
+                if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == c_longsize))
+                    errorMsg(null, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
                 break;
 
             case Format.llu:    // pointer to unsigned long long int
                 if (!(t.ty == Tpointer && tnext.ty == Tuns64))
-                    errorMsg(null, slice, e, "ulong*", t);
+                    errorMsg(null, e, "ulong*", t);
                 break;
 
             case Format.ju:     // pointer to uintmax_t
-                if (!(t.ty == Tpointer && tnext.ty == (is64bit ? Tuns64 : Tuns32)))
-                    errorMsg(null, slice, e, "ulong*", t);
+                if (!(t.ty == Tpointer && tnext.ty == Tuns64))
+                    errorMsg(null, e, "core.stdc.stdint.uintmax_t*", t);
                 break;
 
             case Format.g:      // pointer to float
                 if (!(t.ty == Tpointer && tnext.ty == Tfloat32))
-                    errorMsg(null, slice, e, "float*", t);
+                    errorMsg(null, e, "float*", t);
                 break;
+
             case Format.lg:     // pointer to double
                 if (!(t.ty == Tpointer && tnext.ty == Tfloat64))
-                    errorMsg(null, slice, e, "double*", t);
+                    errorMsg(null, e, "double*", t);
                 break;
+
             case Format.Lg:     // pointer to long double
                 if (!(t.ty == Tpointer && tnext.ty == Tfloat80))
-                    errorMsg(null, slice, e, "real*", t);
+                    errorMsg(null, e, "real*", t);
                 break;
 
+            case Format.GNU_a:
+            case Format.GNU_m:
             case Format.c:
             case Format.s:      // pointer to char string
                 if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
-                    errorMsg(null, slice, e, "char*", t);
+                    errorMsg(null, e, "char*", t);
                 break;
 
             case Format.lc:
             case Format.ls:     // pointer to wchar_t string
-                const twchar_t = global.params.isWindows ? Twchar : Tdchar;
-                if (!(t.ty == Tpointer && tnext.ty == twchar_t))
-                    errorMsg(null, slice, e, "wchar_t*", t);
+                if (!(t.ty == Tpointer && tnext.ty.isSomeChar && tnext.size() == target.c.wchar_tsize))
+                    errorMsg(null, e, "wchar_t*", t);
                 break;
 
             case Format.p:      // double pointer
                 if (!(t.ty == Tpointer && tnext.ty == Tpointer))
-                    errorMsg(null, slice, e, "void**", t);
+                    errorMsg(null, e, "void**", t);
                 break;
 
             case Format.error:
@@ -493,9 +527,8 @@ private:
  * Returns:
  *      Format
  */
-pure nothrow @safe
 Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
-        out bool asterisk)
+        out bool asterisk) nothrow pure @safe
 {
     auto i = idx;
     assert(format[i] == '%');
@@ -583,9 +616,8 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
  * Returns:
  *      Format
  */
-pure nothrow @safe
 Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
-        out bool widthStar, out bool precisionStar)
+        out bool widthStar, out bool precisionStar) nothrow pure @safe
 {
     auto i = idx;
     assert(format[i] == '%');
@@ -767,6 +799,8 @@ enum Format
     jn,         // pointer to intmax_t
     zn,         // pointer to size_t
     tn,         // pointer to ptrdiff_t
+    GNU_a,      // GNU ext. : address to a string with no maximum size (scanf)
+    GNU_m,      // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
     percent,    // %% (i.e. no argument)
     error,      // invalid format specification
 }
@@ -785,9 +819,9 @@ enum Format
  * Returns:
  *      Format
  */
-pure @safe nothrow
 Format parseGenericFormatSpecifier(scope const char[] format,
-    ref size_t idx, out char genSpecifier)
+    ref size_t idx, out char genSpecifier, bool useGNUExts =
+    findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @trusted
 {
     const length = format.length;
 
@@ -859,13 +893,21 @@ Format parseGenericFormatSpecifier(scope const char[] format,
                                                Format.u;
             break;
 
+        case 'a':
+            if (useGNUExts)
+            {
+                // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
+                specifier = Format.GNU_a;
+                break;
+            }
+            goto case;
+
         case 'f':
         case 'F':
         case 'e':
         case 'E':
         case 'g':
         case 'G':
-        case 'a':
         case 'A':
             if (lm == 'L')
                 specifier = Format.Lg;
@@ -910,6 +952,15 @@ Format parseGenericFormatSpecifier(scope const char[] format,
                                                Format.n;
             break;
 
+        case 'm':
+            if (useGNUExts)
+            {
+                // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
+                specifier = Format.GNU_m;
+                break;
+            }
+            goto default;
+
         default:
             specifier = Format.error;
             break;
@@ -1075,7 +1126,8 @@ unittest
      assert(idx == 2);
 
      idx = 0;
-     assert(parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar) == Format.g);
+     Format g = parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar);
+     assert(g == Format.g || g == Format.GNU_a);
      assert(idx == 2);
 
      idx = 0;
@@ -1123,7 +1175,6 @@ unittest
          {
              idx = 0;
              assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar) == Format.error);
-             import std.stdio;
              assert(idx == s.length);
          }
      }
@@ -1245,7 +1296,8 @@ unittest
     assert(idx == 2);
 
     idx = 0;
-    assert(parseScanfFormatSpecifier("%a", idx, asterisk) == Format.g);
+    g = parseScanfFormatSpecifier("%a", idx, asterisk);
+    assert(g == Format.g || g == Format.GNU_a);
     assert(idx == 2);
 
     idx = 0;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index a76f109e66b..094ce0051a0 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -1,7 +1,8 @@
 /**
- * Define the implicit `opEquals`, `opAssign`, post blit, copy constructor and destructor for structs.
+ * Builds struct member functions if needed and not defined by the user.
+ * Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d)
@@ -14,6 +15,7 @@ module dmd.clone;
 import core.stdc.stdio;
 import dmd.aggregate;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dscope;
@@ -21,6 +23,7 @@ import dmd.dstruct;
 import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.dtemplate;
+import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
@@ -31,6 +34,7 @@ import dmd.init;
 import dmd.mtype;
 import dmd.opover;
 import dmd.semantic2;
+import dmd.semantic3;
 import dmd.statement;
 import dmd.target;
 import dmd.typesem;
@@ -1113,8 +1117,8 @@ DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
     if (!dtor)
         return null;
 
-    // ABI incompatible on all (?) x86 32-bit platforms
-    if (ad.classKind != ClassKind.cpp || global.params.is64bit)
+    // Generate shim only when ABI incompatible on target platform
+    if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD)
         return dtor;
 
     // generate member function that adjusts calling convention
@@ -1201,3 +1205,501 @@ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
         return inv;
     }
 }
+
+/*****************************************
+ * Create inclusive postblit for struct by aggregating
+ * all the postblits in postblits[] with the postblits for
+ * all the members.
+ * Note the close similarity with AggregateDeclaration::buildDtor(),
+ * and the ordering changes (runs forward instead of backwards).
+ */
+FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
+{
+    //printf("buildPostBlit() %s\n", sd.toChars());
+    if (sd.isUnionDeclaration())
+        return null;
+
+    const hasUserDefinedPosblit = sd.postblits.dim && !sd.postblits[0].isDisabled ? true : false;
+
+    // by default, the storage class of the created postblit
+    StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+    Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc;
+    Loc loc; // internal code should have no loc to prevent coverage
+
+    // if any of the postblits are disabled, then the generated postblit
+    // will be disabled
+    for (size_t i = 0; i < sd.postblits.dim; i++)
+    {
+        stc |= sd.postblits[i].storage_class & STC.disable;
+    }
+
+    VarDeclaration[] fieldsToDestroy;
+    auto postblitCalls = new Statements();
+    // iterate through all the struct fields that are not disabled
+    for (size_t i = 0; i < sd.fields.dim && !(stc & STC.disable); i++)
+    {
+        auto structField = sd.fields[i];
+        if (structField.storage_class & STC.ref_)
+            continue;
+        if (structField.overlapped)
+            continue;
+        // if it's a struct declaration or an array of structs
+        Type tv = structField.type.baseElemOf();
+        if (tv.ty != Tstruct)
+            continue;
+        auto sdv = (cast(TypeStruct)tv).sym;
+        // which has a postblit declaration
+        if (!sdv.postblit)
+            continue;
+        assert(!sdv.isUnionDeclaration());
+
+        // if this field's postblit is not `nothrow`, add a `scope(failure)`
+        // block to destroy any prior successfully postblitted fields should
+        // this field's postblit fail
+        if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow)
+        {
+             // create a list of destructors that need to be called
+            Expression[] dtorCalls;
+            foreach(sf; fieldsToDestroy)
+            {
+                Expression ex;
+                tv = sf.type.toBasetype();
+                if (tv.ty == Tstruct)
+                {
+                    // this.v.__xdtor()
+
+                    ex = new ThisExp(loc);
+                    ex = new DotVarExp(loc, ex, sf);
+
+                    // This is a hack so we can call destructors on const/immutable objects.
+                    ex = new AddrExp(loc, ex);
+                    ex = new CastExp(loc, ex, sf.type.mutableOf().pointerTo());
+                    ex = new PtrExp(loc, ex);
+                    if (stc & STC.safe)
+                        stc = (stc & ~STC.safe) | STC.trusted;
+
+                    auto sfv = (cast(TypeStruct)sf.type.baseElemOf()).sym;
+
+                    ex = new DotVarExp(loc, ex, sfv.dtor, false);
+                    ex = new CallExp(loc, ex);
+
+                    dtorCalls ~= ex;
+                }
+                else
+                {
+                    // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+                    const length = tv.numberOfElems(loc);
+
+                    ex = new ThisExp(loc);
+                    ex = new DotVarExp(loc, ex, sf);
+
+                    // This is a hack so we can call destructors on const/immutable objects.
+                    ex = new DotIdExp(loc, ex, Id.ptr);
+                    ex = new CastExp(loc, ex, sdv.type.pointerTo());
+                    if (stc & STC.safe)
+                        stc = (stc & ~STC.safe) | STC.trusted;
+
+                    auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+                                                    new IntegerExp(loc, length, Type.tsize_t));
+                    // Prevent redundant bounds check
+                    se.upperIsInBounds = true;
+                    se.lowerIsLessThanUpper = true;
+
+                    ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
+
+                    dtorCalls ~= ex;
+                }
+            }
+            fieldsToDestroy = [];
+
+            // aggregate the destructor calls
+            auto dtors = new Statements();
+            foreach_reverse(dc; dtorCalls)
+            {
+                dtors.push(new ExpStatement(loc, dc));
+            }
+
+            // put destructor calls in a `scope(failure)` block
+            postblitCalls.push(new ScopeGuardStatement(loc, TOK.onScopeFailure, new CompoundStatement(loc, dtors)));
+        }
+
+        // perform semantic on the member postblit in order to
+        // be able to aggregate it later on with the rest of the
+        // postblits
+        sdv.postblit.functionSemantic();
+
+        stc = mergeFuncAttrs(stc, sdv.postblit);
+        stc = mergeFuncAttrs(stc, sdv.dtor);
+
+        // if any of the struct member fields has disabled
+        // its postblit, then `sd` is not copyable, so no
+        // postblit is generated
+        if (stc & STC.disable)
+        {
+            postblitCalls.setDim(0);
+            break;
+        }
+
+        Expression ex;
+        tv = structField.type.toBasetype();
+        if (tv.ty == Tstruct)
+        {
+            // this.v.__xpostblit()
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, structField);
+
+            // This is a hack so we can call postblits on const/immutable objects.
+            ex = new AddrExp(loc, ex);
+            ex = new CastExp(loc, ex, structField.type.mutableOf().pointerTo());
+            ex = new PtrExp(loc, ex);
+            if (stc & STC.safe)
+                stc = (stc & ~STC.safe) | STC.trusted;
+
+            ex = new DotVarExp(loc, ex, sdv.postblit, false);
+            ex = new CallExp(loc, ex);
+        }
+        else
+        {
+            // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
+
+            const length = tv.numberOfElems(loc);
+            if (length == 0)
+                continue;
+
+            ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, structField);
+
+            // This is a hack so we can call postblits on const/immutable objects.
+            ex = new DotIdExp(loc, ex, Id.ptr);
+            ex = new CastExp(loc, ex, sdv.type.pointerTo());
+            if (stc & STC.safe)
+                stc = (stc & ~STC.safe) | STC.trusted;
+
+            auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+                                            new IntegerExp(loc, length, Type.tsize_t));
+            // Prevent redundant bounds check
+            se.upperIsInBounds = true;
+            se.lowerIsLessThanUpper = true;
+            ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayPostblit), se);
+        }
+        postblitCalls.push(new ExpStatement(loc, ex)); // combine in forward order
+
+        /* https://issues.dlang.org/show_bug.cgi?id=10972
+         * When subsequent field postblit calls fail,
+         * this field should be destructed for Exception Safety.
+         */
+        if (sdv.dtor)
+        {
+            sdv.dtor.functionSemantic();
+
+            // keep a list of fields that need to be destroyed in case
+            // of a future postblit failure
+            fieldsToDestroy ~= structField;
+        }
+    }
+
+    void checkShared()
+    {
+        if (sd.type.isShared())
+            stc |= STC.shared_;
+    }
+
+    // Build our own "postblit" which executes a, but only if needed.
+    if (postblitCalls.dim || (stc & STC.disable))
+    {
+        //printf("Building __fieldPostBlit()\n");
+        checkShared();
+        auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
+        dd.generated = true;
+        dd.storage_class |= STC.inference | STC.scope_;
+        dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
+        sd.postblits.shift(dd);
+        sd.members.push(dd);
+        dd.dsymbolSemantic(sc);
+    }
+
+    // create __xpostblit, which is the generated postblit
+    FuncDeclaration xpostblit = null;
+    switch (sd.postblits.dim)
+    {
+    case 0:
+        break;
+
+    case 1:
+        xpostblit = sd.postblits[0];
+        break;
+
+    default:
+        Expression e = null;
+        stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+        for (size_t i = 0; i < sd.postblits.dim; i++)
+        {
+            auto fd = sd.postblits[i];
+            stc = mergeFuncAttrs(stc, fd);
+            if (stc & STC.disable)
+            {
+                e = null;
+                break;
+            }
+            Expression ex = new ThisExp(loc);
+            ex = new DotVarExp(loc, ex, fd, false);
+            ex = new CallExp(loc, ex);
+            e = Expression.combine(e, ex);
+        }
+
+        checkShared();
+        auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
+        dd.generated = true;
+        dd.storage_class |= STC.inference;
+        dd.fbody = new ExpStatement(loc, e);
+        sd.members.push(dd);
+        dd.dsymbolSemantic(sc);
+        xpostblit = dd;
+        break;
+    }
+
+    // Add an __xpostblit alias to make the inclusive postblit accessible
+    if (xpostblit)
+    {
+        auto _alias = new AliasDeclaration(Loc.initial, Id.__xpostblit, xpostblit);
+        _alias.dsymbolSemantic(sc);
+        sd.members.push(_alias);
+        _alias.addMember(sc, sd); // add to symbol table
+    }
+
+    if (sd.hasCopyCtor)
+    {
+        // we have user defined postblit, so we prioritize it
+        if (hasUserDefinedPosblit)
+        {
+            sd.hasCopyCtor = false;
+            return xpostblit;
+        }
+        // we have fields with postblits, so print deprecations
+        if (xpostblit && !xpostblit.isDisabled())
+        {
+            deprecation(sd.loc, "`struct %s` implicitly-generated postblit hides copy constructor.", sd.toChars);
+            deprecationSupplemental(sd.loc, "The field postblit will have priority over the copy constructor.");
+            deprecationSupplemental(sd.loc, "To change this, the postblit should be disabled for `struct %s`", sd.toChars());
+            sd.hasCopyCtor = false;
+        }
+        else
+            xpostblit = null;
+    }
+
+    return xpostblit;
+}
+
+/**
+ * Generates a copy constructor declaration with the specified storage
+ * class for the parameter and the function.
+ *
+ * Params:
+ *  sd = the `struct` that contains the copy constructor
+ *  paramStc = the storage class of the copy constructor parameter
+ *  funcStc = the storage class for the copy constructor declaration
+ *
+ * Returns:
+ *  The copy constructor declaration for struct `sd`.
+ */
+private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
+{
+    auto fparams = new Parameters();
+    auto structType = sd.type;
+    fparams.push(new Parameter(paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null));
+    ParameterList pList = ParameterList(fparams);
+    auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_);
+    auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
+    ccd.storage_class |= funcStc;
+    ccd.storage_class |= STC.inference;
+    ccd.generated = true;
+    return ccd;
+}
+
+/**
+ * Generates a trivial copy constructor body that simply does memberwise
+ * initialization:
+ *
+ *    this.field1 = rhs.field1;
+ *    this.field2 = rhs.field2;
+ *    ...
+ *
+ * Params:
+ *  sd = the `struct` declaration that contains the copy constructor
+ *
+ * Returns:
+ *  A `CompoundStatement` containing the body of the copy constructor.
+ */
+private Statement generateCopyCtorBody(StructDeclaration sd)
+{
+    Loc loc;
+    Expression e;
+    foreach (v; sd.fields)
+    {
+        auto ec = new AssignExp(loc,
+            new DotVarExp(loc, new ThisExp(loc), v),
+            new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
+        e = Expression.combine(e, ec);
+        //printf("e.toChars = %s\n", e.toChars());
+    }
+    Statement s1 = new ExpStatement(loc, e);
+    return new CompoundStatement(loc, s1);
+}
+
+/**
+ * Determine if a copy constructor is needed for struct sd,
+ * if the following conditions are met:
+ *
+ * 1. sd does not define a copy constructor
+ * 2. at least one field of sd defines a copy constructor
+ *
+ * Params:
+ *  sd = the `struct` for which the copy constructor is generated
+ *  hasCpCtor = set to true if a copy constructor is already present
+ *
+ * Returns:
+ *  `true` if one needs to be generated
+ *  `false` otherwise
+ */
+private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
+{
+    if (global.errors)
+        return false;
+
+    auto ctor = sd.search(sd.loc, Id.ctor);
+    if (ctor)
+    {
+        if (ctor.isOverloadSet())
+            return false;
+        if (auto td = ctor.isTemplateDeclaration())
+            ctor = td.funcroot;
+    }
+
+    CtorDeclaration cpCtor;
+    CtorDeclaration rvalueCtor;
+
+    if (!ctor)
+        goto LcheckFields;
+
+    overloadApply(ctor, (Dsymbol s)
+    {
+        if (s.isTemplateDeclaration())
+            return 0;
+        auto ctorDecl = s.isCtorDeclaration();
+        assert(ctorDecl);
+        if (ctorDecl.isCpCtor)
+        {
+            if (!cpCtor)
+                cpCtor = ctorDecl;
+            return 0;
+        }
+
+        auto tf = ctorDecl.type.toTypeFunction();
+        const dim = tf.parameterList.length;
+        if (dim == 1)
+        {
+            auto param = tf.parameterList[0];
+            if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
+            {
+                rvalueCtor = ctorDecl;
+            }
+        }
+        return 0;
+    });
+
+    if (cpCtor)
+    {
+        if (rvalueCtor)
+        {
+            .error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars());
+            errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
+            errorSupplemental(cpCtor.loc, "copy constructor defined here");
+        }
+        hasCpCtor = true;
+        return false;
+    }
+
+LcheckFields:
+    VarDeclaration fieldWithCpCtor;
+    // see if any struct members define a copy constructor
+    foreach (v; sd.fields)
+    {
+        if (v.storage_class & STC.ref_)
+            continue;
+        if (v.overlapped)
+            continue;
+
+        auto ts = v.type.baseElemOf().isTypeStruct();
+        if (!ts)
+            continue;
+        if (ts.sym.hasCopyCtor)
+        {
+            fieldWithCpCtor = v;
+            break;
+        }
+    }
+
+    if (fieldWithCpCtor && rvalueCtor)
+    {
+        .error(sd.loc, "`struct %s` may not define a rvalue constructor and have fields with copy constructors", sd.toChars());
+        errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
+        errorSupplemental(fieldWithCpCtor.loc, "field with copy constructor defined here");
+        return false;
+    }
+    else if (!fieldWithCpCtor)
+        return false;
+    return true;
+}
+
+/**
+ * Generates a copy constructor if needCopyCtor() returns true.
+ * The generated copy constructor will be of the form:
+ *   this(ref return scope inout(S) rhs) inout
+ *   {
+ *      this.field1 = rhs.field1;
+ *      this.field2 = rhs.field2;
+ *      ...
+ *   }
+ *
+ * Params:
+ *  sd = the `struct` for which the copy constructor is generated
+ *  sc = the scope where the copy constructor is generated
+ *
+ * Returns:
+ *  `true` if `struct` sd defines a copy constructor (explicitly or generated),
+ *  `false` otherwise.
+ */
+bool buildCopyCtor(StructDeclaration sd, Scope* sc)
+{
+    bool hasCpCtor;
+    if (!needCopyCtor(sd, hasCpCtor))
+        return hasCpCtor;
+
+    //printf("generating copy constructor for %s\n", sd.toChars());
+    const MOD paramMod = MODFlags.wild;
+    const MOD funcMod = MODFlags.wild;
+    auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
+    auto copyCtorBody = generateCopyCtorBody(sd);
+    ccd.fbody = copyCtorBody;
+    sd.members.push(ccd);
+    ccd.addMember(sc, sd);
+    const errors = global.startGagging();
+    Scope* sc2 = sc.push();
+    sc2.stc = 0;
+    sc2.linkage = LINK.d;
+    ccd.dsymbolSemantic(sc2);
+    ccd.semantic2(sc2);
+    ccd.semantic3(sc2);
+    //printf("ccd semantic: %s\n", ccd.type.toChars());
+    sc2.pop();
+    if (global.endGagging(errors) || sd.isUnionDeclaration())
+    {
+        ccd.storage_class |= STC.disable;
+        ccd.fbody = null;
+    }
+    return true;
+}
+
+
diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d
index 667beb5bf95..28f9ba6fdc4 100644
--- a/gcc/d/dmd/compiler.d
+++ b/gcc/d/dmd/compiler.d
@@ -1,7 +1,7 @@
 /**
  * Describes a back-end compiler and implements compiler-specific actions.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d)
@@ -20,9 +20,6 @@ import dmd.root.array;
 
 extern (C++) __gshared
 {
-    /// Module in which the D main is
-    Module rootHasMain = null;
-
     bool includeImports = false;
     // array of module patterns used to include/exclude imported modules
     Array!(const(char)*) includeModulePatterns;
diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h
index c8259edfa8b..27e87b692a8 100644
--- a/gcc/d/dmd/compiler.h
+++ b/gcc/d/dmd/compiler.h
@@ -22,9 +22,6 @@ class Type;
 struct Scope;
 struct UnionExp;
 
-// Module in which the D main is
-extern Module *rootHasMain;
-
 extern bool includeImports;
 // array of module patterns used to include/exclude imported modules
 extern Array<const char*> includeModulePatterns;
diff --git a/gcc/d/dmd/complex.d b/gcc/d/dmd/complex.d
index 61bffdabb6d..84bf5e9763a 100644
--- a/gcc/d/dmd/complex.d
+++ b/gcc/d/dmd/complex.d
@@ -1,7 +1,7 @@
 /**
  * Implements a complex number type.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/complex.d, _complex.d)
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 22387072e61..cf12ee4e530 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d)
@@ -15,6 +15,7 @@ module dmd.cond;
 
 import core.stdc.string;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.ast_node;
 import dmd.dcast;
 import dmd.dmodule;
@@ -42,7 +43,7 @@ import dmd.func;
 /***********************************************************
  */
 
-enum Include
+enum Include : ubyte
 {
     notComputed,        /// not computed yet
     yes,                /// include the conditional code
@@ -130,8 +131,8 @@ extern (C++) final class StaticForeach : RootObject
     {
         return new StaticForeach(
             loc,
-            aggrfe ? cast(ForeachStatement)aggrfe.syntaxCopy() : null,
-            rangefe ? cast(ForeachRangeStatement)rangefe.syntaxCopy() : null
+            aggrfe ? aggrfe.syntaxCopy() : null,
+            rangefe ? rangefe.syntaxCopy() : null
         );
     }
 
@@ -173,6 +174,7 @@ extern (C++) final class StaticForeach : RootObject
             aggrfe.aggr = new TupleExp(aggr.loc, es);
             aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
             aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
+            aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
         }
         else
         {
@@ -255,7 +257,8 @@ extern (C++) final class StaticForeach : RootObject
         auto ty = new TypeTypeof(loc, new TupleExp(loc, e));
         sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0));
         auto r = cast(TypeStruct)sdecl.type;
-        r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file
+        if (global.params.useTypeInfo && Type.dtypeinfo)
+            r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file
         return r;
     }
 
@@ -364,20 +367,30 @@ extern (C++) final class StaticForeach : RootObject
         sfe.push(new ReturnStatement(aloc, res[0]));
         s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe)));
         s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
-        auto ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
+        Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
         auto aty = ety.arrayOf();
         auto idres = Identifier.generateId("__res");
         auto vard = new VarDeclaration(aloc, aty, idres, null);
         auto s2 = new Statements();
-        s2.push(new ExpStatement(aloc, vard));
-        auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
-        s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
-        s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
+
+        // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
+        // an empty foreach to expose them.
+        uint olderrors = global.startGagging();
+        ety = ety.typeSemantic(aloc, sc);
+        if (global.endGagging(olderrors))
+            s2.push(createForeach(aloc, pparams[1], null));
+        else
+        {
+            s2.push(new ExpStatement(aloc, vard));
+            auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
+            s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
+            s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
+        }
 
         Expression aggr = void;
         Type indexty = void;
 
-        if (rangefe && (indexty = ety.typeSemantic(aloc, sc)).isintegral())
+        if (rangefe && (indexty = ety).isintegral())
         {
             rangefe.lwr.type = indexty;
             rangefe.upr.type = indexty;
@@ -440,11 +453,6 @@ extern (C++) final class StaticForeach : RootObject
             aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
             sc = sc.endCTFE();
             aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
-            auto tab = aggrfe.aggr.type.toBasetype();
-            if (tab.ty != Ttuple)
-            {
-                aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
-            }
         }
 
         if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
@@ -483,15 +491,15 @@ extern (C++) class DVCondition : Condition
     Identifier ident;
     Module mod;
 
-    extern (D) this(Module mod, uint level, Identifier ident)
+    extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
     {
-        super(Loc.initial);
+        super(loc);
         this.mod = mod;
         this.level = level;
         this.ident = ident;
     }
 
-    override final Condition syntaxCopy()
+    override final DVCondition syntaxCopy()
     {
         return this; // don't need to copy
     }
@@ -548,10 +556,11 @@ extern (C++) final class DebugCondition : DVCondition
      *           Only used if `ident` is `null`.
      *   ident = Identifier required for this condition to pass.
      *           If `null`, this conditiion will use an integer level.
+     *  loc = Location in the source file
      */
-    extern (D) this(Module mod, uint level, Identifier ident)
+    extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
     {
-        super(mod, level, ident);
+        super(loc, mod, level, ident);
     }
 
     override int include(Scope* sc)
@@ -655,6 +664,7 @@ extern (C++) final class VersionCondition : DVCondition
             case "CRuntime_Glibc":
             case "CRuntime_Microsoft":
             case "CRuntime_Musl":
+            case "CRuntime_Newlib":
             case "CRuntime_UClibc":
             case "CRuntime_WASI":
             case "Cygwin":
@@ -822,10 +832,11 @@ extern (C++) final class VersionCondition : DVCondition
      *           Only used if `ident` is `null`.
      *   ident = Identifier required for this condition to pass.
      *           If `null`, this conditiion will use an integer level.
+     *  loc = Location in the source file
      */
-    extern (D) this(Module mod, uint level, Identifier ident)
+    extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
     {
-        super(mod, level, ident);
+        super(loc, mod, level, ident);
     }
 
     override int include(Scope* sc)
@@ -891,7 +902,7 @@ extern (C++) final class StaticIfCondition : Condition
         this.exp = exp;
     }
 
-    override Condition syntaxCopy()
+    override StaticIfCondition syntaxCopy()
     {
         return new StaticIfCondition(loc, exp.syntaxCopy());
     }
@@ -958,7 +969,7 @@ extern (C++) final class StaticIfCondition : Condition
  * Returns:
  *      true if found
  */
-bool findCondition(Identifiers* ids, Identifier ident)
+bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure
 {
     if (ids)
     {
@@ -977,7 +988,7 @@ private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[
     if (!global.params.moduleDeps || global.params.moduleDepsFile)
         return;
     OutBuffer* ob = global.params.moduleDeps;
-    Module imod = sc ? sc.instantiatingModule() : condition.mod;
+    Module imod = sc ? sc._module : condition.mod;
     if (!imod)
         return;
     ob.writestring(depType);
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
index 87a2d92409e..4f261162ebb 100644
--- a/gcc/d/dmd/cond.h
+++ b/gcc/d/dmd/cond.h
@@ -62,7 +62,7 @@ public:
     Identifier *ident;
     Module *mod;
 
-    Condition *syntaxCopy();
+    DVCondition *syntaxCopy();
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -92,7 +92,7 @@ class StaticIfCondition : public Condition
 public:
     Expression *exp;
 
-    Condition *syntaxCopy();
+    StaticIfCondition *syntaxCopy();
     int include(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 3d3bafbed15..1dada60de3b 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -5,7 +5,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
@@ -18,6 +18,7 @@ module dmd.constfold;
 import core.stdc.string;
 import core.stdc.stdio;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.complex;
 import dmd.ctfeexpr;
 import dmd.declaration;
@@ -1497,11 +1498,10 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
 
 /* Also return TOK.cantExpression if this fails
  */
-UnionExp Cat(Type type, Expression e1, Expression e2)
+UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
 {
     UnionExp ue = void;
     Expression e = CTFEExp.cantexp;
-    Loc loc = e1.loc;
     Type t;
     Type t1 = e1.type.toBasetype();
     Type t2 = e2.type.toBasetype();
@@ -1731,7 +1731,7 @@ UnionExp Cat(Type type, Expression e1, Expression e2)
                 ? copyElements(e1) : new Expressions();
         elems.push(e2);
 
-        emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
+        emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
 
         e = ue.exp();
         if (type.toBasetype().ty == Tsarray)
@@ -1747,7 +1747,7 @@ UnionExp Cat(Type type, Expression e1, Expression e2)
     {
         auto elems = copyElements(e1, e2);
 
-        emplaceExp!(ArrayLiteralExp)(&ue, e2.loc, cast(Type)null, elems);
+        emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
 
         e = ue.exp();
         if (type.toBasetype().ty == Tsarray)
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
new file mode 100644
index 00000000000..f64813d613f
--- /dev/null
+++ b/gcc/d/dmd/cparse.d
@@ -0,0 +1,4052 @@
+/**
+ * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
+ *
+ * Specification: C11
+ *
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d)
+ * Documentation:  https://dlang.org/phobos/dmd_cparse.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cparse.d
+ */
+
+module dmd.cparse;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.astenums;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.lexer;
+import dmd.parse;
+import dmd.errors;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.tokens;
+
+/***********************************************************
+ */
+final class CParser(AST) : Parser!AST
+{
+    AST.Dsymbols* symbols;      // symbols declared in current scope
+
+    bool addFuncName;             /// add declaration of __func__ to function symbol table
+
+    extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
+                            const ref TARGET target)
+    {
+        super(_module, input, doDocComment);
+
+        //printf("CParser.this()\n");
+        mod = _module;
+        linkage = LINK.c;
+        Ccompile = true;
+
+        // Configure sizes for C `long`, `long double`, `wchar_t`
+        this.longsize = target.longsize;
+        this.long_doublesize = target.long_doublesize;
+        this.wchar_tsize = target.wchar_tsize;
+
+        // C `char` is always unsigned in ImportC
+    }
+
+    /********************************************
+     * Parse translation unit.
+     * C11 6.9
+     * translation-unit:
+     *    external-declaration
+     *    translation-unit external-declaration
+     *
+     * external-declaration:
+     *    function-definition
+     *    declaration
+     * Returns:
+     *  array of Dsymbols that were declared
+     */
+    override AST.Dsymbols* parseModule()
+    {
+        //printf("cparseTranslationUnit()\n");
+        symbols = new AST.Dsymbols();
+        while (1)
+        {
+            if (token.value == TOK.endOfFile)
+            {
+                // wrap the symbols in `extern (C) { symbols }`
+                auto wrap = new AST.Dsymbols();
+                auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
+                wrap.push(ld);
+
+                return wrap;
+            }
+
+            cparseDeclaration(LVL.global);
+        }
+    }
+
+    /******************************************************************************/
+    /********************************* Statement Parser ***************************/
+    //{
+
+    /**********************
+     * C11 6.8
+     * statement:
+     *    labeled-statement
+     *    compound-statement
+     *    expression-statement
+     *    selection-statement
+     *    iteration-statement
+     *    jump-statement
+     *
+     * Params:
+     *      flags = PSxxxx
+     *      endPtr = store location of closing brace
+     *      pEndloc = if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
+     * Returns:
+     *      parsed statement
+     */
+    AST.Statement cparseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
+    {
+        AST.Statement s;
+        const loc = token.loc;
+
+        //printf("cparseStatement()\n");
+
+        auto symbolsSave = symbols;
+        if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
+            symbols = new AST.Dsymbols();
+
+        switch (token.value)
+        {
+        case TOK.identifier:
+            /* A leading identifier can be a declaration, label, or expression.
+             * A quick check of the next token can disambiguate most cases.
+             */
+            switch (peekNext())
+            {
+                case TOK.colon:
+                {
+                    // It's a label
+                    auto ident = token.ident;
+                    nextToken();    // advance to `:`
+                    nextToken();    // advance past `:`
+                    if (token.value == TOK.rightCurly)
+                        s = null;
+                    else if (token.value == TOK.leftCurly)
+                        s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
+                    else
+                        s = cparseStatement(ParseStatementFlags.semiOk);
+                    s = new AST.LabelStatement(loc, ident, s);
+                    break;
+                }
+
+                case TOK.dot:
+                case TOK.arrow:
+                case TOK.plusPlus:
+                case TOK.minusMinus:
+                case TOK.leftBracket:
+                case TOK.question:
+                case TOK.assign:
+                case TOK.addAssign:
+                case TOK.minAssign:
+                case TOK.mulAssign:
+                case TOK.divAssign:
+                case TOK.modAssign:
+                case TOK.andAssign:
+                case TOK.orAssign:
+                case TOK.xorAssign:
+                case TOK.leftShiftAssign:
+                case TOK.rightShiftAssign:
+                    goto Lexp;
+
+                default:
+                {
+                    /* If tokens look like a declaration, assume it is one
+                     */
+                    auto tk = &token;
+                    if (isCDeclaration(tk))
+                        goto Ldeclaration;
+                    goto Lexp;
+                }
+            }
+            break;
+
+        case TOK.int32Literal:
+        case TOK.uns32Literal:
+        case TOK.int64Literal:
+        case TOK.uns64Literal:
+        case TOK.int128Literal:
+        case TOK.uns128Literal:
+        case TOK.float32Literal:
+        case TOK.float64Literal:
+        case TOK.float80Literal:
+        case TOK.imaginary32Literal:
+        case TOK.imaginary64Literal:
+        case TOK.imaginary80Literal:
+        case TOK.leftParenthesis:
+        case TOK.and:
+        case TOK.mul:
+        case TOK.min:
+        case TOK.add:
+        case TOK.tilde:
+        case TOK.not:
+        case TOK.plusPlus:
+        case TOK.minusMinus:
+        case TOK.sizeof_:
+        Lexp:
+            auto exp = cparseExpression();
+            if (token.value == TOK.identifier && exp.op == TOK.identifier)
+            {
+                error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
+                nextToken();
+            }
+            else
+                check(TOK.semicolon, "statement");
+            s = new AST.ExpStatement(loc, exp);
+            break;
+
+        // type-specifiers
+        case TOK.void_:
+        case TOK.char_:
+        case TOK.int16:
+        case TOK.int32:
+        case TOK.int64:
+        case TOK.float32:
+        case TOK.float64:
+        case TOK.signed:
+        case TOK.unsigned:
+        case TOK._Bool:
+        //case TOK._Imaginary:
+        case TOK._Complex:
+        case TOK.struct_:
+        case TOK.union_:
+        case TOK.enum_:
+
+        // storage-class-specifiers
+        case TOK.typedef_:
+        case TOK.extern_:
+        case TOK.static_:
+        case TOK._Thread_local:
+        case TOK.auto_:
+        case TOK.register:
+
+        // function-specifiers
+        case TOK.inline:
+        case TOK._Noreturn:
+
+        // type-qualifiers
+        case TOK.const_:
+        case TOK.volatile:
+        case TOK.restrict:
+
+        // alignment-specifier
+        case TOK._Alignas:
+
+        // atomic-type-specifier or type_qualifier
+        case TOK._Atomic:
+
+        Ldeclaration:
+        {
+            cparseDeclaration(LVL.local);
+            if (symbols.length > 1)
+            {
+                auto as = new AST.Statements();
+                as.reserve(symbols.length);
+                foreach (d; (*symbols)[])
+                {
+                    s = new AST.ExpStatement(loc, d);
+                    as.push(s);
+                }
+                s = new AST.CompoundDeclarationStatement(loc, as);
+                symbols.setDim(0);
+            }
+            else if (symbols.length == 1)
+            {
+                auto d = (*symbols)[0];
+                s = new AST.ExpStatement(loc, d);
+                symbols.setDim(0);
+            }
+            else
+                s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+            if (flags & ParseStatementFlags.scope_)
+                s = new AST.ScopeStatement(loc, s, token.loc);
+            break;
+        }
+
+        case TOK._Static_assert:        // _Static_assert ( constant-expression, string-literal ) ;
+            s = new AST.StaticAssertStatement(cparseStaticAssert());
+            break;
+
+        case TOK.leftCurly:
+        {
+            /* C11 6.8.2
+             * compound-statement:
+             *    { block-item-list (opt) }
+             *
+             * block-item-list:
+             *    block-item
+             *    block-item-list block-item
+             *
+             * block-item:
+             *    declaration
+             *    statement
+             */
+            nextToken();
+            auto statements = new AST.Statements();
+            while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
+            {
+                statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+            }
+            if (endPtr)
+                *endPtr = token.ptr;
+            endloc = token.loc;
+            if (pEndloc)
+            {
+                *pEndloc = token.loc;
+                pEndloc = null; // don't set it again
+            }
+            s = new AST.CompoundStatement(loc, statements);
+            if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
+                s = new AST.ScopeStatement(loc, s, token.loc);
+            check(TOK.rightCurly, "compound statement");
+            break;
+        }
+
+        case TOK.while_:
+        {
+            nextToken();
+            check(TOK.leftParenthesis);
+            auto condition = cparseExpression();
+            check(TOK.rightParenthesis);
+            Loc endloc;
+            auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
+            s = new AST.WhileStatement(loc, condition, _body, endloc, null);
+            break;
+        }
+
+        case TOK.semicolon:
+            /* C11 6.8.3 null statement
+             */
+            nextToken();
+            s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+            break;
+
+        case TOK.do_:
+        {
+            nextToken();
+            auto _body = cparseStatement(ParseStatementFlags.scope_);
+            check(TOK.while_);
+            check(TOK.leftParenthesis);
+            auto condition = cparseExpression();
+            check(TOK.rightParenthesis);
+            check(TOK.semicolon, "terminating `;` required after do-while statement");
+            s = new AST.DoStatement(loc, _body, condition, token.loc);
+            break;
+        }
+
+        case TOK.for_:
+        {
+            AST.Statement _init;
+            AST.Expression condition;
+            AST.Expression increment;
+
+            nextToken();
+            check(TOK.leftParenthesis);
+            if (token.value == TOK.semicolon)
+            {
+                _init = null;
+                nextToken();
+            }
+            else
+            {
+                _init = cparseStatement(0);
+            }
+            if (token.value == TOK.semicolon)
+            {
+                condition = null;
+                nextToken();
+            }
+            else
+            {
+                condition = cparseExpression();
+                check(TOK.semicolon, "`for` condition");
+            }
+            if (token.value == TOK.rightParenthesis)
+            {
+                increment = null;
+                nextToken();
+            }
+            else
+            {
+                increment = cparseExpression();
+                check(TOK.rightParenthesis);
+            }
+            Loc endloc;
+            auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
+            s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
+            break;
+        }
+
+        case TOK.if_:
+        {
+            nextToken();
+            check(TOK.leftParenthesis);
+            auto condition = cparseExpression();
+            check(TOK.rightParenthesis);
+            auto ifbody = cparseStatement(ParseStatementFlags.scope_);
+            AST.Statement elsebody;
+            if (token.value == TOK.else_)
+            {
+                nextToken();
+                elsebody = cparseStatement(ParseStatementFlags.scope_);
+            }
+            else
+                elsebody = null;
+            if (condition && ifbody)
+                s = new AST.IfStatement(loc, null, condition, ifbody, elsebody, token.loc);
+            else
+                s = null; // don't propagate parsing errors
+            break;
+        }
+
+        case TOK.else_:
+            error("found `else` without a corresponding `if` statement");
+            goto Lerror;
+
+        case TOK.switch_:
+        {
+            nextToken();
+            check(TOK.leftParenthesis);
+            auto condition = cparseExpression();
+            check(TOK.rightParenthesis);
+            auto _body = cparseStatement(ParseStatementFlags.scope_);
+            s = new AST.SwitchStatement(loc, condition, _body, false);
+            break;
+        }
+
+        case TOK.case_:
+        {
+
+            nextToken();
+            auto exp = cparseAssignExp();
+            check(TOK.colon);
+
+            if (flags & ParseStatementFlags.curlyScope)
+            {
+                auto statements = new AST.Statements();
+                while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+                {
+                    auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+                    statements.push(cur);
+
+                    // https://issues.dlang.org/show_bug.cgi?id=21739
+                    // Stop at the last break s.t. the following non-case statements are
+                    // not merged into the current case. This can happen for
+                    // case 1: ... break;
+                    // debug { case 2: ... }
+                    if (cur && cur.isBreakStatement())
+                        break;
+                }
+                s = new AST.CompoundStatement(loc, statements);
+            }
+            else
+            {
+                s = cparseStatement(ParseStatementFlags.semi);
+            }
+            s = new AST.ScopeStatement(loc, s, token.loc);
+            s = new AST.CaseStatement(loc, exp, s);
+            break;
+        }
+
+        case TOK.default_:
+        {
+            nextToken();
+            check(TOK.colon);
+
+            if (flags & ParseStatementFlags.curlyScope)
+            {
+                auto statements = new AST.Statements();
+                while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+                {
+                    statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+                }
+                s = new AST.CompoundStatement(loc, statements);
+            }
+            else
+                s = cparseStatement(ParseStatementFlags.semi);
+            s = new AST.ScopeStatement(loc, s, token.loc);
+            s = new AST.DefaultStatement(loc, s);
+            break;
+        }
+
+        case TOK.return_:
+        {
+            /*  return ;
+             *  return expression ;
+             */
+            nextToken();
+            auto exp = token.value == TOK.semicolon ? null : cparseExpression();
+            check(TOK.semicolon, "`return` statement");
+            s = new AST.ReturnStatement(loc, exp);
+            break;
+        }
+
+        case TOK.break_:
+            nextToken();
+            check(TOK.semicolon, "`break` statement");
+            s = new AST.BreakStatement(loc, null);
+            break;
+
+        case TOK.continue_:
+            nextToken();
+            check(TOK.semicolon, "`continue` statement");
+            s = new AST.ContinueStatement(loc, null);
+            break;
+
+        case TOK.goto_:
+        {
+            Identifier ident;
+            nextToken();
+            if (token.value != TOK.identifier)
+            {
+                error("identifier expected following `goto`");
+                ident = null;
+            }
+            else
+            {
+                ident = token.ident;
+                nextToken();
+            }
+            s = new AST.GotoStatement(loc, ident);
+            check(TOK.semicolon, "`goto` statement");
+            break;
+        }
+
+        case TOK.asm_:
+            s = parseAsm();
+            break;
+
+        default:
+            error("found `%s` instead of statement", token.toChars());
+            goto Lerror;
+
+        Lerror:
+            panic();
+            if (token.value == TOK.semicolon)
+                nextToken();
+            s = null;
+            break;
+        }
+        if (pEndloc)
+            *pEndloc = prevloc;
+        symbols = symbolsSave;
+        return s;
+    }
+
+    //}
+    /*******************************************************************************/
+    /********************************* Expression Parser ***************************/
+    //{
+
+    /**************
+     * C11 6.5.17
+     * expression:
+     *  assignment-expression
+     *  expression , assignment-expression
+     */
+    AST.Expression cparseExpression()
+    {
+        auto loc = token.loc;
+
+        //printf("cparseExpression() loc = %d\n", loc.linnum);
+        auto e = cparseAssignExp();
+        while (token.value == TOK.comma)
+        {
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.CommaExp(loc, e, e2, false);
+            loc = token.loc;
+        }
+        return e;
+    }
+
+
+    /*********************
+     * C11 6.5.1
+     * primary-expression:
+     *    identifier
+     *    constant
+     *    string-literal
+     *    ( expression )
+     *    generic-selection
+     */
+    AST.Expression cparsePrimaryExp()
+    {
+        AST.Expression e;
+        const loc = token.loc;
+
+        //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+        switch (token.value)
+        {
+        case TOK.identifier:
+            if (token.ident is Id.__func__)
+            {
+                addFuncName = true;     // implicitly declare __func__
+            }
+            e = new AST.IdentifierExp(loc, token.ident);
+            nextToken();
+            break;
+
+        case TOK.int32Literal:
+            e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
+            nextToken();
+            break;
+
+        case TOK.uns32Literal:
+            e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
+            nextToken();
+            break;
+
+        case TOK.int64Literal:
+            e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
+            nextToken();
+            break;
+
+        case TOK.uns64Literal:
+            e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
+            nextToken();
+            break;
+
+        case TOK.float32Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
+            nextToken();
+            break;
+
+        case TOK.float64Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
+            nextToken();
+            break;
+
+        case TOK.float80Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
+            nextToken();
+            break;
+
+        case TOK.imaginary32Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
+            nextToken();
+            break;
+
+        case TOK.imaginary64Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
+            nextToken();
+            break;
+
+        case TOK.imaginary80Literal:
+            e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
+            nextToken();
+            break;
+
+        case TOK.string_:
+        {
+            // cat adjacent strings
+            auto s = token.ustring;
+            auto len = token.len;
+            auto postfix = token.postfix;
+            while (1)
+            {
+                nextToken();
+                if (token.value == TOK.string_)
+                {
+                    if (token.postfix)
+                    {
+                        if (token.postfix != postfix)
+                            error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
+                        postfix = token.postfix;
+                    }
+
+                    const len1 = len;
+                    const len2 = token.len;
+                    len = len1 + len2;
+                    auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
+                    memcpy(s2, s, len1 * char.sizeof);
+                    memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
+                    s = s2;
+                }
+                else
+                    break;
+            }
+            e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
+            break;
+        }
+
+        case TOK.leftParenthesis:
+            nextToken();
+            e = cparseExpression();
+            check(TOK.rightParenthesis);
+            break;
+
+        case TOK._Generic:
+            e = cparseGenericSelection();
+            break;
+
+        default:
+            error("expression expected, not `%s`", token.toChars());
+            // Anything for e, as long as it's not NULL
+            e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
+            nextToken();
+            break;
+        }
+        return e;
+    }
+
+    /*********************************
+     * C11 6.5.2
+     * postfix-expression:
+     *    primary-expression
+     *    postfix-expression [ expression ]
+     *    postfix-expression ( argument-expression-list (opt) )
+     *    postfix-expression . identifier
+     *    postfix-expression -> identifier
+     *    postfix-expression ++
+     *    postfix-expression --
+     *    ( type-name ) { initializer-list }
+     *    ( type-name ) { initializer-list , }
+     *
+     * argument-expression-list:
+     *    assignment-expression
+     *    argument-expression-list , assignment-expression
+     */
+    private AST.Expression cparsePostfixExp(AST.Expression e)
+    {
+        e = cparsePrimaryExp();
+        return cparsePostfixOperators(e);
+    }
+
+    /********************************
+     * C11 6.5.2
+     * Parse a series of operators for a postfix expression after already parsing
+     * a primary-expression or compound literal expression.
+     * Params:
+     *      e = parsed primary or compound literal expression
+     * Returns:
+     *      parsed postfix expression
+     */
+    private AST.Expression cparsePostfixOperators(AST.Expression e)
+    {
+        while (1)
+        {
+            const loc = token.loc;
+            switch (token.value)
+            {
+            case TOK.dot:
+            case TOK.arrow:
+                nextToken();
+                if (token.value == TOK.identifier)
+                {
+                    Identifier id = token.ident;
+                    e = new AST.DotIdExp(loc, e, id);
+                    break;
+                }
+                error("identifier expected following `.`, not `%s`", token.toChars());
+                break;
+
+            case TOK.plusPlus:
+                e = new AST.PostExp(TOK.plusPlus, loc, e);
+                break;
+
+            case TOK.minusMinus:
+                e = new AST.PostExp(TOK.minusMinus, loc, e);
+                break;
+
+            case TOK.leftParenthesis:
+                e = new AST.CallExp(loc, e, cparseArguments());
+                continue;
+
+            case TOK.leftBracket:
+                {
+                    // array dereferences:
+                    //      array[index]
+                    AST.Expression index;
+                    auto arguments = new AST.Expressions();
+
+                    inBrackets++;
+                    nextToken();
+                    index = cparseAssignExp();
+                    arguments.push(index);
+                    check(TOK.rightBracket);
+                    inBrackets--;
+                    e = new AST.ArrayExp(loc, e, arguments);
+                    continue;
+                }
+            default:
+                return e;
+            }
+            nextToken();
+        }
+    }
+
+    /************************
+     * C11 6.5.3
+     * unary-expression:
+     *    postfix-expression
+     *    ++ unary-expression
+     *    -- unary-expression
+     *    unary-operator cast-expression
+     *    sizeof unary-expression
+     *    sizeof ( type-name )
+     *    _Alignof ( type-name )
+     *
+     * unary-operator:
+     *    & * + - ~ !
+     */
+    private AST.Expression cparseUnaryExp()
+    {
+        AST.Expression e;
+        const loc = token.loc;
+
+        switch (token.value)
+        {
+        case TOK.plusPlus:
+            nextToken();
+            // Parse `++` as an unary operator so that cast expressions only give
+            // an error for being non-lvalues.
+            e = cparseCastExp();
+            e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+            break;
+
+        case TOK.minusMinus:
+            nextToken();
+            // Parse `--` as an unary operator, same as prefix increment.
+            e = cparseCastExp();
+            e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+            break;
+
+        case TOK.and:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.AddrExp(loc, e);
+            break;
+
+        case TOK.mul:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.PtrExp(loc, e);
+            break;
+
+        case TOK.min:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.NegExp(loc, e);
+            break;
+
+        case TOK.add:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.UAddExp(loc, e);
+            break;
+
+        case TOK.not:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.NotExp(loc, e);
+            break;
+
+        case TOK.tilde:
+            nextToken();
+            e = cparseCastExp();
+            e = new AST.ComExp(loc, e);
+            break;
+
+        case TOK.sizeof_:
+        {
+            nextToken();
+            if (token.value == TOK.leftParenthesis)
+            {
+                auto tk = peek(&token);
+                if (isTypeName(tk))
+                {
+                    /* Expression may be either be requesting the sizeof a type-name
+                     * or a compound literal, which requires checking whether
+                     * the next token is `{`
+                     */
+                    nextToken();
+                    auto t = cparseTypeName();
+                    check(TOK.rightParenthesis);
+                    if (token.value == TOK.leftCurly)
+                    {
+                        // ( type-name ) { initializer-list }
+                        auto ci = cparseInitializer();
+                        e = new AST.CompoundLiteralExp(loc, t, ci);
+                        e = cparsePostfixOperators(e);
+                    }
+                    else
+                    {
+                        // ( type-name )
+                        e = new AST.TypeExp(loc, t);
+                    }
+                    e = new AST.DotIdExp(loc, e, Id.__sizeof);
+                    break;
+                }
+            }
+            e = cparseUnaryExp();
+            e = new AST.DotIdExp(loc, e, Id.__sizeof);
+            break;
+        }
+
+        case TOK._Alignof:
+        {
+            nextToken();
+            check(TOK.leftParenthesis);
+            auto t = cparseTypeName();
+            check(TOK.rightParenthesis);
+            e = new AST.TypeExp(loc, t);
+            e = new AST.DotIdExp(loc, e, Id.__xalignof);
+            break;
+        }
+
+        default:
+            e = cparsePostfixExp(e);
+            break;
+        }
+        assert(e);
+        return e;
+    }
+
+    /**************
+     * C11 6.5.4
+     * cast-expression
+     *    unary-expression
+     *    ( type-name ) cast-expression
+     */
+    private AST.Expression cparseCastExp()
+    {
+        if (token.value == TOK.leftParenthesis)
+        {
+            // If ( type-name )
+            auto pt = &token;
+            if (isCastExpression(pt))
+            {
+                // Expression may be either a cast or a compound literal, which
+                // requires checking whether the next token is `{`
+                const loc = token.loc;
+                nextToken();
+                auto t = cparseTypeName();
+                check(TOK.rightParenthesis);
+
+                if (token.value == TOK.leftCurly)
+                {
+                    // C11 6.5.2.5 ( type-name ) { initializer-list }
+                    auto ci = cparseInitializer();
+                    auto ce = new AST.CompoundLiteralExp(loc, t, ci);
+                    return cparsePostfixOperators(ce);
+                }
+                else
+                {
+                    // (type-name) cast-expression
+                    auto ce = cparseCastExp();
+                    return new AST.CastExp(loc, ce, t);
+                }
+            }
+        }
+        return cparseUnaryExp();
+    }
+
+    /**************
+     * C11 6.5.5
+     * multiplicative-expression
+     *    cast-expression
+     *    multiplicative-expression * cast-expression
+     *    multiplicative-expression / cast-expression
+     *    multiplicative-expression % cast-expression
+     */
+    private AST.Expression cparseMulExp()
+    {
+        const loc = token.loc;
+        auto e = cparseCastExp();
+
+        while (1)
+        {
+            switch (token.value)
+            {
+            case TOK.mul:
+                nextToken();
+                auto e2 = cparseCastExp();
+                e = new AST.MulExp(loc, e, e2);
+                continue;
+
+            case TOK.div:
+                nextToken();
+                auto e2 = cparseCastExp();
+                e = new AST.DivExp(loc, e, e2);
+                continue;
+
+            case TOK.mod:
+                nextToken();
+                auto e2 = cparseCastExp();
+                e = new AST.ModExp(loc, e, e2);
+                continue;
+
+            default:
+                break;
+            }
+            break;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.6
+     * additive-expression
+     *    multiplicative-expression
+     *    additive-expression + multiplicative-expression
+     *    additive-expression - multiplicative-expression
+     */
+    private AST.Expression cparseAddExp()
+    {
+        const loc = token.loc;
+        auto e = cparseMulExp();
+
+        while (1)
+        {
+            switch (token.value)
+            {
+            case TOK.add:
+                nextToken();
+                auto e2 = cparseMulExp();
+                e = new AST.AddExp(loc, e, e2);
+                continue;
+
+            case TOK.min:
+                nextToken();
+                auto e2 = cparseMulExp();
+                e = new AST.MinExp(loc, e, e2);
+                continue;
+
+            default:
+                break;
+            }
+            break;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.7
+     * shift-expression
+     *    additive-expression
+     *    shift-expression << additive-expression
+     *    shift-expression >> additive-expression
+     */
+    private AST.Expression cparseShiftExp()
+    {
+        const loc = token.loc;
+        auto e = cparseAddExp();
+
+        while (1)
+        {
+            switch (token.value)
+            {
+            case TOK.leftShift:
+                nextToken();
+                auto e2 = cparseAddExp();
+                e = new AST.ShlExp(loc, e, e2);
+                continue;
+
+            case TOK.rightShift:
+                nextToken();
+                auto e2 = cparseAddExp();
+                e = new AST.ShrExp(loc, e, e2);
+                continue;
+
+            default:
+                break;
+            }
+            break;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.8
+     * relational-expression
+     *    shift-expression
+     *    relational-expression < shift-expression
+     *    relational-expression > shift-expression
+     *    relational-expression <= shift-expression
+     *    relational-expression >= shift-expression
+     */
+    private AST.Expression cparseRelationalExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseShiftExp();
+        TOK op = token.value;
+
+        switch (op)
+        {
+        case TOK.lessThan:
+        case TOK.lessOrEqual:
+        case TOK.greaterThan:
+        case TOK.greaterOrEqual:
+            nextToken();
+            auto e2 = cparseShiftExp();
+            e = new AST.CmpExp(op, loc, e, e2);
+            break;
+
+        default:
+            break;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.9
+     * equality-expression
+     *    relational-expression
+     *    equality-expression == relational-expression
+     *    equality-expression != relational-expression
+     */
+    private AST.Expression cparseEqualityExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseRelationalExp();
+        const TOK op = token.value;
+
+        switch (op)
+        {
+        case TOK.equal:
+        case TOK.notEqual:
+            nextToken();
+            auto e2 = cparseRelationalExp();
+            e = new AST.EqualExp(op, loc, e, e2);
+            break;
+
+        default:
+            break;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.10
+     * AND-expression
+     *    equality-expression
+     *    AND-expression & equality-expression
+     */
+    private AST.Expression cparseAndExp()
+    {
+        Loc loc = token.loc;
+        auto e = cparseEqualityExp();
+        while (token.value == TOK.and)
+        {
+            nextToken();
+            auto e2 = cparseEqualityExp();
+            e = new AST.AndExp(loc, e, e2);
+            loc = token.loc;
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.11
+     * exclusive-OR-expression
+     *    AND-expression
+     *    exclusive-OR-expression ^ AND-expression
+     */
+    private AST.Expression cparseXorExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseAndExp();
+        while (token.value == TOK.xor)
+        {
+            nextToken();
+            auto e2 = cparseAndExp();
+            e = new AST.XorExp(loc, e, e2);
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.12
+     * inclusive-OR-expression
+     *    exclusive-OR-expression
+     *    inclusive-OR-expression | exclusive-OR-expression
+     */
+    private AST.Expression cparseOrExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseXorExp();
+        while (token.value == TOK.or)
+        {
+            nextToken();
+            auto e2 = cparseXorExp();
+            e = new AST.OrExp(loc, e, e2);
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.13
+     * logical-AND-expression
+     *    inclusive-OR-expression
+     *    logical-AND-expression && inclusive-OR-expression
+     */
+    private AST.Expression cparseAndAndExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseOrExp();
+        while (token.value == TOK.andAnd)
+        {
+            nextToken();
+            auto e2 = cparseOrExp();
+            e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.14
+     * logical-OR-expression
+     *    logical-AND-expression
+     *    logical-OR-expression || logical-AND-expression
+     */
+    private AST.Expression cparseOrOrExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseAndAndExp();
+        while (token.value == TOK.orOr)
+        {
+            nextToken();
+            auto e2 = cparseAndAndExp();
+            e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.15
+     * conditional-expression:
+     *    logical-OR-expression
+     *    logical-OR-expression ? expression : conditional-expression
+     */
+    private AST.Expression cparseCondExp()
+    {
+        const loc = token.loc;
+
+        auto e = cparseOrOrExp();
+        if (token.value == TOK.question)
+        {
+            nextToken();
+            auto e1 = cparseExpression();
+            check(TOK.colon);
+            auto e2 = cparseCondExp();
+            e = new AST.CondExp(loc, e, e1, e2);
+        }
+        return e;
+    }
+
+    /**************
+     * C11 6.5.16
+     * assignment-expression:
+     *    conditional-expression
+     *    unary-expression assignment-operator assignment-expression
+     *
+     * assignment-operator:
+     *    = *= /= %= += -= <<= >>= &= ^= |=
+     */
+    AST.Expression cparseAssignExp()
+    {
+        AST.Expression e;
+        e = cparseCondExp(); // constrain it to being unary-expression in semantic pass
+        if (e is null)
+            return e;
+
+        const loc = token.loc;
+        switch (token.value)
+        {
+        case TOK.assign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.AssignExp(loc, e, e2);
+            break;
+
+        case TOK.addAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.AddAssignExp(loc, e, e2);
+            break;
+
+        case TOK.minAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.MinAssignExp(loc, e, e2);
+            break;
+
+        case TOK.mulAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.MulAssignExp(loc, e, e2);
+            break;
+
+        case TOK.divAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.DivAssignExp(loc, e, e2);
+            break;
+
+        case TOK.modAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.ModAssignExp(loc, e, e2);
+            break;
+
+        case TOK.andAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.AndAssignExp(loc, e, e2);
+            break;
+
+        case TOK.orAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.OrAssignExp(loc, e, e2);
+            break;
+
+        case TOK.xorAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.XorAssignExp(loc, e, e2);
+            break;
+
+        case TOK.leftShiftAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.ShlAssignExp(loc, e, e2);
+            break;
+
+        case TOK.rightShiftAssign:
+            nextToken();
+            auto e2 = cparseAssignExp();
+            e = new AST.ShrAssignExp(loc, e, e2);
+            break;
+
+        default:
+            break;
+        }
+
+        return e;
+    }
+
+    /***********************
+     * C11 6.5.1.1
+     * _Generic ( assignment-expression, generic-assoc-list )
+     *
+     * generic-assoc-list:
+     *   generic-association
+     *   generic-assoc-list generic-association
+     *
+     * generic-association:
+     *   type-name : assignment-expression
+     *   default : assignment-expression
+     */
+    private AST.Expression cparseGenericSelection()
+    {
+        const loc = token.loc;
+        nextToken();
+        check(TOK.leftParenthesis);
+        cparseAssignExp();
+        check(TOK.comma);
+        bool sawDefault;
+        while (1)
+        {
+            if (token.value == TOK.default_)
+            {
+                if (sawDefault)
+                    error("only one `default` allowed in generic-assoc-list");
+                sawDefault = true;
+            }
+            else
+                cparseTypeName();
+
+            check(TOK.colon);
+            cparseAssignExp();
+            if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
+                break;
+        }
+        check(TOK.rightParenthesis);
+        error("`_Generic` not supported");  // TODO
+        return new AST.IntegerExp(loc, 0, AST.Type.tint32);
+    }
+
+    /***********************
+     * C11 6.6 Constant expressions
+     * constant-expression:
+     *   conditional-expression
+     */
+    private AST.Expression cparseConstantExp()
+    {
+        return cparseAssignExp();
+    }
+
+    //}
+    /********************************************************************************/
+    /********************************* Declaration Parser ***************************/
+    //{
+
+    /*************************************
+     * C11 6.7
+     * declaration:
+     *    declaration-specifiers init-declarator-list (opt) ;
+     *    static_assert-declaration
+     *
+     * init-declarator-list:
+     *    init-declarator
+     *    init-declarator-list , init-declarator
+     *
+     * init-declarator:
+     *    declarator
+     *    declarator = initializer
+     *
+     * Params:
+     *    level = declaration context
+     */
+    void cparseDeclaration(LVL level)
+    {
+        //printf("cparseDeclaration(level = %d)\n", level);
+        if (token.value == TOK._Static_assert)
+        {
+            auto s = cparseStaticAssert();
+            symbols.push(s);
+            return;
+        }
+
+        auto symbolsSave = symbols;
+        Specifier specifier;
+        auto tspec = cparseDeclarationSpecifiers(level, specifier);
+
+        /* If a declarator does not follow, it is unnamed
+         */
+        if (token.value == TOK.semicolon && tspec)
+        {
+            nextToken();
+            auto tt = tspec.isTypeTag();
+            if (!tt || !tt.id)
+                return; // legal but meaningless empty declaration, ignore it
+
+            /* `struct tag;` and `struct tag { ... };`
+             * always result in a declaration in the current scope
+             */
+            // TODO: merge in specifier
+            auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
+                        (tt.tok == TOK.union_)  ? new AST.UnionDeclaration(tt.loc, tt.id) :
+                                                  new AST.EnumDeclaration(tt.loc, tt.id, AST.Type.tint32);
+            stag.members = tt.members;
+            if (!symbols)
+                symbols = new AST.Dsymbols();
+            symbols.push(stag);
+
+            if (tt.tok == TOK.enum_)
+            {
+                if (!tt.members)
+                    error(tt.loc, "`enum %s` has no members", stag.toChars());
+            }
+            return;
+        }
+
+        if (tspec && specifier.mod & MOD.xconst)
+        {
+            tspec = toConst(tspec);
+            specifier.mod = MOD.xnone;          // 'used' it
+        }
+
+        bool first = true;
+        while (1)
+        {
+            Identifier id;
+            AST.Expression asmname;
+            auto dt = cparseDeclarator(DTR.xdirect, tspec, id);
+            if (!dt)
+            {
+                panic();
+                nextToken();
+                break;          // error recovery
+            }
+
+            /* GNU Extensions
+             * init-declarator:
+             *    declarator simple-asm-expr (opt) gnu-attributes (opt)
+             *    declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
+             */
+            switch (token.value)
+            {
+                case TOK.assign:
+                case TOK.comma:
+                case TOK.semicolon:
+                case TOK.asm_:
+                case TOK.__attribute__:
+                    /* This is a data definition, there cannot now be a
+                     * function definition.
+                     */
+                    first = false;
+                    if (token.value == TOK.asm_)
+                        asmname = cparseSimpleAsmExpr();
+                    if (token.value == TOK.__attribute__)
+                    {
+                        cparseGnuAttributes();
+                        if (token.value == TOK.leftCurly)
+                        {
+                            error("attributes should be specified before the function definition");
+                            auto t = &token;
+                            if (skipBraces(t))
+                            {
+                                token = *t;
+                                return;
+                            }
+                        }
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+
+            /* C11 6.9.1 Function Definitions
+             * function-definition:
+             *   declaration-specifiers declarator declaration-list (opt) compound-statement
+             *
+             * declaration-list:
+             *    declaration
+             *    declaration-list declaration
+             */
+            auto t = &token;
+            if (first &&                   // first declarator
+                id &&
+                dt.isTypeFunction() &&     // function type not inherited from a typedef
+                isDeclarationList(t) &&    // optional declaration-list
+                level == LVL.global &&     // function definitions only at global scope
+                t.value == TOK.leftCurly)  // start of compound-statement
+            {
+                auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier.scw);
+                symbols = symbolsSave;
+                symbols.push(s);
+                return;
+            }
+            AST.Dsymbol s = null;
+            symbols = symbolsSave;
+            if (!symbols)
+                symbols = new AST.Dsymbols;     // lazilly create it
+
+            if (level != LVL.global && !tspec && !specifier.scw && !specifier.mod)
+                error("declaration-specifier-seq required");
+            else if (specifier.scw == SCW.xtypedef)
+            {
+                if (token.value == TOK.assign)
+                    error("no initializer for typedef declaration");
+
+                bool isalias = true;
+                if (auto ts = dt.isTypeStruct())
+                {
+                    if (ts.sym.isAnonymous())
+                    {
+                        // This is a typedef for an anonymous struct-or-union.
+                        // Directly set the ident for the struct-or-union.
+                        ts.sym.ident = id;
+                        isalias = false;
+                    }
+                }
+                else if (auto te = dt.isTypeEnum())
+                {
+                    if (te.sym.isAnonymous())
+                    {
+                        // This is a typedef for an anonymous enum.
+                        te.sym.ident = id;
+                        isalias = false;
+                    }
+                }
+                if (isalias)
+                    s = new AST.AliasDeclaration(token.loc, id, dt);
+            }
+            else if (id)
+            {
+                if (level == LVL.prototype)
+                    break;      // declared later as Parameter, not VarDeclaration
+
+                if (dt.ty == AST.Tvoid)
+                    error("`void` has no value");
+
+                AST.Initializer initializer;
+                bool hasInitializer;
+                if (token.value == TOK.assign)
+                {
+                    nextToken();
+                    hasInitializer = true;
+                    initializer = cparseInitializer();
+                }
+                // declare the symbol
+                assert(id);
+                if (dt.isTypeFunction())
+                {
+                    if (hasInitializer)
+                        error("no initializer for function declaration");
+                    if (specifier.scw & SCW.x_Thread_local)
+                        error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
+                    s = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt);
+                }
+                else
+                {
+                    // Give non-extern variables an implicit void initializer
+                    // if one has not been explicitly set.
+                    if (!hasInitializer && !(specifier.scw & SCW.xextern))
+                        initializer = new AST.VoidInitializer(token.loc);
+                    s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
+                }
+            }
+            if (s !is null)
+            {
+                if (level == LVL.local)
+                {
+                    // Wrap the declaration in `extern (C) { declaration }`
+                    // Necessary for function pointers, but harmless to apply to all.
+                    auto decls = new AST.Dsymbols(1);
+                    (*decls)[0] = s;
+                    s = new AST.LinkDeclaration(s.loc, linkage, decls);
+                }
+                // Saw `asm("name")` in the function, type, or variable definition.
+                // This maps directly to `pragma(mangle, "name")`
+                if (asmname)
+                {
+                    auto args = new AST.Expressions(1);
+                    (*args)[0] = asmname;
+                    auto decls = new AST.Dsymbols(1);
+                    (*decls)[0] = s;
+                    s = new AST.PragmaDeclaration(asmname.loc, Id.mangle, args, decls);
+                }
+                symbols.push(s);
+            }
+            first = false;
+
+            switch (token.value)
+            {
+                case TOK.identifier:
+                    error("missing comma");
+                    goto default;
+
+                case TOK.semicolon:
+                    nextToken();
+                    return;
+
+                case TOK.comma:
+                    nextToken();
+                    break;
+
+                default:
+                    error("`=`, `;` or `,` expected");
+                    while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+                        nextToken();
+                    nextToken();
+                    return;
+            }
+        }
+    }
+
+    /***************************************
+     * C11 Function Definitions
+     * function-definition
+     *    declaration-specifiers declarator declaration-list (opt) compound-statement
+     *
+     * declaration-list:
+     *    declaration
+     *    declaration-list declaration
+     *
+     * It's already been parsed up to the declaration-list (opt).
+     * Pick it up from there.
+     * Params:
+     *    id = function identifier
+     *    ft = function type
+     *    scw = function storage classes
+     * Returns:
+     *  Dsymbol for the function
+     */
+    AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, SCW scw)
+    {
+        if (token.value != TOK.leftCurly)       // if not start of a compound-statement
+        {
+            // Do declaration-list
+            do
+            {
+                cparseDeclaration(LVL.parameter);
+            } while (token.value != TOK.leftCurly);
+
+            /* Since there were declarations, the parameter-list must have been
+             * an identifier-list.
+             */
+            auto pl = ft.parameterList;
+            pl.hasIdentifierList = true;        // semantic needs to know to adjust parameter types
+            if (pl.varargs != AST.VarArg.none)
+                error("function identifier-list cannot end with `...`");
+            auto plLength = pl.length;
+            if (symbols.length != plLength)
+                error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
+
+            /* Transfer the types and storage classes from symbols[] to pl[]
+             */
+            foreach (i; 0 .. plLength)
+            {
+                auto p = pl[i];  // yes, quadratic
+
+                // Convert typedef-identifier to identifier
+                if (p.type)
+                {
+                    if (auto t = p.type.isTypeIdentifier())
+                    {
+                        p.ident = t.ident;
+                        p.type = null;
+                    }
+                }
+
+                if (p.type || !(p.storageClass & STC.parameter))
+                    error("storage class and type are not allowed in identifier-list");
+                foreach (s; (*symbols)[]) // yes, quadratic
+                {
+                    auto d = s.isDeclaration();
+                    if (p.ident == d.ident && d.type)
+                    {
+                        p.type = d.type;
+                        p.storageClass = d.storage_class;
+                        d.type = null; // don't reuse
+                        break;
+                    }
+                }
+                if (!p.type)
+                    error("no declaration for identifier `%s`", p.ident.toChars());
+            }
+        }
+
+        addFuncName = false;    // gets set to true if somebody references __func__ in this function
+        const locFunc = token.loc;
+
+        auto body = cparseStatement(ParseStatementFlags.curly);  // don't start a new scope; continue with parameter scope
+        Specifier specifier;
+        specifier.scw = scw;
+        auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(LVL.global, specifier), ft);
+
+        if (addFuncName)
+        {
+            auto s = createFuncName(locFunc, id);
+            body = new AST.CompoundStatement(locFunc, s, body);
+        }
+        fd.fbody = body;
+
+        // TODO add `symbols` to the function's local symbol table `sc2` in FuncDeclaration::semantic3()
+
+        return fd;
+    }
+
+    /***************************************
+     * C11 Initialization
+     * initializer:
+     *    assignment-expression
+     *    { initializer-list }
+     *    { initializer-list , }
+     *
+     * initializer-list:
+     *    designation (opt) initializer
+     *    initializer-list , designation (opt) initializer
+     *
+     * designation:
+     *    designator-list =
+     *
+     * designator-list:
+     *    designator
+     *    designator-list designator
+     *
+     * designator:
+     *    [ constant-expression ]
+     *    . identifier
+     * Returns:
+     *    initializer
+     */
+    AST.Initializer cparseInitializer()
+    {
+        if (token.value != TOK.leftCurly)
+        {
+            auto ae = cparseAssignExp();        // assignment-expression
+            return new AST.ExpInitializer(token.loc, ae);
+        }
+        nextToken();
+        const loc = token.loc;
+
+        /* Collect one or more `designation (opt) initializer`
+         * into ci.initializerList, but lazily create ci
+         */
+        AST.CInitializer ci;
+        while (1)
+        {
+            /* There can be 0 or more designators preceding an initializer.
+             * Collect them in desigInit
+             */
+            AST.DesigInit desigInit;
+            while (1)
+            {
+                if (token.value == TOK.leftBracket)     // [ constant-expression ]
+                {
+                    nextToken();
+                    auto e = cparseConstantExp();
+                    check(TOK.rightBracket);
+                    if (!desigInit.designatorList)
+                        desigInit.designatorList = new AST.Designators;
+                    desigInit.designatorList.push(AST.Designator(e));
+                }
+                else if (token.value == TOK.dot)        // . identifier
+                {
+                    nextToken();
+                    if (token.value != TOK.identifier)
+                    {
+                        error("identifier expected following `.` designator");
+                        break;
+                    }
+                    if (!desigInit.designatorList)
+                        desigInit.designatorList = new AST.Designators;
+                    desigInit.designatorList.push(AST.Designator(token.ident));
+                    nextToken();
+                }
+                else
+                {
+                    if (desigInit.designatorList)
+                        check(TOK.assign);
+                    break;
+                }
+            }
+
+            desigInit.initializer = cparseInitializer();
+            if (!ci)
+                ci = new AST.CInitializer(loc);
+            ci.initializerList.push(desigInit);
+            if (token.value == TOK.comma)
+            {
+                nextToken();
+                if (token.value != TOK.rightCurly)
+                    continue;
+            }
+            break;
+        }
+        check(TOK.rightCurly);
+        //printf("ci: %s\n", ci.toChars());
+        return ci;
+    }
+
+    /*************************************
+     * C11 6.7
+     * declaration-specifier:
+     *    storage-class-specifier declaration-specifiers (opt)
+     *    type-specifier declaration-specifiers (opt)
+     *    type-qualifier declaration-specifiers (opt)
+     *    function-specifier declaration-specifiers (opt)
+     *    alignment-specifier declaration-specifiers (opt)
+     * Params:
+     *  level = declaration context
+     *  specifier = specifiers in and out
+     * Returns:
+     *  resulting type, null if not specified
+     */
+    private AST.Type cparseDeclarationSpecifiers(LVL level, ref Specifier specifier)
+    {
+        enum TKW : uint
+        {
+            xnone      = 0,
+            xchar      = 1,
+            xsigned    = 2,
+            xunsigned  = 4,
+            xshort     = 8,
+            xint       = 0x10,
+            xlong      = 0x20,
+            xllong     = 0x40,
+            xfloat     = 0x80,
+            xdouble    = 0x100,
+            xldouble   = 0x200,
+            xtag       = 0x400,
+            xident     = 0x800,
+            xvoid      = 0x1000,
+            xbool      = 0x4000,
+            ximaginary = 0x8000,
+            xcomplex   = 0x10000,
+            x_Atomic   = 0x20000,
+        }
+
+        AST.Type t;
+        Loc loc;
+        //printf("parseDeclarationSpecifiers()\n");
+
+        TKW tkw;
+        SCW scw = specifier.scw & SCW.xtypedef;
+        MOD mod;
+        Identifier id;
+        Identifier previd;
+
+    Lwhile:
+        while (1)
+        {
+            //printf("token %s\n", token.toChars());
+            TKW tkwx;
+            SCW scwx;
+            MOD modx;
+            switch (token.value)
+            {
+                // Storage class specifiers
+                case TOK.static_:    scwx = SCW.xstatic;    break;
+                case TOK.extern_:    scwx = SCW.xextern;    break;
+                case TOK.auto_:      scwx = SCW.xauto;      break;
+                case TOK.register:   scwx = SCW.xregister;  break;
+                case TOK.typedef_:   scwx = SCW.xtypedef;   break;
+                case TOK.inline:     scwx = SCW.xinline;    break;
+                case TOK._Noreturn:  scwx = SCW.x_Noreturn; break;
+                case TOK._Thread_local: scwx = SCW.x_Thread_local; break;
+
+                // Type qualifiers
+                case TOK.const_:     modx = MOD.xconst;     break;
+                case TOK.volatile:   modx = MOD.xvolatile;  break;
+                case TOK.restrict:   modx = MOD.xrestrict;  break;
+
+                // Type specifiers
+                case TOK.char_:      tkwx = TKW.xchar;      break;
+                case TOK.signed:     tkwx = TKW.xsigned;    break;
+                case TOK.unsigned:   tkwx = TKW.xunsigned;  break;
+                case TOK.int16:      tkwx = TKW.xshort;     break;
+                case TOK.int32:      tkwx = TKW.xint;       break;
+                case TOK.int64:      tkwx = TKW.xlong;      break;
+                case TOK.float32:    tkwx = TKW.xfloat;     break;
+                case TOK.float64:    tkwx = TKW.xdouble;    break;
+                case TOK.void_:      tkwx = TKW.xvoid;      break;
+                case TOK._Bool:      tkwx = TKW.xbool;      break;
+                case TOK._Imaginary: tkwx = TKW.ximaginary; break;
+                case TOK._Complex:   tkwx = TKW.xcomplex;   break;
+
+                case TOK.identifier:
+                    tkwx = TKW.xident;
+                    id = token.ident;
+                    break;
+
+                case TOK.struct_:
+                case TOK.union_:
+                {
+                    const structOrUnion = token.value;
+                    const sloc = token.loc;
+                    nextToken();
+
+                    /* GNU Extensions
+                     * struct-or-union-specifier:
+                     *    struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt)
+                     *    struct-or-union gnu-attribute (opt) identifier
+                     */
+                    if (token.value == TOK.__attribute__)
+                        cparseGnuAttributes();
+
+                    t = cparseStruct(sloc, structOrUnion, symbols);
+                    tkwx = TKW.xtag;
+                    break;
+                }
+
+                case TOK.enum_:
+                    t = cparseEnum(symbols);
+                    tkwx = TKW.xtag;
+                    break;
+
+                case TOK._Atomic:
+                {
+                    // C11 6.7.2.4
+                    // type-specifier if followed by `( type-name )`
+                    auto tk = peek(&token);
+                    if (tk.value == TOK.leftParenthesis)
+                    {
+                        tk = peek(tk);
+                        if (isTypeName(tk) && tk.value == TOK.rightParenthesis)
+                        {
+                            nextToken();
+                            t = cparseTypeName();
+                            // TODO - implement the "atomic" part of t
+                            tkwx = TKW.x_Atomic;
+                            break;
+                        }
+                    }
+                    // C11 6.7.3 type-qualifier if not
+                    modx = MOD.x_Atomic;
+                    break;
+                }
+
+                case TOK._Alignas:
+                {
+                    /* C11 6.7.5
+                     * _Alignas ( type-name )
+                     * _Alignas ( constant-expression )
+                     */
+                    nextToken();
+                    check(TOK.leftParenthesis);
+                    auto tk = &token;
+                    if (isTypeName(tk))
+                    {
+                        cparseTypeName();
+                    }
+                    else
+                    {
+                        cparseConstantExp();
+                    }
+                    check(TOK.rightParenthesis);
+                    error("`_Alignas` not supported");  // TODO
+                    break;
+                }
+
+                case TOK.__attribute__:
+                {
+                    /* GNU Extensions
+                     * declaration-specifiers:
+                     *    gnu-attributes declaration-specifiers (opt)
+                     */
+                    cparseGnuAttributes();
+                    break;
+                }
+
+                default:
+                    break Lwhile;
+            }
+
+            if (tkwx)
+            {
+                if (tkw & TKW.xlong && tkwx & TKW.xlong)
+                {
+                    tkw &= ~TKW.xlong;
+                    tkwx = TKW.xllong;
+                }
+                if (tkw && tkwx & TKW.xident)
+                {
+                    // 2nd identifier can't be a typedef
+                    break Lwhile; // leave parser on the identifier for the following declarator
+                }
+                else if (tkwx & TKW.xident)
+                {
+                    // 1st identifier, save it for TypeIdentifier
+                    previd = id;
+                }
+                if (tkw & TKW.xident && tkwx ||  // typedef-name followed by type-specifier
+                    tkw & tkwx)                  // duplicate type-specifiers
+                {
+                    error("illegal combination of type specifiers");
+                    tkwx = TKW.init;
+                }
+                tkw |= tkwx;
+                if (!(tkwx & TKW.xtag)) // if parser already advanced
+                    nextToken();
+                continue;
+            }
+
+            if (modx)
+            {
+                mod |= modx;
+                nextToken();
+                continue;
+            }
+
+            if (scwx)
+            {
+                if (scw & scwx)
+                    error("duplicate storage class");
+                scw |= scwx;
+                const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef);
+                if (scw2 & (scw2 - 1) ||
+                    scw & (SCW.xauto | SCW.xregister) && scw & (SCW.xinline | SCW.x_Noreturn))
+                {
+                    error("conflicting storage class");
+                    scw &= ~scwx;
+                }
+                if (level & (LVL.parameter | LVL.prototype) &&
+                    scw & ~SCW.xregister)
+                {
+                    error("only `register` storage class allowed for function parameters");
+                    scw &= ~scwx;
+                }
+                if (level == LVL.global &&
+                    scw & (SCW.xauto | SCW.xregister))
+                {
+                    error("`auto` and `register` storage class not allowed for global");
+                    scw &= ~scwx;
+                }
+                nextToken();
+                continue;
+            }
+        }
+
+        specifier.scw = scw;
+        specifier.mod = mod;
+
+        // Convert TKW bits to type t
+        switch (tkw)
+        {
+            case TKW.xnone:                     t = null; break;
+
+            case TKW.xchar:                     t = AST.Type.tchar; break;
+            case TKW.xsigned | TKW.xchar:       t = AST.Type.tint8; break;
+            case TKW.xunsigned | TKW.xchar:     t = AST.Type.tuns8; break;
+
+            case TKW.xshort:
+            case TKW.xsigned | TKW.xshort:
+            case TKW.xsigned | TKW.xshort | TKW.xint:
+            case TKW.xshort | TKW.xint:         t = AST.Type.tint16; break;
+
+            case TKW.xunsigned | TKW.xshort | TKW.xint:
+            case TKW.xunsigned | TKW.xshort:    t = AST.Type.tuns16; break;
+
+            case TKW.xint:
+            case TKW.xsigned:
+            case TKW.xsigned | TKW.xint:        t = AST.Type.tint32; break;
+
+            case TKW.xunsigned:
+            case TKW.xunsigned | TKW.xint:      t = AST.Type.tuns32; break;
+
+            case TKW.xlong:
+            case TKW.xsigned | TKW.xlong:
+            case TKW.xsigned | TKW.xlong | TKW.xint:
+            case TKW.xlong | TKW.xint:          t = longsize == 4 ? AST.Type.tint32 : AST.Type.tint64; break;
+
+            case TKW.xunsigned | TKW.xlong | TKW.xint:
+            case TKW.xunsigned | TKW.xlong:     t = longsize == 4 ? AST.Type.tuns32 : AST.Type.tuns64; break;
+
+            case TKW.xllong:
+            case TKW.xsigned | TKW.xllong:
+            case TKW.xsigned | TKW.xllong | TKW.xint:
+            case TKW.xllong | TKW.xint:          t = AST.Type.tint64; break;
+
+            case TKW.xunsigned | TKW.xllong | TKW.xint:
+            case TKW.xunsigned | TKW.xllong:     t = AST.Type.tuns64; break;
+
+            case TKW.xvoid:                     t = AST.Type.tvoid; break;
+            case TKW.xbool:                     t = AST.Type.tbool; break;
+
+            case TKW.xfloat:                    t = AST.Type.tfloat32; break;
+            case TKW.xdouble:                   t = AST.Type.tfloat64; break;
+            case TKW.xlong | TKW.xdouble:       t = realType(RTFlags.realfloat); break;
+
+            case TKW.ximaginary | TKW.xfloat:              t = AST.Type.timaginary32; break;
+            case TKW.ximaginary | TKW.xdouble:             t = AST.Type.timaginary64; break;
+            case TKW.ximaginary | TKW.xlong | TKW.xdouble: t = realType(RTFlags.imaginary); break;
+
+            case TKW.xcomplex | TKW.xfloat:                t = AST.Type.tcomplex32; break;
+            case TKW.xcomplex | TKW.xdouble:               t = AST.Type.tcomplex64; break;
+            case TKW.xcomplex | TKW.xlong | TKW.xdouble:   t = realType(RTFlags.complex); break;
+
+            case TKW.xident:                    t = new AST.TypeIdentifier(loc, previd);
+                break;
+
+            case TKW.xtag:
+                break;          // t is already set
+
+            default:
+                error("illegal type combination");
+                t = AST.Type.terror;
+                break;
+        }
+
+        return t;
+    }
+
+    /********************************
+     * C11 6.7.6
+     * Parse a declarator (including function definitions).
+     * declarator:
+     *    pointer (opt) direct-declarator
+     *
+     * direct-declarator :
+     *    identifier
+     *    ( declarator )
+     *    direct-declarator [ type-qualifier-list (opt) assignment-expression (opt) ]
+     *    direct-declarator [ static type-qualifier-list (opt) assignment-expression ]
+     *    direct-declarator [ type-qualifier-list static assignment-expression (opt) ]
+     *    direct-declarator [ type-qualifier-list (opt) * ]
+     *    direct-declarator ( parameter-type-list )
+     *    direct-declarator ( identifier-list (opt) )
+     *
+     * pointer :
+     *    * type-qualifier-list (opt)
+     *    * type-qualifier-list (opt) pointer
+     *
+     * type-qualifier-list :
+     *    type-qualifier
+     *    type-qualifier-list type-qualifier
+     *
+     * parameter-type-list :
+     *    parameter-list
+     *    parameter-list , ...
+     *
+     * parameter-list :
+     *    parameter-declaration
+     *    parameter-list , parameter-declaration
+     *
+     * parameter-declaration :
+     *    declaration-specifiers declarator
+     *    declaration-specifiers abstract-declarator (opt)
+     *
+     * identifier-list :
+     *    identifier
+     *    identifier-list , identifier
+     *
+     * Params:
+     *  declarator   = declarator kind
+     *  t            = base type to start with
+     *  pident       = set to Identifier if there is one, null if not
+     *  storageClass = any storage classes seen so far that apply to a function
+     * Returns:
+     *  type declared. If a TypeFunction is returned, this.symbols is the
+     *  symbol table for the parameter-type-list, which will contain any
+     *  declared struct, union or enum tags.
+     */
+    private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
+        out Identifier pident, StorageClass storageClass = 0)
+    {
+        //printf("cparseDeclarator(%d)\n", declarator);
+        AST.Types constTypes; // all the Types that will need `const` applied to them
+        constTypes.setDim(0);
+
+        AST.Type parseDecl(AST.Type t)
+        {
+            AST.Type ts;
+            while (1)
+            {
+                switch (token.value)
+                {
+                case TOK.identifier:        // identifier
+                    //printf("identifier %s\n", token.ident.toChars());
+                    if (declarator == DTR.xabstract)
+                        error("identifier not allowed in abstract-declarator");
+                    pident = token.ident;
+                    ts = t;
+                    nextToken();
+                    break;
+
+                case TOK.leftParenthesis:   // ( declarator )
+                    /* like: T (*fp)();
+                     *       T ((*fp))();
+                     */
+                    nextToken();
+                    ts = parseDecl(t);
+                    check(TOK.rightParenthesis);
+                    break;
+
+                case TOK.mul:               // pointer
+                    t = new AST.TypePointer(t);
+                    nextToken();
+                    // add post fixes const/volatile/restrict/_Atomic
+                    const mod = cparseTypeQualifierList();
+                    if (mod & MOD.xconst)
+                        constTypes.push(t);
+                    continue;
+
+                default:
+                    if (declarator == DTR.xdirect)
+                    {
+                        error("identifier or `(` expected"); // )
+                        panic();
+                    }
+                    ts = t;
+                    break;
+                }
+                break;
+            }
+
+            // parse DeclaratorSuffixes
+            while (1)
+            {
+                /* Insert tx -> t into
+                 *   ts -> ... -> t
+                 * so that
+                 *   ts -> ... -> tx -> t
+                 */
+                static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t)
+                {
+                    AST.Type* pt;
+                    for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
+                    {
+                    }
+                    *pt = tx;
+                }
+
+                switch (token.value)
+                {
+                    case TOK.leftBracket:
+                    {
+                        // post [] syntax.
+                        AST.Type ta;
+                        nextToken();
+
+                        // pick up any leading type qualifiers, `static` and `*`
+                        bool isStatic;
+                        if (token.value == TOK.static_)
+                        {
+                            isStatic = true;
+                            nextToken();
+                        }
+
+                        bool isVLA;
+                        if (!isStatic)
+                        {
+                            if (token.value == TOK.static_)
+                            {
+                                isStatic = true;
+                                nextToken();
+                            }
+                            else if (token.value == TOK.mul)
+                            {
+                                if (peekNext() == TOK.rightBracket)
+                                {
+                                    isVLA = true;
+                                    nextToken();
+                                }
+                            }
+                        }
+                        if (isVLA) // C11 6.7.6.2
+                        {
+                            error("variable length arrays are not supported");
+                        }
+                        if (isStatic) // C11 6.7.6.3
+                        {
+                            error("static array parameters are not supported");
+                        }
+
+                        if (token.value == TOK.rightBracket)
+                        {
+                            // An array of unknown size, fake it with a DArray
+                            ta = new AST.TypeDArray(t); // []
+                            nextToken();
+                        }
+                        else
+                        {
+                            //printf("It's a static array\n");
+                            AST.Expression e = cparseAssignExp(); // [ expression ]
+                            ta = new AST.TypeSArray(t, e);
+                            check(TOK.rightBracket);
+                        }
+
+                        const mod = cparseTypeQualifierList(); // const/volatile/restrict/_Atomic
+                        if (mod & MOD.xconst) // ignore the other bits
+                            ta = toConst(ta);
+
+                        insertTx(ts, ta, t);  // ts -> ... -> ta -> t
+                        continue;
+                    }
+
+                    case TOK.leftParenthesis:
+                    {
+                        // New symbol table for parameter-list
+                        auto symbolsSave = this.symbols;
+                        this.symbols = null;
+
+                        auto parameterList = cparseParameterList();
+                        AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0);
+    //                  tf = tf.addSTC(storageClass);  // TODO
+                        insertTx(ts, tf, t);  // ts -> ... -> tf -> t
+
+                        if (ts != tf)
+                            this.symbols = symbolsSave;
+                        break;
+                    }
+
+                    default:
+                        break;
+                }
+                break;
+            }
+            return ts;
+        }
+
+        t = parseDecl(t);
+
+        /* Because const is transitive, cannot assemble types from
+         * fragments. Instead, types to be annotated with const are put
+         * in constTypes[], and a bottom up scan of t is done to apply
+         * const
+         */
+        if (constTypes.length)
+        {
+            AST.Type constApply(AST.Type t)
+            {
+                if (t.nextOf())
+                {
+                    auto tn = cast(AST.TypeNext)t; // t.nextOf() should return a ref instead of this
+                    tn.next = constApply(tn.next);
+                }
+                foreach (tc; constTypes[])
+                {
+                    if (tc is t)
+                    {
+                        return toConst(t);
+                    }
+                }
+                return t;
+            }
+
+            t = constApply(t);
+        }
+
+        //printf("result: %s\n", t.toChars());
+        return t;
+    }
+
+    /******************************
+     * C11 6.7.3
+     * type-qualifier:
+     *    const
+     *    restrict
+     *    volatile
+     *    _Atomic
+     */
+    MOD cparseTypeQualifierList()
+    {
+        MOD mod;
+        while (1)
+        {
+            switch (token.value)
+            {
+                case TOK.const_:     mod |= MOD.xconst;     break;
+                case TOK.volatile:   mod |= MOD.xvolatile;  break;
+                case TOK.restrict:   mod |= MOD.xrestrict;  break;
+                case TOK._Atomic:    mod |= MOD.x_Atomic;   break;
+
+                default:
+                    return mod;
+            }
+            nextToken();
+        }
+    }
+
+    /***********************************
+     * C11 6.7.7
+     */
+    AST.Type cparseTypeName()
+    {
+        Specifier specifier;
+        auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
+        Identifier id;
+        return cparseDeclarator(DTR.xabstract, tspec, id);
+    }
+
+    /***********************************
+     * C11 6.7.2.1
+     * specifier-qualifier-list:
+     *    type-specifier specifier-qualifier-list (opt)
+     *    type-qualifier specifier-qualifier-list (opt)
+     * Params:
+     *  level = declaration context
+     *  specifier = specifiers in and out
+     * Returns:
+     *  resulting type, null if not specified
+     */
+    AST.Type cparseSpecifierQualifierList(LVL level, ref Specifier specifier)
+    {
+        auto t = cparseDeclarationSpecifiers(level, specifier);
+        if (specifier.scw)
+            error("storage class not allowed in specifier-qualified-list");
+        return t;
+    }
+
+    /***********************************
+     * C11 6.7.6.3
+     * ( parameter-type-list )
+     * ( identifier-list (opt) )
+     */
+    AST.ParameterList cparseParameterList()
+    {
+        auto parameters = new AST.Parameters();
+        AST.VarArg varargs = AST.VarArg.none;
+        StorageClass varargsStc;
+
+        check(TOK.leftParenthesis);
+        if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis)
+        {
+            nextToken();
+            nextToken();
+            return AST.ParameterList(parameters, varargs, varargsStc);
+        }
+
+        /* The check for identifier-list comes later,
+         * when doing the trailing declaration-list (opt)
+         */
+        while (1)
+        {
+            if (token.value == TOK.rightParenthesis)
+                break;
+            if (token.value == TOK.dotDotDot)
+            {
+                varargs = AST.VarArg.variadic;  // C-style variadics
+                nextToken();
+                check(TOK.rightParenthesis);
+                return AST.ParameterList(parameters, varargs, varargsStc);
+            }
+
+            Specifier specifier;
+            auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
+
+            Identifier id;
+            auto t = cparseDeclarator(DTR.xparameter, tspec, id);
+            if (specifier.mod & MOD.xconst)
+                t = toConst(t);
+            auto param = new AST.Parameter(STC.parameter, t, id, null, null);
+            parameters.push(param);
+            if (token.value == TOK.rightParenthesis)
+                break;
+            check(TOK.comma);
+        }
+        nextToken();
+        return AST.ParameterList(parameters, varargs, varargsStc);
+    }
+
+    /***********************************
+     * C11 6.7.10
+     * _Static_assert ( constant-expression , string-literal ) ;
+     */
+    private AST.StaticAssert cparseStaticAssert()
+    {
+        const loc = token.loc;
+
+        //printf("cparseStaticAssert()\n");
+        nextToken();
+        check(TOK.leftParenthesis);
+        auto exp = cparseConstantExp();
+        check(TOK.comma);
+        if (token.value != TOK.string_)
+            error("string literal expected");
+        auto msg = cparsePrimaryExp();
+        check(TOK.rightParenthesis);
+        check(TOK.semicolon);
+        return new AST.StaticAssert(loc, exp, msg);
+    }
+
+    /*************************
+     * Collect argument list.
+     * Parser is on opening parenthesis.
+     * Returns:
+     *    the arguments
+     */
+    private AST.Expressions* cparseArguments()
+    {
+        nextToken();
+        auto arguments = new AST.Expressions();
+        while (token.value != TOK.rightParenthesis && token.value != TOK.endOfFile)
+        {
+            auto arg = cparseAssignExp();
+            arguments.push(arg);
+            if (token.value != TOK.comma)
+                break;
+
+            nextToken(); // consume comma
+        }
+
+        check(TOK.rightParenthesis);
+
+        return arguments;
+    }
+
+    /*************************
+     * __declspec parser
+     * https://docs.microsoft.com/en-us/cpp/cpp/declspec
+     * decl-specifier:
+     *    __declspec ( extended-decl-modifier-seq )
+     *
+     * extended-decl-modifier-seq:
+     *    extended-decl-modifier (opt)
+     *    extended-decl-modifier extended-decl-modifier-seq
+     *
+     * extended-decl-modifier:
+     *    dllimport
+     *    dllexport
+     */
+    private void cparseDeclspec()
+    {
+        /* Check for dllexport, dllimport
+         * Ignore the rest
+         */
+        bool dllimport;  // TODO implement
+        bool dllexport;  // TODO implement
+        nextToken();     // move past __declspec
+        check(TOK.leftParenthesis);
+        while (1)
+        {
+            if (token.value == TOK.rightParenthesis)
+            {
+                nextToken();
+                break;
+            }
+            else if (token.value == TOK.endOfFile)
+                break;
+            else if (token.value == TOK.identifier)
+            {
+                if (token.ident == Id.dllimport)
+                {
+                    dllimport = true;
+                    nextToken();
+                }
+                else if (token.ident == Id.dllexport)
+                {
+                    dllexport = true;
+                    nextToken();
+                }
+                else
+                {
+                    nextToken();
+                    if (token.value == TOK.leftParenthesis)
+                        cparseParens();
+                }
+            }
+            else
+            {
+                error("extended-decl-modifier expected");
+            }
+            break;
+        }
+    }
+
+    /*************************
+     * Simple asm parser
+     * https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
+     * simple-asm-expr:
+     *   asm ( asm-string-literal )
+     *
+     * asm-string-literal:
+     *   string-literal
+     */
+    private AST.Expression cparseSimpleAsmExpr()
+    {
+        nextToken();     // move past asm
+        check(TOK.leftParenthesis);
+        if (token.value != TOK.string_)
+            error("string literal expected");
+        auto label = cparsePrimaryExp();
+        check(TOK.rightParenthesis);
+        return label;
+    }
+
+    /*************************
+     * __attribute__ parser
+     * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+     * gnu-attributes:
+     *   gnu-attributes gnu-attribute-specifier
+     *
+     * gnu-attribute-specifier:
+     *    __attribute__ (( gnu-attribute-list ))
+     *
+     * gnu-attribute-list:
+     *    gnu-attribute (opt)
+     *    gnu-attribute-list , gnu-attribute
+     */
+    private void cparseGnuAttributes()
+    {
+        while (token.value == TOK.__attribute__)
+        {
+            nextToken();     // move past __attribute__
+            check(TOK.leftParenthesis);
+            cparseParens(); // TODO: implement
+            check(TOK.rightParenthesis);
+        }
+    }
+
+    /*************************
+     * Parse a single GNU attribute
+     * gnu-attribute:
+     *    gnu-attribute-name
+     *    gnu-attribute-name ( identifier )
+     *    gnu-attribute-name ( identifier , expression-list )
+     *    gnu-attribute-name ( expression-list (opt) )
+     *
+     * gnu-attribute-name:
+     *    keyword
+     *    identifier
+     *
+     * expression-list:
+     *    constant-expression
+     *    expression-list , constant-expression
+     */
+    private void cparseGnuAttribute()
+    {
+        /* Check for dllimport, dllexport, vector_size(bytes)
+         * Ignore the rest
+         */
+        bool dllimport;  // TODO implement
+        bool dllexport;  // TODO implement
+        nextToken();     // move past __attribute__
+        check(TOK.leftParenthesis);
+        check(TOK.leftParenthesis);
+        while (1)
+        {
+            if (token.value == TOK.rightParenthesis)
+            {
+                nextToken();
+                check(TOK.rightParenthesis);
+                break;
+            }
+            else if (token.value == TOK.endOfFile)
+                break;
+            else if (token.value == TOK.identifier)
+            {
+                if (token.ident == Id.dllimport)
+                {
+                    dllimport = true;
+                    nextToken();
+                }
+                else if (token.ident == Id.dllexport)
+                {
+                    dllexport = true;
+                    nextToken();
+                }
+                else if (token.ident == Id.vector_size)
+                {
+                    nextToken();
+                    check(TOK.leftParenthesis);
+                    cparseConstantExp();  // TODO implement
+                    check(TOK.rightParenthesis);
+                }
+                else
+                {
+                    nextToken();
+                    if (token.value == TOK.leftParenthesis)
+                        cparseParens();
+                }
+            }
+            else
+            {
+                error("extended-decl-modifier expected");
+            }
+            break;
+        }
+    }
+
+    /***************************
+     * Like skipParens(), but consume the tokens.
+     */
+    private void cparseParens()
+    {
+        check(TOK.leftParenthesis);
+        int parens = 1;
+
+        while (1)
+        {
+            switch (token.value)
+            {
+                case TOK.leftParenthesis:
+                    ++parens;
+                    break;
+
+                case TOK.rightParenthesis:
+                    --parens;
+                    if (parens < 0)
+                    {
+                        error("extra right parenthesis");
+                        return;
+                    }
+                    if (parens == 0)
+                    {
+                        nextToken();
+                        return;
+                    }
+                    break;
+
+                case TOK.endOfFile:
+                    error("end of file found before right parenthesis");
+                    return;
+
+                default:
+                    break;
+            }
+            nextToken();
+        }
+    }
+
+    //}
+    /******************************************************************************/
+    /***************************** Struct & Enum Parser ***************************/
+    //{
+
+    /*************************************
+     * C11 6.7.2.2
+     * enum-specifier:
+     *    enum identifier (opt) { enumerator-list }
+     *    enum identifier (opt) { enumerator-list , }
+     *    enum identifier
+     *
+     * enumerator-list:
+     *    enumerator
+     *    enumerator-list , enumerator
+     *
+     * enumerator:
+     *    enumeration-constant
+     *    enumeration-constant = constant-expression
+     *
+     * enumeration-constant:
+     *    identifier
+     *
+     * Params:
+     *  symbols = symbols to add enum declaration to
+     * Returns:
+     *  type of the enum
+     */
+    private AST.Type cparseEnum(ref AST.Dsymbols* symbols)
+    {
+        const loc = token.loc;
+        nextToken();
+
+        /* GNU Extensions
+         * enum-specifier:
+         *    enum gnu-attributes (opt) identifier (opt) { enumerator-list } gnu-attributes (opt)
+         *    enum gnu-attributes (opt) identifier (opt) { enumerator-list , } gnu-attributes (opt)
+         *    enum gnu-attributes (opt) identifier
+         */
+        if (token.value == TOK.__attribute__)
+            cparseGnuAttributes();
+
+        Identifier tag;
+        if (token.value == TOK.identifier)
+        {
+            tag = token.ident;
+            nextToken();
+        }
+
+        AST.Dsymbols* members;
+        if (token.value == TOK.leftCurly)
+        {
+            nextToken();
+            members = new AST.Dsymbols();
+
+            if (token.value == TOK.rightCurly)  // C11 6.7.2.2-1
+            {
+                if (tag)
+                    error("no members for `enum %s`", tag.toChars());
+                else
+                    error("no members for anonymous enum");
+            }
+
+            while (token.value == TOK.identifier)
+            {
+                auto ident = token.ident;  // enumeration-constant
+                nextToken();
+                auto mloc = token.loc;
+
+                AST.Expression value;
+                if (token.value == TOK.assign)
+                {
+                    nextToken();
+                    value = cparseConstantExp();
+                    // TODO C11 6.7.2.2-2 value must fit into an int
+                }
+
+                auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
+                members.push(em);
+
+                if (token.value == TOK.comma)
+                {
+                    nextToken();
+                    continue;
+                }
+                break;
+            }
+            check(TOK.rightCurly);
+
+            /* GNU Extensions
+             * Parse the postfix gnu-attributes (opt)
+             */
+            if (token.value == TOK.__attribute__)
+                cparseGnuAttributes();
+        }
+        else if (!tag)
+            error("missing `identifier` after `enum`");
+
+        /* Need semantic information to determine if this is a declaration,
+         * redeclaration, or reference to existing declaration.
+         * Defer to the semantic() pass with a TypeTag.
+         */
+        return new AST.TypeTag(loc, TOK.enum_, tag, members);
+    }
+
+    /*************************************
+     * C11 6.7.2.1
+     * Parse struct and union specifiers.
+     * Parser is advanced to the tag identifier or brace.
+     * struct-or-union-specifier:
+     *    struct-or-union identifier (opt) { struct-declaration-list }
+     *    struct-or-union identifier
+     *
+     * struct-or-union:
+     *    struct
+     *    union
+     *
+     * struct-declaration-list:
+     *    struct-declaration
+     *    struct-declaration-list struct-declaration
+     *
+     * Params:
+     *  loc = location of `struct` or `union`
+     *  structOrUnion = TOK.struct_ or TOK.union_
+     *  symbols = symbols to add struct-or-union declaration to
+     * Returns:
+     *  type of the struct
+     */
+    private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref AST.Dsymbols* symbols)
+    {
+        Identifier tag;
+
+        if (token.value == TOK.identifier)
+        {
+            tag = token.ident;
+            nextToken();
+        }
+
+        AST.Dsymbols* members;
+        if (token.value == TOK.leftCurly)
+        {
+            nextToken();
+            auto symbolsSave = symbols;
+            symbols = new AST.Dsymbols();
+            while (token.value != TOK.rightCurly)
+            {
+                cparseStructDeclaration();
+
+                if (token.value == TOK.endOfFile)
+                    break;
+            }
+            members = symbols;          // `members` will be non-null even with 0 members
+            symbols = symbolsSave;
+            check(TOK.rightCurly);
+
+            if ((*members).length == 0) // C11 6.7.2.1-8
+                /* TODO: not strict enough, should really be contains "no named members",
+                 * not just "no members".
+                 * I.e. an unnamed bit field, _Static_assert, etc, are not named members,
+                 * but will pass this check.
+                 * Be careful to detect named members that come anonymous structs.
+                 * Correctly doing this will likely mean moving it to typesem.d.
+                 */
+                error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr);
+        }
+        else if (!tag)
+            error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
+
+        /* Need semantic information to determine if this is a declaration,
+         * redeclaration, or reference to existing declaration.
+         * Defer to the semantic() pass with a TypeTag.
+         */
+        return new AST.TypeTag(loc, structOrUnion, tag, members);
+    }
+
+    /*************************************
+     * C11 6.7.2.1
+     * Parse a struct declaration member.
+     * struct-declaration:
+     *    specifier-qualifier-list struct-declarator-list (opt) ;
+     *    static_assert-declaration
+     *
+     * struct-declarator-list:
+     *    struct-declarator
+     *    struct-declarator-list , struct-declarator
+     *
+     * struct-declarator:
+     *    declarator
+     *    declarator (opt) : constant-expression
+     */
+    void cparseStructDeclaration()
+    {
+        //printf("cparseStructDeclaration()\n");
+        if (token.value == TOK._Static_assert)
+        {
+            auto s = cparseStaticAssert();
+            symbols.push(s);
+            return;
+        }
+
+        auto symbolsSave = symbols;
+        Specifier specifier;
+        auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
+
+        /* If a declarator does not follow, it is unnamed
+         */
+        if (token.value == TOK.semicolon && tspec)
+        {
+            nextToken();
+            auto tt = tspec.isTypeTag();
+            if (!tt)
+                return; // legal but meaningless empty declaration
+
+            /* If anonymous struct declaration
+             *   struct { ... members ... };
+             * C11 6.7.2.1-13
+             */
+            if (!tt.id && tt.members)
+            {
+                /* members of anonymous struct are considered members of
+                 * the containing struct
+                 */
+                // TODO: merge in specifier
+                auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
+                if (!symbols)
+                    symbols = new AST.Dsymbols();
+                symbols.push(ad);
+                return;
+            }
+            if (!tt.id && !tt.members)
+                return; // already gave error in cparseStruct()
+
+            /* `struct tag;` and `struct tag { ... };`
+             * always result in a declaration in the current scope
+             */
+            // TODO: merge in specifier
+            auto stag = (tt.tok == TOK.struct_)
+                ? new AST.StructDeclaration(tt.loc, tt.id, false)
+                : new AST.UnionDeclaration(tt.loc, tt.id);
+            stag.members = tt.members;
+            if (!symbols)
+                symbols = new AST.Dsymbols();
+            symbols.push(stag);
+            return;
+        }
+
+        while (1)
+        {
+            Identifier id;
+            AST.Type dt;
+            if (token.value == TOK.colon)
+            {
+                // C11 6.7.2.1-12 unnamed bit-field
+                nextToken();
+                cparseConstantExp();
+                error("unnamed bit fields are not supported"); // TODO
+                dt = AST.Type.tuns32;
+            }
+            else
+                dt = cparseDeclarator(DTR.xdirect, tspec, id);
+            if (!dt)
+            {
+                panic();
+                nextToken();
+                break;          // error recovery
+            }
+            if (id && token.value == TOK.colon)
+            {
+                // C11 6.7.2.1-10 bit-field
+                nextToken();
+                cparseConstantExp();
+                error("bit fields are not supported"); // TODO
+            }
+
+            if (specifier.mod & MOD.xconst)
+                dt = toConst(dt);
+
+            /* GNU Extensions
+             * struct-declarator:
+             *    declarator gnu-attributes (opt)
+             *    declarator (opt) : constant-expression gnu-attributes (opt)
+             */
+            if (token.value == TOK.__attribute__)
+                cparseGnuAttributes();
+
+            AST.Dsymbol s = null;
+            symbols = symbolsSave;
+            if (!symbols)
+                symbols = new AST.Dsymbols;     // lazilly create it
+
+            if (!tspec && !specifier.scw && !specifier.mod)
+                error("specifier-qualifier-list required");
+            else if (id)
+            {
+                if (dt.ty == AST.Tvoid)
+                    error("`void` has no value");
+
+                // declare the symbol
+                // Give member variables an implicit void initializer
+                auto initializer = new AST.VoidInitializer(token.loc);
+                s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
+            }
+            if (s !is null)
+                symbols.push(s);
+
+            switch (token.value)
+            {
+                case TOK.identifier:
+                    error("missing comma");
+                    goto default;
+
+                case TOK.semicolon:
+                    nextToken();
+                    return;
+
+                case TOK.comma:
+                    nextToken();
+                    break;
+
+                default:
+                    error("`;` or `,` expected");
+                    while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+                        nextToken();
+                    nextToken();
+                    return;
+            }
+        }
+    }
+
+    //}
+    /******************************************************************************/
+    /********************************* Lookahead Parser ***************************/
+    //{
+
+    /************************************
+     * Determine if the scanner is sitting on the start of a declaration.
+     * Params:
+     *      t       = current token of the scanner
+     *      needId  = flag with additional requirements for a declaration
+     *      endtok  = ending token
+     *      pt      = will be set ending token (if not null)
+     * Returns:
+     *      true at start of a declaration
+     */
+    private bool isCDeclaration(ref Token* pt)
+    {
+        //printf("isCDeclaration()\n");
+        auto t = pt;
+        if (!isDeclarationSpecifiers(t))
+            return false;
+
+        while (1)
+        {
+            if (t.value == TOK.semicolon)
+            {
+                t = peek(t);
+                pt = t;
+                return true;
+            }
+            if (!isCDeclarator(t, DTR.xdirect))
+                return false;
+            if (t.value == TOK.asm_)
+            {
+                t = peek(t);
+                if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
+                    return false;
+            }
+            if (t.value == TOK.__attribute__)
+            {
+                t = peek(t);
+                if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
+                    return false;
+            }
+            if (t.value == TOK.assign)
+            {
+                t = peek(t);
+                if (!isInitializer(t))
+                    return false;
+            }
+            switch (t.value)
+            {
+                case TOK.comma:
+                    t = peek(t);
+                    break;
+
+                case TOK.semicolon:
+                    t = peek(t);
+                    pt = t;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+    }
+
+    /********************************
+     * See if match for initializer.
+     * Params:
+     *  pt = starting token, updated to one past end of initializer if true
+     * Returns:
+     *  true if initializer
+     */
+    private bool isInitializer(ref Token* pt)
+    {
+        //printf("isInitializer()\n");
+        auto t = pt;
+
+        if (t.value == TOK.leftCurly)
+        {
+            if (!skipBraces(t))
+                return false;
+            pt = t;
+            return true;
+        }
+
+        // skip over assignment-expression, ending before comma or semiColon or EOF
+        if (!isAssignmentExpression(t))
+            return false;
+        pt = t;
+        return true;
+    }
+
+    /********************************
+     * See if match for assignment-expression.
+     * Params:
+     *  pt = starting token, updated to one past end of assignment-expression if true
+     * Returns:
+     *  true if assignment-expression
+     */
+    private bool isAssignmentExpression(ref Token* pt)
+    {
+        //printf("isAssignmentExpression()\n");
+        auto t = pt;
+
+        /* This doesn't actually check for grammar matching an
+         * assignment-expression. It just matches ( ) [ ] looking for
+         * an ending token that would terminate one.
+         */
+        bool any;
+        while (1)
+        {
+            switch (t.value)
+            {
+                case TOK.comma:
+                case TOK.semicolon:
+                case TOK.rightParenthesis:
+                case TOK.rightBracket:
+                case TOK.endOfFile:
+                    if (!any)
+                        return false;
+                    break;
+
+                case TOK.leftParenthesis:
+                    if (!skipParens(t, &t))
+                        return false;
+                    continue;
+
+                case TOK.leftBracket:
+                    if (!skipBrackets(t))
+                        return false;
+                    continue;
+
+                default:
+                    any = true;   // assume token was part of an a-e
+                    t = peek(t);
+                    continue;
+            }
+            pt = t;
+            return true;
+        }
+    }
+
+    /********************************
+     * See if match for constant-expression.
+     * Params:
+     *  pt = starting token, updated to one past end of constant-expression if true
+     * Returns:
+     *  true if constant-expression
+     */
+    private bool isConstantExpression(ref Token* pt)
+    {
+        return isAssignmentExpression(pt);
+    }
+
+    /********************************
+     * See if match for declaration-specifiers.
+     * No errors are diagnosed.
+     * Params:
+     *  pt = starting token, updated to one past end of declaration-specifiers if true
+     * Returns:
+     *  true if declaration-specifiers
+     */
+    private bool isDeclarationSpecifiers(ref Token* pt)
+    {
+        //printf("isDeclarationSpecifiers()\n");
+
+        auto t = pt;
+
+        bool any;
+        while (1)
+        {
+            switch (t.value)
+            {
+                // type-specifiers
+                case TOK.void_:
+                case TOK.char_:
+                case TOK.int16:
+                case TOK.int32:
+                case TOK.int64:
+                case TOK.float32:
+                case TOK.float64:
+                case TOK.signed:
+                case TOK.unsigned:
+                case TOK._Bool:
+                //case TOK._Imaginary:
+                case TOK._Complex:
+                case TOK.identifier: // typedef-name
+                    t = peek(t);
+                    any = true;
+                    break;
+
+                case TOK.struct_:
+                case TOK.union_:
+                case TOK.enum_:
+                    t = peek(t);
+                    if (t.value == TOK.identifier)
+                    {
+                        t = peek(t);
+                        if (t.value == TOK.leftCurly)
+                        {
+                            if (!skipBraces(t))
+                                return false;
+                        }
+                    }
+                    else if (t.value == TOK.leftCurly)
+                    {
+                        if (!skipBraces(t))
+                            return false;
+                    }
+                    else
+                        return false;
+                    any = true;
+                    continue;
+
+                // storage-class-specifiers
+                case TOK.typedef_:
+                case TOK.extern_:
+                case TOK.static_:
+                case TOK._Thread_local:
+                case TOK.auto_:
+                case TOK.register:
+
+                // function-specifiers
+                case TOK.inline:
+                case TOK._Noreturn:
+
+                // type-qualifiers
+                case TOK.const_:
+                case TOK.volatile:
+                case TOK.restrict:
+                    t = peek(t);
+                    any = true;
+                    continue;
+
+                case TOK._Alignas:      // alignment-specifier
+                case TOK.__declspec:    // decl-specifier
+                case TOK.__attribute__: // attribute-specifier
+                    t = peek(t);
+                    if (!skipParens(t, &t))
+                        return false;
+                    any = true;
+                    continue;
+
+                // either atomic-type-specifier or type_qualifier
+                case TOK._Atomic:  // TODO _Atomic ( type-name )
+                    t = peek(t);
+                    if (t.value == TOK.leftParenthesis) // maybe atomic-type-specifier
+                    {
+                        auto tsave = t;
+                        t = peek(t);
+                        if (!isTypeName(t) || t.value != TOK.rightParenthesis)
+                        {   // it's a type-qualifier
+                            t = tsave;  // back up parser
+                            any = true;
+                            continue;
+                        }
+                        t = peek(t);    // move past right parenthesis of atomic-type-specifier
+                    }
+                    any = true;
+                    continue;
+
+                default:
+                    break;
+            }
+            break;
+        }
+
+        if (any)
+        {
+            pt = t;
+            return true;
+        }
+        return false;
+    }
+
+    /**************************************
+     * See if declaration-list is present.
+     * Returns:
+     *    true if declaration-list is present, even an empty one
+     */
+    bool isDeclarationList(ref Token* pt)
+    {
+        auto t = pt;
+        while (1)
+        {
+            if (t.value == TOK.leftCurly)
+            {
+                pt = t;
+                return true;
+            }
+            if (!isCDeclaration(t))
+                return false;
+        }
+    }
+
+    /*******************************************
+     * Skip braces.
+     * Params:
+     *      pt = enters on left brace, set to token past right bracket on true
+     * Returns:
+     *      true if successful
+     */
+    private bool skipBraces(ref Token* pt)
+    {
+        auto t = pt;
+        if (t.value != TOK.leftCurly)
+            return false;
+
+        int braces = 0;
+
+        while (1)
+        {
+            switch (t.value)
+            {
+                case TOK.leftCurly:
+                    ++braces;
+                    t = peek(t);
+                    continue;
+
+                case TOK.rightCurly:
+                    --braces;
+                    if (braces == 0)
+                    {
+                        pt = peek(t);
+                        return true;
+                    }
+                    if (braces < 0)
+                        return false;
+
+                    t = peek(t);
+                    continue;
+
+                case TOK.endOfFile:
+                    return false;
+
+                default:
+                    t = peek(t);
+                    continue;
+            }
+        }
+    }
+
+    /*******************************************
+     * Skip brackets.
+     * Params:
+     *      pt = enters on left bracket, set to token past right bracket on true
+     * Returns:
+     *      true if successful
+     */
+    private bool skipBrackets(ref Token* pt)
+    {
+        auto t = pt;
+        if (t.value != TOK.leftBracket)
+            return false;
+
+        int brackets = 0;
+
+        while (1)
+        {
+            switch (t.value)
+            {
+                case TOK.leftBracket:
+                    ++brackets;
+                    t = peek(t);
+                    continue;
+
+                case TOK.rightBracket:
+                    --brackets;
+                    if (brackets == 0)
+                    {
+                        pt = peek(t);
+                        return true;
+                    }
+                    if (brackets < 0)
+                        return false;
+
+                    t = peek(t);
+                    continue;
+
+                case TOK.endOfFile:
+                    return false;
+
+                default:
+                    t = peek(t);
+                    continue;
+            }
+        }
+    }
+
+    /*********************************
+     * Check to see if tokens starting with *pt form a declarator.
+     * Params:
+     *  pt = pointer to starting token, updated to point past declarator if true is returned
+     *  declarator = declarator kind
+     * Returns:
+     *  true if it does
+     */
+    private bool isCDeclarator(ref Token* pt, DTR declarator)
+    {
+        auto t = pt;
+        while (1)
+        {
+            if (t.value == TOK.mul)     // pointer
+            {
+                t = peek(t);
+                if (!isTypeQualifierList(t))
+                    return false;
+            }
+            else
+                break;
+        }
+
+        if (t.value == TOK.identifier)
+        {
+            if (declarator == DTR.xabstract)
+                return false;
+            t = peek(t);
+        }
+        else if (t.value == TOK.leftParenthesis)
+        {
+            t = peek(t);
+            if (!isCDeclarator(t, declarator))
+                return false;
+            if (t.value != TOK.rightParenthesis)
+                return false;
+            t = peek(t);
+        }
+        else if (declarator == DTR.xdirect)
+        {
+            return false;
+        }
+
+        if (t.value == TOK.leftBracket)
+        {
+            if (!skipBrackets(t))
+                return false;
+        }
+        else if (t.value == TOK.leftParenthesis)
+        {
+            if (!skipParens(t, &t))
+                 return false;
+        }
+        pt = t;
+        return true;
+    }
+
+    /***************************
+     * Is this the start of a type-qualifier-list?
+     * (Can be empty.)
+     * Params:
+     *  pt = first token; updated with past end of type-qualifier-list if true
+     * Returns:
+     *  true if start of type-qualifier-list
+     */
+    private bool isTypeQualifierList(ref Token* pt)
+    {
+        auto t = pt;
+        while (1)
+        {
+            switch (t.value)
+            {
+                case TOK.const_:
+                case TOK.restrict:
+                case TOK.volatile:
+                case TOK._Atomic:
+                    t = peek(t);
+                    continue;
+
+                default:
+                    break;
+            }
+            break;
+        }
+        pt = t;
+        return true;
+    }
+
+    /***************************
+     * Is this the start of a type-name?
+     * Params:
+     *  pt = first token; updated with past end of type-name if true
+     * Returns:
+     *  true if start of type-name
+     */
+    private bool isTypeName(ref Token* pt)
+    {
+        auto t = pt;
+        //printf("isTypeName() %s\n", t.toChars());
+        if (!isSpecifierQualifierList(t))
+            return false;
+        if (!isCDeclarator(t, DTR.xabstract))
+            return false;
+        pt = t;
+        return true;
+    }
+
+    /***************************
+     * Is this the start of a specifier-qualifier-list?
+     * Params:
+     *  pt = first token; updated with past end of specifier-qualifier-list if true
+     * Returns:
+     *  true if start of specifier-qualifier-list
+     */
+    private bool isSpecifierQualifierList(ref Token* pt)
+    {
+        auto t = pt;
+        bool result;
+        while (1)
+        {
+            switch (t.value)
+            {
+                // Type Qualifiers
+                case TOK.const_:
+                case TOK.restrict:
+                case TOK.volatile:
+
+                // Type Specifiers
+                case TOK.char_:
+                case TOK.signed:
+                case TOK.unsigned:
+                case TOK.int16:
+                case TOK.int32:
+                case TOK.int64:
+                case TOK.float32:
+                case TOK.float64:
+                case TOK.void_:
+                case TOK._Bool:
+                //case TOK._Imaginary: // ? missing in Spec
+                case TOK._Complex:
+
+                // typedef-name
+                case TOK.identifier:    // will not know until semantic if typedef
+                    t = peek(t);
+                    break;
+
+                // struct-or-union-specifier
+                // enum-specifier
+                case TOK.struct_:
+                case TOK.union_:
+                case TOK.enum_:
+                    t = peek(t);
+                    if (t.value == TOK.identifier)
+                    {
+                        t = peek(t);
+                        if (t.value == TOK.leftCurly)
+                        {
+                            if (!skipBraces(t))
+                                return false;
+                        }
+                    }
+                    else if (t.value == TOK.leftCurly)
+                    {
+                        if (!skipBraces(t))
+                            return false;
+                    }
+                    else
+                        return false;
+                    break;
+
+                // atomic-type-specifier
+                case TOK._Atomic:
+                    t = peek(t);
+                    if (t.value != TOK.leftParenthesis ||
+                        !skipParens(t, &t))
+                        return false;
+                    break;
+
+                default:
+                    if (result)
+                        pt = t;
+                    return result;
+            }
+            result = true;
+        }
+    }
+
+    /************************************
+     * Looking at the leading left parenthesis, and determine if it is
+     * either of the following:
+     *    ( type-name ) cast-expression
+     *    ( type-name ) { initializer-list }
+     * as opposed to:
+     *    ( expression )
+     * Params:
+     *    pt = starting token, updated to one past end of constant-expression if true
+     *    afterParenType = true if already seen ( type-name )
+     * Returns:
+     *    true if matches ( type-name ) ...
+     */
+    private bool isCastExpression(ref Token* pt, bool afterParenType = false)
+    {
+        auto t = pt;
+        switch (t.value)
+        {
+            case TOK.leftParenthesis:
+                auto tk = peek(t);  // move past left parenthesis
+                if (!isTypeName(tk) || tk.value != TOK.rightParenthesis)
+                {
+                    if (afterParenType)
+                        goto default; // could be ( type-name ) ( unary-expression )
+                    return false;
+                }
+                t = peek(tk);  // move past right parenthesis
+
+                if (t.value == TOK.leftCurly)
+                {
+                    // ( type-name ) { initializer-list }
+                    if (!isInitializer(t))
+                        return false;
+                    break;
+                }
+                if (!isCastExpression(t, true))
+                    return false;
+                // ( type-name ) cast-expression
+                break;
+
+            default:
+                if (!afterParenType || !isUnaryExpression(t, afterParenType))
+                    return false;
+                // if we've already seen ( type-name ), then this is a cast
+                break;
+        }
+        pt = t;
+        return true;
+    }
+
+    /********************************
+     * See if match for unary-expression.
+     * Params:
+     *    pt = starting token, updated to one past end of constant-expression if true
+     *    afterParenType = true if already seen ( type-name ) of a cast-expression
+     * Returns:
+     *    true if unary-expression
+     */
+    private bool isUnaryExpression(ref Token* pt, bool afterParenType = false)
+    {
+        auto t = pt;
+        switch (t.value)
+        {
+            case TOK.plusPlus:
+            case TOK.minusMinus:
+                t = peek(t);
+                if (!isUnaryExpression(t, afterParenType))
+                    return false;
+                break;
+
+            case TOK.and:
+            case TOK.mul:
+            case TOK.min:
+            case TOK.add:
+            case TOK.not:
+            case TOK.tilde:
+                t = peek(t);
+                if (!isCastExpression(t, afterParenType))
+                    return false;
+                break;
+
+            case TOK.sizeof_:
+                t = peek(t);
+                if (t.value == TOK.leftParenthesis)
+                {
+                    auto tk = peek(t);
+                    if (isTypeName(tk))
+                    {
+                        if (tk.value != TOK.rightParenthesis)
+                            return false;
+                        t = peek(tk);
+                        break;
+                    }
+                }
+                if (!isUnaryExpression(t, afterParenType))
+                    return false;
+                break;
+
+            case TOK._Alignof:
+                t = peek(t);
+                if (t.value != TOK.leftParenthesis)
+                    return false;
+                t = peek(t);
+                if (!isTypeName(t) || t.value != TOK.rightParenthesis)
+                    return false;
+                break;
+
+            default:
+                // Compound literals are handled by cast and sizeof expressions,
+                // so be content with just seeing a primary expression.
+                if (!isPrimaryExpression(t))
+                    return false;
+                break;
+        }
+        pt = t;
+        return true;
+    }
+
+    /********************************
+     * See if match for primary-expression.
+     * Params:
+     *    pt = starting token, updated to one past end of constant-expression if true
+     * Returns:
+     *    true if primary-expression
+     */
+    private bool isPrimaryExpression(ref Token* pt)
+    {
+        auto t = pt;
+        switch (t.value)
+        {
+            case TOK.identifier:
+            case TOK.int32Literal:
+            case TOK.uns32Literal:
+            case TOK.int64Literal:
+            case TOK.uns64Literal:
+            case TOK.float32Literal:
+            case TOK.float64Literal:
+            case TOK.float80Literal:
+            case TOK.imaginary32Literal:
+            case TOK.imaginary64Literal:
+            case TOK.imaginary80Literal:
+            case TOK.string_:
+                t = peek(t);
+                break;
+
+            case TOK.leftParenthesis:
+                // ( expression )
+                if (!skipParens(t, &t))
+                    return false;
+                break;
+
+            case TOK._Generic:
+                t = peek(t);
+                if (!skipParens(t, &t))
+                    return false;
+                break;
+
+            default:
+                return false;
+        }
+        pt = t;
+        return true;
+    }
+
+    //}
+    /******************************************************************************/
+    /********************************* More ***************************************/
+    //{
+
+    /**************
+     * Declaration context
+     */
+    enum LVL
+    {
+        global    = 1,    /// global
+        parameter = 2,    /// function parameter (declarations for function identifier-list)
+        prototype = 4,    /// function prototype
+        local     = 8,    /// local
+        member    = 0x10, /// struct member
+    }
+
+    /// Types of declarator to parse
+    enum DTR
+    {
+        xdirect    = 1, /// C11 6.7.6 direct-declarator
+        xabstract  = 2, /// C11 6.7.7 abstract-declarator
+        xparameter = 3, /// parameter declarator may be either direct or abstract
+    }
+
+    /// C11 6.7.1 Storage-class specifiers
+    enum SCW : uint
+    {
+        xnone      = 0,
+        xtypedef   = 1,
+        xextern    = 2,
+        xstatic    = 4,
+        x_Thread_local = 8,
+        xauto      = 0x10,
+        xregister  = 0x20,
+        // C11 6.7.4 Function specifiers
+        xinline    = 0x40,
+        x_Noreturn = 0x80,
+    }
+
+    /// C11 6.7.3 Type qualifiers
+    enum MOD : uint
+    {
+        xnone     = 0,
+        xconst    = 1,
+        xvolatile = 2,
+        xrestrict = 4,
+        x_Atomic  = 8,
+    }
+
+    /**********************************
+     * Aggregate for all the various specifiers
+     */
+    struct Specifier
+    {
+        SCW scw;        /// storage-class specifiers
+        MOD mod;        /// type qualifiers
+    }
+
+    /***********************
+     * Convert from C specifiers to D storage class
+     * Params:
+     *  level = declaration context
+     *  specifier = specifiers, context, etc.
+     * Returns:
+     *  corresponding D storage class
+     */
+    StorageClass specifiersToSTC(LVL level, const ref Specifier specifier)
+    {
+        StorageClass stc;
+        if (specifier.scw & SCW.x_Thread_local)
+        {
+            if (level == LVL.global)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_;
+            }
+            else if (level == LVL.local)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_;
+                else if (specifier.scw & SCW.xstatic)
+                    stc = AST.STC.static_;
+            }
+            else if (level == LVL.member)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_;
+                else if (specifier.scw & SCW.xstatic)
+                    stc = AST.STC.static_;
+            }
+        }
+        else
+        {
+            if (level == LVL.global)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_ | AST.STC.gshared;
+                else
+                    stc = AST.STC.gshared;
+            }
+            else if (level == LVL.local)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_ | AST.STC.gshared;
+                else if (specifier.scw & SCW.xstatic)
+                    stc = AST.STC.gshared;
+            }
+            else if (level == LVL.member)
+            {
+                if (specifier.scw & SCW.xextern)
+                   stc = AST.STC.extern_ | AST.STC.gshared;
+                else if (specifier.scw & SCW.xstatic)
+                    stc = AST.STC.gshared;
+            }
+        }
+        return stc;
+    }
+
+    /***********************
+     * Return suitable D float type for C `long double`
+     * Params:
+     *  flags = kind of float to return (real, imaginary, complex).
+     * Returns:
+     *  corresponding D type
+     */
+    private AST.Type realType(RTFlags flags)
+    {
+        if (long_doublesize == AST.Type.tfloat80.size())
+        {
+            // On GDC and LDC, D `real` types map to C `long double`, so never
+            // return a double type when real.sizeof == double.sizeof.
+            final switch (flags)
+            {
+                case RTFlags.realfloat: return AST.Type.tfloat80;
+                case RTFlags.imaginary: return AST.Type.timaginary80;
+                case RTFlags.complex:   return AST.Type.tcomplex80;
+            }
+        }
+        else
+        {
+            final switch (flags)
+            {
+                case RTFlags.realfloat: return long_doublesize == 8 ? AST.Type.tfloat64 : AST.Type.tfloat80;
+                case RTFlags.imaginary: return long_doublesize == 8 ? AST.Type.timaginary64 : AST.Type.timaginary80;
+                case RTFlags.complex:   return long_doublesize == 8 ? AST.Type.tcomplex64 : AST.Type.tcomplex80;
+            }
+        }
+    }
+
+    /**************
+     * Flags for realType
+     */
+    private enum RTFlags
+    {
+        realfloat,
+        imaginary,
+        complex,
+    }
+
+    /********************
+     * C11 6.4.2.2 Create declaration to predefine __func__
+     *    `static const char __func__[] = " function-name ";`
+     * Params:
+     *    loc = location for this declaration
+     *    id = identifier of function
+     * Returns:
+     *    statement representing the declaration of __func__
+     */
+    private AST.Statement createFuncName(Loc loc, Identifier id)
+    {
+        const fn = id.toString();  // function-name
+        auto efn = new AST.StringExp(loc, fn, fn.length, 1, 'c');
+        auto ifn = new AST.ExpInitializer(loc, efn);
+        auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0
+        auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn);
+        efn.type = tfn.immutableOf();
+        efn.committed = 1;
+        auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_);
+        auto e = new AST.DeclarationExp(loc, sfn);
+        return new AST.ExpStatement(loc, e);
+    }
+
+    /************************
+     * After encountering an error, scan forward until a right brace or ; is found
+     * or the end of the file.
+     */
+    void panic()
+    {
+        while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
+            nextToken();
+    }
+
+    /**************************
+     * Apply `const` to a type.
+     * Params:
+     *    t = type to add const to
+     * Returns:
+     *    resulting type
+     */
+    private AST.Type toConst(AST.Type t)
+    {
+        // `const` is always applied to the return type, not the
+        // type function itself.
+        if (auto tf = t.isTypeFunction())
+            tf.next = tf.next.addSTC(STC.const_);
+        else
+            t = t.addSTC(STC.const_);
+        return t;
+    }
+
+    //}
+}
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 93395ca471e..0381f9ad6a4 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -4,7 +4,7 @@
  * This is the POSIX side of the implementation.
  * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`.
  *
- * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors: Walter Bright, http://www.digitalmars.com
  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d)
@@ -27,6 +27,7 @@ import core.stdc.string;
 import core.stdc.stdio;
 
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.attrib;
 import dmd.declaration;
 import dmd.dsymbol;
@@ -85,6 +86,17 @@ extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s)
     return buf.extractChars();
 }
 
+///
+extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
+{
+    //printf("cppThunkMangleItanium(%s)\n", fd.toChars());
+    OutBuffer buf;
+    buf.printf("_ZThn%u_", offset);  // "Th" means thunk, "n%u" is the call offset
+    scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc);
+    v.mangle_function_encoding(fd);
+    return buf.extractChars();
+}
+
 /******************************
  * Determine if sym is the 'primary' destructor, that is,
  * the most-aggregate destructor (the one that is defined as __xdtor)
@@ -259,19 +271,18 @@ private final class CppMangleVisitor : Visitor
     {
         //printf("substitute %s\n", p ? p.toChars() : null);
         auto i = find(p);
-        if (i >= 0)
-        {
-            //printf("\tmatch\n");
-            /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
-             */
-            if (nested)
-                buf.writeByte('N');
-            buf.writeByte('S');
-            writeSequenceFromIndex(i);
-            buf.writeByte('_');
-            return true;
-        }
-        return false;
+        if (i < 0)
+            return false;
+
+        //printf("\tmatch\n");
+        /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
+         */
+        if (nested)
+            buf.writeByte('N');
+        buf.writeByte('S');
+        writeSequenceFromIndex(i);
+        buf.writeByte('_');
+        return true;
     }
 
     /******
@@ -600,51 +611,74 @@ private final class CppMangleVisitor : Visitor
             auto sl = this.buf.peekSlice();
             assert(sl.length == 0 || haveNE || s.cppnamespace is null || sl != "_ZN");
         }
-        if (TemplateInstance ti = s.isTemplateInstance())
+        auto ti = s.isTemplateInstance();
+
+        if (!ti)
         {
-            bool needsTa = false;
+            auto ag = s.isAggregateDeclaration();
+            const ident = (ag && ag.mangleOverride) ? ag.mangleOverride.id : s.ident;
+            this.writeNamespace(s.cppnamespace, () {
+                this.writeIdentifier(ident);
+                this.abiTags.writeSymbol(s, this);
+                },
+                haveNE);
+            return;
+        }
 
-            // https://issues.dlang.org/show_bug.cgi?id=20413
-            // N..E is not needed when substituting members of the std namespace.
-            // This is observed in the GCC and Clang implementations.
-            // The Itanium specification is not clear enough on this specific case.
-            // References:
-            //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name
-            //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression
-            Dsymbol q = getQualifier(ti.tempdecl);
-            Dsymbol ns = ti.tempdecl.cppnamespace;
-            const inStd = ns && isStd(ns) || q && isStd(q);
-            const isNested = !inStd && (ns || q);
+        bool needsTa = false;
 
-            if (substitute(ti.tempdecl, !haveNE && isNested))
-            {
+        // https://issues.dlang.org/show_bug.cgi?id=20413
+        // N..E is not needed when substituting members of the std namespace.
+        // This is observed in the GCC and Clang implementations.
+        // The Itanium specification is not clear enough on this specific case.
+        // References:
+        //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name
+        //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression
+        Dsymbol q = getQualifier(ti.tempdecl);
+        Dsymbol ns = ti.tempdecl.cppnamespace;
+        const inStd = ns && isStd(ns) || q && isStd(q);
+        const isNested = !inStd && (ns || q);
+
+        if (substitute(ti.tempdecl, !haveNE && isNested))
+        {
+            template_args(ti);
+            if (!haveNE && isNested)
+                buf.writeByte('E');
+            return;
+        }
+        else if (this.writeStdSubstitution(ti, needsTa))
+        {
+            this.abiTags.writeSymbol(ti, this);
+            if (needsTa)
                 template_args(ti);
-                if (!haveNE && isNested)
-                    buf.writeByte('E');
-            }
-            else if (this.writeStdSubstitution(ti, needsTa))
-            {
-                this.abiTags.writeSymbol(ti, this);
-                if (needsTa)
-                    template_args(ti);
-            }
-            else
-            {
-                this.writeNamespace(
-                    s.cppnamespace, () {
-                        this.writeIdentifier(ti.tempdecl.toAlias().ident);
-                        append(ti.tempdecl);
-                        this.abiTags.writeSymbol(ti.tempdecl, this);
-                        template_args(ti);
-                    }, haveNE);
-            }
+            return;
+        }
+
+        auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null;
+        if (ag && ag.mangleOverride)
+        {
+            this.writeNamespace(
+                ti.toAlias().cppnamespace, () {
+                    this.writeIdentifier(ag.mangleOverride.id);
+                    if (ag.mangleOverride.agg && ag.mangleOverride.agg.isInstantiated())
+                    {
+                        auto to = ag.mangleOverride.agg.isInstantiated();
+                        append(to);
+                        this.abiTags.writeSymbol(to.tempdecl, this);
+                        template_args(to);
+                    }
+              }, haveNE);
         }
         else
-            this.writeNamespace(s.cppnamespace, () {
-                    this.writeIdentifier(s.ident);
-                    this.abiTags.writeSymbol(s, this);
-                },
-                haveNE);
+        {
+            this.writeNamespace(
+                s.cppnamespace, () {
+                    this.writeIdentifier(ti.tempdecl.toAlias().ident);
+                    append(ti.tempdecl);
+                    this.abiTags.writeSymbol(ti.tempdecl, this);
+                    template_args(ti);
+                }, haveNE);
+        }
     }
 
     /********
@@ -850,7 +884,6 @@ private final class CppMangleVisitor : Visitor
         return false;
     }
 
-
     void cpp_mangle_name(Dsymbol s, bool qualified)
     {
         //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified);
@@ -864,74 +897,75 @@ private final class CppMangleVisitor : Visitor
                 write_prefix = false;
             p = p.toParent();
         }
-        if (p && !p.isModule())
+        if (!p || p.isModule())
         {
-            /* The N..E is not required if:
-             * 1. the parent is 'std'
-             * 2. 'std' is the initial qualifier
-             * 3. there is no CV-qualifier or a ref-qualifier for a member function
-             * ABI 5.1.8
-             */
-            if (isStd(p) && !qualified)
+            source_name(se, false);
+            append(s);
+            return;
+        }
+
+        if (!isStd(p) || qualified)
+        {
+            buf.writeByte('N');
+            if (write_prefix)
             {
-                TemplateInstance ti = se.isTemplateInstance();
-                if (s.ident == Id.allocator)
-                {
-                    buf.writestring("Sa"); // "Sa" is short for ::std::allocator
-                    template_args(ti);
-                }
-                else if (s.ident == Id.basic_string)
-                {
-                    // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
-                    if (ti.tiargs.dim == 3 &&
-                        isChar((*ti.tiargs)[0]) &&
-                        isChar_traits_char((*ti.tiargs)[1]) &&
-                        isAllocator_char((*ti.tiargs)[2]))
-                    {
-                        buf.writestring("Ss");
-                        return;
-                    }
-                    buf.writestring("Sb");      // ::std::basic_string
-                    template_args(ti);
-                }
-                else
-                {
-                    // ::std::basic_istream<char, ::std::char_traits<char>>
-                    if (s.ident == Id.basic_istream)
-                    {
-                        if (char_std_char_traits_char(ti, "Si"))
-                            return;
-                    }
-                    else if (s.ident == Id.basic_ostream)
-                    {
-                        if (char_std_char_traits_char(ti, "So"))
-                            return;
-                    }
-                    else if (s.ident == Id.basic_iostream)
-                    {
-                        if (char_std_char_traits_char(ti, "Sd"))
-                            return;
-                    }
+                if (isStd(p))
                     buf.writestring("St");
-                    source_name(se, true);
-                }
+                else
+                    prefix_name(p);
             }
-            else
+            source_name(se, true);
+            buf.writeByte('E');
+            append(s);
+            return;
+        }
+        /* The N..E is not required if:
+         * 1. the parent is 'std'
+         * 2. 'std' is the initial qualifier
+         * 3. there is no CV-qualifier or a ref-qualifier for a member function
+         * ABI 5.1.8
+         */
+        TemplateInstance ti = se.isTemplateInstance();
+        if (s.ident == Id.allocator)
+        {
+            buf.writestring("Sa"); // "Sa" is short for ::std::allocator
+            template_args(ti);
+        }
+        else if (s.ident == Id.basic_string)
+        {
+            // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+            if (ti.tiargs.dim == 3 &&
+                isChar((*ti.tiargs)[0]) &&
+                isChar_traits_char((*ti.tiargs)[1]) &&
+                isAllocator_char((*ti.tiargs)[2]))
             {
-                buf.writeByte('N');
-                if (write_prefix)
-                {
-                    if (isStd(p))
-                        buf.writestring("St");
-                    else
-                        prefix_name(p);
-                }
-                source_name(se, true);
-                buf.writeByte('E');
+                buf.writestring("Ss");
+                return;
             }
+            buf.writestring("Sb");      // ::std::basic_string
+            template_args(ti);
         }
         else
-            source_name(se, false);
+        {
+            // ::std::basic_istream<char, ::std::char_traits<char>>
+            if (s.ident == Id.basic_istream)
+            {
+                if (char_std_char_traits_char(ti, "Si"))
+                    return;
+            }
+            else if (s.ident == Id.basic_ostream)
+            {
+                if (char_std_char_traits_char(ti, "So"))
+                    return;
+            }
+            else if (s.ident == Id.basic_iostream)
+            {
+                if (char_std_char_traits_char(ti, "Sd"))
+                    return;
+            }
+            buf.writestring("St");
+            source_name(se, true);
+        }
         append(s);
     }
 
@@ -1003,12 +1037,20 @@ private final class CppMangleVisitor : Visitor
         //printf("mangle_function(%s)\n", d.toChars());
         /*
          * <mangled-name> ::= _Z <encoding>
+         */
+        buf.writestring("_Z");
+        this.mangle_function_encoding(d);
+    }
+
+    void mangle_function_encoding(FuncDeclaration d)
+    {
+        //printf("mangle_function_encoding(%s)\n", d.toChars());
+        /*
          * <encoding> ::= <function name> <bare-function-type>
          *            ::= <data name>
          *            ::= <special-name>
          */
         TypeFunction tf = cast(TypeFunction)d.type;
-        buf.writestring("_Z");
 
         if (TemplateDeclaration ftd = getFuncTemplateDecl(d))
         {
@@ -1017,45 +1059,44 @@ private final class CppMangleVisitor : Visitor
             TemplateInstance ti = d.parent.isTemplateInstance();
             assert(ti);
             this.mangleTemplatedFunction(d, tf, ftd, ti);
+            return;
+        }
+
+        Dsymbol p = d.toParent();
+        if (p && !p.isModule() && tf.linkage == LINK.cpp)
+        {
+            this.mangleNestedFuncPrefix(tf, p);
+
+            if (auto ctor = d.isCtorDeclaration())
+                buf.writestring(ctor.isCpCtor ? "C2" : "C1");
+            else if (d.isPrimaryDtor())
+                buf.writestring("D1");
+            else if (d.ident && d.ident == Id.assign)
+                buf.writestring("aS");
+            else if (d.ident && d.ident == Id.eq)
+                buf.writestring("eq");
+            else if (d.ident && d.ident == Id.index)
+                buf.writestring("ix");
+            else if (d.ident && d.ident == Id.call)
+                buf.writestring("cl");
+            else
+                source_name(d, true);
+            buf.writeByte('E');
         }
         else
         {
-            Dsymbol p = d.toParent();
-            if (p && !p.isModule() && tf.linkage == LINK.cpp)
-            {
-                this.mangleNestedFuncPrefix(tf, p);
-
-                if (auto ctor = d.isCtorDeclaration())
-                    buf.writestring(ctor.isCpCtor ? "C2" : "C1");
-                else if (d.isPrimaryDtor())
-                    buf.writestring("D1");
-                else if (d.ident && d.ident == Id.assign)
-                    buf.writestring("aS");
-                else if (d.ident && d.ident == Id.eq)
-                    buf.writestring("eq");
-                else if (d.ident && d.ident == Id.index)
-                    buf.writestring("ix");
-                else if (d.ident && d.ident == Id.call)
-                    buf.writestring("cl");
-                else
-                    source_name(d, true);
-                buf.writeByte('E');
-            }
-            else
-            {
-                source_name(d, false);
-            }
+            source_name(d, false);
+        }
 
-            // Save offset for potentially writing tags
-            const size_t off = this.buf.length();
+        // Save offset for potentially writing tags
+        const size_t off = this.buf.length();
 
-            // Template args accept extern "C" symbols with special mangling
-            if (tf.linkage == LINK.cpp)
-                mangleFunctionParameters(tf.parameterList);
+        // Template args accept extern "C" symbols with special mangling
+        if (tf.linkage == LINK.cpp)
+            mangleFunctionParameters(tf.parameterList);
 
-            if (!tf.next.isTypeBasic())
-                this.writeRemainingTags(off, tf);
-        }
+        if (!tf.next.isTypeBasic())
+            this.writeRemainingTags(off, tf);
     }
 
     /**
@@ -1073,7 +1114,7 @@ private final class CppMangleVisitor : Visitor
     {
         void runDg () { if (dg !is null) dg(); }
 
-        if (ns is null)
+        if (ns is null || ns.ident is null)
             return runDg();
 
         if (isStd(ns))
@@ -1140,121 +1181,123 @@ private final class CppMangleVisitor : Visitor
         if (d.isCtorDeclaration())
         {
             buf.writestring("C1");
+            mangleFunctionParameters(tf.parameterList);
+            return;
         }
         else if (d.isPrimaryDtor())
         {
             buf.writestring("D1");
+            mangleFunctionParameters(tf.parameterList);
+            return;
         }
-        else
-        {
-            int firstTemplateArg = 0;
-            bool appendReturnType = true;
-            bool isConvertFunc = false;
-            string symName;
 
-            // test for special symbols
-            CppOperator whichOp = isCppOperator(ti.name);
-            final switch (whichOp)
+        int firstTemplateArg = 0;
+        bool appendReturnType = true;
+        bool isConvertFunc = false;
+        string symName;
+
+        // test for special symbols
+        CppOperator whichOp = isCppOperator(ti.name);
+        final switch (whichOp)
+        {
+        case CppOperator.Unknown:
+            break;
+        case CppOperator.Cast:
+            symName = "cv";
+            firstTemplateArg = 1;
+            isConvertFunc = true;
+            appendReturnType = false;
+            break;
+        case CppOperator.Assign:
+            symName = "aS";
+            break;
+        case CppOperator.Eq:
+            symName = "eq";
+            break;
+        case CppOperator.Index:
+            symName = "ix";
+            break;
+        case CppOperator.Call:
+            symName = "cl";
+            break;
+        case CppOperator.Unary:
+        case CppOperator.Binary:
+        case CppOperator.OpAssign:
+            TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+            assert(td);
+            assert(ti.tiargs.dim >= 1);
+            TemplateParameter tp = (*td.parameters)[0];
+            TemplateValueParameter tv = tp.isTemplateValueParameter();
+            if (!tv || !tv.valType.isString())
+                break; // expecting a string argument to operators!
+            Expression exp = (*ti.tiargs)[0].isExpression();
+            StringExp str = exp.toStringExp();
+            switch (whichOp)
             {
-            case CppOperator.Unknown:
-                break;
-            case CppOperator.Cast:
-                symName = "cv";
-                firstTemplateArg = 1;
-                isConvertFunc = true;
-                appendReturnType = false;
-                break;
-            case CppOperator.Assign:
-                symName = "aS";
-                break;
-            case CppOperator.Eq:
-                symName = "eq";
-                break;
-            case CppOperator.Index:
-                symName = "ix";
-                break;
-            case CppOperator.Call:
-                symName = "cl";
-                break;
             case CppOperator.Unary:
+                switch (str.peekString())
+                {
+                case "*":   symName = "de"; goto continue_template;
+                case "++":  symName = "pp"; goto continue_template;
+                case "--":  symName = "mm"; goto continue_template;
+                case "-":   symName = "ng"; goto continue_template;
+                case "+":   symName = "ps"; goto continue_template;
+                case "~":   symName = "co"; goto continue_template;
+                default:    break;
+                }
+                break;
             case CppOperator.Binary:
+                switch (str.peekString())
+                {
+                case ">>":  symName = "rs"; goto continue_template;
+                case "<<":  symName = "ls"; goto continue_template;
+                case "*":   symName = "ml"; goto continue_template;
+                case "-":   symName = "mi"; goto continue_template;
+                case "+":   symName = "pl"; goto continue_template;
+                case "&":   symName = "an"; goto continue_template;
+                case "/":   symName = "dv"; goto continue_template;
+                case "%":   symName = "rm"; goto continue_template;
+                case "^":   symName = "eo"; goto continue_template;
+                case "|":   symName = "or"; goto continue_template;
+                default:    break;
+                }
+                break;
             case CppOperator.OpAssign:
-                TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
-                assert(td);
-                assert(ti.tiargs.dim >= 1);
-                TemplateParameter tp = (*td.parameters)[0];
-                TemplateValueParameter tv = tp.isTemplateValueParameter();
-                if (!tv || !tv.valType.isString())
-                    break; // expecting a string argument to operators!
-                Expression exp = (*ti.tiargs)[0].isExpression();
-                StringExp str = exp.toStringExp();
-                switch (whichOp)
+                switch (str.peekString())
                 {
-                case CppOperator.Unary:
-                    switch (str.peekString())
-                    {
-                    case "*":   symName = "de"; goto continue_template;
-                    case "++":  symName = "pp"; goto continue_template;
-                    case "--":  symName = "mm"; goto continue_template;
-                    case "-":   symName = "ng"; goto continue_template;
-                    case "+":   symName = "ps"; goto continue_template;
-                    case "~":   symName = "co"; goto continue_template;
-                    default:    break;
-                    }
-                    break;
-                case CppOperator.Binary:
-                    switch (str.peekString())
-                    {
-                    case ">>":  symName = "rs"; goto continue_template;
-                    case "<<":  symName = "ls"; goto continue_template;
-                    case "*":   symName = "ml"; goto continue_template;
-                    case "-":   symName = "mi"; goto continue_template;
-                    case "+":   symName = "pl"; goto continue_template;
-                    case "&":   symName = "an"; goto continue_template;
-                    case "/":   symName = "dv"; goto continue_template;
-                    case "%":   symName = "rm"; goto continue_template;
-                    case "^":   symName = "eo"; goto continue_template;
-                    case "|":   symName = "or"; goto continue_template;
-                    default:    break;
-                    }
-                    break;
-                case CppOperator.OpAssign:
-                    switch (str.peekString())
-                    {
-                    case "*":   symName = "mL"; goto continue_template;
-                    case "+":   symName = "pL"; goto continue_template;
-                    case "-":   symName = "mI"; goto continue_template;
-                    case "/":   symName = "dV"; goto continue_template;
-                    case "%":   symName = "rM"; goto continue_template;
-                    case ">>":  symName = "rS"; goto continue_template;
-                    case "<<":  symName = "lS"; goto continue_template;
-                    case "&":   symName = "aN"; goto continue_template;
-                    case "|":   symName = "oR"; goto continue_template;
-                    case "^":   symName = "eO"; goto continue_template;
-                    default:    break;
-                    }
-                    break;
-                default:
-                    assert(0);
-                continue_template:
-                    firstTemplateArg = 1;
-                    break;
+                case "*":   symName = "mL"; goto continue_template;
+                case "+":   symName = "pL"; goto continue_template;
+                case "-":   symName = "mI"; goto continue_template;
+                case "/":   symName = "dV"; goto continue_template;
+                case "%":   symName = "rM"; goto continue_template;
+                case ">>":  symName = "rS"; goto continue_template;
+                case "<<":  symName = "lS"; goto continue_template;
+                case "&":   symName = "aN"; goto continue_template;
+                case "|":   symName = "oR"; goto continue_template;
+                case "^":   symName = "eO"; goto continue_template;
+                default:    break;
                 }
                 break;
+            default:
+                assert(0);
+            continue_template:
+                firstTemplateArg = 1;
+                break;
             }
-            if (symName.length == 0)
-                source_name(ti, true);
-            else
-            {
-                buf.writestring(symName);
-                if (isConvertFunc)
-                    template_arg(ti, 0);
-                appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType;
-            }
-            buf.writeByte('E');
-            if (appendReturnType)
-                headOfType(tf.nextOf());  // mangle return type
+            break;
+        }
+        if (symName.length == 0)
+            source_name(ti, true);
+        else
+        {
+            buf.writestring(symName);
+            if (isConvertFunc)
+                template_arg(ti, 0);
+            appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType;
         }
+        buf.writeByte('E');
+        if (appendReturnType)
+            headOfType(tf.nextOf());  // mangle return type
         mangleFunctionParameters(tf.parameterList);
     }
 
@@ -1291,6 +1334,10 @@ private final class CppMangleVisitor : Visitor
                     return (*tf.parameterList.parameters)[n].type;
                 }());
             scope (exit) this.context.pop(prev);
+
+            if (this.context.ti && global.params.cplusplus >= CppStdRevision.cpp11)
+                handleParamPack(t, this.context.ti.tempdecl.isTemplateDeclaration().parameters);
+
             headOfType(t);
             ++numparams;
         }
@@ -1468,6 +1515,26 @@ private final class CppMangleVisitor : Visitor
         prefix_name(parent);
     }
 
+    /**
+     * Write `Dp` (C++11 function parameter pack prefix) if 't' is a TemplateSequenceParameter (T...).
+     *
+     * Params:
+     *   t      = Parameter type
+     *   params = Template parameters of the function
+     */
+    private void handleParamPack(Type t, TemplateParameters* params)
+    {
+        if (t.isTypeReference())
+            t = t.nextOf();
+        auto ti = t.isTypeIdentifier();
+        if (!ti)
+            return;
+
+        auto idx = templateParamIndex(ti.ident, params);
+        if (idx < params.length && (*params)[idx].isTemplateTupleParameter())
+            buf.writestring("Dp");
+    }
+
     /**
      * Helper function to write a `T..._` template index.
      *
@@ -1480,9 +1547,6 @@ private final class CppMangleVisitor : Visitor
         // expressions are mangled in <X..E>
         if (param.isTemplateValueParameter())
             buf.writeByte('X');
-        else if (param.isTemplateTupleParameter() &&
-                 global.params.cplusplus >= CppStdRevision.cpp11)
-            buf.writestring("Dp");
         buf.writeByte('T');
         writeSequenceFromIndex(idx);
         buf.writeByte('_');
@@ -1580,6 +1644,14 @@ extern(C++):
         writeBasicType(t, 'D', 'n');
     }
 
+    override void visit(TypeNoreturn t)
+    {
+        if (t.isImmutable() || t.isShared())
+            return error(t);
+
+        writeBasicType(t, 0, 'v');      // mangle like `void`
+    }
+
     override void visit(TypeBasic t)
     {
         if (t.isImmutable() || t.isShared())
@@ -1688,15 +1760,11 @@ extern(C++):
         else
         {
             assert(t.basetype && t.basetype.ty == Tsarray);
-            assert((cast(TypeSArray)t.basetype).dim);
-            version (none)
-            {
-                buf.writestring("Dv");
-                buf.print((cast(TypeSArray *)t.basetype).dim.toInteger()); // -- Gnu ABI v.4
-                buf.writeByte('_');
-            }
-            else
-                buf.writestring("U8__vector"); //-- Gnu ABI v.3
+            auto tsa = t.basetype.isTypeSArray();
+            assert(tsa.dim);
+            buf.writestring("Dv");          // -- Gnu ABI v.4
+            buf.print(tsa.dim.toInteger());
+            buf.writeByte('_');
             t.basetype.nextOf().accept(this);
         }
     }
@@ -1796,7 +1864,7 @@ extern(C++):
         if (t.isImmutable() || t.isShared())
             return error(t);
 
-        /* __c_(u)long(long) get special mangling
+        /* __c_(u)long(long) and others get special mangling
          */
         const id = t.sym.ident;
         //printf("enum id = '%s'\n", id.toChars());
@@ -1810,6 +1878,12 @@ extern(C++):
             return writeBasicType(t, 0, 'x');
         else if (id == Id.__c_ulonglong)
             return writeBasicType(t, 0, 'y');
+        else if (id == Id.__c_complex_float)
+            return writeBasicType(t, 'C', 'f');
+        else if (id == Id.__c_complex_double)
+            return writeBasicType(t, 'C', 'd');
+        else if (id == Id.__c_complex_real)
+            return writeBasicType(t, 'C', 'e');
 
         doSymbol(t);
     }
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index d9f9044f95d..91d1b663fa8 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -1,7 +1,7 @@
 /**
  * CTFE for expressions involving pointers, slices, array concatenation etc.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d)
@@ -15,6 +15,7 @@ import core.stdc.stdio;
 import core.stdc.stdlib;
 import core.stdc.string;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.complex;
 import dmd.constfold;
 import dmd.compiler;
@@ -179,7 +180,7 @@ extern (C++) final class CTFEExp : Expression
         case TOK.cantExpression:
             return "<cant>";
         case TOK.voidExpression:
-            return "<void>";
+            return "cast(void)0";
         case TOK.showCtfeContext:
             return "<error>";
         case TOK.break_:
@@ -453,7 +454,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
         return ue;
     }
     // If it is a cast to inout, retain the original type of the referenced part.
-    if (type.hasWild() && type.hasPointers())
+    if (type.hasWild())
     {
         emplaceExp!(UnionExp)(&ue, lit);
         ue.exp().type = type;
@@ -686,7 +687,7 @@ bool isSafePointerCast(Type srcPointee, Type destPointee)
         return true;
     // It's OK if function pointers differ only in safe/pure/nothrow
     if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
-        return srcPointee.covariant(destPointee) == 1;
+        return srcPointee.covariant(destPointee) == 1 || destPointee.covariant(srcPointee) == 1;
     // it's OK to cast to void*
     if (destPointee.ty == Tvoid)
         return true;
@@ -1510,7 +1511,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
         ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
         return ue;
     }
-    ue = Cat(type, e1, e2);
+    ue = Cat(loc, type, e1, e2);
     return ue;
 }
 
diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d
index 10024fa8385..c8b61be44a5 100644
--- a/gcc/d/dmd/ctorflow.d
+++ b/gcc/d/dmd/ctorflow.d
@@ -1,7 +1,7 @@
 /**
  * Manage flow analysis for constructors.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d)
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index df4120cd7bd..cd360e93cad 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -1,7 +1,7 @@
 /**
  * Semantic analysis for cast-expressions.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d)
@@ -17,6 +17,7 @@ import dmd.aggregate;
 import dmd.aliasthis;
 import dmd.arrayop;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dscope;
@@ -44,9 +45,20 @@ import dmd.visitor;
 
 enum LOG = false;
 
-/**************************************
- * Do an implicit cast.
- * Issue error if it can't be done.
+/**
+ * Attempt to implicitly cast the expression into type `t`.
+ *
+ * This routine will change `e`. To check the matching level,
+ * use `implicitConvTo`.
+ *
+ * Params:
+ *   e = Expression that is to be casted
+ *   sc = Current scope
+ *   t = Expected resulting type
+ *
+ * Returns:
+ *   The resulting casted expression (mutating `e`), or `ErrorExp`
+ *    if such an implicit conversion is not possible.
  */
 Expression implicitCastTo(Expression e, Scope* sc, Type t)
 {
@@ -68,7 +80,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
         {
             //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
 
-            if (const match = e.implicitConvTo(t))
+            if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
             {
                 if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t)))
                 {
@@ -206,9 +218,19 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
     return v.result;
 }
 
-/*******************************************
- * Return MATCH level of implicitly converting e to type t.
- * Don't do the actual cast; don't change e.
+/**
+ * Checks whether or not an expression can be implicitly converted
+ * to type `t`.
+ *
+ * Unlike `implicitCastTo`, this routine does not perform the actual cast,
+ * but only checks up to what `MATCH` level the conversion would be possible.
+ *
+ * Params:
+ *   e = Expression that is to be casted
+ *   t = Expected resulting type
+ *
+ * Returns:
+ *   The `MATCH` level between `e.type` and `t`.
  */
 MATCH implicitConvTo(Expression e, Type t)
 {
@@ -834,7 +856,7 @@ MATCH implicitConvTo(Expression e, Type t)
              * convert to immutable
              */
             if (e.f && e.f.isReturnIsolated() &&
-                (!global.params.vsafe ||        // lots of legacy code breaks with the following purity check
+                (global.params.useDIP1000 != FeatureState.enabled ||        // lots of legacy code breaks with the following purity check
                  e.f.isPure() >= PURE.strong ||
                  // Special case exemption for Object.dup() which we assume is implemented correctly
                  e.f.ident == Id.dup &&
@@ -1311,7 +1333,7 @@ MATCH implicitConvTo(Expression e, Type t)
 
                     struct ClassCheck
                     {
-                        extern (C++) static bool convertible(Loc loc, ClassDeclaration cd, MOD mod)
+                        extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod)
                         {
                             for (size_t i = 0; i < cd.fields.dim; i++)
                             {
@@ -1324,6 +1346,11 @@ MATCH implicitConvTo(Expression e, Type t)
                                     }
                                     else if (ExpInitializer ei = _init.isExpInitializer())
                                     {
+                                        // https://issues.dlang.org/show_bug.cgi?id=21319
+                                        // This is to prevent re-analyzing the same expression
+                                        // over and over again.
+                                        if (ei.exp == e)
+                                            return false;
                                         Type tb = v.type.toBasetype();
                                         if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch)
                                             return false;
@@ -1335,14 +1362,14 @@ MATCH implicitConvTo(Expression e, Type t)
                                         return false;
                                     }
                                 }
-                                else if (!v.type.isZeroInit(loc))
+                                else if (!v.type.isZeroInit(e.loc))
                                     return false;
                             }
-                            return cd.baseClass ? convertible(loc, cd.baseClass, mod) : true;
+                            return cd.baseClass ? convertible(e, cd.baseClass, mod) : true;
                         }
                     }
 
-                    if (!ClassCheck.convertible(e.loc, cd, mod))
+                    if (!ClassCheck.convertible(e, cd, mod))
                         return;
                 }
             }
@@ -1374,7 +1401,13 @@ MATCH implicitConvTo(Expression e, Type t)
             {
                 typeb = toStaticArrayType(e);
                 if (typeb)
+                {
+                    // Try: T[] -> T[dim]
+                    // (Slice with compile-time known boundaries to static array)
                     result = typeb.implicitConvTo(t);
+                    if (result > MATCH.convert)
+                        result = MATCH.convert; // match with implicit conversion at most
+                }
                 return;
             }
 
@@ -1423,6 +1456,42 @@ MATCH implicitConvTo(Expression e, Type t)
     return v.result;
 }
 
+/**
+ * Same as implicitConvTo(); except follow C11 rules, which are quite a bit
+ * more permissive than D.
+ * C11 6.3 and 6.5.16.1
+ * Params:
+ *   e = Expression that is to be casted
+ *   t = Expected resulting type
+ * Returns:
+ *   The `MATCH` level between `e.type` and `t`.
+ */
+MATCH cimplicitConvTo(Expression e, Type t)
+{
+    Type tb = t.toBasetype();
+    Type typeb = e.type.toBasetype();
+
+    if (tb.equals(typeb))
+        return MATCH.exact;
+    if ((typeb.isintegral() || typeb.isfloating()) &&
+        (tb.isintegral() || tb.isfloating()))
+        return MATCH.convert;
+    if (tb.ty == Tpointer && typeb.isintegral()) // C11 6.3.2.3-5
+        return MATCH.convert;
+    if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
+        return MATCH.convert;
+    if (tb.ty == Tpointer && typeb.ty == Tpointer)
+    {
+        if (tb.isTypePointer().next.ty == Tvoid ||
+            typeb.isTypePointer().next.ty == Tvoid)
+            return MATCH.convert;       // convert to/from void* C11 6.3.2.3-1
+    }
+
+    return implicitConvTo(e, t);
+}
+
+/*****************************************
+ */
 Type toStaticArrayType(SliceExp e)
 {
     if (e.lwr && e.upr)
@@ -1446,32 +1515,12 @@ Type toStaticArrayType(SliceExp e)
     return null;
 }
 
-// Try casting the alias this member. Return the expression if it succeeds, null otherwise.
-private Expression tryAliasThisCast(Expression e, Scope* sc, Type tob, Type t1b, Type t)
-{
-    Expression result;
-    AggregateDeclaration t1ad = isAggregate(t1b);
-    if (!t1ad)
-        return null;
-
-    AggregateDeclaration toad = isAggregate(tob);
-    if (t1ad == toad || !t1ad.aliasthis)
-        return null;
-
-    /* Forward the cast to our alias this member, rewrite to:
-     *   cast(to)e1.aliasthis
-     */
-    result = resolveAliasThis(sc, e);
-    const errors = global.startGagging();
-    result = result.castTo(sc, t);
-    return global.endGagging(errors) ? null : result;
-}
-
 /**************************************
  * Do an explicit cast.
- * Assume that the 'this' expression does not have any indirections.
+ * Assume that the expression `e` does not have any indirections.
+ * (Parameter 'att' is used to stop 'alias this' recursion)
  */
-Expression castTo(Expression e, Scope* sc, Type t)
+Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
 {
     extern (C++) final class CastTo : Visitor
     {
@@ -1547,6 +1596,22 @@ Expression castTo(Expression e, Scope* sc, Type t)
             const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
             const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
 
+            // Try casting the alias this member.
+            // Return the expression if it succeeds, null otherwise.
+            Expression tryAliasThisCast()
+            {
+                if (isRecursiveAliasThis(att, t1b))
+                    return null;
+
+                /* Forward the cast to our alias this member, rewrite to:
+                 *   cast(to)e1.aliasthis
+                 */
+                auto exp = resolveAliasThis(sc, e);
+                const errors = global.startGagging();
+                exp = castTo(exp, sc, t, att);
+                return global.endGagging(errors) ? null : exp;
+            }
+
             bool hasAliasThis;
             if (AggregateDeclaration t1ad = isAggregate(t1b))
             {
@@ -1608,7 +1673,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
             {
                 if (hasAliasThis)
                 {
-                    result = tryAliasThisCast(e, sc, tob, t1b, t);
+                    result = tryAliasThisCast();
                     if (result)
                         return;
                 }
@@ -1698,7 +1763,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
                  */
                 if (hasAliasThis)
                 {
-                    result = tryAliasThisCast(e, sc, tob, t1b, t);
+                    result = tryAliasThisCast();
                     if (result)
                         return;
                 }
@@ -2069,9 +2134,9 @@ Expression castTo(Expression e, Scope* sc, Type t)
                 {
                     f.tookAddressOf++;
                     auto se = new SymOffExp(e.loc, f, 0, false);
-                    se.expressionSemantic(sc);
+                    auto se2 = se.expressionSemantic(sc);
                     // Let SymOffExp::castTo() do the heavy lifting
-                    visit(se);
+                    visit(se2);
                     return;
                 }
             }
@@ -2149,7 +2214,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
             ArrayLiteralExp ae = e;
 
             Type tb = t.toBasetype();
-            if (tb.ty == Tarray && global.params.vsafe)
+            if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled)
             {
                 if (checkArrayLiteralEscape(sc, ae, false))
                 {
@@ -2537,6 +2602,23 @@ Expression castTo(Expression e, Scope* sc, Type t)
         }
     }
 
+    // Casting to noreturn isn't an actual cast
+    // Rewrite cast(<qual> noreturn) <exp>
+    // as      <exp>, assert(false)
+    if (t.isTypeNoreturn())
+    {
+        // Don't generate an unreachable assert(false) if e will abort
+        if (e.type.isTypeNoreturn())
+        {
+            // Paint e to accomodate for different type qualifiers
+            e.type = t;
+            return e;
+        }
+
+        auto ini = t.defaultInitLiteral(e.loc);
+        return Expression.combine(e, ini);
+    }
+
     scope CastTo v = new CastTo(sc, t);
     e.accept(v);
     return v.result;
@@ -2711,38 +2793,32 @@ private bool isVoidArrayLiteral(Expression e, Type other)
     return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
 }
 
-/**************************************
- * Combine types.
- * Output:
- *      *pt     merged type, if *pt is not NULL
- *      *pe1    rewritten e1
- *      *pe2    rewritten e2
+/**
+ * Merge types of `e1` and `e2` into a common subset
+ *
+ * Parameters `e1` and `e2` will be rewritten in place as needed.
+ *
+ * Params:
+ *     sc  = Current scope
+ *     op  = Operator such as `e1 op e2`. In practice, either TOK.question
+ *           or one of the binary operator.
+ *     pe1 = The LHS of the operation, will be rewritten
+ *     pe2 = The RHS of the operation, will be rewritten
+ *
  * Returns:
- *      true    success
- *      false   failed
+ *      The resulting type in case of success, `null` in case of error
  */
-bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2)
+Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
 {
-    //printf("typeMerge() %s op %s\n", pe1.toChars(), pe2.toChars());
+    //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
 
-    MATCH m;
-    Expression e1 = *pe1;
-    Expression e2 = *pe2;
+    Expression e1 = pe1;
+    Expression e2 = pe2;
 
-    Type t1 = e1.type;
-    Type t2 = e2.type;
-
-    Type t1b = e1.type.toBasetype();
-    Type t2b = e2.type.toBasetype();
-
-    Type t;
-
-    bool Lret()
+    Type Lret(Type result)
     {
-        if (!*pt)
-            *pt = t;
-        *pe1 = e1;
-        *pe2 = e2;
+        pe1 = e1;
+        pe2 = e2;
 
         version (none)
         {
@@ -2751,26 +2827,28 @@ bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2)
                 printf("\tt1 = %s\n", e1.type.toChars());
             if (e2.type)
                 printf("\tt2 = %s\n", e2.type.toChars());
-            printf("\ttype = %s\n", t.toChars());
+            printf("\ttype = %s\n", result.toChars());
         }
-        return true;
+        return result;
     }
 
-    bool Lt1()
+    /// Converts one of the expression too the other
+    Type convert(ref Expression from, Type to)
     {
-        e2 = e2.castTo(sc, t1);
-        t = t1;
-        return Lret();
+        from = from.castTo(sc, to);
+        return Lret(to);
     }
 
-    bool Lt2()
+    /// Converts both expression to a third type
+    Type coerce(Type towards)
     {
-        e1 = e1.castTo(sc, t2);
-        t = t2;
-        return Lret();
+        e1 = e1.castTo(sc, towards);
+        e2 = e2.castTo(sc, towards);
+        return Lret(towards);
     }
 
-    bool Lincompatible() { return false; }
+    Type t1b = e1.type.toBasetype();
+    Type t2b = e2.type.toBasetype();
 
     if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
     {
@@ -2786,10 +2864,11 @@ bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2)
         }
     }
 
-    t1 = e1.type;
-    t2 = e2.type;
+    MATCH m;
+    Type t1 = e1.type;
+    Type t2 = e2.type;
     assert(t1);
-    t = t1;
+    Type t = t1;
 
     /* The start type of alias this type recursion.
      * In following case, we should save A, and stop recursion
@@ -2799,15 +2878,6 @@ bool typeMerge(Scope* sc, TOK op, Type* pt, Expression* pe1, Expression* pe2)
     Type att1 = null;
     Type att2 = null;
 
-    //if (t1) printf("\tt1 = %s\n", t1.toChars());
-    //if (t2) printf("\tt2 = %s\n", t2.toChars());
-    debug
-    {
-        if (!t2)
-            printf("\te2 = '%s'\n", e2.toChars());
-    }
-    assert(t2);
-
     if (t1.mod != t2.mod &&
         t1.ty == Tenum && t2.ty == Tenum &&
         (cast(TypeEnum)t1).sym == (cast(TypeEnum)t2).sym)
@@ -2821,78 +2891,71 @@ Lagain:
     t1b = t1.toBasetype();
     t2b = t2.toBasetype();
 
-    TY ty = cast(TY)impcnvResult[t1b.ty][t2b.ty];
+    const ty = implicitConvCommonTy(t1b.ty, t2b.ty);
     if (ty != Terror)
     {
-        TY ty1 = cast(TY)impcnvType1[t1b.ty][t2b.ty];
-        TY ty2 = cast(TY)impcnvType2[t1b.ty][t2b.ty];
+        const ty1 = implicitConvTy1(t1b.ty, t2b.ty);
+        const ty2 = implicitConvTy1(t2b.ty, t1b.ty);
 
         if (t1b.ty == ty1) // if no promotions
         {
             if (t1.equals(t2))
-            {
-                t = t1;
-                return Lret();
-            }
+                return Lret(t1);
 
             if (t1b.equals(t2b))
-            {
-                t = t1b;
-                return Lret();
-            }
+                return Lret(t1b);
         }
 
-        t = Type.basic[ty];
-
         t1 = Type.basic[ty1];
         t2 = Type.basic[ty2];
         e1 = e1.castTo(sc, t1);
         e2 = e2.castTo(sc, t2);
-        return Lret();
+        return Lret(Type.basic[ty]);
     }
 
     t1 = t1b;
     t2 = t2b;
 
     if (t1.ty == Ttuple || t2.ty == Ttuple)
-        return Lincompatible();
+        return null;
 
     if (t1.equals(t2))
     {
         // merging can not result in new enum type
         if (t.ty == Tenum)
-            t = t1b;
+            return Lret(t1b);
+        return Lret(t);
     }
-    else if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate))
+
+    if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate))
     {
         // Bring pointers to compatible type
         Type t1n = t1.nextOf();
         Type t2n = t2.nextOf();
 
         if (t1n.equals(t2n))
-        {
-        }
-        else if (t1n.ty == Tvoid) // pointers to void are always compatible
-            t = t2;
-        else if (t2n.ty == Tvoid)
-        {
-        }
-        else if (t1.implicitConvTo(t2))
-        {
-            return Lt2();
-        }
-        else if (t2.implicitConvTo(t1))
-        {
-            return Lt1();
-        }
-        else if (t1n.ty == Tfunction && t2n.ty == Tfunction)
+            return Lret(t);
+
+        if (t1n.ty == Tvoid) // pointers to void are always compatible
+            return Lret(t2);
+
+        if (t2n.ty == Tvoid)
+            return Lret(t);
+
+        if (t1.implicitConvTo(t2))
+            return convert(e1, t2);
+
+        if (t2.implicitConvTo(t1))
+            return convert(e2, t1);
+
+        if (t1n.ty == Tfunction && t2n.ty == Tfunction)
         {
             TypeFunction tf1 = cast(TypeFunction)t1n;
             TypeFunction tf2 = cast(TypeFunction)t2n;
             tf1.purityLevel();
             tf2.purityLevel();
 
-            TypeFunction d = cast(TypeFunction)tf1.syntaxCopy();
+            TypeFunction d = tf1.syntaxCopy();
 
             if (tf1.purity != tf2.purity)
                 d.purity = PURE.impure;
@@ -2908,36 +2971,26 @@ Lagain:
             else
                 d.trust = TRUST.trusted;
 
-            Type tx = null;
-            if (t1.ty == Tdelegate)
-            {
-                tx = new TypeDelegate(d);
-            }
-            else
-                tx = d.pointerTo();
-
+            Type tx = (t1.ty == Tdelegate) ? new TypeDelegate(d) : d.pointerTo();
             tx = tx.typeSemantic(e1.loc, sc);
 
             if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx))
-            {
-                t = tx;
-                e1 = e1.castTo(sc, t);
-                e2 = e2.castTo(sc, t);
-                return Lret();
-            }
-            return Lincompatible();
+                return coerce(tx);
+            return null;
         }
-        else if (t1n.mod != t2n.mod)
+
+        if (t1n.mod != t2n.mod)
         {
             if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
-                return Lincompatible();
+                return null;
             ubyte mod = MODmerge(t1n.mod, t2n.mod);
             t1 = t1n.castMod(mod).pointerTo();
             t2 = t2n.castMod(mod).pointerTo();
             t = t1;
             goto Lagain;
         }
-        else if (t1n.ty == Tclass && t2n.ty == Tclass)
+
+        if (t1n.ty == Tclass && t2n.ty == Tclass)
         {
             ClassDeclaration cd1 = t1n.isClassHandle();
             ClassDeclaration cd2 = t2n.isClassHandle();
@@ -2946,32 +2999,29 @@ Lagain:
             {
                 if (offset)
                     e2 = e2.castTo(sc, t);
+                return Lret(t);
             }
-            else if (cd2.isBaseOf(cd1, &offset))
+
+            if (cd2.isBaseOf(cd1, &offset))
             {
-                t = t2;
                 if (offset)
-                    e1 = e1.castTo(sc, t);
-            }
-            else
-                return Lincompatible();
-        }
-        else
-        {
-            t1 = t1n.constOf().pointerTo();
-            t2 = t2n.constOf().pointerTo();
-            if (t1.implicitConvTo(t2))
-            {
-                return Lt2();
-            }
-            else if (t2.implicitConvTo(t1))
-            {
-                return Lt1();
+                    e1 = e1.castTo(sc, t2);
+                return Lret(t2);
             }
-            return Lincompatible();
+
+            return null;
         }
+
+        t1 = t1n.constOf().pointerTo();
+        t2 = t2n.constOf().pointerTo();
+        if (t1.implicitConvTo(t2))
+            return convert(e1, t2);
+        if (t2.implicitConvTo(t1))
+            return convert(e2, t1);
+        return null;
     }
-    else if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && (cast(TypeSArray)t2).dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+
+    if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && (cast(TypeSArray)t2).dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
     {
         /*  (T[n] op void*)   => T[]
          *  (T[]  op void*)   => T[]
@@ -2980,9 +3030,10 @@ Lagain:
          *  (T[n] op void[])  => T[]
          *  (T[]  op void[])  => T[]
          */
-        goto Lx1;
+        return coerce(t1.nextOf().arrayOf());
     }
-    else if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && (cast(TypeSArray)t1).dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+
+    if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && (cast(TypeSArray)t1).dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
     {
         /*  (void*   op T[n]) => T[]
          *  (void*   op T[])  => T[]
@@ -2991,35 +3042,37 @@ Lagain:
          *  (void[]  op T[n]) => T[]
          *  (void[]  op T[])  => T[]
          */
-        goto Lx2;
+        return coerce(t2.nextOf().arrayOf());
     }
-    else if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
+
+    if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
     {
         // https://issues.dlang.org/show_bug.cgi?id=7285
         // Tsarray op [x, y, ...] should to be Tsarray
         // https://issues.dlang.org/show_bug.cgi?id=14737
         // Tsarray ~ [x, y, ...] should to be Tarray
         if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate)
-            return Lt1();
+            return convert(e2, t1);
         if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign))
         {
             // Don't make the lvalue const
-            t = t2;
-            return Lret();
+            return Lret(t2);
         }
-        return Lt2();
+        return convert(e1, t2);
     }
-    else if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1))
+
+    if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1))
     {
         // https://issues.dlang.org/show_bug.cgi?id=7285
         // https://issues.dlang.org/show_bug.cgi?id=14737
         if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate)
-            return Lt2();
-        return Lt1();
+            return convert(e1, t2);
+        return convert(e2, t1);
     }
-    else if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod)
+
+    if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod)
     {
-        /* If one is mutable and the other invariant, then retry
+        /* If one is mutable and the other immutable, then retry
          * with both of them as const
          */
         Type t1n = t1.nextOf();
@@ -3030,7 +3083,7 @@ Lagain:
         else if (e1.op != TOK.null_ && e2.op == TOK.null_)
             mod = t1n.mod;
         else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
-            return Lincompatible();
+            return null;
         else
             mod = MODmerge(t1n.mod, t2n.mod);
 
@@ -3046,7 +3099,8 @@ Lagain:
         t = t1;
         goto Lagain;
     }
-    else if (t1.ty == Tclass && t2.ty == Tclass)
+
+    if (t1.ty == Tclass && t2.ty == Tclass)
     {
         if (t1.mod != t2.mod)
         {
@@ -3056,7 +3110,7 @@ Lagain:
             else if (e1.op != TOK.null_ && e2.op == TOK.null_)
                 mod = t1.mod;
             else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
-                return Lincompatible();
+                return null;
             else
                 mod = MODmerge(t1.mod, t2.mod);
             t1 = t1.castMod(mod);
@@ -3066,7 +3120,8 @@ Lagain:
         }
         goto Lcc;
     }
-    else if (t1.ty == Tclass || t2.ty == Tclass)
+
+    if (t1.ty == Tclass || t2.ty == Tclass)
     {
     Lcc:
         while (1)
@@ -3084,16 +3139,11 @@ Lagain:
             }
 
             if (i2)
-            {
-                e2 = e2.castTo(sc, t2);
-                return Lt2();
-            }
-            else if (i1)
-            {
-                e1 = e1.castTo(sc, t1);
-                return Lt1();
-            }
-            else if (t1.ty == Tclass && t2.ty == Tclass)
+                return coerce(t2);
+            if (i1)
+                return coerce(t1);
+
+            if (t1.ty == Tclass && t2.ty == Tclass)
             {
                 TypeClass tc1 = cast(TypeClass)t1;
                 TypeClass tc2 = cast(TypeClass)t2;
@@ -3112,14 +3162,12 @@ Lagain:
                 else if (cd2)
                     t2 = cd2.type;
                 else
-                    return Lincompatible();
+                    return null;
             }
             else if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis)
             {
-                if (att1 && e1.type == att1)
-                    return Lincompatible();
-                if (!att1 && e1.type.checkAliasThisRec())
-                    att1 = e1.type;
+                if (isRecursiveAliasThis(att1, e1.type))
+                    return null;
                 //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars());
                 e1 = resolveAliasThis(sc, e1);
                 t1 = e1.type;
@@ -3127,25 +3175,24 @@ Lagain:
             }
             else if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis)
             {
-                if (att2 && e2.type == att2)
-                    return Lincompatible();
-                if (!att2 && e2.type.checkAliasThisRec())
-                    att2 = e2.type;
+                if (isRecursiveAliasThis(att2, e2.type))
+                    return null;
                 //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars());
                 e2 = resolveAliasThis(sc, e2);
                 t2 = e2.type;
                 continue;
             }
             else
-                return Lincompatible();
+                return null;
         }
     }
-    else if (t1.ty == Tstruct && t2.ty == Tstruct)
+
+    if (t1.ty == Tstruct && t2.ty == Tstruct)
     {
         if (t1.mod != t2.mod)
         {
             if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
-                return Lincompatible();
+                return null;
             ubyte mod = MODmerge(t1.mod, t2.mod);
             t1 = t1.castMod(mod);
             t2 = t2.castMod(mod);
@@ -3158,7 +3205,7 @@ Lagain:
         if (ts1.sym != ts2.sym)
         {
             if (!ts1.sym.aliasthis && !ts2.sym.aliasthis)
-                return Lincompatible();
+                return null;
 
             MATCH i1 = MATCH.nomatch;
             MATCH i2 = MATCH.nomatch;
@@ -3167,31 +3214,27 @@ Lagain:
             Expression e2b = null;
             if (ts2.sym.aliasthis)
             {
-                if (att2 && e2.type == att2)
-                    return Lincompatible();
-                if (!att2 && e2.type.checkAliasThisRec())
-                    att2 = e2.type;
+                if (isRecursiveAliasThis(att2, e2.type))
+                    return null;
                 //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars());
                 e2b = resolveAliasThis(sc, e2);
                 i1 = e2b.implicitConvTo(t1);
             }
             if (ts1.sym.aliasthis)
             {
-                if (att1 && e1.type == att1)
-                    return Lincompatible();
-                if (!att1 && e1.type.checkAliasThisRec())
-                    att1 = e1.type;
+                if (isRecursiveAliasThis(att1, e1.type))
+                    return null;
                 //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars());
                 e1b = resolveAliasThis(sc, e1);
                 i2 = e1b.implicitConvTo(t2);
             }
             if (i1 && i2)
-                return Lincompatible();
+                return null;
 
             if (i1)
-                return Lt1();
-            else if (i2)
-                return Lt2();
+                return convert(e2, t1);
+            if (i2)
+                return convert(e1, t2);
 
             if (e1b)
             {
@@ -3207,14 +3250,13 @@ Lagain:
             goto Lagain;
         }
     }
-    else if (t1.ty == Tstruct || t2.ty == Tstruct)
+
+    if (t1.ty == Tstruct || t2.ty == Tstruct)
     {
         if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis)
         {
-            if (att1 && e1.type == att1)
-                return Lincompatible();
-            if (!att1 && e1.type.checkAliasThisRec())
-                att1 = e1.type;
+            if (isRecursiveAliasThis(att1, e1.type))
+                return null;
             //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
             e1 = resolveAliasThis(sc, e1);
             t1 = e1.type;
@@ -3223,41 +3265,27 @@ Lagain:
         }
         if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis)
         {
-            if (att2 && e2.type == att2)
-                return Lincompatible();
-            if (!att2 && e2.type.checkAliasThisRec())
-                att2 = e2.type;
+            if (isRecursiveAliasThis(att2, e2.type))
+                return null;
             //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
             e2 = resolveAliasThis(sc, e2);
             t2 = e2.type;
             t = t2;
             goto Lagain;
         }
-        return Lincompatible();
-    }
-    else if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
-    {
-        return Lt2();
-    }
-    else if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1))
-    {
-        return Lt1();
-    }
-    else if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
-    {
-    Lx1:
-        t = t1.nextOf().arrayOf(); // T[]
-        e1 = e1.castTo(sc, t);
-        e2 = e2.castTo(sc, t);
-    }
-    else if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf()))
-    {
-    Lx2:
-        t = t2.nextOf().arrayOf();
-        e1 = e1.castTo(sc, t);
-        e2 = e2.castTo(sc, t);
+        return null;
     }
-    else if (t1.ty == Tvector && t2.ty == Tvector)
+
+    if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
+        return convert(e1, t2);
+    if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1))
+        return convert(e2, t1);
+    if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
+        return coerce(t1.nextOf().arrayOf());
+    if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf()))
+        return coerce(t2.nextOf().arrayOf());
+
+    if (t1.ty == Tvector && t2.ty == Tvector)
     {
         // https://issues.dlang.org/show_bug.cgi?id=13841
         // all vector types should have no common types between
@@ -3265,30 +3293,33 @@ Lagain:
         auto tv1 = cast(TypeVector)t1;
         auto tv2 = cast(TypeVector)t2;
         if (!tv1.basetype.equals(tv2.basetype))
-            return Lincompatible();
+            return null;
 
         goto LmodCompare;
     }
-    else if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1))
+
+    if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1))
     {
         e2 = e2.castTo(sc, t1);
         t2 = t1;
         t = t1;
         goto Lagain;
     }
-    else if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2))
+
+    if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2))
     {
         e1 = e1.castTo(sc, t2);
         t1 = t2;
         t = t1;
         goto Lagain;
     }
-    else if (t1.isintegral() && t2.isintegral())
+
+    if (t1.isintegral() && t2.isintegral())
     {
         if (t1.ty != t2.ty)
         {
             if (t1.ty == Tvector || t2.ty == Tvector)
-                return Lincompatible();
+                return null;
             e1 = integralPromotions(e1, sc);
             e2 = integralPromotions(e2, sc);
             t1 = e1.type;
@@ -3298,7 +3329,7 @@ Lagain:
         assert(t1.ty == t2.ty);
 LmodCompare:
         if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
-            return Lincompatible();
+            return null;
         ubyte mod = MODmerge(t1.mod, t2.mod);
 
         t1 = t1.castMod(mod);
@@ -3308,39 +3339,34 @@ LmodCompare:
         e2 = e2.castTo(sc, t);
         goto Lagain;
     }
-    else if (t1.ty == Tnull && t2.ty == Tnull)
-    {
-        ubyte mod = MODmerge(t1.mod, t2.mod);
 
-        t = t1.castMod(mod);
-        e1 = e1.castTo(sc, t);
-        e2 = e2.castTo(sc, t);
-        return Lret();
-    }
-    else if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray))
+    if (t1.ty == Tnull && t2.ty == Tnull)
     {
-        return Lt1();
-    }
-    else if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
-    {
-        return Lt2();
+        ubyte mod = MODmerge(t1.mod, t2.mod);
+        return coerce(t1.castMod(mod));
     }
-    else if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
+
+    if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray))
+        return convert(e2, t1);
+    if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
+        return convert(e1, t2);
+
+    if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
     {
         if (e2.implicitConvTo(t1.nextOf()))
         {
             // T[] op T
             // T[] op cast(T)U
             e2 = e2.castTo(sc, t1.nextOf());
-            t = t1.nextOf().arrayOf();
+            return Lret(t1.nextOf().arrayOf());
         }
-        else if (t1.nextOf().implicitConvTo(e2.type))
+        if (t1.nextOf().implicitConvTo(e2.type))
         {
             // (cast(T)U)[] op T    (https://issues.dlang.org/show_bug.cgi?id=12780)
             // e1 is left as U[], it will be handled in arrayOp() later.
-            t = e2.type.arrayOf();
+            return Lret(e2.type.arrayOf());
         }
-        else if (t2.ty == Tarray && isArrayOpOperand(e2))
+        if (t2.ty == Tarray && isArrayOpOperand(e2))
         {
             if (t1.nextOf().implicitConvTo(t2.nextOf()))
             {
@@ -3349,8 +3375,9 @@ LmodCompare:
                 // if cast won't be handled in arrayOp() later
                 if (!isArrayOpImplicitCast(t1.isTypeDArray(), t2.isTypeDArray()))
                     e1 = e1.castTo(sc, t);
+                return Lret(t);
             }
-            else if (t2.nextOf().implicitConvTo(t1.nextOf()))
+            if (t2.nextOf().implicitConvTo(t1.nextOf()))
             {
                 // T[] op (cast(T)U)[]  (https://issues.dlang.org/show_bug.cgi?id=12780)
                 // e2 is left as U[], it will be handled in arrayOp() later.
@@ -3358,12 +3385,11 @@ LmodCompare:
                 // if cast won't be handled in arrayOp() later
                 if (!isArrayOpImplicitCast(t2.isTypeDArray(), t1.isTypeDArray()))
                     e2 = e2.castTo(sc, t);
+                return Lret(t);
             }
-            else
-                return Lincompatible();
+            return null;
         }
-        else
-            return Lincompatible();
+        return null;
     }
     else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
     {
@@ -3381,7 +3407,7 @@ LmodCompare:
             t = e1.type.arrayOf();
         }
         else
-            return Lincompatible();
+            return null;
 
         //printf("test %s\n", Token::toChars(op));
         e1 = e1.optimize(WANTvalue);
@@ -3394,12 +3420,10 @@ LmodCompare:
             e1 = e2;
             e2 = tmp;
         }
+        return Lret(t);
     }
-    else
-    {
-        return Lincompatible();
-    }
-    return Lret();
+
+    return null;
 }
 
 /************************************
@@ -3431,7 +3455,12 @@ Expression typeCombine(BinExp be, Scope* sc)
             return errorReturn();
     }
 
-    if (!typeMerge(sc, be.op, &be.type, &be.e1, &be.e2))
+    if (auto result = typeMerge(sc, be.op, be.e1, be.e2))
+    {
+        if (be.type is null)
+            be.type = result;
+    }
+    else
         return errorReturn();
 
     // If the types have no value, return an error
@@ -3487,7 +3516,7 @@ Expression integralPromotions(Expression e, Scope* sc)
 
 void fix16997(Scope* sc, UnaExp ue)
 {
-    if (global.params.fix16997)
+    if (global.params.fix16997 || sc.flags & SCOPE.Cfile)
         ue.e1 = integralPromotions(ue.e1, sc);          // desired C-like behavor
     else
     {
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 22c163b1a17..9c5f0da2f97 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d)
@@ -19,6 +19,7 @@ import core.stdc.string;
 import dmd.aggregate;
 import dmd.apply;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.gluelayer;
 import dmd.declaration;
 import dmd.dscope;
@@ -34,7 +35,7 @@ import dmd.root.rmem;
 import dmd.target;
 import dmd.visitor;
 
-enum Abstract : int
+enum Abstract : ubyte
 {
     fwdref = 0,      // whether an abstract class is not yet computed
     yes,             // is abstract class
@@ -129,7 +130,7 @@ extern (C++) struct BaseClass
     }
 }
 
-enum ClassFlags : int
+enum ClassFlags : uint
 {
     none          = 0x0,
     isCOMclass    = 0x1,
@@ -380,7 +381,15 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         return new ClassDeclaration(loc, id, baseclasses, members, inObject);
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override const(char)* toPrettyChars(bool qualifyTypes = false)
+    {
+        if (objc.isMeta)
+            return .objc.toPrettyChars(this, qualifyTypes);
+
+        return super.toPrettyChars(qualifyTypes);
+    }
+
+    override ClassDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
         ClassDeclaration cd =
@@ -397,7 +406,8 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
             (*cd.baseclasses)[i] = b2;
         }
 
-        return ScopeDsymbol.syntaxCopy(cd);
+        ScopeDsymbol.syntaxCopy(cd);
+        return cd;
     }
 
     override Scope* newScope(Scope* sc)
@@ -488,7 +498,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         if (!members || !symtab) // opaque or addMember is not yet done
         {
             // .stringof is always defined (but may be hidden by some other symbol)
-            if (ident != Id.stringof)
+            if (ident != Id.stringof && !(flags & IgnoreErrors))
                 error("is forward referenced when looking for `%s`", ident.toChars());
             //*(char*)0=0;
             return null;
@@ -519,7 +529,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
                             continue;
                         else if (s == this) // happens if s is nested in this and derives from this
                             s = null;
-                        else if (!(flags & IgnoreSymbolVisibility) && !(s.prot().kind == Prot.Kind.protected_) && !symbolIsVisible(this, s))
+                        else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
                             s = null;
                         else
                             break;
@@ -565,10 +575,13 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
             assert(baseClass.sizeok == Sizeok.done);
 
             alignsize = baseClass.alignsize;
-            structsize = baseClass.structsize;
-            if (classKind == ClassKind.cpp && global.params.isWindows)
-                structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+            if (classKind == ClassKind.cpp)
+                structsize = target.cpp.derivedClassOffset(baseClass);
+            else
+                structsize = baseClass.structsize;
         }
+        else if (classKind == ClassKind.objc)
+            structsize = 0; // no hidden member for an Objective-C class
         else if (isInterfaceDeclaration())
         {
             if (interfaces.length == 0)
@@ -997,12 +1010,13 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration
         }
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override InterfaceDeclaration syntaxCopy(Dsymbol s)
     {
         InterfaceDeclaration id =
             s ? cast(InterfaceDeclaration)s
               : new InterfaceDeclaration(loc, ident, null);
-        return ClassDeclaration.syntaxCopy(id);
+        ClassDeclaration.syntaxCopy(id);
+        return id;
     }
 
 
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 98bfd8a982d..2135ef039dd 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -2,7 +2,7 @@
  * Miscellaneous declarations, including typedef, alias, variable declarations including the
  * implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d)
@@ -15,6 +15,7 @@ module dmd.declaration;
 import core.stdc.stdio;
 import dmd.aggregate;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.ctorflow;
 import dmd.dclass;
 import dmd.delegatize;
@@ -89,18 +90,15 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
         if (s)
             fd = s.isFuncDeclaration();
         if (fd &&
-            ((var.isField() && (fd.isCtorDeclaration() || fd.isPostBlitDeclaration())) ||
-             (!var.isField() && fd.isStaticCtorDeclaration())) &&
+            ((fd.isCtorDeclaration() && var.isField()) ||
+             (fd.isStaticCtorDeclaration() && !var.isField())) &&
             fd.toParentDecl() == var.toParent2() &&
             (!e1 || e1.op == TOK.this_))
         {
             bool result = true;
 
-            if (!fd.isPostBlitDeclaration())
-            {
-                var.ctorinit = true;
-                //printf("setting ctorinit\n");
-            }
+            var.ctorinit = true;
+            //printf("setting ctorinit\n");
 
             if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
             {
@@ -196,75 +194,6 @@ extern (C++) void ObjectNotFound(Identifier id)
     fatal();
 }
 
-enum STC : ulong
-{
-    undefined_          = 0L,
-    static_             = (1L << 0),
-    extern_             = (1L << 1),
-    const_              = (1L << 2),
-    final_              = (1L << 3),
-    abstract_           = (1L << 4),
-    parameter           = (1L << 5),
-    field               = (1L << 6),
-    override_           = (1L << 7),
-    auto_               = (1L << 8),
-    synchronized_       = (1L << 9),
-    deprecated_         = (1L << 10),
-    in_                 = (1L << 11),   // in parameter
-    out_                = (1L << 12),   // out parameter
-    lazy_               = (1L << 13),   // lazy parameter
-    foreach_            = (1L << 14),   // variable for foreach loop
-                          //(1L << 15)
-    variadic            = (1L << 16),   // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
-    ctorinit            = (1L << 17),   // can only be set inside constructor
-    templateparameter   = (1L << 18),   // template parameter
-    scope_              = (1L << 19),
-    immutable_          = (1L << 20),
-    ref_                = (1L << 21),
-    init                = (1L << 22),   // has explicit initializer
-    manifest            = (1L << 23),   // manifest constant
-    nodtor              = (1L << 24),   // don't run destructor
-    nothrow_            = (1L << 25),   // never throws exceptions
-    pure_               = (1L << 26),   // pure function
-    tls                 = (1L << 27),   // thread local
-    alias_              = (1L << 28),   // alias parameter
-    shared_             = (1L << 29),   // accessible from multiple threads
-    gshared             = (1L << 30),   // accessible from multiple threads, but not typed as "shared"
-    wild                = (1L << 31),   // for "wild" type constructor
-    property            = (1L << 32),
-    safe                = (1L << 33),
-    trusted             = (1L << 34),
-    system              = (1L << 35),
-    ctfe                = (1L << 36),   // can be used in CTFE, even if it is static
-    disable             = (1L << 37),   // for functions that are not callable
-    result              = (1L << 38),   // for result variables passed to out contracts
-    nodefaultctor       = (1L << 39),   // must be set inside constructor
-    temp                = (1L << 40),   // temporary variable
-    rvalue              = (1L << 41),   // force rvalue for variables
-    nogc                = (1L << 42),   // @nogc
-    volatile_           = (1L << 43),   // destined for volatile in the back end
-    return_             = (1L << 44),   // 'return ref' or 'return scope' for function parameters
-    autoref             = (1L << 45),   // Mark for the already deduced 'auto ref' parameter
-    inference           = (1L << 46),   // do attribute inference
-    exptemp             = (1L << 47),   // temporary variable that has lifetime restricted to an expression
-    maybescope          = (1L << 48),   // parameter might be 'scope'
-    scopeinferred       = (1L << 49),   // 'scope' has been inferred and should not be part of mangling
-    future              = (1L << 50),   // introducing new base class function
-    local               = (1L << 51),   // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
-    returninferred      = (1L << 52),   // 'return' has been inferred and should not be part of mangling
-    live                = (1L << 53),   // function @live attribute
-
-    // Group members are mutually exclusive (there can be only one)
-    safeGroup = STC.safe | STC.trusted | STC.system,
-
-    /// Group for `in` / `out` / `ref` storage classes on parameter
-    IOR  = STC.in_ | STC.ref_ | STC.out_,
-
-    TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild),
-    FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live |
-                STC.safeGroup),
-}
-
 enum STCStorageClass =
     (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ | STC.abstract_ | STC.synchronized_ |
      STC.deprecated_ | STC.future | STC.override_ | STC.lazy_ | STC.alias_ | STC.out_ | STC.in_ | STC.manifest |
@@ -295,9 +224,13 @@ extern (C++) abstract class Declaration : Dsymbol
     Type type;
     Type originalType;  // before semantic analysis
     StorageClass storage_class = STC.undefined_;
-    Prot protection;
+    Visibility visibility;
     LINK linkage = LINK.default_;
-    int inuse;          // used to detect cycles
+    short inuse;          // used to detect cycles
+
+    ubyte adFlags;         // control re-assignment of AliasDeclaration (put here for packing reasons)
+      enum wasRead    = 1; // set if AliasDeclaration was read
+      enum ignoreRead = 2; // ignore any reads of AliasDeclaration
 
     // overridden symbol with pragma(mangle, "...")
     const(char)[] mangleOverride;
@@ -305,13 +238,13 @@ extern (C++) abstract class Declaration : Dsymbol
     final extern (D) this(Identifier ident)
     {
         super(ident);
-        protection = Prot(Prot.Kind.undefined);
+        visibility = Visibility(Visibility.Kind.undefined);
     }
 
     final extern (D) this(const ref Loc loc, Identifier ident)
     {
         super(loc, ident);
-        protection = Prot(Prot.Kind.undefined);
+        visibility = Visibility(Visibility.Kind.undefined);
     }
 
     override const(char)* kind() const
@@ -347,11 +280,42 @@ extern (C++) abstract class Declaration : Dsymbol
         if (sc.func && sc.func.storage_class & STC.disable)
             return true;
 
-        auto p = toParent();
-        if (p && isPostBlitDeclaration())
+        if (auto p = toParent())
         {
-            p.error(loc, "is not copyable because it is annotated with `@disable`");
-            return true;
+            if (auto postblit = isPostBlitDeclaration())
+            {
+                /* https://issues.dlang.org/show_bug.cgi?id=21885
+                 *
+                 * If the generated postblit is disabled, it
+                 * means that one of the fields has a disabled
+                 * postblit. Print the first field that has
+                 * a disabled postblit.
+                 */
+                if (postblit.generated)
+                {
+                    auto sd = p.isStructDeclaration();
+                    assert(sd);
+                    for (size_t i = 0; i < sd.fields.dim; i++)
+                    {
+                        auto structField = sd.fields[i];
+                        if (structField.overlapped)
+                            continue;
+                        Type tv = structField.type.baseElemOf();
+                        if (tv.ty != Tstruct)
+                            continue;
+                        auto sdv = (cast(TypeStruct)tv).sym;
+                        if (!sdv.postblit)
+                            continue;
+                        if (sdv.postblit.isDisabled())
+                        {
+                            p.error(loc, "is not copyable because field `%s` is not copyable", structField.toChars());
+                            return true;
+                        }
+                    }
+                }
+                p.error(loc, "is not copyable because it has a disabled postblit");
+                return true;
+            }
         }
 
         // if the function is @disabled, maybe there
@@ -418,7 +382,7 @@ extern (C++) abstract class Declaration : Dsymbol
                 if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
                 {
                     if (!flag)
-                        error(loc, "cannot modify parameter 'this' in contract");
+                        error(loc, "cannot modify parameter `this` in contract");
                     return Modifiable.initialization; // do not report type related errors
                 }
             }
@@ -567,9 +531,9 @@ extern (C++) abstract class Declaration : Dsymbol
         return (storage_class & STC.future) != 0;
     }
 
-    override final Prot prot() pure nothrow @nogc @safe
+    override final Visibility visible() pure nothrow @nogc @safe
     {
-        return protection;
+        return visibility;
     }
 
     override final inout(Declaration) isDeclaration() inout
@@ -597,7 +561,7 @@ extern (C++) final class TupleDeclaration : Declaration
         this.objects = objects;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override TupleDeclaration syntaxCopy(Dsymbol s)
     {
         assert(0);
     }
@@ -743,7 +707,7 @@ extern (C++) final class AliasDeclaration : Declaration
         return new AliasDeclaration(loc, id, type);
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override AliasDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("AliasDeclaration::syntaxCopy()\n");
         assert(!s);
@@ -786,18 +750,22 @@ extern (C++) final class AliasDeclaration : Declaration
              * aliassym is determined already. See the case in: test/compilable/test61.d
              */
             auto sa = aliassym.toAlias();
+
+            if (auto td = s.toAlias().isTemplateDeclaration())
+                s = td.funcroot ? td.funcroot : td;
+
             if (auto fd = sa.isFuncDeclaration())
             {
                 auto fa = new FuncAliasDeclaration(ident, fd);
-                fa.protection = protection;
+                fa.visibility = visibility;
                 fa.parent = parent;
                 aliassym = fa;
                 return aliassym.overloadInsert(s);
             }
             if (auto td = sa.isTemplateDeclaration())
             {
-                auto od = new OverDeclaration(ident, td);
-                od.protection = protection;
+                auto od = new OverDeclaration(ident, td.funcroot ? td.funcroot : td);
+                od.visibility = visibility;
                 od.parent = parent;
                 aliassym = od;
                 return aliassym.overloadInsert(s);
@@ -807,7 +775,7 @@ extern (C++) final class AliasDeclaration : Declaration
                 if (sa.ident != ident || sa.parent != parent)
                 {
                     od = new OverDeclaration(ident, od);
-                    od.protection = protection;
+                    od.visibility = visibility;
                     od.parent = parent;
                     aliassym = od;
                 }
@@ -818,7 +786,7 @@ extern (C++) final class AliasDeclaration : Declaration
                 if (sa.ident != ident || sa.parent != parent)
                 {
                     os = new OverloadSet(ident, os);
-                    // TODO: protection is lost here b/c OverloadSets have no protection attribute
+                    // TODO: visibility is lost here b/c OverloadSets have no visibility attribute
                     // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow.
                     // ----
                     // module os1;
@@ -833,7 +801,7 @@ extern (C++) final class AliasDeclaration : Declaration
                     // import os1, os2;
                     // void test() { merged(123); } // should only look at os2.merged
                     //
-                    // os.protection = protection;
+                    // os.visibility = visibility;
                     os.parent = parent;
                     aliassym = os;
                 }
@@ -872,6 +840,11 @@ extern (C++) final class AliasDeclaration : Declaration
         //    loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse);
         assert(this != aliassym);
         //static int count; if (++count == 10) *(char*)0=0;
+
+        // Reading the AliasDeclaration
+        if (!(adFlags & ignoreRead))
+            adFlags |= wasRead;                 // can never assign to this AliasDeclaration again
+
         if (inuse == 1 && type && _scope)
         {
             inuse = 2;
@@ -986,23 +959,11 @@ extern (C++) final class OverDeclaration : Declaration
 {
     Dsymbol overnext;   // next in overload list
     Dsymbol aliassym;
-    bool hasOverloads;
 
-    extern (D) this(Identifier ident, Dsymbol s, bool hasOverloads = true)
+    extern (D) this(Identifier ident, Dsymbol s)
     {
         super(ident);
         this.aliassym = s;
-        this.hasOverloads = hasOverloads;
-        if (hasOverloads)
-        {
-            if (OverDeclaration od = aliassym.isOverDeclaration())
-                this.hasOverloads = od.hasOverloads;
-        }
-        else
-        {
-            // for internal use
-            assert(!aliassym.isOverDeclaration());
-        }
     }
 
     override const(char)* kind() const
@@ -1019,25 +980,9 @@ extern (C++) final class OverDeclaration : Declaration
         if (!s)
             return false;
 
-        auto od1 = this;
         if (auto od2 = s.isOverDeclaration())
-        {
-            return od1.aliassym.equals(od2.aliassym) && od1.hasOverloads == od2.hasOverloads;
-        }
-        if (aliassym == s)
-        {
-            if (hasOverloads)
-                return true;
-            if (auto fd = s.isFuncDeclaration())
-            {
-                return fd.isUnique();
-            }
-            if (auto td = s.isTemplateDeclaration())
-            {
-                return td.overnext is null;
-            }
-        }
-        return false;
+            return this.aliassym.equals(od2.aliassym);
+        return this.aliassym == s;
     }
 
     override bool overloadInsert(Dsymbol s)
@@ -1058,15 +1003,6 @@ extern (C++) final class OverDeclaration : Declaration
 
     Dsymbol isUnique()
     {
-        if (!hasOverloads)
-        {
-            if (aliassym.isFuncDeclaration() ||
-                aliassym.isTemplateDeclaration())
-            {
-                return aliassym;
-            }
-        }
-
         Dsymbol result = null;
         overloadApply(aliassym, (Dsymbol s)
         {
@@ -1100,11 +1036,24 @@ extern (C++) final class OverDeclaration : Declaration
 extern (C++) class VarDeclaration : Declaration
 {
     Initializer _init;
+    FuncDeclarations nestedrefs;    // referenced by these lexically nested functions
+    Dsymbol aliassym;               // if redone as alias to another symbol
+    VarDeclaration lastVar;         // Linked list of variables for goto-skips-init detection
+    Expression edtor;               // if !=null, does the destruction of the variable
+    IntRange* range;                // if !=null, the variable is known to be within the range
+    VarDeclarations* maybes;        // STC.maybescope variables that are assigned to this STC.maybescope variable
+
+    uint endlinnum;                 // line number of end of scope that this var lives in
     uint offset;
     uint sequenceNumber;            // order the variables are declared
     __gshared uint nextSequenceNumber;   // the counter for sequenceNumber
-    FuncDeclarations nestedrefs;    // referenced by these lexically nested functions
     structalign_t alignment;
+
+    // When interpreting, these point to the value (NULL if value not determinable)
+    // The index of this variable on the CTFE stack, AdrOnStackNone if not allocated
+    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
@@ -1121,19 +1070,8 @@ extern (C++) class VarDeclaration : Declaration
     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
-    Dsymbol aliassym;               // if redone as alias to another symbol
-    VarDeclaration lastVar;         // Linked list of variables for goto-skips-init detection
-    uint endlinnum;                 // line number of end of scope that this var lives in
-
-    // When interpreting, these point to the value (NULL if value not determinable)
-    // The index of this variable on the CTFE stack, AdrOnStackNone if not allocated
-    enum AdrOnStackNone = ~0u;
-    uint ctfeAdrOnStack;
-
-    Expression edtor;               // if !=null, does the destruction of the variable
-    IntRange* range;                // if !=null, the variable is known to be within the range
 
-    VarDeclarations* maybes;        // STC.maybescope variables that are assigned to this STC.maybescope variable
+    bool isArgDtorVar;              // temporary created to handle scope destruction of a function argument
 
     final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
     in
@@ -1166,7 +1104,7 @@ extern (C++) class VarDeclaration : Declaration
         return new VarDeclaration(loc, type, ident, _init, storage_class);
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override VarDeclaration syntaxCopy(Dsymbol s)
     {
         //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
         assert(!s);
@@ -1293,12 +1231,12 @@ extern (C++) class VarDeclaration : Declaration
 
     override final bool isExport() const
     {
-        return protection.kind == Prot.Kind.export_;
+        return visibility.kind == Visibility.Kind.export_;
     }
 
     override final bool isImportedSymbol() const
     {
-        if (protection.kind == Prot.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule()))
+        if (visibility.kind == Visibility.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule()))
             return true;
         return false;
     }
@@ -1479,14 +1417,22 @@ extern (C++) class VarDeclaration : Declaration
                 //if (cd.isInterfaceDeclaration())
                 //    error("interface `%s` cannot be scope", cd.toChars());
 
-                // Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them.
-                // See https://issues.dlang.org/show_bug.cgi?id=13182
-                if (cd.classKind == ClassKind.cpp)
-                {
-                    break;
-                }
                 if (mynew || onstack) // if any destructors
                 {
+                    // delete'ing C++ classes crashes (and delete is deprecated anyway)
+                    if (cd.classKind == ClassKind.cpp)
+                    {
+                        // Don't call non-existant dtor
+                        if (!cd.dtor)
+                            break;
+
+                        e = new VarExp(loc, this);
+                        e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
+                        e = new DotVarExp(loc, e, cd.dtor, false);
+                        e = new CallExp(loc, e);
+                        break;
+                    }
+
                     // delete this;
                     Expression ec;
                     ec = new VarExp(loc, this);
@@ -1668,7 +1614,37 @@ extern (C++) class VarDeclaration : Declaration
      */
     final bool enclosesLifetimeOf(VarDeclaration v) const pure
     {
-        return sequenceNumber < v.sequenceNumber;
+        // 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))
+        {
+            // FIXME: VarDeclaration's for parameters are created in semantic3, so
+            //        they will have a greater sequence number than local variables.
+            //        Hence reverse the result for mixed comparisons.
+            const exp = this.isParameter() == v.isParameter();
+
+            return (this.sequenceNumber < v.sequenceNumber) == exp;
+        }
+
+        // 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 (auto ld = this.loc.linnum - v.loc.linnum)
+            return ld < 0;
+
+        if (auto cd = this.loc.charnum - v.loc.charnum)
+            return cd < 0;
+
+        // Default fallback
+        return this.sequenceNumber < v.sequenceNumber;
     }
 
     /***************************************
@@ -1726,7 +1702,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
         super(Loc.initial, Type.dtypeinfo.type, tinfo.getTypeInfoIdent(), null);
         this.tinfo = tinfo;
         storage_class = STC.static_ | STC.gshared;
-        protection = Prot(Prot.Kind.public_);
+        visibility = Visibility(Visibility.Kind.public_);
         linkage = LINK.c;
         alignment = target.ptrsize;
     }
@@ -1736,7 +1712,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
         return new TypeInfoDeclaration(tinfo);
     }
 
-    override final Dsymbol syntaxCopy(Dsymbol s)
+    override final TypeInfoDeclaration syntaxCopy(Dsymbol s)
     {
         assert(0); // should never be produced by syntax
     }
@@ -2173,7 +2149,7 @@ extern (C++) final class ThisDeclaration : VarDeclaration
         storage_class |= STC.nodtor;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override ThisDeclaration syntaxCopy(Dsymbol s)
     {
         assert(0); // should never be produced by syntax
     }
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 2b32e2caf1e..58f72c6e7a0 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -87,6 +87,8 @@ struct IntRange;
 #define STCfuture        0x4000000000000ULL // introducing new base class function
 #define STClocal         0x8000000000000ULL // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
 #define STCreturninferred 0x10000000000000ULL   // 'return' has been inferred and should not be part of mangling
+#define STClive          0x20000000000000ULL   // function @live attribute
+#define STCregister      0x40000000000000ULL   // `register` storage class
 
 void ObjectNotFound(Identifier *id);
 
@@ -98,9 +100,10 @@ public:
     Type *type;
     Type *originalType;         // before semantic analysis
     StorageClass storage_class;
-    Prot protection;
+    Visibility visibility;
     LINK linkage;
-    int inuse;                  // used to detect cycles
+    short inuse;                // used to detect cycles
+    uint8_t adFlags;
     DString mangleOverride;     // overridden symbol with pragma(mangle, "...")
 
     const char *kind() const;
@@ -134,7 +137,7 @@ public:
 
     bool isFuture() const { return (storage_class & STCfuture) != 0; }
 
-    Prot prot();
+    Visibility visible();
 
     Declaration *isDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
@@ -150,7 +153,7 @@ public:
 
     TypeTuple *tupletype;       // !=NULL if this is a type tuple
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    TupleDeclaration *syntaxCopy(Dsymbol *);
     const char *kind() const;
     Type *getType();
     Dsymbol *toAlias2();
@@ -170,7 +173,7 @@ public:
     Dsymbol *_import;           // !=NULL if unresolved internal alias for selective import
 
     static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
-    Dsymbol *syntaxCopy(Dsymbol *);
+    AliasDeclaration *syntaxCopy(Dsymbol *);
     bool overloadInsert(Dsymbol *s);
     const char *kind() const;
     Type *getType();
@@ -189,7 +192,6 @@ class OverDeclaration : public Declaration
 public:
     Dsymbol *overnext;          // next in overload list
     Dsymbol *aliassym;
-    bool hasOverloads;
 
     const char *kind() const;
     bool equals(const RootObject *o) const;
@@ -209,10 +211,22 @@ class VarDeclaration : public Declaration
 {
 public:
     Initializer *_init;
+    FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+    Dsymbol *aliassym;          // if redone as alias to another symbol
+    VarDeclaration *lastVar;    // Linked list of variables for goto-skips-init detection
+    Expression *edtor;          // if !=NULL, does the destruction of the variable
+    IntRange *range;            // if !NULL, the variable is known to be within the range
+    VarDeclarations *maybes;    // STCmaybescope variables that are assigned to this STCmaybescope variable
+
+    unsigned endlinnum;         // line number of end of scope that this var lives in
     unsigned offset;
     unsigned sequenceNumber;     // order the variables are declared
-    FuncDeclarations nestedrefs; // referenced by these lexically nested functions
     structalign_t alignment;
+
+    // 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
@@ -225,21 +239,11 @@ public:
     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
-    Dsymbol *aliassym;          // if redone as alias to another symbol
-    VarDeclaration *lastVar;    // Linked list of variables for goto-skips-init detection
-    unsigned endlinnum;         // line number of end of scope that this var lives in
-
-    // When interpreting, these point to the value (NULL if value not determinable)
-    // The index of this variable on the CTFE stack, ~0u if not allocated
-    unsigned ctfeAdrOnStack;
-    Expression *edtor;          // if !=NULL, does the destruction of the variable
-    IntRange *range;            // if !NULL, the variable is known to be within the range
-
-    VarDeclarations *maybes;    // STCmaybescope variables that are assigned to this STCmaybescope variable
+    bool isArgDtorVar;          // temporary created to handle scope destruction of a function argument
 
 public:
     static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
-    Dsymbol *syntaxCopy(Dsymbol *);
+    VarDeclaration *syntaxCopy(Dsymbol *);
     void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
     const char *kind() const;
     AggregateDeclaration *isThis();
@@ -281,7 +285,7 @@ public:
     Type *tinfo;
 
     static TypeInfoDeclaration *create(Type *tinfo);
-    Dsymbol *syntaxCopy(Dsymbol *);
+    TypeInfoDeclaration *syntaxCopy(Dsymbol *);
     const char *toChars() const;
 
     TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
@@ -421,12 +425,12 @@ public:
 class ThisDeclaration : public VarDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    ThisDeclaration *syntaxCopy(Dsymbol *);
     ThisDeclaration *isThisDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
 };
 
-enum ILS
+enum class ILS : unsigned char
 {
     ILSuninitialized,   // not computed yet
     ILSno,              // cannot inline
@@ -584,7 +588,7 @@ public:
     ObjcFuncDeclaration objc;
 
     static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type);
-    Dsymbol *syntaxCopy(Dsymbol *);
+    FuncDeclaration *syntaxCopy(Dsymbol *);
     bool functionSemantic();
     bool functionSemantic3();
     bool equals(const RootObject *o) const;
@@ -595,7 +599,7 @@ public:
     bool overloadInsert(Dsymbol *s);
     bool inUnittest();
     MATCH leastAsSpecialized(FuncDeclaration *g);
-    LabelDsymbol *searchLabel(Identifier *ident);
+    LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
     int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference
     int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd);
     const char *toPrettyChars(bool QualifyTypes = false);
@@ -635,7 +639,7 @@ public:
     static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
     static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
 
-    bool checkNrvo();
+    bool checkNRVO();
 
     FuncDeclaration *isFuncDeclaration() { return this; }
 
@@ -665,7 +669,7 @@ public:
     // backend
     bool deferToObj;
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    FuncLiteralDeclaration *syntaxCopy(Dsymbol *);
     bool isNested() const;
     AggregateDeclaration *isThis();
     bool isVirtual() const;
@@ -684,7 +688,7 @@ class CtorDeclaration : public FuncDeclaration
 {
 public:
     bool isCpCtor;
-    Dsymbol *syntaxCopy(Dsymbol *);
+    CtorDeclaration *syntaxCopy(Dsymbol *);
     const char *kind() const;
     const char *toChars() const;
     bool isVirtual() const;
@@ -698,7 +702,7 @@ public:
 class PostBlitDeclaration : public FuncDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    PostBlitDeclaration *syntaxCopy(Dsymbol *);
     bool isVirtual() const;
     bool addPreInvariant();
     bool addPostInvariant();
@@ -711,7 +715,7 @@ public:
 class DtorDeclaration : public FuncDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    DtorDeclaration *syntaxCopy(Dsymbol *);
     const char *kind() const;
     const char *toChars() const;
     bool isVirtual() const;
@@ -726,7 +730,7 @@ public:
 class StaticCtorDeclaration : public FuncDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    StaticCtorDeclaration *syntaxCopy(Dsymbol *);
     AggregateDeclaration *isThis();
     bool isVirtual() const;
     bool addPreInvariant();
@@ -740,7 +744,7 @@ public:
 class SharedStaticCtorDeclaration : public StaticCtorDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *);
 
     SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
@@ -751,7 +755,7 @@ class StaticDtorDeclaration : public FuncDeclaration
 public:
     VarDeclaration *vgate;      // 'gate' variable
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    StaticDtorDeclaration *syntaxCopy(Dsymbol *);
     AggregateDeclaration *isThis();
     bool isVirtual() const;
     bool hasStaticCtorOrDtor();
@@ -765,7 +769,7 @@ public:
 class SharedStaticDtorDeclaration : public StaticDtorDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *);
 
     SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
@@ -774,7 +778,7 @@ public:
 class InvariantDeclaration : public FuncDeclaration
 {
 public:
-    Dsymbol *syntaxCopy(Dsymbol *);
+    InvariantDeclaration *syntaxCopy(Dsymbol *);
     bool isVirtual() const;
     bool addPreInvariant();
     bool addPostInvariant();
@@ -791,7 +795,7 @@ public:
     // toObjFile() these nested functions after this one
     FuncDeclarations deferredNested;
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    UnitTestDeclaration *syntaxCopy(Dsymbol *);
     AggregateDeclaration *isThis();
     bool isVirtual() const;
     bool addPreInvariant();
@@ -807,7 +811,7 @@ public:
     Parameters *parameters;
     VarArg varargs;
 
-    Dsymbol *syntaxCopy(Dsymbol *);
+    NewDeclaration *syntaxCopy(Dsymbol *);
     const char *kind() const;
     bool isVirtual() const;
     bool addPreInvariant();
diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d
index 3aa4f84ce9f..07c1bbda650 100644
--- a/gcc/d/dmd/delegatize.d
+++ b/gcc/d/dmd/delegatize.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d)
@@ -15,6 +15,7 @@ module dmd.delegatize;
 
 import core.stdc.stdio;
 import dmd.apply;
+import dmd.astenums;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index 95197a4e6c6..2d449af9f7d 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d)
@@ -50,7 +50,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
     Type type;              // the TypeEnum
     Type memtype;           // type of the members
 
-    Prot protection;
+    Visibility visibility;
     Expression maxval;
     Expression minval;
     Expression defaultval;  // default initializer
@@ -64,14 +64,15 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
         //printf("EnumDeclaration() %s\n", toChars());
         type = new TypeEnum(this);
         this.memtype = memtype;
-        protection = Prot(Prot.Kind.undefined);
+        visibility = Visibility(Visibility.Kind.undefined);
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override EnumDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
         auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null);
-        return ScopeDsymbol.syntaxCopy(ed);
+        ScopeDsymbol.syntaxCopy(ed);
+        return ed;
     }
 
     override void addMember(Scope* sc, ScopeDsymbol sds)
@@ -85,29 +86,12 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
                 printf("    member %s\n", em.toChars());
             }
         }
-
-        /* Anonymous enum members get added to enclosing scope.
-         */
-        ScopeDsymbol scopesym = isAnonymous() ? sds : this;
-
         if (!isAnonymous())
         {
             ScopeDsymbol.addMember(sc, sds);
-            if (!symtab)
-                symtab = new DsymbolTable();
         }
 
-        if (members)
-        {
-            for (size_t i = 0; i < members.dim; i++)
-            {
-                EnumMember em = (*members)[i].isEnumMember();
-                em.ed = this;
-                //printf("add %s to scope %s\n", em.toChars(), scopesym.toChars());
-                em.addMember(sc, isAnonymous() ? scopesym : this);
-            }
-        }
-        added = true;
+        addEnumMembers(this, sc, sds);
     }
 
     override void setScope(Scope* sc)
@@ -143,13 +127,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
             dsymbolSemantic(this, _scope);
         }
 
-        if (!members || !symtab || _scope)
-        {
-            error("is forward referenced when looking for `%s`", ident.toChars());
-            //*(char*)0=0;
-            return null;
-        }
-
         Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
         return s;
     }
@@ -160,9 +137,9 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
         return isdeprecated;
     }
 
-    override Prot prot() pure nothrow @nogc @safe
+    override Visibility visible() pure nothrow @nogc @safe
     {
-        return protection;
+        return visibility;
     }
 
     /******************************
@@ -209,7 +186,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
             dsymbolSemantic(this, _scope);
         if (errors)
             return errorReturn();
-        if (semanticRun == PASS.init || !members)
+        if (!members)
         {
             if (isSpecial())
             {
@@ -218,7 +195,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
                 return memtype.getProperty(_scope, loc, id, 0);
             }
 
-            error("is forward referenced looking for `.%s`", id.toChars());
+            error(loc, "is opaque and has no `.%s`", id.toChars());
             return errorReturn();
         }
         if (!(memtype && memtype.isintegral()))
@@ -239,6 +216,13 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
                 continue;
             }
 
+            if (em.semanticRun < PASS.semanticdone)
+            {
+                em.error("is forward referenced looking for `.%s`", id.toChars());
+                errors = true;
+                continue;
+            }
+
             if (first)
             {
                 *pval = em.value;
@@ -298,16 +282,16 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
             dsymbolSemantic(this, _scope);
         if (errors)
             return handleErrors();
-        if (semanticRun == PASS.init || !members)
+        if (!members)
         {
             if (isSpecial())
             {
                 /* Allow these special enums to not need a member list
                  */
-                return memtype.defaultInit(loc);
+                return defaultval = memtype.defaultInit(loc);
             }
 
-            error(loc, "forward reference of `%s.init`", toChars());
+            error(loc, "is opaque and has no default initializer");
             return handleErrors();
         }
 
@@ -316,6 +300,12 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
             EnumMember em = (*members)[i].isEnumMember();
             if (em)
             {
+                if (em.semanticRun < PASS.semanticdone)
+                {
+                    error(loc, "forward reference of `%s.init`", toChars());
+                    return handleErrors();
+                }
+
                 defaultval = em.value;
                 return defaultval;
             }
@@ -337,13 +327,13 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
             }
             else
             {
-                if (!isAnonymous() && members)
-                    memtype = Type.tint32;
+                // Run semantic to get the type from a possible first member value
+                dsymbolSemantic(this, _scope);
             }
         }
         if (!memtype)
         {
-            if (!isAnonymous() && members)
+            if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone))
                 memtype = Type.tint32;
             else
             {
@@ -407,7 +397,7 @@ extern (C++) final class EnumMember : VarDeclaration
         depdecl = dd;
     }
 
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override EnumMember syntaxCopy(Dsymbol s)
     {
         assert(!s);
         return new EnumMember(
@@ -415,8 +405,8 @@ extern (C++) final class EnumMember : VarDeclaration
             value ? value.syntaxCopy() : null,
             origType ? origType.syntaxCopy() : null,
             storage_class,
-            userAttribDecl ? cast(UserAttributeDeclaration)userAttribDecl.syntaxCopy(s) : null,
-            depdecl ? cast(DeprecatedDeclaration)depdecl.syntaxCopy(s) : null);
+            userAttribDecl ? userAttribDecl.syntaxCopy(s) : null,
+            depdecl ? depdecl.syntaxCopy(s) : null);
     }
 
     override const(char)* kind() const
@@ -469,5 +459,8 @@ bool isSpecialEnumIdent(const Identifier ident) @nogc nothrow
             ident == Id.__c_longlong ||
             ident == Id.__c_ulonglong ||
             ident == Id.__c_long_double ||
-            ident == Id.__c_wchar_t;
+            ident == Id.__c_wchar_t ||
+            ident == Id.__c_complex_float ||
+            ident == Id.__c_complex_double ||
+            ident == Id.__c_complex_real;
 }
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 31947645542..8cd436422ee 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -1,7 +1,7 @@
 /**
  * A `Dsymbol` representing a renamed import.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d)
@@ -12,6 +12,7 @@
 module dmd.dimport;
 
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.declaration;
 import dmd.dmodule;
 import dmd.dscope;
@@ -22,7 +23,6 @@ import dmd.expression;
 import dmd.globals;
 import dmd.identifier;
 import dmd.mtype;
-import dmd.root.rmem;
 import dmd.visitor;
 
 /***********************************************************
@@ -31,11 +31,11 @@ extern (C++) final class Import : Dsymbol
 {
     /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
      */
-    Identifiers* packages;  // array of Identifier's representing packages
+    Identifier[] packages;  // array of Identifier's representing packages
     Identifier id;          // module Identifier
     Identifier aliasId;
     int isstatic;           // !=0 if static import
-    Prot protection;
+    Visibility visibility;
 
     // Pairs of alias=name to bind into current namespace
     Identifiers names;
@@ -47,7 +47,7 @@ extern (C++) final class Import : Dsymbol
     // corresponding AliasDeclarations for alias=name pairs
     AliasDeclarations aliasdecls;
 
-    extern (D) this(const ref Loc loc, Identifiers* packages, Identifier id, Identifier aliasId, int isstatic)
+    extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic)
     {
         Identifier selectIdent()
         {
@@ -57,10 +57,10 @@ extern (C++) final class Import : Dsymbol
                 // import [aliasId] = std.stdio;
                 return aliasId;
             }
-            else if (packages && packages.dim)
+            else if (packages.length > 0)
             {
                 // import [std].stdio;
-                return (*packages)[0];
+                return packages[0];
             }
             else
             {
@@ -75,13 +75,9 @@ extern (C++) final class Import : Dsymbol
         version (none)
         {
             printf("Import::Import(");
-            if (packages && packages.dim)
+            foreach (id; packages)
             {
-                for (size_t i = 0; i < packages.dim; i++)
-                {
-                    Identifier id = (*packages)[i];
-                    printf("%s.", id.toChars());
-                }
+                printf("%s.", id.toChars());
             }
             printf("%s)\n", id.toChars());
         }
@@ -89,7 +85,7 @@ extern (C++) final class Import : Dsymbol
         this.id = id;
         this.aliasId = aliasId;
         this.isstatic = isstatic;
-        this.protection = Prot.Kind.private_; // default to private
+        this.visibility = Visibility.Kind.private_; // default to private
     }
 
     extern (D) void addAlias(Identifier name, Identifier _alias)
@@ -107,13 +103,13 @@ extern (C++) final class Import : Dsymbol
         return isstatic ? "static import" : "import";
     }
 
-    override Prot prot() pure nothrow @nogc @safe
+    override Visibility visible() pure nothrow @nogc @safe
     {
-        return protection;
+        return visibility;
     }
 
     // copy only syntax trees
-    override Dsymbol syntaxCopy(Dsymbol s)
+    override Import syntaxCopy(Dsymbol s)
     {
         assert(!s);
         auto si = new Import(loc, packages, id, aliasId, isstatic);
@@ -234,12 +230,45 @@ extern (C++) final class Import : Dsymbol
             isstatic = true;
         mod.importAll(null);
         mod.checkImportDeprecation(loc, sc);
-        if (sc.explicitProtection)
-            protection = sc.protection;
+        if (sc.explicitVisibility)
+            visibility = sc.visibility;
         if (!isstatic && !aliasId && !names.dim)
-            sc.scopesym.importScope(mod, protection);
+            sc.scopesym.importScope(mod, visibility);
+        // Enable access to pkgs/mod as soon as posible, because compiler
+        // can traverse them before the import gets semantic (Issue: 21501)
+        if (!aliasId && !names.dim)
+            addPackageAccess(sc.scopesym);
     }
 
+    /*******************************
+     * Mark the imported packages as accessible from the current
+     * scope. This access check is necessary when using FQN b/c
+     * we're using a single global package tree.
+     * https://issues.dlang.org/show_bug.cgi?id=313
+     */
+    extern (D) void addPackageAccess(ScopeDsymbol scopesym)
+    {
+        //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
+        if (packages.length > 0)
+        {
+            // import a.b.c.d;
+            auto p = pkg; // a
+            scopesym.addAccessiblePackage(p, visibility);
+            foreach (id; packages[1 .. $]) // [b, c]
+            {
+                p = cast(Package) p.symtab.lookup(id);
+                // https://issues.dlang.org/show_bug.cgi?id=17991
+                // An import of truly empty file/package can happen
+                // https://issues.dlang.org/show_bug.cgi?id=20151
+                // Package in the path conflicts with a module name
+                if (p is null)
+                    break;
+                scopesym.addAccessiblePackage(p, visibility);
+            }
+        }
+        scopesym.addAccessiblePackage(mod, visibility); // d
+     }
+
     override Dsymbol toAlias()
     {
         if (aliasId)
@@ -266,7 +295,7 @@ extern (C++) final class Import : Dsymbol
             Identifier _alias = aliases[i];
             if (!_alias)
                 _alias = name;
-            auto tname = Pool!TypeIdentifier.make(loc, name);
+            auto tname = new TypeIdentifier(loc, name);
             auto ad = new AliasDeclaration(loc, _alias, tname);
             ad._import = this;
             ad.addMember(sc, sd);
@@ -283,7 +312,7 @@ extern (C++) final class Import : Dsymbol
                 importAll(sc);
 
             sc = sc.push(mod);
-            sc.protection = protection;
+            sc.visibility = visibility;
             foreach (ad; aliasdecls)
                 ad.setScope(sc);
             sc = sc.pop();
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 78e5777bf05..853758a7197 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -3,7 +3,7 @@
  *
  * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
@@ -18,6 +18,7 @@ import core.stdc.stdlib;
 import core.stdc.string;
 import dmd.apply;
 import dmd.arraytypes;
+import dmd.astenums;
 import dmd.attrib;
 import dmd.builtin;
 import dmd.constfold;
@@ -38,6 +39,7 @@ import dmd.identifier;
 import dmd.init;
 import dmd.initsem;
 import dmd.mtype;
+import dmd.printast;
 import dmd.root.rmem;
 import dmd.root.array;
 import dmd.root.region;
@@ -70,6 +72,10 @@ public Expression ctfeInterpret(Expression e)
         case TOK.super_:
         case TOK.type:
         case TOK.typeid_:
+        case TOK.template_:              // non-eponymous template/instance
+        case TOK.scope_:                 // ditto
+        case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+        case TOK.dot:                    // ditto
              if (e.type.ty == Terror)
                 return ErrorExp.get();
             goto case TOK.error;
@@ -308,6 +314,7 @@ public:
 
     extern (C++) Expression getValue(VarDeclaration v)
     {
+        //printf("getValue() %s\n", v.toChars());
         if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
         {
             assert(v.ctfeAdrOnStack < globalValues.dim);
@@ -319,6 +326,7 @@ public:
 
     extern (C++) void setValue(VarDeclaration v, Expression e)
     {
+        //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
         assert(!v.isDataseg() || v.isCTFE());
         assert(v.ctfeAdrOnStack < stackPointer());
         values[v.ctfeAdrOnStack] = e;
@@ -326,6 +334,7 @@ public:
 
     extern (C++) void push(VarDeclaration v)
     {
+        //printf("push() %s\n", v.toChars());
         assert(!v.isDataseg() || v.isCTFE());
         if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
         {
@@ -417,11 +426,12 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
     if (!fd.functionSemantic3())
         return CTFEExp.cantexp;
     if (fd.semanticRun < PASS.semantic3done)
+    {
+        fd.error("circular dependency. Functions cannot be interpreted while being compiled");
         return CTFEExp.cantexp;
+    }
 
-    Type tb = fd.type.toBasetype();
-    assert(tb.ty == Tfunction);
-    TypeFunction tf = cast(TypeFunction)tb;
+    auto tf = fd.type.toBasetype().isTypeFunction();
     if (tf.parameterList.varargs != VarArg.none && arguments &&
         ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
     {
@@ -498,11 +508,11 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
             if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
                 earg = copyLiteral(earg).copy();
         }
-        if (earg.op == TOK.thrownException)
+        if (auto tee = earg.isThrownExceptionExp())
         {
             if (istate)
-                return earg;
-            (cast(ThrownExceptionExp)earg).generateUncaughtError();
+                return tee;
+            tee.generateUncaughtError();
             return CTFEExp.cantexp;
         }
         eargs[i] = earg;
@@ -552,9 +562,9 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
         ctfeGlobals.stack.push(v);
 
         if (fparam.isReference() && earg.op == TOK.variable &&
-            (cast(VarExp)earg).var.toParent2() == fd)
+            earg.isVarExp().var.toParent2() == fd)
         {
-            VarDeclaration vx = (cast(VarExp)earg).var.isVarDeclaration();
+            VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
             if (!vx)
             {
                 fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
@@ -655,23 +665,22 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
     // If fell off the end of a void function, return void
     if (!e && tf.next.ty == Tvoid)
         e = CTFEExp.voidexp;
-    if (tf.isref && e.op == TOK.variable && (cast(VarExp)e).var == fd.vthis)
+    if (tf.isref && e.op == TOK.variable && e.isVarExp().var == fd.vthis)
         e = thisarg;
     if (tf.isref && fd.isThis2 && e.op == TOK.index)
     {
-        auto ie = cast(IndexExp)e;
+        auto ie = e.isIndexExp();
         auto pe = ie.e1.isPtrExp();
         auto ve = !pe ?  null : pe.e1.isVarExp();
         if (ve && ve.var == fd.vthis)
         {
             auto ne = ie.e2.isIntegerExp();
             assert(ne);
-            assert(thisarg.op == TOK.address);
-            e = (cast(AddrExp)thisarg).e1;
-            e = (*(cast(ArrayLiteralExp)e).elements)[cast(size_t)ne.getInteger()];
-            if (e.op == TOK.address)
+            auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
+            e = (*ale.elements)[cast(size_t)ne.getInteger()];
+            if (auto ae = e.isAddrExp())
             {
-                e = (cast(AddrExp)e).e1;
+                e = ae.e1;
             }
         }
     }
@@ -683,11 +692,11 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
     ctfeGlobals.stack.endFrame();
 
     // If it generated an uncaught exception, report error.
-    if (!istate && e.op == TOK.thrownException)
+    if (!istate && e.isThrownExceptionExp())
     {
         if (e == pue.exp())
             e = pue.copy();
-        (cast(ThrownExceptionExp)e).generateUncaughtError();
+        e.isThrownExceptionExp().generateUncaughtError();
         e = CTFEExp.cantexp;
     }
 
@@ -1432,9 +1441,9 @@ public:
         Expression e = interpret(s._body, istate);
 
         // An exception was thrown
-        if (e && e.op == TOK.thrownException)
+        if (e && e.isThrownExceptionExp())
         {
-            ThrownExceptionExp ex = cast(ThrownExceptionExp)e;
+            ThrownExceptionExp ex = e.isThrownExceptionExp();
             Type extype = ex.thrown.originalClass().type;
 
             // Search for an appropriate catch clause.
@@ -1565,11 +1574,11 @@ public:
             result = ey;
             return;
         }
-        if (ey && ey.op == TOK.thrownException)
+        if (ey && ey.isThrownExceptionExp())
         {
             // Check for collided exceptions
-            if (ex && ex.op == TOK.thrownException)
-                ex = chainExceptions(cast(ThrownExceptionExp)ex, cast(ThrownExceptionExp)ey);
+            if (ex && ex.isThrownExceptionExp())
+                ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
             else
                 ex = ey;
         }
@@ -2086,6 +2095,7 @@ public:
                     e = v._init.initializerToExpression();
                 }
                 else
+                    // Zero-length arrays don't have an initializer
                     e = v.type.defaultInitLiteral(e.loc);
 
                 e = interpret(e, istate);
@@ -2098,17 +2108,23 @@ public:
             else
             {
                 e = hasValue(v) ? getValue(v) : null;
-                if (!e && !v.isCTFE() && v.isDataseg())
-                {
-                    error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
-                    return CTFEExp.cantexp;
-                }
                 if (!e)
                 {
-                    assert(!(v._init && v._init.isVoidInitializer()));
-                    // CTFE initiated from inside a function
-                    error(loc, "variable `%s` cannot be read at compile time", v.toChars());
-                    return CTFEExp.cantexp;
+                    // Zero-length arrays don't have an initializer
+                    if (v.type.size() == 0)
+                        e = v.type.defaultInitLiteral(loc);
+                    else if (!v.isCTFE() && v.isDataseg())
+                    {
+                        error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
+                        return CTFEExp.cantexp;
+                    }
+                    else
+                    {
+                        assert(!(v._init && v._init.isVoidInitializer()));
+                        // CTFE initiated from inside a function
+                        error(loc, "variable `%s` cannot be read at compile time", v.toChars());
+                        return CTFEExp.cantexp;
+                    }
                 }
                 if (auto vie = e.isVoidInitExp())
                 {
@@ -2199,6 +2215,15 @@ public:
         result = getVarExp(e.loc, istate, e.var, goal);
         if (exceptionOrCant(result))
             return;
+
+        // Visit the default initializer for noreturn variables
+        // (Custom initializers would abort the current function call and exit above)
+        if (result.type.ty == Tnoreturn)
+        {
+            result.accept(this);
+            return;
+        }
+
         if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
         {
             /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
@@ -2221,6 +2246,12 @@ public:
             printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
         }
         Dsymbol s = e.declaration;
+        while (s.isAttribDeclaration())
+        {
+            auto ad = cast(AttribDeclaration)s;
+            assert(ad.decl && ad.decl.dim == 1); // Currently, only one allowed when parsing
+            s = (*ad.decl)[0];
+        }
         if (VarDeclaration v = s.isVarDeclaration())
         {
             if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
@@ -2303,20 +2334,8 @@ public:
             }
             return;
         }
-        if (s.isAttribDeclaration() || s.isTemplateMixin() || s.isTupleDeclaration())
+        if (s.isTemplateMixin() || s.isTupleDeclaration())
         {
-            // Check for static struct declarations, which aren't executable
-            AttribDeclaration ad = e.declaration.isAttribDeclaration();
-            if (ad && ad.decl && ad.decl.dim == 1)
-            {
-                Dsymbol sparent = (*ad.decl)[0];
-                if (sparent.isAggregateDeclaration() || sparent.isTemplateDeclaration() || sparent.isAliasDeclaration())
-                {
-                    result = null;
-                    return; // static (template) struct declaration. Nothing to do.
-                }
-            }
-
             // These can be made to work, too lazy now
             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
             result = CTFEExp.cantexp;
@@ -2994,16 +3013,6 @@ public:
             er = interpret(pue, ex, istate);
             if (exceptionOrCant(er))
                 return false;
-            if (er.isConst() != 1)
-            {
-                if (er.op == TOK.arrayLiteral)
-                    // Until we get it to work, issue a reasonable error message
-                    e.error("cannot interpret array literal expression `%s` at compile time", e.toChars());
-                else
-                    e.error("CTFE internal error: non-constant value `%s`", ex.toChars());
-                result = CTFEExp.cantexp;
-                return false;
-            }
             return true;
         }
 
@@ -3028,7 +3037,67 @@ public:
                 return;
             }
         }
-        *pue = (*fp)(e.loc, e.type, e1, e2);
+
+        /******************************************
+         * Perform the operation fp on operands e1 and e2.
+         */
+        UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
+        {
+            UnionExp ue = void;
+            auto ae1 = e1.isArrayLiteralExp();
+            auto ae2 = e2.isArrayLiteralExp();
+            if (ae1 || ae2)
+            {
+                /* Cases:
+                 * 1. T[] op T[]
+                 * 2. T op T[]
+                 * 3. T[] op T
+                 */
+                if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
+                    ae2 = null;
+                else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
+                    ae1 = null;
+                // else case 1
+
+                auto aex = ae1 ? ae1 : ae2;
+                if (!aex.elements)
+                {
+                    emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
+                    return ue;
+                }
+                const length = aex.elements.length;
+                Expressions* elements = new Expressions(length);
+
+                emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
+                foreach (i; 0 .. length)
+                {
+                    Expression e1x = ae1 ? ae1[i] : e1;
+                    Expression e2x = ae2 ? ae2[i] : e2;
+                    UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
+                    // This can be made more efficient by making use of ue.basis
+                    (*elements)[i] = uex.copy();
+                }
+                return ue;
+            }
+
+            if (e1.isConst() != 1)
+            {
+                // The following should really be an assert()
+                e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
+                emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+                return ue;
+            }
+            if (e2.isConst() != 1)
+            {
+                e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
+                emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+                return ue;
+            }
+
+            return (*fp)(loc, type, e1, e2);
+        }
+
+        *pue = evaluate(e.loc, e.type, e1, e2);
         result = (*pue).exp();
         if (CTFEExp.isCantExp(result))
             e.error("`%s` cannot be interpreted at compile time", e.toChars());
@@ -3694,6 +3763,7 @@ public:
 
     private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
     {
+        //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
         VarDeclaration vd = null;
         Expression* payload = null; // dead-store to prevent spurious warning
         Expression oldval;
@@ -3786,6 +3856,17 @@ public:
         Type t1b = e1.type.toBasetype();
         bool wantCopy = t1b.baseElemOf().ty == Tstruct;
 
+        if (auto ve = newval.isVectorExp())
+        {
+            // Ensure ve is an array literal, and not a broadcast
+            if (ve.e1.op == TOK.int64 || ve.e1.op == TOK.float64) // if broadcast
+            {
+                UnionExp ue = void;
+                Expression ex = interpretVectorToArray(&ue, ve);
+                ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
+            }
+        }
+
         if (newval.op == TOK.structLiteral && oldval)
         {
             assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_);
@@ -4800,12 +4881,11 @@ public:
             {
                 // Make a virtual function call.
                 // Get the function from the vtable of the original class
-                assert(pthis.op == TOK.classReference);
-                ClassDeclaration cd = (cast(ClassReferenceExp)pthis).originalClass();
+                ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
 
                 // We can't just use the vtable index to look it up, because
                 // vtables for interfaces don't get populated until the glue layer.
-                fd = cd.findFunc(fd.ident, cast(TypeFunction)fd.type);
+                fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
                 assert(fd);
             }
         }
@@ -4879,10 +4959,10 @@ public:
         // (this is particularly important for struct constructors)
         if (e.e1.op == TOK.declaration &&
             e.e2.op == TOK.variable &&
-            (cast(DeclarationExp)e.e1).declaration == (cast(VarExp)e.e2).var &&
-            (cast(VarExp)e.e2).var.storage_class & STC.ctfe)
+            e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
+            e.e2.isVarExp().var.storage_class & STC.ctfe)
         {
-            VarExp ve = cast(VarExp)e.e2;
+            VarExp ve = e.e2.isVarExp();
             VarDeclaration v = ve.var.isVarDeclaration();
             ctfeGlobals.stack.push(v);
             if (!v._init && !getValue(v))
@@ -4985,7 +5065,7 @@ public:
     static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
     {
         if (auto ale = e.e1.isArrayLiteralExp())
-            return ale;
+            return ale;         // it's already an array literal
         if (e.e1.op == TOK.int64 || e.e1.op == TOK.float64)
         {
             // Convert literal __vector(int) -> __vector([array])
@@ -4995,7 +5075,7 @@ public:
             auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
             assert(type);
             emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
-            auto ale = cast(ArrayLiteralExp)pue.exp();
+            auto ale = pue.exp().isArrayLiteralExp();
             ale.ownedByCtfe = OwnedBy.ctfe;
             return ale;
         }
@@ -5026,7 +5106,7 @@ public:
         if (e1 == pue.exp())
             e1 = pue.copy();
         emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
-        auto ve = cast(VectorExp)pue.exp();
+        auto ve = pue.exp().isVectorExp();
         ve.type = e.type;
         ve.dim = e.dim;
         ve.ownedByCtfe = OwnedBy.ctfe;
@@ -5657,12 +5737,26 @@ public:
             auto cre = cast(ClassReferenceExp)result;
             auto cd = cre.originalClass();
 
-            if (cd.dtor)
+            // Find dtor(s) in inheritance chain
+            do
             {
-                result = interpretFunction(pue, cd.dtor, istate, null, cre);
-                if (exceptionOrCant(result))
-                    return;
-            }
+                if (cd.dtor)
+                {
+                    result = interpretFunction(pue, cd.dtor, istate, null, cre);
+                    if (exceptionOrCant(result))
+                        return;
+
+                    // Dtors of Non-extern(D) classes use implicit chaining (like structs)
+                    import dmd.aggregate : ClassKind;
+                    if (cd.classKind != ClassKind.d)
+                        break;
+                }
+
+                // Emulate manual chaining as done in rt_finalize2
+                cd = cd.baseClass;
+
+            } while (cd); // Stop after Object
+
             break;
 
         case Tpointer:
@@ -7349,6 +7443,7 @@ private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
 
 private void setValue(VarDeclaration vd, Expression newval)
 {
+    //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
     version (none)
     {
         if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
index 3a31926fe97..ddfee2ccab0 100644
--- a/gcc/d/dmd/dmacro.d
+++ b/gcc/d/dmd/dmacro.d
@@ -1,7 +1,7 @@
 /**
  * Text macro processor for Ddoc.
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d)
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index fbc52cc1175..71b8c7a6098 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
  *
- * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors: Walter Bright, http://www.digitalmars.com
  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d)
@@ -14,6 +14,113 @@
 
 module dmd.dmangle;
 
+import dmd.astenums;
+
+/******************************************************************************
+ * Returns exact mangled name of function.
+ */
+extern (C++) const(char)* mangleExact(FuncDeclaration fd)
+{
+    if (!fd.mangleString)
+    {
+        OutBuffer buf;
+        scope Mangler v = new Mangler(&buf);
+        v.mangleExact(fd);
+        fd.mangleString = buf.extractChars();
+    }
+    return fd.mangleString;
+}
+
+extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
+{
+    if (t.deco)
+        buf.writestring(t.deco);
+    else
+    {
+        scope Mangler v = new Mangler(buf, t);
+        v.visitWithMask(t, 0);
+    }
+}
+
+extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
+{
+    scope Mangler v = new Mangler(buf);
+    e.accept(v);
+}
+
+extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
+{
+    scope Mangler v = new Mangler(buf);
+    s.accept(v);
+}
+
+extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
+{
+    scope Mangler v = new Mangler(buf);
+    v.mangleTemplateInstance(ti);
+}
+
+/// Returns: `true` if the given character is a valid mangled character
+package bool isValidMangling(dchar c) nothrow
+{
+    return
+        c >= 'A' && c <= 'Z' ||
+        c >= 'a' && c <= 'z' ||
+        c >= '0' && c <= '9' ||
+        c != 0 && strchr("$%().:?@[]_", c) ||
+        isUniAlpha(c);
+}
+
+// valid mangled characters
+unittest
+{
+    assert('a'.isValidMangling);
+    assert('B'.isValidMangling);
+    assert('2'.isValidMangling);
+    assert('@'.isValidMangling);
+    assert('_'.isValidMangling);
+}
+
+// invalid mangled characters
+unittest
+{
+    assert(!'-'.isValidMangling);
+    assert(!0.isValidMangling);
+    assert(!'/'.isValidMangling);
+    assert(!'\\'.isValidMangling);
+}
+
+/**********************************************
+ * Convert a string representing a type (the deco) and
+ * return its equivalent Type.
+ * Params:
+ *      deco = string containing the deco
+ * Returns:
+ *      null for failed to convert
+ *      Type for succeeded
+ */
+
+public Type decoToType(const(char)[] deco)
+{
+    //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr);
+    if (auto sv = Type.stringtable.lookup(deco))
+    {
+        if (sv.value)
+        {
+            Type t = cast(Type)sv.value;
+            assert(t.deco);
+            return t;
+        }
+    }
+    return null;
+}
+
+
+/***************************************** private ***************************************/
+
+private:
+
+
 import core.stdc.ctype;
 import core.stdc.stdio;
 import core.stdc.string;
@@ -35,6 +142,7 @@ import dmd.root.ctfloat;
 import dmd.root.outbuffer;
 import dmd.root.aav;
 import dmd.root.string;
+import dmd.root.stringtable;
 import dmd.target;
 import dmd.tokens;
 import dmd.utf;
@@ -55,8 +163,7 @@ private immutable char[TMAX] mangleChar =
     Tuns32       : 'k',
     Tint64       : 'l',
     Tuns64       : 'm',
-    Tnone        : 'n',
-    Tnull        : 'n', // yes, same as TypeNone
+    Tnull        : 'n',
     Timaginary32 : 'o',
     Timaginary64 : 'p',
     Tcomplex32   : 'q',
@@ -84,7 +191,7 @@ private immutable char[TMAX] mangleChar =
     //              K   // ref
     //              L   // lazy
     //              M   // has this, or scope
-    //              N   // Nh:vector Ng:wild
+    //              N   // Nh:vector Ng:wild Nn:noreturn
     //              O   // shared
     Tpointer     : 'P',
     //              Q   // Type/symbol/identifier backward reference
@@ -92,13 +199,13 @@ private immutable char[TMAX] mangleChar =
     Tstruct      : 'S',
     //              T   // Ttypedef
     //              U   // C function
-    //              V   // Pascal function
     //              W   // Windows function
     //              X   // variadic T t...)
     //              Y   // variadic T t,...)
     //              Z   // not variadic, end of parameters
 
     // '@' shouldn't appear anywhere in the deco'd names
+    Tnone        : '@',
     Tident       : '@',
     Tinstance    : '@',
     Terror       : '@',
@@ -108,6 +215,8 @@ private immutable char[TMAX] mangleChar =
     Tvector      : '@',
     Ttraits      : '@',
     Tmixin       : '@',
+    Ttag         : '@',
+    Tnoreturn    : '@',         // becomes 'Nn'
 ];
 
 unittest
@@ -180,10 +289,12 @@ public:
     AssocArray!(Type, size_t) types;        // Type => (offset+1) in buf
     AssocArray!(Identifier, size_t) idents; // Identifier => (offset+1) in buf
     OutBuffer* buf;
+    Type rootType;
 
-    extern (D) this(OutBuffer* buf)
+    extern (D) this(OutBuffer* buf, Type rootType = null)
     {
         this.buf = buf;
+        this.rootType = rootType;
     }
 
     /**
@@ -191,7 +302,7 @@ public:
     *  using upper case letters for all digits but the last digit which uses
     *  a lower case letter.
     * The decoder has to look up the referenced position to determine
-    *  whether the back reference is an identifer (starts with a digit)
+    *  whether the back reference is an identifier (starts with a digit)
     *  or a type (starts with a letter).
     *
     * Params:
@@ -229,9 +340,28 @@ public:
     */
     bool backrefType(Type t)
     {
-        if (!t.isTypeBasic())
-            return backrefImpl(types, t);
-        return false;
+        if (t.isTypeBasic())
+            return false;
+
+        /**
+         * https://issues.dlang.org/show_bug.cgi?id=21591
+         *
+         * Special case for unmerged TypeFunctions: use the generic merged
+         * function type as backref cache key to avoid missed backrefs.
+         *
+         * Merging is based on mangling, so we need to avoid an infinite
+         * recursion by excluding the case where `t` is the root type passed to
+         * `mangleToBuffer()`.
+         */
+        if (t != rootType)
+        {
+            if (t.isFunction_Delegate_PtrToFunction())
+            {
+                t = t.merge2();
+            }
+        }
+
+        return backrefImpl(types, t);
     }
 
     /**
@@ -369,9 +499,6 @@ public:
         case LINK.windows:
             mc = 'W';
             break;
-        case LINK.pascal:
-            mc = 'V';
-            break;
         case LINK.cpp:
             mc = 'R';
             break;
@@ -466,6 +593,11 @@ public:
         visit(cast(Type)t);
     }
 
+    override void visit(TypeNoreturn t)
+    {
+        buf.writestring("Nn");
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     void mangleDecl(Declaration sthis)
     {
@@ -486,6 +618,7 @@ public:
 
     void mangleParent(Dsymbol s)
     {
+        //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
         Dsymbol p;
         if (TemplateInstance ti = s.isTemplateInstance())
             p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
@@ -493,10 +626,12 @@ public:
             p = s.parent;
         if (p)
         {
+            uint localNum = s.localNum;
             mangleParent(p);
             auto ti = p.isTemplateInstance();
             if (ti && !ti.isTemplateMixin())
             {
+                localNum = ti.tempdecl.localNum;
                 mangleTemplateInstance(ti);
             }
             else if (p.getIdent())
@@ -507,6 +642,25 @@ public:
             }
             else
                 buf.writeByte('0');
+
+            /* There can be multiple different declarations in the same
+             * function that have the same mangled name.
+             * This results in localNum having a non-zero number, which
+             * is used to add a fake parent of the form `__Sddd` to make
+             * the mangled names unique.
+             * https://issues.dlang.org/show_bug.cgi?id=20565
+             */
+            if (localNum)
+            {
+                uint ndigits = 1;
+                auto n = localNum;
+                while (n >= 10)
+                {
+                    n /= 10;
+                    ++ndigits;
+                }
+                buf.printf("%u__S%u", ndigits + 3, localNum);
+            }
         }
     }
 
@@ -574,13 +728,14 @@ public:
         const par = d.toParent(); //toParent() skips over mixin templates
         if (!par || par.isModule() || d.linkage == LINK.cpp)
         {
+            if (d.linkage != LINK.d && d.localNum)
+                d.error("the same declaration cannot be in multiple scopes with non-D linkage");
             final switch (d.linkage)
             {
                 case LINK.d:
                     break;
                 case LINK.c:
                 case LINK.windows:
-                case LINK.pascal:
                 case LINK.objc:
                     return d.ident.toString();
                 case LINK.cpp:
@@ -682,7 +837,7 @@ public:
         }
         if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
         {
-            if (!od.hasOverloads || fd.isUnique())
+            if (fd.isUnique())
             {
                 mangleExact(fd);
                 return;
@@ -690,7 +845,7 @@ public:
         }
         if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
         {
-            if (!od.hasOverloads || td.overnext is null)
+            if (td.overnext is null)
             {
                 mangleSymbol(td);
                 return;
@@ -1091,6 +1246,15 @@ public:
         }
     }
 
+    override void visit(FuncExp e)
+    {
+        buf.writeByte('f');
+        if (e.td)
+            mangleSymbol(e.td);
+        else
+            mangleSymbol(e.fd);
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     override void visit(Parameter p)
@@ -1131,99 +1295,3 @@ public:
         visitWithMask(p.type, (p.storageClass & STC.in_) ? MODFlags.const_ : 0);
     }
 }
-
-/// Returns: `true` if the given character is a valid mangled character
-package bool isValidMangling(dchar c) nothrow
-{
-    return
-        c >= 'A' && c <= 'Z' ||
-        c >= 'a' && c <= 'z' ||
-        c >= '0' && c <= '9' ||
-        c != 0 && strchr("$%().:?@[]_", c) ||
-        isUniAlpha(c);
-}
-
-// valid mangled characters
-unittest
-{
-    assert('a'.isValidMangling);
-    assert('B'.isValidMangling);
-    assert('2'.isValidMangling);
-    assert('@'.isValidMangling);
-    assert('_'.isValidMangling);
-}
-
-// invalid mangled characters
-unittest
-{
-    assert(!'-'.isValidMangling);
-    assert(!0.isValidMangling);
-    assert(!'/'.isValidMangling);
-    assert(!'\\'.isValidMangling);
-}
-
-/******************************************************************************
- * Returns exact mangled name of function.
- */
-extern (C++) const(char)* mangleExact(FuncDeclaration fd)
-{
-    if (!fd.mangleString)
-    {
-        OutBuffer buf;
-        scope Mangler v = new Mangler(&buf);
-        v.mangleExact(fd);
-        fd.mangleString = buf.extractChars();
-    }
-    return fd.mangleString;
-}
-
-extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
-{
-    if (t.deco)
-        buf.writestring(t.deco);
-    else
-    {
-        scope Mangler v = new Mangler(buf);
-        v.visitWithMask(t, 0);
-    }
-}
-
-extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
-{
-    scope Mangler v = new Mangler(buf);
-    e.accept(v);
-}
-
-extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
-{
-    scope Mangler v = new Mangler(buf);
-    s.accept(v);
-}
-
-extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
-{
-    scope Mangler v = new Mangler(buf);
-    v.mangleTemplateInstance(ti);
-}
-
-/******************************************************************************
- * Mangle function signatures ('this' qualifier, and parameter types)
- * to check conflicts in function overloads.
- * It's different from fd.type.deco. For example, fd.type.deco would be null
- * if fd is an auto function.
- *
- * Params:
- *    buf = `OutBuffer` to write the mangled function signature to
-*     fd  = `FuncDeclaration` to mangle
- */
-void mangleToFuncSignature(ref OutBuffer buf, FuncDeclaration fd)
-{
-    auto tf = fd.type.isTypeFunction();
-
-    scope Mangler v = new Mangler(&buf);
-
-    MODtoDecoBuffer(&buf, tf.mod);
-    foreach (idx, param; tf.parameterList)
-        param.accept(v);
-    buf.writeByte('Z' - tf.parameterList.varargs);
-}
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 504c7bc09d6..841fff6c485 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -3,7 +3,7 @@
  *
  * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules)
  *
- * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d)
@@ -19,6 +19,7 @@ import core.stdc.string;
 import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astcodegen;
+import dmd.astenums;
 import dmd.compiler;
 import dmd.gluelayer;
 import dmd.dimport;
@@ -34,6 +35,8 @@ import dmd.globals;
 import dmd.id;
 import dmd.identifier;
 import dmd.parse;
+import dmd.cparse;
+import dmd.root.array;
 import dmd.root.file;
 import dmd.root.filename;
 import dmd.root.outbuffer;
@@ -43,79 +46,96 @@ import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.semantic2;
 import dmd.semantic3;
+import dmd.target;
+import dmd.utils;
 import dmd.visitor;
 
-version(Windows) {
-    extern (C) char* getcwd(char* buffer, size_t maxlen);
-} else {
-    import core.sys.posix.unistd : getcwd;
-}
+enum package_d  = "package." ~ mars_ext;
+enum package_di = "package." ~ hdr_ext;
 
-/* ===========================  ===================== */
 /********************************************
  * Look for the source file if it's different from filename.
  * Look for .di, .d, directory, and along global.path.
  * Does not open the file.
- * Input:
- *      filename        as supplied by the user
- *      global.path
+ * Params:
+ *      filename = as supplied by the user
+ *      path = path to look for filename
  * Returns:
- *      NULL if it's not different from filename.
+ *      the found file name or
+ *      `null` if it is not different from filename.
  */
-private const(char)[] lookForSourceFile(const(char)[] filename)
+private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
 {
-    /* Search along global.path for .di file, then .d file.
+    //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
+    /* Search along path[] for .di file, then .d file.
      */
-    const sdi = FileName.forceExt(filename, global.hdr_ext);
+    const sdi = FileName.forceExt(filename, hdr_ext);
     if (FileName.exists(sdi) == 1)
         return sdi;
     scope(exit) FileName.free(sdi.ptr);
-    const sd = FileName.forceExt(filename, global.mars_ext);
+
+    const sd = FileName.forceExt(filename, mars_ext);
     if (FileName.exists(sd) == 1)
         return sd;
     scope(exit) FileName.free(sd.ptr);
+
+    const sc = FileName.forceExt(filename, c_ext);
+    if (FileName.exists(sc) == 1)
+        return sc;
+    scope(exit) FileName.free(sc.ptr);
+
     if (FileName.exists(filename) == 2)
     {
         /* The filename exists and it's a directory.
          * Therefore, the result should be: filename/package.d
          * iff filename/package.d is a file
          */
-        const ni = FileName.combine(filename, "package.di");
+        const ni = FileName.combine(filename, package_di);
         if (FileName.exists(ni) == 1)
             return ni;
         FileName.free(ni.ptr);
-        const n = FileName.combine(filename, "package.d");
+
+        const n = FileName.combine(filename, package_d);
         if (FileName.exists(n) == 1)
             return n;
         FileName.free(n.ptr);
     }
     if (FileName.absolute(filename))
         return null;
-    if (!global.path)
+    if (!path.length)
         return null;
-    for (size_t i = 0; i < global.path.dim; i++)
+    foreach (entry; path)
     {
-        const p = (*global.path)[i].toDString();
+        const p = entry.toDString();
+
         const(char)[] n = FileName.combine(p, sdi);
         if (FileName.exists(n) == 1) {
             return n;
         }
         FileName.free(n.ptr);
+
         n = FileName.combine(p, sd);
         if (FileName.exists(n) == 1) {
             return n;
         }
         FileName.free(n.ptr);
+
+        n = FileName.combine(p, sc);
+        if (FileName.exists(n) == 1) {
+            return n;
+        }
+        FileName.free(n.ptr);
+
         const b = FileName.removeExt(filename);
         n = FileName.combine(p, b);
         FileName.free(b.ptr);
         if (FileName.exists(n) == 2)
         {
-            const n2i = FileName.combine(n, "package.di");
+            const n2i = FileName.combine(n, package_di);
             if (FileName.exists(n2i) == 1)
                 return n2i;
             FileName.free(n2i.ptr);
-            const n2 = FileName.combine(n, "package.d");
+            const n2 = FileName.combine(n, package_d);
             if (FileName.exists(n2) == 1) {
                 return n2;
             }
@@ -169,11 +189,11 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules)
  * Returns:
  *  the filename of the child package or module
  */
-private const(char)[] getFilename(Identifiers* packages, Identifier ident)
+private const(char)[] getFilename(Identifier[] packages, Identifier ident)
 {
     const(char)[] filename = ident.toString();
 
-    if (packages == null || packages.dim == 0)
+    if (packages.length == 0)
         return filename;
 
     OutBuffer buf;
@@ -203,7 +223,7 @@ private const(char)[] getFilename(Identifiers* packages, Identifier ident)
         dotmods.writeByte('.');
     }
 
-    foreach (pid; *packages)
+    foreach (pid; packages)
     {
         const p = pid.toString();
         buf.writestring(p);
@@ -224,13 +244,6 @@ private const(char)[] getFilename(Identifiers* packages, Identifier ident)
     return filename;
 }
 
-enum PKG : int
-{
-    unknown,     // not yet determined whether it's a package.d or not
-    module_,      // already determined that's an actual package.d
-    package_,     // already determined that's an actual package
-}
-
 /***********************************************************
  */
 extern (C++) class Package : ScopeDsymbol
@@ -269,52 +282,49 @@ extern (C++) class Package : ScopeDsymbol
      *      *pparent        the rightmost package, i.e. pkg2, or NULL if no packages
      *      *ppkg           the leftmost package, i.e. pkg1, or NULL if no packages
      */
-    extern (D) static DsymbolTable resolve(Identifiers* packages, Dsymbol* pparent, Package* ppkg)
+    extern (D) static DsymbolTable resolve(Identifier[] packages, Dsymbol* pparent, Package* ppkg)
     {
         DsymbolTable dst = Module.modules;
         Dsymbol parent = null;
         //printf("Package::resolve()\n");
         if (ppkg)
             *ppkg = null;
-        if (packages)
+        foreach (pid; packages)
         {
-            for (size_t i = 0; i < packages.dim; i++)
+            Package pkg;
+            Dsymbol p = dst.lookup(pid);
+            if (!p)
             {
-                Identifier pid = (*packages)[i];
-                Package pkg;
-                Dsymbol p = dst.lookup(pid);
-                if (!p)
-                {
-                    pkg = new Package(Loc.initial, pid);
-                    dst.insert(pkg);
-                    pkg.parent = parent;
+                pkg = new Package(Loc.initial, pid);
+                dst.insert(pkg);
+                pkg.parent = parent;
+                pkg.symtab = new DsymbolTable();
+            }
+            else
+            {
+                pkg = p.isPackage();
+                assert(pkg);
+                // It might already be a module, not a package, but that needs
+                // to be checked at a higher level, where a nice error message
+                // can be generated.
+                // dot net needs modules and packages with same name
+                // But we still need a symbol table for it
+                if (!pkg.symtab)
                     pkg.symtab = new DsymbolTable();
-                }
-                else
-                {
-                    pkg = p.isPackage();
-                    assert(pkg);
-                    // It might already be a module, not a package, but that needs
-                    // to be checked at a higher level, where a nice error message
-                    // can be generated.
-                    // dot net needs modules and packages with same name
-                    // But we still need a symbol table for it
-                    if (!pkg.symtab)
-                        pkg.symtab = new DsymbolTable();
-                }
-                parent = pkg;
-                dst = pkg.symtab;
-                if (ppkg && !*ppkg)
-                    *ppkg = pkg;
-                if (pkg.isModule())
-                {
-                    // Return the module so that a nice error message can be generated
-                    if (ppkg)
-                        *ppkg = cast(Package)p;
-                    break;
-                }
+            }
+            parent = pkg;
+            dst = pkg.symtab;
+            if (ppkg && !*ppkg)
+                *ppkg = pkg;
+            if (pkg[...]

[diff truncated at 524288 bytes]


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-07-30  8:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-30  8:44 [gcc(refs/users/ibuclaw/heads/gdc)] Import dmd v2.097.0: dmd 2a48c54ad, druntime c3a4c517, phobos 61c00065a Iain Buclaw

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).