/* d-lang.cc -- Language-dependent hooks for D.
- Copyright (C) 2006-2018 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
#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"
#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. */
bool deps_skip_system; /* -MM */
const char *deps_filename; /* -M[M]D */
const char *deps_filename_user; /* -MF <arg> */
- OutBuffer *deps_target; /* -M[QT] <arg> */
+ vec <const char *> deps_target; /* -M[QT] <arg> */
bool deps_phony; /* -MP */
bool stdinc; /* -nostdinc */
/* 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;
static GTY(()) tree global_context;
/* Array of all global declarations to pass back to the middle-end. */
-static GTY(()) vec<tree, va_gc> *global_declarations;
+static GTY(()) vec <tree, va_gc> *global_declarations;
/* Support for GCC-style command-line make dependency generation.
Adds TARGET to the make dependencies target buffer.
static void
deps_add_target (const char *target, bool quoted)
{
- if (!d_option.deps_target)
- d_option.deps_target = new OutBuffer ();
- else
- d_option.deps_target->writeByte (' ');
-
- d_option.deps_target->reserve (strlen (target));
+ obstack buffer;
+ gcc_obstack_init (&buffer);
if (!quoted)
{
- d_option.deps_target->writestring (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--)
- d_option.deps_target->writeByte ('\\');
- d_option.deps_target->writeByte ('\\');
- break;
+ while (slashes--)
+ obstack_1grow (&buffer, '\\');
+ obstack_1grow (&buffer, '\\');
+ goto Ldef;
case '$':
- d_option.deps_target->writeByte ('$');
- break;
+ obstack_1grow (&buffer, '$');
+ goto Ldef;
case '#':
- d_option.deps_target->writeByte ('\\');
- break;
+ case ':':
+ obstack_1grow (&buffer, '\\');
+ goto Ldef;
default:
+ Ldef:
+ slashes = 0;
break;
}
- d_option.deps_target->writeByte (*p);
+ obstack_1grow (&buffer, *p);
}
+
+ obstack_1grow (&buffer, '\0');
+ d_option.deps_target.safe_push ((const char *) obstack_finish (&buffer));
}
-/* Write out all dependencies of a given MODULE to the specified BUFFER.
+/* Write STR, with a leading space to BUFFER, updating COLUMN as appropriate.
COLMAX is the number of columns to word-wrap at (0 means don't wrap). */
static void
-deps_write (Module *module, OutBuffer *buffer, unsigned colmax = 72)
+deps_write_string (const char *str, obstack *buffer, unsigned &column,
+ unsigned colmax = 72)
+{
+ unsigned size = strlen (str);
+
+ if (column != 0)
+ {
+ if (colmax && column + size > colmax)
+ {
+ obstack_grow (buffer, " \\\n ", 4);
+ column = 1;
+ }
+ else
+ {
+ obstack_1grow (buffer, ' ');
+ column++;
+ }
+ }
+
+ column += size;
+ obstack_grow (buffer, str, size);
+}
+
+/* Write out all dependencies of a given MODULE to the specified BUFFER. */
+
+static void
+deps_write (Module *module, obstack *buffer)
{
- hash_set <const char *> dependencies;
+ hash_set <const char *> seen_modules;
+ vec <const char *> dependencies = vNULL;
Modules modlist;
modlist.push (module);
- Modules phonylist;
-
- const char *str;
- unsigned size;
+ vec <const char *> phonylist = vNULL;
unsigned column = 0;
/* Write out make target module name. */
- if (d_option.deps_target)
+ if (d_option.deps_target.length ())
{
- size = d_option.deps_target->offset;
- str = d_option.deps_target->extractString ();
+ for (unsigned i = 0; i < d_option.deps_target.length (); i++)
+ deps_write_string (d_option.deps_target[i], buffer, column);
}
else
- {
- str = module->objfile->name->str;
- size = strlen (str);
- }
+ deps_write_string (module->objfile.toChars (), buffer, column);
- buffer->writestring (str);
- column = size;
- buffer->writestring (":");
+ obstack_1grow (buffer, ':');
column++;
- /* Write out all make dependencies. */
- while (modlist.dim > 0)
+ /* Search all modules for file dependencies. */
+ while (modlist.length > 0)
{
Module *depmod = modlist.pop ();
- str = depmod->srcfile->name->str;
- size = strlen (str);
+ const char *modstr = depmod->srcfile.toChars ();
- /* Skip dependencies that have already been written. */
- if (dependencies.add (str))
+ /* Skip modules that have already been looked at. */
+ if (seen_modules.add (modstr))
continue;
- column += size;
-
- if (colmax && column > colmax)
- {
- buffer->writestring (" \\\n ");
- column = size + 1;
- }
- else
- {
- buffer->writestring (" ");
- column++;
- }
-
- buffer->writestring (str);
+ dependencies.safe_push (modstr);
/* Add to list of phony targets if is not being compile. */
if (d_option.deps_phony && !depmod->isRoot ())
- phonylist.push (depmod);
+ phonylist.safe_push (modstr);
+
+ /* Add imported files to dependency list. */
+ for (size_t i = 0; i < depmod->contentImportedFiles.length; i++)
+ {
+ const char *impstr = depmod->contentImportedFiles[i];
+ dependencies.safe_push (impstr);
+ phonylist.safe_push (impstr);
+ }
- /* Search all imports of the written dependency. */
- for (size_t i = 0; i < depmod->aimports.dim; i++)
+ /* Search all imports of the module. */
+ for (size_t i = 0; i < depmod->aimports.length; i++)
{
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
&& 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")
}
}
- buffer->writenl ();
+ /* Write out all make dependencies. */
+ for (size_t i = 0; i < dependencies.length (); i++)
+ deps_write_string (dependencies[i], buffer, column);
+
+ obstack_1grow (buffer, '\n');
/* Write out all phony targets. */
- for (size_t i = 0; i < phonylist.dim; i++)
+ for (size_t i = 0; i < phonylist.length (); i++)
{
- Module *m = phonylist[i];
-
- buffer->writenl ();
- buffer->writestring (m->srcfile->name->str);
- buffer->writestring (":\n");
+ const char *str = phonylist[i];
+ obstack_1grow (buffer, '\n');
+ 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.
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 = true;
- global.params.useInvariants = true;
- global.params.useIn = true;
- global.params.useOut = true;
- global.params.useArrayBounds = BOUNDSCHECKdefault;
- global.params.useSwitchError = true;
- global.params.useInline = false;
- global.params.obj = true;
- global.params.hdrStripPlainFunctions = true;
- global.params.betterC = false;
- global.params.allInst = false;
-
- global.params.linkswitches = new Strings ();
- global.params.libfiles = new Strings ();
- global.params.objfiles = new Strings ();
- global.params.ddocfiles = new Strings ();
+
+ /* Default extern(C++) mangling to C++17. */
+ global.params.cplusplus = CppStdRevisionCpp17;
/* Warnings and deprecations are disabled by default. */
- global.params.useDeprecated = DIAGNOSTICoff;
+ 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.modFileAliasStrings = new Strings ();
+ global.params.imppath = d_gc_malloc<Strings> ();
+ global.params.fileImppath = d_gc_malloc<Strings> ();
/* Extra GDC-specific options. */
d_option.fonly = NULL;
d_option.deps_skip_system = false;
d_option.deps_filename = NULL;
d_option.deps_filename_user = NULL;
- d_option.deps_target = NULL;
+ d_option.deps_target = vNULL;
d_option.deps_phony = false;
d_option.stdinc = true;
}
/* 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. */
+ /* Unlike C, there is no global `errno' variable. */
opts->x_flag_errno_math = 0;
opts->frontend_set_flag_errno_math = true;
- /* Keep in sync with existing -fbounds-check flag. */
- opts->x_flag_bounds_check = global.params.useArrayBounds;
-
/* D says that signed overflow is precisely defined. */
opts->x_flag_wrapv = 1;
}
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
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> ();
+ global_binding_level = ggc_cleared_alloc <binding_level> ();
current_binding_level = global_binding_level;
/* This allows the code in d-builtins.cc to not have to worry about
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");
- Target::_init ();
+ target._init (global.params);
d_init_versions ();
/* Insert all library-configured identifiers and import paths. */
break;
case OPT_fassert:
- global.params.useAssert = value;
+ global.params.useAssert = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fbounds_check:
- global.params.useArrayBounds = value
- ? BOUNDSCHECKon : BOUNDSCHECKoff;
+ global.params.useArrayBounds = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fbounds_check_:
- global.params.useArrayBounds = (value == 2) ? BOUNDSCHECKon
- : (value == 1) ? BOUNDSCHECKsafeonly : BOUNDSCHECKoff;
+ global.params.useArrayBounds = (value == 2) ? CHECKENABLEon
+ : (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:
break;
case OPT_fdebug_:
- if (ISDIGIT (arg[0]))
- {
- int level = integral_argument (arg);
- if (level != -1)
- {
- DebugCondition::setGlobalLevel (level);
- break;
- }
- }
-
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
DebugCondition::addGlobalIdent (arg);
break;
}
- error ("bad argument for -fdebug %qs", arg);
+ error ("bad argument for %<-fdebug%>: %qs", arg);
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;
+ case OPT_fexceptions:
+ 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;
case OPT_finvariants:
- global.params.useInvariants = value;
+ global.params.useInvariants = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fmain:
break;
case OPT_fmodule_file_:
- global.params.modFileAliasStrings->push (arg);
+ global.params.modFileAliasStrings.push (arg);
if (!strchr (arg, '='))
- error ("bad argument for -fmodule-file %qs", arg);
+ error ("bad argument for %<-fmodule-file%>: %qs", arg);
break;
case OPT_fmoduleinfo:
- global.params.betterC = !value;
+ global.params.useModuleInfo = value;
break;
case OPT_fonly_:
break;
case OPT_fpostconditions:
- global.params.useOut = value;
+ global.params.useOut = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fpreconditions:
- global.params.useIn = 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_fswitch_errors:
- global.params.useSwitchError = value;
+ case OPT_frevert_all:
+ global.params.useDIP1000 = FeatureState::disabled;
+ global.params.dtorFields = FeatureState::disabled;
+ global.params.fix16997 = !value;
break;
- case OPT_ftransition_all:
- global.params.vtls = value;
- global.params.vfield = value;
- global.params.vcomplex = value;
+ case OPT_frevert_dip1000:
+ global.params.useDIP1000 = FeatureState::disabled;
+ break;
+
+ case OPT_frevert_dtorfields:
+ global.params.dtorFields = FeatureState::disabled;
+ break;
+
+ case OPT_frevert_intpromote:
+ global.params.fix16997 = !value;
break;
- case OPT_ftransition_checkimports:
- global.params.check10378 = value;
+ case OPT_frtti:
+ global.params.useTypeInfo = value;
break;
- case OPT_ftransition_complex:
- global.params.vcomplex = 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_dip1000:
- global.params.vsafe = value;
- global.params.useDIP25 = value;
+ case OPT_fswitch_errors:
+ global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
break;
- case OPT_ftransition_dip25:
- global.params.useDIP25 = value;
+ 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:
break;
case OPT_fversion_:
- if (ISDIGIT (arg[0]))
- {
- int level = integral_argument (arg);
- if (level != -1)
- {
- VersionCondition::setGlobalLevel (level);
- break;
- }
- }
-
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
VersionCondition::addGlobalIdent (arg);
break;
}
- error ("bad argument for -fversion %qs", arg);
+ error ("bad argument for %<-fversion%>: %qs", arg);
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:
break;
case OPT_v:
- global.params.verbose = value;
+ global.params.v.verbose = value;
break;
case OPT_Wall:
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:
*fn = filename;
/* Release mode doesn't turn off bounds checking for safe functions. */
- if (global.params.useArrayBounds == BOUNDSCHECKdefault)
+ if (global.params.useArrayBounds == CHECKENABLEdefault)
{
global.params.useArrayBounds = global.params.release
- ? BOUNDSCHECKsafeonly : BOUNDSCHECKon;
- flag_bounds_check = !global.params.release;
+ ? CHECKENABLEsafeonly : CHECKENABLEon;
}
- if (global.params.release)
+ /* Assert code is generated if unittests are being compiled also, even if
+ release mode is turned on. */
+ if (global.params.useAssert == CHECKENABLEdefault)
{
- if (!global_options_set.x_flag_invariants)
- global.params.useInvariants = false;
+ if (global.params.useUnitTests || !global.params.release)
+ global.params.useAssert = CHECKENABLEon;
+ else
+ global.params.useAssert = CHECKENABLEoff;
+ }
+
+ /* Checks for switches without a default are turned off in release mode. */
+ if (global.params.useSwitchError == CHECKENABLEdefault)
+ {
+ global.params.useSwitchError = global.params.release
+ ? CHECKENABLEoff : CHECKENABLEon;
+ }
+
+ /* Contracts are turned off in release mode. */
+ if (global.params.useInvariants == CHECKENABLEdefault)
+ {
+ global.params.useInvariants = global.params.release
+ ? CHECKENABLEoff : CHECKENABLEon;
+ }
+
+ if (global.params.useIn == CHECKENABLEdefault)
+ {
+ global.params.useIn = global.params.release
+ ? CHECKENABLEoff : CHECKENABLEon;
+ }
- if (!global_options_set.x_flag_preconditions)
- global.params.useIn = false;
+ if (global.params.useOut == CHECKENABLEdefault)
+ {
+ global.params.useOut = global.params.release
+ ? CHECKENABLEoff : CHECKENABLEon;
+ }
+
+ /* When not linking against D runtime, turn off all code generation that
+ would otherwise reference it. */
+ if (global.params.betterC)
+ {
+ if (!OPTION_SET_P (flag_moduleinfo))
+ global.params.useModuleInfo = false;
- if (!global_options_set.x_flag_postconditions)
- global.params.useOut = 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_assert)
- global.params.useAssert = false;
+ if (!OPTION_SET_P (flag_exceptions))
+ {
+ global.params.useExceptions = false;
+ flag_exceptions = false;
+ }
- if (!global_options_set.x_flag_switch_errors)
- global.params.useSwitchError = 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 (!OPTION_SET_P (flag_reorder_blocks_and_partition))
+ global_options.x_flag_reorder_blocks_and_partition = 0;
+
/* Error about use of deprecated features. */
if (global.params.useDeprecated == DIAGNOSTICinform
&& global.params.warnings == DIAGNOSTICerror)
global.params.useDeprecated = DIAGNOSTICerror;
- /* Make -fmax-errors visible to frontend's diagnostic machinery. */
- if (global_options_set.x_flag_max_errors)
- global.errorLimit = flag_max_errors;
+ if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
+ flag_excess_precision = EXCESS_PRECISION_STANDARD;
+
+ global.params.useInline = flag_inline_functions;
- if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
- flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+ /* Make -fmax-errors visible to frontend's diagnostic machinery. */
+ if (OPTION_SET_P (flag_max_errors))
+ global.params.v.errorLimit = flag_max_errors;
- if (global.params.useUnitTests)
- global.params.useAssert = true;
+ global.params.v.showColumns = flag_show_column;
+ global.params.v.printErrorContext = flag_diagnostics_show_caret;
- global.params.symdebug = write_symbols != NO_DEBUG;
- global.params.useInline = flag_inline_functions;
- global.params.showColumns = flag_show_column;
+ /* Keep the front-end location type in sync with params. */
+ Loc::set (global.params.v.showColumns, global.params.v.messageStyle);
if (global.params.useInline)
- global.params.hdrStripPlainFunctions = false;
+ global.params.dihdr.fullOutput = true;
global.params.obj = !flag_syntax_only;
- /* Has no effect yet. */
- global.params.pic = flag_pic != 0;
+ /* 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;
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);
+ int fd = open (ddocfiles[i], O_RDONLY);
+ bool ok = false;
+ struct stat buf;
- if (TREE_SIDE_EFFECTS (op1))
- gimplify_and_add (op1, pre_p);
-
- *expr_p = TREE_OPERAND (*expr_p, 0);
- ret = GS_OK;
- }
- break;
-
- case ADDR_EXPR:
- op0 = TREE_OPERAND (*expr_p, 0);
- /* Constructors are not lvalues, so make them one. */
- if (TREE_CODE (op0) == CONSTRUCTOR)
+ 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;
-
- /* Or if all arguments are already free of side-effects. */
- bool has_side_effects = false;
- for (int i = 0; i < nargs; i++)
- {
- if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
- {
- has_side_effects = true;
- break;
- }
- }
-
- if (!has_side_effects)
- break;
+ unsigned size = unsigned (buf.st_size);
+ char *buffer = (char *) xmalloc (size);
- /* Leave the last argument for gimplify_call_expr. */
- for (int i = 0; i < nargs - 1; i++)
+ if (read (fd, buffer, size) == ssize_t (size))
{
- 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);
- message ("version %s", global.version);
+ message ("binary %s", global.params.argv0.ptr);
+ message ("version %s", global.versionChars ());
- if (global.params.versionids)
+ if (global.versionids)
{
- OutBuffer buf;
- buf.writestring ("predefs ");
- for (size_t i = 0; i < global.params.versionids->dim; i++)
+ obstack buffer;
+ gcc_obstack_init (&buffer);
+ obstack_grow (&buffer, "predefs ", 9);
+ for (size_t i = 0; i < global.versionids->length; i++)
{
- const char *s = (*global.params.versionids)[i];
- buf.writestring (" ");
- buf.writestring (s);
+ Identifier *id = (*global.versionids)[i];
+ const char *str = id->toChars ();
+ obstack_1grow (&buffer, ' ');
+ obstack_grow (&buffer, str, strlen (str));
}
- message ("%.*s", (int) buf.offset, (char *) buf.data);
+ obstack_1grow (&buffer, '\0');
+ message ("%s", (char *) obstack_finish (&buffer));
}
}
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)
- error ("-fonly= argument is different from first input file name");
+ error ("%<-fonly=%> argument is different from first input file name");
for (size_t i = 0; i < num_in_fnames; i++)
{
if (strcmp (in_fnames[i], "-") == 0)
{
- /* Handling stdin, generate a unique name for the module. */
- obstack buffer;
- gcc_obstack_init (&buffer);
- int c;
+ /* 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
{
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);
}
}
/* Read all D source files. */
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
m->read (Loc ());
}
/* Parse all D source files. */
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- if (global.params.verbose)
+ if (global.params.v.verbose)
message ("parse %s", m->toChars ());
if (!Module::rootModule)
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--;
}
/* 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))
+ 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
are generated before any semantic analysis. */
- for (size_t i = 0; i < modules.dim; i++)
+ 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)
goto had_errors;
/* Load all unconditional imports for better symbol resolving. */
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- if (global.params.verbose)
+ if (global.params.v.verbose)
message ("importall %s", m->toChars ());
m->importAll (NULL);
/* Do semantic analysis. */
doing_semantic_analysis_p = true;
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
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.dim)
+ if (Module::deferred.length)
{
- for (size_t i = 0; i < Module::deferred.dim; i++)
+ for (size_t i = 0; i < Module::deferred.length; i++)
{
Dsymbol *sd = Module::deferred[i];
error_at (make_location_t (sd->loc),
}
/* Process all built-in modules or functions now for CTFE. */
- while (builtin_modules.dim != 0)
+ while (builtin_modules.length != 0)
{
Module *m = builtin_modules.pop ();
d_maybe_set_builtin (m);
}
/* Do pass 2 semantic analysis. */
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
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 ();
goto had_errors;
/* Do pass 3 semantic analysis. */
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
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 ();
/* Check again, incase semantic3 pass loaded any more modules. */
- while (builtin_modules.dim != 0)
+ while (builtin_modules.length != 0)
{
Module *m = builtin_modules.pop ();
d_maybe_set_builtin (m);
/* Declare the name of the root module as the first global name in order
to make the middle-end fully deterministic. */
OutBuffer buf;
- mangleToBuffer (Module::rootModule, &buf);
- first_global_object_name = buf.extractString ();
+ mangleToBuffer (Module::rootModule, buf);
+ first_global_object_name = buf.extractChars ();
}
/* Make dependencies. */
if (d_option.deps)
{
- OutBuffer buf;
+ obstack buffer;
+ gcc_obstack_init (&buffer);
- for (size_t i = 0; i < modules.dim; i++)
- deps_write (modules[i], &buf);
+ for (size_t i = 0; i < modules.length; i++)
+ deps_write (modules[i], &buffer);
/* -MF <arg> overrides -M[M]D. */
if (d_option.deps_filename_user)
d_option.deps_filename = d_option.deps_filename_user;
- if (d_option.deps_filename)
- {
- File *fdeps = File::create (d_option.deps_filename);
- fdeps->setbuffer ((void *) buf.data, buf.offset);
- fdeps->ref = 1;
- writeFile (Loc (), fdeps);
- }
- else
- message ("%.*s", (int) buf.offset, (char *) buf.data);
+ 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;
-
- if (name && (name[0] != '-' || name[1] != '\0'))
- {
- const char *nameext = FileName::defaultExt (name, global.json_ext);
- File *fjson = File::create (nameext);
- fjson->setbuffer ((void *) buf.data, buf.offset);
- fjson->ref = 1;
- writeFile (Loc (), fjson);
- }
- else
- message ("%.*s", (int) buf.offset, (char *) buf.data);
+ 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.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- gendocfile (m);
+ d_generate_ddoc_file (m, ddocbuf);
}
}
/* Handle -fdump-d-original. */
if (global.params.vcg_ast)
{
- for (size_t i = 0; i < modules.dim; i++)
+ for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
OutBuffer buf;
buf.doindent = 1;
- moduleToBuffer (&buf, m);
- message ("%.*s", (int) buf.offset, (char *) buf.data);
+ moduleToBuffer (buf, m);
+ message ("%s", buf.peekChars ());
}
}
- for (size_t i = 0; i < modules.dim; i++)
+ /* 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. */
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));
if (mode == TYPE_MODE (build_pointer_type (d_int_type)))
return build_pointer_type (d_int_type);
+ for (int i = 0; i < NUM_INT_N_ENTS; i ++)
+ {
+ if (int_n_enabled_p[i] && mode == int_n_data[i].m)
+ {
+ if (unsignedp)
+ return int_n_trees[i].unsigned_type;
+ else
+ return int_n_trees[i].signed_type;
+ }
+ }
+
if (COMPLEX_MODE_P (mode))
{
machine_mode inner_mode;
if (bits <= TYPE_PRECISION (d_cent_type))
return unsignedp ? d_ucent_type : d_cent_type;
+ for (int i = 0; i < NUM_INT_N_ENTS; i ++)
+ {
+ if (int_n_enabled_p[i] && bits == int_n_data[i].bitsize)
+ {
+ if (unsignedp)
+ return int_n_trees[i].unsigned_type;
+ else
+ return int_n_trees[i].signed_type;
+ }
+ }
+
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);
-}
-
-/* Return the unsigned version of TYPE, an integral 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;
-tree
-d_unsigned_type (tree type)
-{
- return d_signed_or_unsigned_type (1, type);
-}
+ if (type == char32_type_node)
+ return d_uint_type;
-/* Return the signed version of TYPE, an integral type. */
+ if (TYPE_PRECISION (type) < TYPE_PRECISION (d_int_type))
+ return d_int_type;
+ }
-tree
-d_signed_type (tree type)
-{
- return d_signed_or_unsigned_type (0, type);
-}
+ /* Float arguments are converted to doubles. */
+ if (type == float_type_node)
+ return double_type_node;
-/* 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;
}
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;
}
d_classify_record (tree type)
{
Type *t = TYPE_LANG_FRONTEND (type);
+ TypeClass *tc = t ? t->isTypeClass () : NULL;
- if (t && t->ty == Tclass)
+ if (tc != NULL)
{
- TypeClass *tc = (TypeClass *) t;
-
/* extern(C++) interfaces get emitted as classes. */
if (tc->sym->isInterfaceDeclaration ()
&& !tc->sym->isCPPinterface ())
struct lang_type *
build_lang_type (Type *t)
{
- struct lang_type *lt = ggc_cleared_alloc<struct lang_type> ();
+ struct lang_type *lt = ggc_cleared_alloc <struct lang_type> ();
lt->type = t;
return lt;
}
there's no associated frontend symbol to refer to (yet). If the symbol
appears later in the compilation, then the slot will be re-used. */
if (d == NULL)
- return ggc_cleared_alloc<struct lang_decl> ();
+ return ggc_cleared_alloc <struct lang_decl> ();
struct lang_decl *ld = (d->csym) ? DECL_LANG_SPECIFIC (d->csym) : NULL;
if (ld == NULL)
- ld = ggc_cleared_alloc<struct lang_decl> ();
+ ld = ggc_cleared_alloc <struct lang_decl> ();
if (ld->decl == NULL)
ld->decl = d;
static void
d_dup_lang_specific_decl (tree node)
{
- if (! DECL_LANG_SPECIFIC (node))
+ if (!DECL_LANG_SPECIFIC (node))
return;
- struct lang_decl *ld = ggc_alloc<struct lang_decl> ();
+ struct lang_decl *ld = ggc_alloc <struct lang_decl> ();
memcpy (ld, DECL_LANG_SPECIFIC (node), sizeof (struct lang_decl));
DECL_LANG_SPECIFIC (node) = ld;
}
d_build_eh_runtime_type (tree type)
{
Type *t = TYPE_LANG_FRONTEND (type);
+ gcc_assert (t != NULL);
+ t = t->toBasetype ();
- if (t != NULL)
- t = t->toBasetype ();
-
- gcc_assert (t != NULL && t->ty == Tclass);
- ClassDeclaration *cd = ((TypeClass *) t)->sym;
+ ClassDeclaration *cd = t->isTypeClass ()->sym;
tree decl;
if (cd->isCPPclass ())
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
#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
#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
#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
#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;