/* 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
#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 "output.h"
#include "print-tree.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. */
/* 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;
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));
}
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++;
{
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))
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")
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 = 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;
/* 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;
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> ();
current_binding_level = global_binding_level;
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");
: (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;
}
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;
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;
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_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)
- {
- 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;
}
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:
? 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. */
&& 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;
builtin_modules.push (m);
}
-/* Record the entrypoint module ENTRY which will be compiled in the current
- compilation. ROOT is the module scope where this was requested from. */
+/* Writes to FILENAME. DATA is the full content of the file to be written. */
-void
-d_add_entrypoint_module (Module *entry, Module *root)
+static void
+d_write_file (const char *filename, const char *data)
+{
+ FILE *stream;
+
+ 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;
+ }
+
+ fprintf (stream, "%s", data);
+
+ if (stream != stdout && (ferror (stream) || fclose (stream)))
+ error ("writing output file %s: %m", filename);
+}
+
+/* Read ddoc macro files named by the DDOCFILES, then write the concatenated
+ the contents into DDOCBUF. */
+
+static void
+d_read_ddoc_files (Strings &ddocfiles, OutBuffer &ddocbuf)
+{
+ if (ddocbuf.length ())
+ return;
+
+ for (size_t i = 0; i < ddocfiles.length; i++)
+ {
+ int fd = open (ddocfiles[i], O_RDONLY);
+ bool ok = false;
+ struct stat buf;
+
+ if (fd == -1 || fstat (fd, &buf))
+ {
+ error ("unable to open %s for reading: %m", ddocfiles[i]);
+ continue;
+ }
+
+ /* 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
+ {
+ unsigned size = unsigned (buf.st_size);
+ char *buffer = (char *) xmalloc (size);
+
+ if (read (fd, buffer, size) == ssize_t (size))
+ {
+ ddocbuf.write (buffer, size);
+ ok = true;
+ }
+
+ free (buffer);
+ }
+
+ close (fd);
+ if (!ok)
+ fatal_error (input_location, "reading ddoc file %s: %m", ddocfiles[i]);
+ }
+}
+
+static void
+d_generate_ddoc_file (Module *m, OutBuffer &ddocbuf)
{
- /* We are emitting this straight to object file. */
- entrypoint_module = entry;
- entrypoint_root_module = root;
+ input_location = make_location_t (m->loc);
+
+ d_read_ddoc_files (global.params.ddoc.files, ddocbuf);
+
+ 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. */
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)
{
obstack_grow (&buffer, str, strlen (str));
}
+ 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)
/* 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);
+ /* 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 = len;
- m->srcfile->buffer = buffer;
+ 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);
}
{
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))
{
- 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
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)
{
Module *m = modules[i];
- if (global.params.verbose)
+ if (global.params.v.verbose)
message ("importall %s", m->toChars ());
m->importAll (NULL);
{
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)
{
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 ();
{
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 ();
/* 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 ();
}
if (d_option.deps)
{
obstack buffer;
- FILE *deps_stream;
-
gcc_obstack_init (&buffer);
for (size_t i = 0; i < modules.length; i++)
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);
}
}
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. */
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));
/* Promotions are only applied on unnamed function arguments for declarations
with `extern(C)' or `extern(C++)' linkage. */
if (cfun && DECL_LANG_FRONTEND (cfun->decl)
- && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINKd)
+ && DECL_LANG_FRONTEND (cfun->decl)->resolvedLinkage () != LINK::d)
{
/* In [type/integer-promotions], integer promotions are conversions of the
following types:
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;
}
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;