]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/d/d-lang.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / d / d-lang.cc
index 2c474f8adea3a785e95a3de7f8ea56e78f2fe1fa..7840cf8a13283c5586e63a8d0e89ba819f137614 100644 (file)
@@ -1,5 +1,5 @@
 /* d-lang.cc -- Language-dependent hooks for D.
-   Copyright (C) 2006-2020 Free Software Foundation, Inc.
+   Copyright (C) 2006-2024 Free Software Foundation, Inc.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -26,13 +26,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "dmd/errors.h"
 #include "dmd/expression.h"
 #include "dmd/hdrgen.h"
+#include "dmd/id.h"
 #include "dmd/identifier.h"
 #include "dmd/json.h"
 #include "dmd/mangle.h"
-#include "dmd/mars.h"
 #include "dmd/module.h"
 #include "dmd/mtype.h"
 #include "dmd/target.h"
+#include "dmd/template.h"
 
 #include "opts.h"
 #include "alias.h"
@@ -43,17 +44,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "target.h"
+#include "function.h"
 #include "stringpool.h"
 #include "stor-layout.h"
 #include "varasm.h"
 #include "output.h"
 #include "print-tree.h"
-#include "gimple-expr.h"
-#include "gimplify.h"
 #include "debug.h"
+#include "input.h"
 
 #include "d-tree.h"
-#include "id.h"
+#include "d-frontend.h"
 
 
 /* Array of D frontend type/decl nodes.  */
@@ -83,10 +84,6 @@ d_option;
 /* List of modules being compiled.  */
 static Modules builtin_modules;
 
-/* Module where `C main' is defined, compiled in if needed.  */
-static Module *entrypoint_module = NULL;
-static Module *entrypoint_root_module = NULL;
-
 /* The current and global binding level in effect.  */
 struct binding_level *current_binding_level;
 struct binding_level *global_binding_level;
@@ -109,38 +106,48 @@ deps_add_target (const char *target, bool quoted)
 
   if (!quoted)
     {
-      obstack_grow (&buffer, target, strlen (target));
+      obstack_grow0 (&buffer, target, strlen (target));
       d_option.deps_target.safe_push ((const char *) obstack_finish (&buffer));
       return;
     }
 
   /* Quote characters in target which are significant to Make.  */
+  unsigned slashes = 0;
+
   for (const char *p = target; *p != '\0'; p++)
     {
       switch (*p)
        {
+       case '\\':
+         slashes++;
+         break;
+
        case ' ':
        case '\t':
-         for (const char *q = p - 1; target <= q && *q == '\\';  q--)
+         while (slashes--)
            obstack_1grow (&buffer, '\\');
          obstack_1grow (&buffer, '\\');
-         break;
+         goto Ldef;
 
        case '$':
          obstack_1grow (&buffer, '$');
-         break;
+         goto Ldef;
 
        case '#':
+       case ':':
          obstack_1grow (&buffer, '\\');
-         break;
+         goto Ldef;
 
        default:
+       Ldef:
+         slashes = 0;
          break;
        }
 
       obstack_1grow (&buffer, *p);
     }
 
+  obstack_1grow (&buffer, '\0');
   d_option.deps_target.safe_push ((const char *) obstack_finish (&buffer));
 }
 
@@ -192,7 +199,7 @@ deps_write (Module *module, obstack *buffer)
        deps_write_string (d_option.deps_target[i], buffer, column);
     }
   else
-    deps_write_string (module->objfile->name->str, buffer, column);
+    deps_write_string (module->objfile.toChars (), buffer, column);
 
   obstack_1grow (buffer, ':');
   column++;
@@ -202,7 +209,7 @@ deps_write (Module *module, obstack *buffer)
     {
       Module *depmod = modlist.pop ();
 
-      const char *modstr = depmod->srcfile->name->str;
+      const char *modstr = depmod->srcfile.toChars ();
 
       /* Skip modules that have already been looked at.  */
       if (seen_modules.add (modstr))
@@ -228,9 +235,7 @@ deps_write (Module *module, obstack *buffer)
          Module *m = depmod->aimports[i];
 
          /* Ignore compiler-generated modules.  */
-         if ((m->ident == Identifier::idPool ("__entrypoint")
-              || m->ident == Identifier::idPool ("__main"))
-             && m->parent == NULL)
+         if (m->ident == Identifier::idPool ("__main") && m->parent == NULL)
            continue;
 
          /* Don't search system installed modules, this includes
@@ -241,9 +246,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")
@@ -270,6 +275,8 @@ deps_write (Module *module, obstack *buffer)
       obstack_grow (buffer, str, strlen (str));
       obstack_grow (buffer, ":\n", 2);
     }
+
+  obstack_1grow (buffer, '\0');
 }
 
 /* Implements the lang_hooks.init_options routine for language D.
@@ -279,38 +286,27 @@ deps_write (Module *module, obstack *buffer)
 static void
 d_init_options (unsigned int, cl_decoded_option *decoded_options)
 {
+  /* Initialize the D runtime.  */
+  rt_init ();
+  gc_disable ();
+
   /* Set default values.  */
   global._init ();
 
-  global.vendor = lang_hooks.name;
+  global.compileEnv.vendor = lang_hooks.name;
   global.params.argv0 = xstrdup (decoded_options[0].arg);
-  global.params.link = true;
-  global.params.useAssert = CHECKENABLEdefault;
-  global.params.useInvariants = CHECKENABLEdefault;
-  global.params.useIn = CHECKENABLEdefault;
-  global.params.useOut = CHECKENABLEdefault;
-  global.params.useArrayBounds = CHECKENABLEdefault;
-  global.params.useSwitchError = CHECKENABLEdefault;
-  global.params.checkAction = CHECKACTION_D;
-  global.params.useModuleInfo = true;
-  global.params.useTypeInfo = true;
-  global.params.useExceptions = true;
-  global.params.useInline = false;
-  global.params.obj = true;
-  global.params.hdrStripPlainFunctions = true;
-  global.params.betterC = false;
-  global.params.allInst = false;
-  global.params.errorLimit = flag_max_errors;
-
-  /* Default extern(C++) mangling to C++14.  */
-  global.params.cplusplus = CppStdRevisionCpp14;
+
+  /* Default extern(C++) mangling to C++17.  */
+  global.params.cplusplus = CppStdRevisionCpp17;
 
   /* Warnings and deprecations are disabled by default.  */
   global.params.useDeprecated = DIAGNOSTICinform;
   global.params.warnings = DIAGNOSTICoff;
+  global.params.v.errorLimit = flag_max_errors;
+  global.params.v.messageStyle = MessageStyle::gnu;
 
-  global.params.imppath = new Strings ();
-  global.params.fileImppath = new Strings ();
+  global.params.imppath = d_gc_malloc<Strings> ();
+  global.params.fileImppath = d_gc_malloc<Strings> ();
 
   /* Extra GDC-specific options.  */
   d_option.fonly = NULL;
@@ -334,9 +330,6 @@ d_init_options_struct (gcc_options *opts)
   /* GCC options.  */
   opts->x_flag_exceptions = 1;
 
-  /* Avoid range issues for complex multiply and divide.  */
-  opts->x_flag_complex_method = 2;
-
   /* Unlike C, there is no global `errno' variable.  */
   opts->x_flag_errno_math = 0;
   opts->frontend_set_flag_errno_math = true;
@@ -354,6 +347,19 @@ d_option_lang_mask (void)
   return CL_D;
 }
 
+/* Implements input charset and BOM skipping configuration for
+   diagnostics.  */
+static const char *d_input_charset_callback (const char * /*filename*/)
+{
+  /* TODO: The input charset is automatically determined by code in
+     dmd/dmodule.c based on the contents of the file.  If this detection
+     logic were factored out and could be reused here, then we would be able
+     to return UTF-16 or UTF-32 as needed here.  For now, we return always
+     NULL, which means no conversion is necessary, i.e. the input is assumed
+     to be UTF-8 when diagnostics read this file.  */
+  return nullptr;
+}
+
 /* Implements the lang_hooks.init routine for language D.  */
 
 static bool
@@ -365,6 +371,11 @@ d_init (void)
   Expression::_init ();
   Objc::_init ();
 
+  /* Diagnostics input init, to enable BOM skipping and
+     input charset conversion.  */
+  diagnostic_initialize_input_context (global_dc,
+                                      d_input_charset_callback, true);
+
   /* Back-end init.  */
   global_binding_level = ggc_cleared_alloc <binding_level> ();
   current_binding_level = global_binding_level;
@@ -381,7 +392,7 @@ d_init (void)
     using_eh_for_cleanups ();
 
   if (!supports_one_only ())
-    flag_weak = 0;
+    flag_weak_templates = 0;
 
   /* This is the C main, not the D main.  */
   main_identifier_node = get_identifier ("main");
@@ -435,26 +446,19 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
        : (value == 1) ? CHECKENABLEsafeonly : CHECKENABLEoff;
       break;
 
+    case OPT_fcheckaction_:
+      global.params.checkAction = (value == 0) ? CHECKACTION_D
+       : (value == 1) ? CHECKACTION_halt : CHECKACTION_context;
+      break;
+
     case OPT_fdebug:
       global.params.debuglevel = value ? 1 : 0;
       break;
 
     case OPT_fdebug_:
-      if (ISDIGIT (arg[0]))
-       {
-         int level = integral_argument (arg);
-         if (level != -1)
-           {
-             global.params.debuglevel = level;
-             break;
-           }
-       }
-
       if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
        {
-         if (!global.params.debugids)
-           global.params.debugids = new Strings ();
-         global.params.debugids->push (arg);
+         DebugCondition::addGlobalIdent (arg);
          break;
        }
 
@@ -462,27 +466,36 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_fdoc:
-      global.params.doDocComments = value;
+      global.params.ddoc.doOutput = value;
       break;
 
     case OPT_fdoc_dir_:
-      global.params.doDocComments = true;
-      global.params.docdir = arg;
+      global.params.ddoc.doOutput = true;
+      global.params.ddoc.dir = arg;
       break;
 
     case OPT_fdoc_file_:
-      global.params.doDocComments = true;
-      global.params.docname = arg;
+      global.params.ddoc.doOutput = true;
+      global.params.ddoc.name = arg;
       break;
 
     case OPT_fdoc_inc_:
-      global.params.ddocfiles.push (arg);
+      global.params.ddoc.files.push (arg);
       break;
 
     case OPT_fdruntime:
       global.params.betterC = !value;
       break;
 
+    case OPT_fdump_c___spec_:
+      global.params.cxxhdr.doOutput = true;
+      global.params.cxxhdr.name = arg;
+      break;
+
+    case OPT_fdump_c___spec_verbose:
+      global.params.cxxhdr.fullOutput = true;
+      break;
+
     case OPT_fdump_d_original:
       global.params.vcg_ast = value;
       break;
@@ -491,6 +504,22 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.useExceptions = value;
       break;
 
+    case OPT_fextern_std_:
+      switch (value)
+       {
+       case CppStdRevisionCpp98:
+       case CppStdRevisionCpp11:
+       case CppStdRevisionCpp14:
+       case CppStdRevisionCpp17:
+       case CppStdRevisionCpp20:
+         global.params.cplusplus = (CppStdRevision) value;
+         break;
+
+       default:
+         error ("bad argument for %<-fextern-std%>: %qs", arg);
+       }
+      break;
+
     case OPT_fignore_unknown_pragmas:
       global.params.ignoreUnsupportedPragmas = value;
       break;
@@ -525,55 +554,136 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.useIn = value ? CHECKENABLEon : CHECKENABLEoff;
       break;
 
+    case OPT_fpreview_all:
+      global.params.ehnogc = value;
+      global.params.useDIP1000 = FeatureState::enabled;
+      global.params.useDIP1021 = value;
+      global.params.bitfields = value;
+      global.params.dtorFields = FeatureState::enabled;
+      global.params.fieldwise = FeatureState::enabled;
+      global.params.fixAliasThis = value;
+      global.params.previewIn = value;
+      global.params.fix16997 = value;
+      global.params.noSharedAccess = FeatureState::enabled;
+      global.params.rvalueRefParam = FeatureState::enabled;
+      global.params.inclusiveInContracts = value;
+      global.params.systemVariables = FeatureState::enabled;
+      global.params.fixImmutableConv = value;
+      break;
+
+    case OPT_fpreview_bitfields:
+      global.params.bitfields = value;
+      break;
+
+    case OPT_fpreview_dip1000:
+      global.params.useDIP1000 = FeatureState::enabled;
+      break;
+
+    case OPT_fpreview_dip1008:
+      global.params.ehnogc = value;
+      break;
+
+    case OPT_fpreview_dip1021:
+      global.params.useDIP1021 = value;
+      break;
+
+    case OPT_fpreview_dtorfields:
+      global.params.dtorFields = FeatureState::enabled;
+      break;
+
+    case OPT_fpreview_fieldwise:
+      global.params.fieldwise = FeatureState::enabled;
+      break;
+
+    case OPT_fpreview_fixaliasthis:
+      global.params.fixAliasThis = value;
+      break;
+
+    case OPT_fpreview_fiximmutableconv:
+      global.params.fixImmutableConv = value;
+      break;
+
+    case OPT_fpreview_in:
+      global.params.previewIn = value;
+      break;
+
+    case OPT_fpreview_inclusiveincontracts:
+      global.params.inclusiveInContracts = value;
+      break;
+
+    case OPT_fpreview_nosharedaccess:
+      global.params.noSharedAccess = FeatureState::enabled;
+      break;
+
+    case OPT_fpreview_rvaluerefparam:
+      global.params.rvalueRefParam = FeatureState::enabled;
+      break;
+
+    case OPT_fpreview_systemvariables:
+      global.params.systemVariables = FeatureState::enabled;
+      break;
+
     case OPT_frelease:
       global.params.release = value;
       break;
 
-    case OPT_frtti:
-      global.params.useTypeInfo = value;
+    case OPT_frevert_all:
+      global.params.useDIP1000 = FeatureState::disabled;
+      global.params.dtorFields = FeatureState::disabled;
+      global.params.fix16997 = !value;
       break;
 
-    case OPT_fswitch_errors:
-      global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
+    case OPT_frevert_dip1000:
+      global.params.useDIP1000 = FeatureState::disabled;
       break;
 
-    case OPT_ftransition_all:
-      global.params.vtls = value;
-      global.params.vfield = value;
-      global.params.vcomplex = value;
+    case OPT_frevert_dtorfields:
+      global.params.dtorFields = FeatureState::disabled;
       break;
 
-    case OPT_ftransition_checkimports:
-      global.params.check10378 = value;
+    case OPT_frevert_intpromote:
+      global.params.fix16997 = !value;
       break;
 
-    case OPT_ftransition_complex:
-      global.params.vcomplex = value;
+    case OPT_frtti:
+      global.params.useTypeInfo = value;
       break;
 
-    case OPT_ftransition_dip1000:
-      global.params.vsafe = value;
-      global.params.useDIP25 = value;
+    case OPT_fsave_mixins_:
+      global.params.mixinOut.doOutput = true;
+      global.params.mixinOut.name = arg;
+      global.params.mixinOut.buffer = d_gc_malloc<OutBuffer> ();
       break;
 
-    case OPT_ftransition_dip25:
-      global.params.useDIP25 = value;
+    case OPT_fswitch_errors:
+      global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
+      break;
+
+    case OPT_ftransition_all:
+      global.params.v.field = value;
+      global.params.v.gc = value;
+      global.params.v.vin = value;
+      global.params.v.tls = value;
       break;
 
     case OPT_ftransition_field:
-      global.params.vfield = value;
+      global.params.v.field = value;
       break;
 
-    case OPT_ftransition_import:
-      global.params.bug10378 = value;
+    case OPT_ftransition_in:
+      global.params.v.vin = value;
       break;
 
     case OPT_ftransition_nogc:
-      global.params.vgc = value;
+      global.params.v.gc = value;
+      break;
+
+    case OPT_ftransition_templates:
+      global.params.v.templates = value;
       break;
 
     case OPT_ftransition_tls:
-      global.params.vtls = value;
+      global.params.v.tls = value;
       break;
 
     case OPT_funittest:
@@ -581,21 +691,9 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_fversion_:
-      if (ISDIGIT (arg[0]))
-       {
-         int level = integral_argument (arg);
-         if (level != -1)
-           {
-             global.params.versionlevel = level;
-             break;
-           }
-       }
-
       if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
        {
-         if (!global.params.versionids)
-           global.params.versionids = new Strings ();
-         global.params.versionids->push (arg);
+         VersionCondition::addGlobalIdent (arg);
          break;
        }
 
@@ -603,17 +701,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_H:
-      global.params.doHdrGeneration = true;
+      global.params.dihdr.doOutput = true;
       break;
 
     case OPT_Hd:
-      global.params.doHdrGeneration = true;
-      global.params.hdrdir = arg;
+      global.params.dihdr.doOutput = true;
+      global.params.dihdr.dir = arg;
       break;
 
     case OPT_Hf:
-      global.params.doHdrGeneration = true;
-      global.params.hdrname = arg;
+      global.params.dihdr.doOutput = true;
+      global.params.dihdr.name = arg;
       break;
 
     case OPT_imultilib:
@@ -671,7 +769,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_v:
-      global.params.verbose = value;
+      global.params.v.verbose = value;
       break;
 
     case OPT_Wall:
@@ -690,15 +788,15 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 
     case OPT_Wspeculative:
       if (value)
-       global.params.showGaggedErrors = 1;
+       global.params.v.showGaggedErrors = 1;
       break;
 
     case OPT_Xf:
-      global.params.jsonfilename = arg;
+      global.params.json.name = arg;
       /* Fall through.  */
 
     case OPT_X:
-      global.params.doJsonGeneration = true;
+      global.params.json.doOutput = true;
       break;
 
     default:
@@ -771,27 +869,42 @@ d_post_options (const char ** fn)
        ? CHECKENABLEoff : CHECKENABLEon;
     }
 
+  /* When not linking against D runtime, turn off all code generation that
+     would otherwise reference it.  */
   if (global.params.betterC)
     {
-      if (!global_options_set.x_flag_moduleinfo)
+      if (!OPTION_SET_P (flag_moduleinfo))
        global.params.useModuleInfo = false;
 
-      if (!global_options_set.x_flag_rtti)
-       global.params.useTypeInfo = false;
+      /* Ensure that the front-end options are in sync with the `-frtti' and
+        `-fexceptions' flags.  */
+      if (!OPTION_SET_P (flag_rtti))
+       {
+         global.params.useTypeInfo = false;
+         flag_rtti = false;
+       }
 
-      if (!global_options_set.x_flag_exceptions)
-       global.params.useExceptions = false;
+      if (!OPTION_SET_P (flag_exceptions))
+       {
+         global.params.useExceptions = false;
+         flag_exceptions = false;
+       }
 
+      global.params.useGC = false;
       global.params.checkAction = CHECKACTION_C;
     }
 
+  /* Enabling DIP1021 implies DIP1000.  */
+  if (global.params.useDIP1021)
+    global.params.useDIP1000 = FeatureState::enabled;
+
   /* Keep in sync with existing -fbounds-check flag.  */
   flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon);
 
   /* Turn off partitioning unless it was explicitly requested, as it doesn't
      work with D exception chaining, where EH handler uses LSDA to determine
      whether two thrown exception are in the same context.  */
-  if (!global_options_set.x_flag_reorder_blocks_and_partition)
+  if (!OPTION_SET_P (flag_reorder_blocks_and_partition))
     global_options.x_flag_reorder_blocks_and_partition = 0;
 
   /* Error about use of deprecated features.  */
@@ -799,43 +912,30 @@ d_post_options (const char ** fn)
       && global.params.warnings == DIAGNOSTICerror)
     global.params.useDeprecated = DIAGNOSTICerror;
 
-  /* Make -fmax-errors visible to frontend's diagnostic machinery.  */
-  if (global_options_set.x_flag_max_errors)
-    global.params.errorLimit = flag_max_errors;
-
   if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
     flag_excess_precision = EXCESS_PRECISION_STANDARD;
 
-  global.params.symdebug = write_symbols != NO_DEBUG;
   global.params.useInline = flag_inline_functions;
-  global.params.showColumns = flag_show_column;
 
-  if (global.params.useInline)
-    global.params.hdrStripPlainFunctions = false;
+  /* Make -fmax-errors visible to frontend's diagnostic machinery.  */
+  if (OPTION_SET_P (flag_max_errors))
+    global.params.v.errorLimit = flag_max_errors;
 
-  global.params.obj = !flag_syntax_only;
+  global.params.v.showColumns = flag_show_column;
+  global.params.v.printErrorContext = flag_diagnostics_show_caret;
 
-  /* Has no effect yet.  */
-  global.params.pic = flag_pic != 0;
+  /* Keep the front-end location type in sync with params.  */
+  Loc::set (global.params.v.showColumns, global.params.v.messageStyle);
 
-  /* Add in versions given on the command line.  */
-  if (global.params.versionids)
-    {
-      for (size_t i = 0; i < global.params.versionids->length; i++)
-       {
-         const char *s = (*global.params.versionids)[i];
-         VersionCondition::addGlobalIdent (s);
-       }
-    }
+  if (global.params.useInline)
+    global.params.dihdr.fullOutput = true;
 
-  if (global.params.debugids)
-    {
-      for (size_t i = 0; i < global.params.debugids->length; i++)
-       {
-         const char *s = (*global.params.debugids)[i];
-         DebugCondition::addGlobalIdent (s);
-       }
-    }
+  global.params.obj = !flag_syntax_only;
+
+  /* The front-end parser only has access to `compileEnv', synchronize its
+     fields with params.  */
+  global.compileEnv.previewIn = global.params.previewIn;
+  global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
 
   if (warn_return_type == -1)
     warn_return_type = 0;
@@ -843,194 +943,109 @@ d_post_options (const char ** fn)
   return false;
 }
 
-/* Return TRUE if an operand OP of a given TYPE being copied has no data.
-   The middle-end does a similar check with zero sized types.  */
+/* Add the module M to the list of modules that may declare GCC builtins.
+   These are scanned after first semantic and before codegen passes.
+   See d_maybe_set_builtin() for the implementation.  */
 
-static bool
-empty_modify_p (tree type, tree op)
+void
+d_add_builtin_module (Module *m)
 {
-  tree_code code = TREE_CODE (op);
-  switch (code)
-    {
-    case COMPOUND_EXPR:
-      return empty_modify_p (type, TREE_OPERAND (op, 1));
+  builtin_modules.push (m);
+}
 
-    case CONSTRUCTOR:
-      /* Non-empty construcors are valid.  */
-      if (CONSTRUCTOR_NELTS (op) != 0 || TREE_CLOBBER_P (op))
-       return false;
-      break;
+/* Writes to FILENAME.  DATA is the full content of the file to be written.  */
 
-    case CALL_EXPR:
-      /* Leave nrvo alone because it isn't a copy.  */
-      if (CALL_EXPR_RETURN_SLOT_OPT (op))
-       return false;
-      break;
+static void
+d_write_file (const char *filename, const char *data)
+{
+  FILE *stream;
 
-    default:
-      /* If the operand doesn't have a simple form.  */
-      if (!is_gimple_lvalue (op) && !INDIRECT_REF_P (op))
-       return false;
-      break;
+  if (filename && (filename[0] != '-' || filename[1] != '\0'))
+    stream = fopen (filename, "w");
+  else
+    stream = stdout;
+
+  if (!stream)
+    {
+      error ("unable to open %s for writing: %m", filename);
+      return;
     }
 
-  return empty_aggregate_p (type);
+  fprintf (stream, "%s", data);
+
+  if (stream != stdout && (ferror (stream) || fclose (stream)))
+    error ("writing output file %s: %m", filename);
 }
 
-/* Implements the lang_hooks.gimplify_expr routine for language D.
-   Do gimplification of D specific expression trees in EXPR_P.  */
+/* Read ddoc macro files named by the DDOCFILES, then write the concatenated
+   the contents into DDOCBUF.  */
 
-int
-d_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
-                gimple_seq *post_p ATTRIBUTE_UNUSED)
+static void
+d_read_ddoc_files (Strings &ddocfiles, OutBuffer &ddocbuf)
 {
-  tree_code code = TREE_CODE (*expr_p);
-  enum gimplify_status ret = GS_UNHANDLED;
-  tree op0, op1;
-  tree type;
+  if (ddocbuf.length ())
+    return;
 
-  switch (code)
+  for (size_t i = 0; i < ddocfiles.length; i++)
     {
-    case INIT_EXPR:
-    case MODIFY_EXPR:
-      op0 = TREE_OPERAND (*expr_p, 0);
-      op1 = TREE_OPERAND (*expr_p, 1);
-
-      if (!error_operand_p (op0) && !error_operand_p (op1)
-         && (AGGREGATE_TYPE_P (TREE_TYPE (op0))
-             || AGGREGATE_TYPE_P (TREE_TYPE (op1)))
-         && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0)))
-       {
-         /* If the back end isn't clever enough to know that the lhs and rhs
-            types are the same, add an explicit conversion.  */
-         TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
-                                             TREE_TYPE (op0), op1);
-         ret = GS_OK;
-       }
-      else if (empty_modify_p (TREE_TYPE (op0), op1))
-       {
-         /* Remove any copies of empty aggregates.  */
-         gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                        is_gimple_lvalue, fb_lvalue);
-
-         if (TREE_SIDE_EFFECTS (op1))
-           gimplify_and_add (op1, pre_p);
-
-         *expr_p = TREE_OPERAND (*expr_p, 0);
-         ret = GS_OK;
-       }
-      break;
+      int fd = open (ddocfiles[i], O_RDONLY);
+      bool ok = false;
+      struct stat buf;
 
-    case ADDR_EXPR:
-      op0 = TREE_OPERAND (*expr_p, 0);
-      /* Constructors are not lvalues, so make them one.  */
-      if (TREE_CODE (op0) == CONSTRUCTOR)
+      if (fd == -1 || fstat (fd, &buf))
        {
-         TREE_OPERAND (*expr_p, 0) = force_target_expr (op0);
-         ret = GS_OK;
+         error ("unable to open %s for reading: %m", ddocfiles[i]);
+         continue;
        }
-      break;
 
-    case CALL_EXPR:
-      if (CALL_EXPR_ARGS_ORDERED (*expr_p))
+      /* Check we've not been given a directory, or a file bigger than 4GB.  */
+      if (S_ISDIR (buf.st_mode))
+       errno = ENOENT;
+      else if (buf.st_size != unsigned (buf.st_size))
+       errno = EMFILE;
+      else
        {
-         /* Strictly evaluate all arguments from left to right.  */
-         int nargs = call_expr_nargs (*expr_p);
-         location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
-
-         /* No need to enforce evaluation order if only one argument.  */
-         if (nargs < 2)
-           break;
+         unsigned size = unsigned (buf.st_size);
+         char *buffer = (char *) xmalloc (size);
 
-         /* Or if all arguments are already free of side-effects.  */
-         bool has_side_effects = false;
-         for (int i = 0; i < nargs; i++)
+         if (read (fd, buffer, size) == ssize_t (size))
            {
-             if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
-               {
-                 has_side_effects = true;
-                 break;
-               }
-           }
-
-         if (!has_side_effects)
-           break;
-
-         /* Leave the last argument for gimplify_call_expr.  */
-         for (int i = 0; i < nargs - 1; i++)
-           {
-             tree new_arg = CALL_EXPR_ARG (*expr_p, i);
-
-             /* If argument has a side-effect, gimplify_arg will handle it.  */
-             if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
-               ret = GS_ERROR;
-
-             /* Even if an argument itself doesn't have any side-effects, it
-                might be altered by another argument in the list.  */
-             if (new_arg == CALL_EXPR_ARG (*expr_p, i)
-                 && !really_constant_p (new_arg))
-               new_arg = get_formal_tmp_var (new_arg, pre_p);
-
-             CALL_EXPR_ARG (*expr_p, i) = new_arg;
+             ddocbuf.write (buffer, size);
+             ok = true;
            }
 
-         if (ret != GS_ERROR)
-           ret = GS_OK;
+         free (buffer);
        }
-      break;
-
-    case UNSIGNED_RSHIFT_EXPR:
-      /* Convert op0 to an unsigned type.  */
-      op0 = TREE_OPERAND (*expr_p, 0);
-      op1 = TREE_OPERAND (*expr_p, 1);
-
-      type = d_unsigned_type (TREE_TYPE (op0));
-
-      *expr_p = convert (TREE_TYPE (*expr_p),
-                        build2 (RSHIFT_EXPR, type, convert (type, op0), op1));
-      ret = GS_OK;
-      break;
-
-    case FLOAT_MOD_EXPR:
-      gcc_unreachable ();
 
-    default:
-      break;
+      close (fd);
+      if (!ok)
+       fatal_error (input_location, "reading ddoc file %s: %m", ddocfiles[i]);
     }
-
-  return ret;
 }
 
-/* Add the module M to the list of modules that may declare GCC builtins.
-   These are scanned after first semantic and before codegen passes.
-   See d_maybe_set_builtin() for the implementation.  */
-
-void
-d_add_builtin_module (Module *m)
+static void
+d_generate_ddoc_file (Module *m, OutBuffer &ddocbuf)
 {
-  builtin_modules.push (m);
-}
+  input_location = make_location_t (m->loc);
 
-/* Record the entrypoint module ENTRY which will be compiled in the current
-   compilation.  ROOT is the module scope where this was requested from.  */
+  d_read_ddoc_files (global.params.ddoc.files, ddocbuf);
 
-void
-d_add_entrypoint_module (Module *entry, Module *root)
-{
-  /* We are emitting this straight to object file.  */
-  entrypoint_module = entry;
-  entrypoint_root_module = root;
+  OutBuffer ddocbuf_out;
+  gendocfile (m, ddocbuf.peekChars (), ddocbuf.length (), global.datetime,
+             global.errorSink, ddocbuf_out);
+
+  d_write_file (m->docfile.toChars (), ddocbuf_out.peekChars ());
 }
 
 /* Implements the lang_hooks.parse_file routine for language D.  */
 
-void
+static void
 d_parse_file (void)
 {
-  if (global.params.verbose)
+  if (global.params.v.verbose)
     {
       message ("binary    %s", global.params.argv0.ptr);
-      message ("version   %s", global.version.ptr);
+      message ("version   %s", global.versionChars ());
 
       if (global.versionids)
        {
@@ -1045,6 +1060,7 @@ d_parse_file (void)
              obstack_grow (&buffer, str, strlen (str));
            }
 
+         obstack_1grow (&buffer, '\0');
          message ("%s", (char *) obstack_finish (&buffer));
        }
     }
@@ -1057,6 +1073,9 @@ d_parse_file (void)
   Modules modules;
   modules.reserve (num_in_fnames);
 
+  /* Buffer for contents of .ddoc files.  */
+  OutBuffer ddocbuf;
+
   /* In this mode, the first file name is supposed to be a duplicate
      of one of the input files.  */
   if (d_option.fonly && strcmp (d_option.fonly, main_input_filename) != 0)
@@ -1066,32 +1085,46 @@ d_parse_file (void)
     {
       if (strcmp (in_fnames[i], "-") == 0)
        {
-         /* Handling stdin, generate a unique name for the module.  */
-         obstack buffer;
-         gcc_obstack_init (&buffer);
-         int c;
+         /* Load the entire contents of stdin into memory.  8 kilobytes should
+            be a good enough initial size, but double on each iteration.
+            16 bytes are added for the final '\n' and 15 bytes of padding.  */
+         ssize_t size = 8 * 1024;
+         uchar *buffer = XNEWVEC (uchar, size + 16);
+         ssize_t len = 0;
+         ssize_t count;
+
+         while ((count = read (STDIN_FILENO, buffer + len, size - len)) > 0)
+           {
+             len += count;
+             if (len == size)
+               {
+                 size *= 2;
+                 buffer = XRESIZEVEC (uchar, buffer, size + 16);
+               }
+           }
 
+         if (count < 0)
+           {
+             error (Loc ("stdin", 0, 0), "%s", xstrerror (errno));
+             free (buffer);
+             continue;
+           }
+
+         /* Handling stdin, generate a unique name for the module.  */
          Module *m = Module::create (in_fnames[i],
-                                     Identifier::generateId ("__stdin"),
-                                     global.params.doDocComments,
-                                     global.params.doHdrGeneration);
+                                     Identifier::idPool ("__stdin"),
+                                     global.params.ddoc.doOutput,
+                                     global.params.dihdr.doOutput);
          modules.push (m);
 
-         /* Load the entire contents of stdin into memory.  */
-         while ((c = getc (stdin)) != EOF)
-           obstack_1grow (&buffer, c);
-
-         if (!obstack_object_size (&buffer))
-           obstack_1grow (&buffer, '\0');
+         /* Zero the padding past the end of the buffer so the D lexer has a
+            sentinel.  The lexer only reads up to 4 bytes at a time.  */
+         memset (buffer + len, '\0', 16);
 
          /* Overwrite the source file for the module, the one created by
             Module::create would have a forced a `.d' suffix.  */
-         m->srcfile = File::create ("<stdin>");
-         m->srcfile->len = obstack_object_size (&buffer);
-         m->srcfile->buffer = (unsigned char *) obstack_finish (&buffer);
-
-         /* Tell the front-end not to free the buffer after parsing.  */
-         m->srcfile->ref = 1;
+         m->src.length = len;
+         m->src.ptr = buffer;
        }
       else
        {
@@ -1100,8 +1133,8 @@ d_parse_file (void)
          const char *name = FileName::removeExt (basename);
 
          Module *m = Module::create (in_fnames[i], Identifier::idPool (name),
-                                     global.params.doDocComments,
-                                     global.params.doHdrGeneration);
+                                     global.params.ddoc.doOutput,
+                                     global.params.dihdr.doOutput);
          modules.push (m);
          FileName::free (name);
        }
@@ -1119,7 +1152,7 @@ d_parse_file (void)
     {
       Module *m = modules[i];
 
-      if (global.params.verbose)
+      if (global.params.v.verbose)
        message ("parse     %s", m->toChars ());
 
       if (!Module::rootModule)
@@ -1127,11 +1160,11 @@ d_parse_file (void)
 
       m->importedFrom = m;
       m->parse ();
-      Compiler::loadModule (m);
 
-      if (m->isDocFile)
+      if (m->filetype == FileType::ddoc)
        {
-         gendocfile (m);
+         d_generate_ddoc_file (m, ddocbuf);
+
          /* Remove M from list of modules.  */
          modules.remove (i);
          i--;
@@ -1139,22 +1172,27 @@ d_parse_file (void)
     }
 
   /* Load the module containing D main.  */
+  Module *main_module = NULL;
   if (global.params.addMain)
     {
       unsigned errors = global.startGagging ();
-      Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
+      main_module = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
 
       if (!global.endGagging (errors))
        {
-         m->importedFrom = m;
-         modules.push (m);
+         main_module->importedFrom = main_module;
+         modules.push (main_module);
        }
     }
 
+  /* If an error occurs later during compilation, remember that we generated
+     the headers, so that they can be removed before exit.  */
+  bool dump_headers = false;
+
   if (global.errors)
     goto had_errors;
 
-  if (global.params.doHdrGeneration)
+  if (global.params.dihdr.doOutput)
     {
       /* Generate 'header' import files.  Since 'header' import files must be
         independent of command line switches and what else is imported, they
@@ -1162,14 +1200,19 @@ d_parse_file (void)
       for (size_t i = 0; i < modules.length; i++)
        {
          Module *m = modules[i];
-         if (d_option.fonly && m != Module::rootModule)
+         if (m->filetype == FileType::dhdr
+             || (d_option.fonly && m != Module::rootModule))
            continue;
 
-         if (global.params.verbose)
+         if (global.params.v.verbose)
            message ("import    %s", m->toChars ());
 
-         genhdrfile (m);
+         OutBuffer buf;
+         genhdrfile (m, buf);
+         d_write_file (m->hdrfile.toChars (), buf.peekChars ());
        }
+
+      dump_headers = true;
     }
 
   if (global.errors)
@@ -1180,7 +1223,7 @@ d_parse_file (void)
     {
       Module *m = modules[i];
 
-      if (global.params.verbose)
+      if (global.params.v.verbose)
        message ("importall %s", m->toChars ());
 
       m->importAll (NULL);
@@ -1196,14 +1239,21 @@ d_parse_file (void)
     {
       Module *m = modules[i];
 
-      if (global.params.verbose)
+      /* If this is the `__main` module, check that `D main` hasn't already
+        been declared in user code before running semantic on it.  */
+      if (m == main_module && global.hasMainFunction)
+       {
+         modules.remove (i);
+         continue;
+       }
+
+      if (global.params.v.verbose)
        message ("semantic  %s", m->toChars ());
 
-      m->semantic (NULL);
+      dsymbolSemantic (m, NULL);
     }
 
   /* Do deferred semantic analysis.  */
-  Module::dprogress = 1;
   Module::runDeferredSemantic ();
 
   if (Module::deferred.length)
@@ -1228,10 +1278,10 @@ d_parse_file (void)
     {
       Module *m = modules[i];
 
-      if (global.params.verbose)
+      if (global.params.v.verbose)
        message ("semantic2 %s", m->toChars ());
 
-      m->semantic2 (NULL);
+      semantic2 (m, NULL);
     }
 
   Module::runDeferredSemantic2 ();
@@ -1244,10 +1294,10 @@ d_parse_file (void)
     {
       Module *m = modules[i];
 
-      if (global.params.verbose)
+      if (global.params.v.verbose)
        message ("semantic3 %s", m->toChars ());
 
-      m->semantic3 (NULL);
+      semantic3 (m, NULL);
     }
 
   Module::runDeferredSemantic3 ();
@@ -1271,7 +1321,7 @@ d_parse_file (void)
       /* Declare the name of the root module as the first global name in order
         to make the middle-end fully deterministic.  */
       OutBuffer buf;
-      mangleToBuffer (Module::rootModule, &buf);
+      mangleToBuffer (Module::rootModule, buf);
       first_global_object_name = buf.extractChars ();
     }
 
@@ -1279,8 +1329,6 @@ d_parse_file (void)
   if (d_option.deps)
     {
       obstack buffer;
-      FILE *deps_stream;
-
       gcc_obstack_init (&buffer);
 
       for (size_t i = 0; i < modules.length; i++)
@@ -1290,66 +1338,28 @@ d_parse_file (void)
       if (d_option.deps_filename_user)
        d_option.deps_filename = d_option.deps_filename_user;
 
-      if (d_option.deps_filename)
-       {
-         deps_stream = fopen (d_option.deps_filename, "w");
-         if (!deps_stream)
-           {
-             fatal_error (input_location, "opening dependency file %s: %m",
-                          d_option.deps_filename);
-             goto had_errors;
-           }
-       }
-      else
-       deps_stream = stdout;
-
-      fprintf (deps_stream, "%s", (char *) obstack_finish (&buffer));
-
-      if (deps_stream != stdout
-         && (ferror (deps_stream) || fclose (deps_stream)))
-       {
-         fatal_error (input_location, "closing dependency file %s: %m",
-                      d_option.deps_filename);
-       }
+      d_write_file (d_option.deps_filename,
+                   (char *) obstack_finish (&buffer));
     }
 
+  if (global.params.v.templates)
+    printTemplateStats ();
+
   /* Generate JSON files.  */
-  if (global.params.doJsonGeneration)
+  if (global.params.json.doOutput)
     {
       OutBuffer buf;
-      json_generate (&buf, &modules);
-
-      const char *name = global.params.jsonfilename.ptr;
-      FILE *json_stream;
-
-      if (name && (name[0] != '-' || name[1] != '\0'))
-       {
-         const char *nameext
-           = FileName::defaultExt (name, global.json_ext.ptr);
-         json_stream = fopen (nameext, "w");
-         if (!json_stream)
-           {
-             fatal_error (input_location, "opening json file %s: %m", nameext);
-             goto had_errors;
-           }
-       }
-      else
-       json_stream = stdout;
-
-      fprintf (json_stream, "%s", buf.peekChars ());
-
-      if (json_stream != stdout
-         && (ferror (json_stream) || fclose (json_stream)))
-       fatal_error (input_location, "closing json file %s: %m", name);
+      json_generate (modules, buf);
+      d_write_file (global.params.json.name.ptr, buf.peekChars ());
     }
 
   /* Generate Ddoc files.  */
-  if (global.params.doDocComments && !global.errors && !errorcount)
+  if (global.params.ddoc.doOutput && !global.errors && !errorcount)
     {
       for (size_t i = 0; i < modules.length; i++)
        {
          Module *m = modules[i];
-         gendocfile (m);
+         d_generate_ddoc_file (m, ddocbuf);
        }
     }
 
@@ -1362,27 +1372,33 @@ d_parse_file (void)
          OutBuffer buf;
          buf.doindent = 1;
 
-         moduleToBuffer (&buf, m);
+         moduleToBuffer (buf, m);
          message ("%s", buf.peekChars ());
        }
     }
 
+  /* Generate C++ header files.  */
+  if (global.params.cxxhdr.doOutput)
+    genCppHdrFiles (modules);
+
+  if (global.errors)
+    goto had_errors;
+
   for (size_t i = 0; i < modules.length; i++)
     {
       Module *m = modules[i];
-      if (d_option.fonly && m != Module::rootModule)
+
+      /* Skip generating code for header files, or when the module wasn't
+        specified by `-fonly=`.  */
+      if ((m->filetype == FileType::dhdr && m != main_module)
+         || (d_option.fonly && m != Module::rootModule))
        continue;
 
-      if (global.params.verbose)
+      if (global.params.v.verbose)
        message ("code      %s", m->toChars ());
 
       if (!flag_syntax_only)
-       {
-         if ((entrypoint_module != NULL) && (m == entrypoint_root_module))
-           build_decl_tree (entrypoint_module);
-
-         build_decl_tree (m);
-       }
+       build_decl_tree (m);
     }
 
   /* And end the main input file, if the debug writer wants it.  */
@@ -1394,6 +1410,27 @@ d_parse_file (void)
      exit with an error status.  */
   errorcount += (global.errors + global.warnings);
 
+  /* We want to write the mixin expansion file also on error.  */
+  if (global.params.mixinOut.doOutput)
+    {
+      d_write_file (global.params.mixinOut.name.ptr,
+                   global.params.mixinOut.buffer->peekChars ());
+    }
+
+  /* Remove generated .di files on error.  */
+  if (errorcount && dump_headers)
+    {
+      for (size_t i = 0; i < modules.length; i++)
+       {
+         Module *m = modules[i];
+         if (m->filetype == FileType::dhdr
+             || (d_option.fonly && m != Module::rootModule))
+           continue;
+
+         remove (m->hdrfile.toChars ());
+       }
+    }
+
   /* Write out globals.  */
   d_finish_compilation (vec_safe_address (global_declarations),
                        vec_safe_length (global_declarations));
@@ -1507,55 +1544,65 @@ d_type_for_size (unsigned bits, int unsignedp)
   return 0;
 }
 
-/* Return the signed or unsigned version of TYPE, an integral type, the
-   signedness being specified by UNSIGNEDP.  */
+/* Implements the lang_hooks.types.type_promotes_to routine for language D.  */
 
 static tree
-d_signed_or_unsigned_type (int unsignedp, tree type)
+d_type_promotes_to (tree type)
 {
-  if (TYPE_UNSIGNED (type) == (unsigned) unsignedp)
-    return type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (d_cent_type))
-    return unsignedp ? d_ucent_type : d_cent_type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (d_long_type))
-    return unsignedp ? d_ulong_type : d_long_type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (d_int_type))
-    return unsignedp ? d_uint_type : d_int_type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (d_short_type))
-    return unsignedp ? d_ushort_type : d_short_type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (d_byte_type))
-    return unsignedp ? d_ubyte_type : d_byte_type;
-
-  return signed_or_unsigned_type_for (unsignedp, type);
-}
+  /* 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)->resolvedLinkage () != LINK::d)
+    {
+      /* In [type/integer-promotions], integer promotions are conversions of the
+        following types:
+
+               bool    int
+               byte    int
+               ubyte   int
+               short   int
+               ushort  int
+               char    int
+               wchar   int
+               dchar   uint
+
+        If an enum has as a base type one of the types in the left column, it
+        is converted to the type in the right column.  */
+      if (TREE_CODE (type) == ENUMERAL_TYPE && ENUM_IS_SCOPED (type))
+       type = TREE_TYPE (type);
+
+      type = TYPE_MAIN_VARIANT (type);
+
+      /* Check for promotions of target-defined types first.  */
+      tree promoted_type = targetm.promoted_type (type);
+      if (promoted_type)
+       return promoted_type;
+
+      if (TREE_CODE (type) == BOOLEAN_TYPE)
+       return d_int_type;
+
+      if (INTEGRAL_TYPE_P (type))
+       {
+         if (type == d_byte_type || type == d_ubyte_type
+             || type == d_short_type || type == d_ushort_type
+             || type == char8_type_node || type == char16_type_node)
+           return d_int_type;
 
-/* Return the unsigned version of TYPE, an integral type.  */
+         if (type == char32_type_node)
+           return d_uint_type;
 
-tree
-d_unsigned_type (tree type)
-{
-  return d_signed_or_unsigned_type (1, type);
-}
+         if (TYPE_PRECISION (type) < TYPE_PRECISION (d_int_type))
+           return d_int_type;
+       }
 
-/* Return the signed version of TYPE, an integral type.  */
+      /* Float arguments are converted to doubles.  */
+      if (type == float_type_node)
+       return double_type_node;
 
-tree
-d_signed_type (tree type)
-{
-  return d_signed_or_unsigned_type (0, type);
-}
-
-/* Implements the lang_hooks.types.type_promotes_to routine for language D.
-   All promotions for variable arguments are handled by the D frontend.  */
+      if (type == ifloat_type_node)
+       return idouble_type_node;
+    }
 
-static tree
-d_type_promotes_to (tree type)
-{
   return type;
 }
 
@@ -1658,7 +1705,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;
     }
 
@@ -1860,6 +1908,31 @@ d_build_eh_runtime_type (tree type)
   return convert (ptr_type_node, build_address (decl));
 }
 
+/* Implements the lang_hooks.enum_underlying_base_type routine for language D.
+   Returns the underlying type of the given enumeration TYPE.  */
+
+static tree
+d_enum_underlying_base_type (const_tree type)
+{
+  gcc_assert (TREE_CODE (type) == ENUMERAL_TYPE);
+  return TREE_TYPE (type);
+}
+
+/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
+   based on the list in SARIF v2.1.0 Appendix J.  */
+
+static const char *
+d_get_sarif_source_language (const char *)
+{
+  return "d";
+}
+
+const scoped_attribute_specs *const d_langhook_attribute_table[] =
+{
+  &d_langhook_gnu_attribute_table,
+  &d_langhook_common_attribute_table,
+};
+
 /* Definitions for our language-specific hooks.  */
 
 #undef LANG_HOOKS_NAME
@@ -1871,11 +1944,11 @@ d_build_eh_runtime_type (tree type)
 #undef LANG_HOOKS_HANDLE_OPTION
 #undef LANG_HOOKS_POST_OPTIONS
 #undef LANG_HOOKS_PARSE_FILE
-#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
 #undef LANG_HOOKS_ATTRIBUTE_TABLE
 #undef LANG_HOOKS_GET_ALIAS_SET
 #undef LANG_HOOKS_TYPES_COMPATIBLE_P
 #undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
 #undef LANG_HOOKS_REGISTER_BUILTIN_TYPE
 #undef LANG_HOOKS_FINISH_INCOMPLETE_DECL
 #undef LANG_HOOKS_GIMPLIFY_EXPR
@@ -1885,12 +1958,14 @@ d_build_eh_runtime_type (tree type)
 #undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
 #undef LANG_HOOKS_EH_PERSONALITY
 #undef LANG_HOOKS_EH_RUNTIME_TYPE
+#undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE
 #undef LANG_HOOKS_PUSHDECL
 #undef LANG_HOOKS_GETDECLS
 #undef LANG_HOOKS_GLOBAL_BINDINGS_P
 #undef LANG_HOOKS_TYPE_FOR_MODE
 #undef LANG_HOOKS_TYPE_FOR_SIZE
 #undef LANG_HOOKS_TYPE_PROMOTES_TO
+#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
 
 #define LANG_HOOKS_NAME                            "GNU D"
 #define LANG_HOOKS_INIT                            d_init
@@ -1901,11 +1976,11 @@ d_build_eh_runtime_type (tree type)
 #define LANG_HOOKS_HANDLE_OPTION           d_handle_option
 #define LANG_HOOKS_POST_OPTIONS                    d_post_options
 #define LANG_HOOKS_PARSE_FILE              d_parse_file
-#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE   d_langhook_common_attribute_table
 #define LANG_HOOKS_ATTRIBUTE_TABLE         d_langhook_attribute_table
 #define LANG_HOOKS_GET_ALIAS_SET           d_get_alias_set
 #define LANG_HOOKS_TYPES_COMPATIBLE_P      d_types_compatible_p
 #define LANG_HOOKS_BUILTIN_FUNCTION        d_builtin_function
+#define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE d_builtin_function_ext_scope
 #define LANG_HOOKS_REGISTER_BUILTIN_TYPE    d_register_builtin_type
 #define LANG_HOOKS_FINISH_INCOMPLETE_DECL   d_finish_incomplete_decl
 #define LANG_HOOKS_GIMPLIFY_EXPR           d_gimplify_expr
@@ -1915,12 +1990,14 @@ d_build_eh_runtime_type (tree type)
 #define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL   d_dup_lang_specific_decl
 #define LANG_HOOKS_EH_PERSONALITY          d_eh_personality
 #define LANG_HOOKS_EH_RUNTIME_TYPE         d_build_eh_runtime_type
+#define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE d_enum_underlying_base_type
 #define LANG_HOOKS_PUSHDECL                d_pushdecl
 #define LANG_HOOKS_GETDECLS                d_getdecls
 #define LANG_HOOKS_GLOBAL_BINDINGS_P       d_global_bindings_p
 #define LANG_HOOKS_TYPE_FOR_MODE           d_type_for_mode
 #define LANG_HOOKS_TYPE_FOR_SIZE           d_type_for_size
 #define LANG_HOOKS_TYPE_PROMOTES_TO        d_type_promotes_to
+#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE d_get_sarif_source_language
 
 struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;