8sa1-gcc/gcc/d/d-lang.cc
Iain Buclaw a3b38b7781 d: Merge upstream dmd 7132b3537
Splits out all semantic passes for Dsymbol, Type, and TemplateParameter
nodes into Visitors in separate files, and the copyright years of all
sources have been updated.

Reviewed-on: https://github.com/dlang/dmd/pull/12190

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 7132b3537.
	* Make-lang.in (D_FRONTEND_OBJS): Add d/dsymbolsem.o, d/semantic2.o,
	d/semantic3.o, and d/templateparamsem.o.
	* d-compiler.cc (Compiler::genCmain): Update calls to semantic
	entrypoint functions.
	* d-lang.cc (d_parse_file): Likewise.
	* typeinfo.cc (make_frontend_typeinfo): Likewise.
2021-02-13 12:50:45 +01:00

1791 lines
46 KiB
C++

/* d-lang.cc -- Language-dependent hooks for D.
Copyright (C) 2006-2021 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
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "dmd/aggregate.h"
#include "dmd/cond.h"
#include "dmd/declaration.h"
#include "dmd/doc.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/hdrgen.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 "opts.h"
#include "alias.h"
#include "tree.h"
#include "diagnostic.h"
#include "fold-const.h"
#include "toplev.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 "debug.h"
#include "d-tree.h"
#include "id.h"
/* Array of D frontend type/decl nodes. */
tree d_global_trees[DTI_MAX];
/* True if compilation is currently inside the D frontend semantic passes. */
bool doing_semantic_analysis_p = false;
/* Options handled by the compiler that are separate from the frontend. */
struct d_option_data
{
const char *fonly; /* -fonly=<arg> */
const char *multilib; /* -imultilib <dir> */
const char *prefix; /* -iprefix <dir> */
bool deps; /* -M */
bool deps_skip_system; /* -MM */
const char *deps_filename; /* -M[M]D */
const char *deps_filename_user; /* -MF <arg> */
vec <const char *> deps_target; /* -M[QT] <arg> */
bool deps_phony; /* -MP */
bool stdinc; /* -nostdinc */
}
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;
/* The context to be used for global declarations. */
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;
/* Support for GCC-style command-line make dependency generation.
Adds TARGET to the make dependencies target buffer.
QUOTED is true if the string should be quoted. */
static void
deps_add_target (const char *target, bool quoted)
{
obstack buffer;
gcc_obstack_init (&buffer);
if (!quoted)
{
obstack_grow (&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':
while (slashes--)
obstack_1grow (&buffer, '\\');
obstack_1grow (&buffer, '\\');
goto Ldef;
case '$':
obstack_1grow (&buffer, '$');
goto Ldef;
case '#':
case ':':
obstack_1grow (&buffer, '\\');
goto Ldef;
default:
Ldef:
slashes = 0;
break;
}
obstack_1grow (&buffer, *p);
}
d_option.deps_target.safe_push ((const char *) obstack_finish (&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_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 *> seen_modules;
vec <const char *> dependencies = vNULL;
Modules modlist;
modlist.push (module);
vec <const char *> phonylist = vNULL;
unsigned column = 0;
/* Write out make target module name. */
if (d_option.deps_target.length ())
{
for (unsigned i = 0; i < d_option.deps_target.length (); i++)
deps_write_string (d_option.deps_target[i], buffer, column);
}
else
deps_write_string (module->objfile->name->str, buffer, column);
obstack_1grow (buffer, ':');
column++;
/* Search all modules for file dependencies. */
while (modlist.length > 0)
{
Module *depmod = modlist.pop ();
const char *modstr = depmod->srcfile->name->str;
/* Skip modules that have already been looked at. */
if (seen_modules.add (modstr))
continue;
dependencies.safe_push (modstr);
/* Add to list of phony targets if is not being compile. */
if (d_option.deps_phony && !depmod->isRoot ())
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 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)
continue;
/* Don't search system installed modules, this includes
object, core.*, std.*, and gcc.* packages. */
if (d_option.deps_skip_system)
{
if (m->ident == Identifier::idPool ("object")
&& m->parent == NULL)
continue;
if (m->md && m->md->packages)
{
Identifier *package = (*m->md->packages)[0];
if (package == Identifier::idPool ("core")
|| package == Identifier::idPool ("std")
|| package == Identifier::idPool ("gcc"))
continue;
}
}
modlist.push (m);
}
}
/* 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.length (); i++)
{
const char *str = phonylist[i];
obstack_1grow (buffer, '\n');
obstack_grow (buffer, str, strlen (str));
obstack_grow (buffer, ":\n", 2);
}
}
/* Implements the lang_hooks.init_options routine for language D.
This initializes the global state for the D frontend before calling
the option handlers. */
static void
d_init_options (unsigned int, cl_decoded_option *decoded_options)
{
/* Set default values. */
global._init ();
global.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;
/* Warnings and deprecations are disabled by default. */
global.params.useDeprecated = DIAGNOSTICinform;
global.params.warnings = DIAGNOSTICoff;
global.params.imppath = new Strings ();
global.params.fileImppath = new Strings ();
/* Extra GDC-specific options. */
d_option.fonly = NULL;
d_option.multilib = NULL;
d_option.prefix = NULL;
d_option.deps = false;
d_option.deps_skip_system = false;
d_option.deps_filename = NULL;
d_option.deps_filename_user = NULL;
d_option.deps_target = vNULL;
d_option.deps_phony = false;
d_option.stdinc = true;
}
/* Implements the lang_hooks.init_options_struct routine for language D.
Initializes the options structure OPTS. */
static void
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;
/* D says that signed overflow is precisely defined. */
opts->x_flag_wrapv = 1;
}
/* Implements the lang_hooks.lang_mask routine for language D.
Returns language mask for option parsing. */
static unsigned int
d_option_lang_mask (void)
{
return CL_D;
}
/* Implements the lang_hooks.init routine for language D. */
static bool
d_init (void)
{
Type::_init ();
Id::initialize ();
Module::_init ();
Expression::_init ();
Objc::_init ();
/* Back-end init. */
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
converting (C signed char *) to (D char *) for string arguments of
built-in functions. The parameter (signed_char = false) specifies
whether char is signed. */
build_common_tree_nodes (false);
d_init_builtins ();
if (flag_exceptions)
using_eh_for_cleanups ();
if (!supports_one_only ())
flag_weak = 0;
/* This is the C main, not the D main. */
main_identifier_node = get_identifier ("main");
target._init (global.params);
d_init_versions ();
/* Insert all library-configured identifiers and import paths. */
add_import_paths (d_option.prefix, d_option.multilib, d_option.stdinc);
return 1;
}
/* Implements the lang_hooks.init_ts routine for language D. */
static void
d_init_ts (void)
{
MARK_TS_TYPED (FLOAT_MOD_EXPR);
MARK_TS_TYPED (UNSIGNED_RSHIFT_EXPR);
}
/* Implements the lang_hooks.handle_option routine for language D.
Handles D specific options. Return false if we didn't do anything. */
static bool
d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
int kind ATTRIBUTE_UNUSED,
location_t loc ATTRIBUTE_UNUSED,
const cl_option_handlers *handlers ATTRIBUTE_UNUSED)
{
opt_code code = (opt_code) scode;
bool result = true;
switch (code)
{
case OPT_fall_instantiations:
global.params.allInst = value;
break;
case OPT_fassert:
global.params.useAssert = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fbounds_check:
global.params.useArrayBounds = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fbounds_check_:
global.params.useArrayBounds = (value == 2) ? CHECKENABLEon
: (value == 1) ? CHECKENABLEsafeonly : CHECKENABLEoff;
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);
break;
}
error ("bad argument for %<-fdebug%>: %qs", arg);
break;
case OPT_fdoc:
global.params.doDocComments = value;
break;
case OPT_fdoc_dir_:
global.params.doDocComments = true;
global.params.docdir = arg;
break;
case OPT_fdoc_file_:
global.params.doDocComments = true;
global.params.docname = arg;
break;
case OPT_fdoc_inc_:
global.params.ddocfiles.push (arg);
break;
case OPT_fdruntime:
global.params.betterC = !value;
break;
case OPT_fdump_d_original:
global.params.vcg_ast = value;
break;
case OPT_fexceptions:
global.params.useExceptions = value;
break;
case OPT_fignore_unknown_pragmas:
global.params.ignoreUnsupportedPragmas = value;
break;
case OPT_finvariants:
global.params.useInvariants = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fmain:
global.params.addMain = value;
break;
case OPT_fmodule_file_:
global.params.modFileAliasStrings.push (arg);
if (!strchr (arg, '='))
error ("bad argument for %<-fmodule-file%>: %qs", arg);
break;
case OPT_fmoduleinfo:
global.params.useModuleInfo = value;
break;
case OPT_fonly_:
d_option.fonly = arg;
break;
case OPT_fpostconditions:
global.params.useOut = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_fpreconditions:
global.params.useIn = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_frelease:
global.params.release = value;
break;
case OPT_frtti:
global.params.useTypeInfo = value;
break;
case OPT_fswitch_errors:
global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
break;
case OPT_ftransition_all:
global.params.vtls = value;
global.params.vfield = value;
global.params.vcomplex = value;
break;
case OPT_ftransition_complex:
global.params.vcomplex = value;
break;
case OPT_ftransition_dip1000:
global.params.vsafe = value;
global.params.useDIP25 = value;
break;
case OPT_ftransition_dip25:
global.params.useDIP25 = value;
break;
case OPT_ftransition_field:
global.params.vfield = value;
break;
case OPT_ftransition_nogc:
global.params.vgc = value;
break;
case OPT_ftransition_tls:
global.params.vtls = value;
break;
case OPT_funittest:
global.params.useUnitTests = 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);
break;
}
error ("bad argument for %<-fversion%>: %qs", arg);
break;
case OPT_H:
global.params.doHdrGeneration = true;
break;
case OPT_Hd:
global.params.doHdrGeneration = true;
global.params.hdrdir = arg;
break;
case OPT_Hf:
global.params.doHdrGeneration = true;
global.params.hdrname = arg;
break;
case OPT_imultilib:
d_option.multilib = arg;
break;
case OPT_iprefix:
d_option.prefix = arg;
break;
case OPT_I:
global.params.imppath->push (arg);
break;
case OPT_J:
global.params.fileImppath->push (arg);
break;
case OPT_MM:
d_option.deps_skip_system = true;
/* Fall through. */
case OPT_M:
d_option.deps = true;
break;
case OPT_MMD:
d_option.deps_skip_system = true;
/* Fall through. */
case OPT_MD:
d_option.deps = true;
d_option.deps_filename = arg;
break;
case OPT_MF:
/* If specified multiple times, last one wins. */
d_option.deps_filename_user = arg;
break;
case OPT_MP:
d_option.deps_phony = true;
break;
case OPT_MQ:
deps_add_target (arg, true);
break;
case OPT_MT:
deps_add_target (arg, false);
break;
case OPT_nostdinc:
d_option.stdinc = false;
break;
case OPT_v:
global.params.verbose = value;
break;
case OPT_Wall:
if (value)
global.params.warnings = DIAGNOSTICinform;
break;
case OPT_Wdeprecated:
global.params.useDeprecated = value ? DIAGNOSTICinform : DIAGNOSTICoff;
break;
case OPT_Werror:
if (value)
global.params.warnings = DIAGNOSTICerror;
break;
case OPT_Wspeculative:
if (value)
global.params.showGaggedErrors = 1;
break;
case OPT_Xf:
global.params.jsonfilename = arg;
/* Fall through. */
case OPT_X:
global.params.doJsonGeneration = true;
break;
default:
break;
}
D_handle_option_auto (&global_options, &global_options_set,
scode, arg, value,
d_option_lang_mask (), kind,
loc, handlers, global_dc);
return result;
}
/* Implements the lang_hooks.post_options routine for language D.
Deal with any options that imply the turning on/off of features.
FN is the main input filename passed on the command line. */
static bool
d_post_options (const char ** fn)
{
/* Verify the input file name. */
const char *filename = *fn;
if (!filename || strcmp (filename, "-") == 0)
filename = "";
/* The front end considers the first input file to be the main one. */
*fn = filename;
/* Release mode doesn't turn off bounds checking for safe functions. */
if (global.params.useArrayBounds == CHECKENABLEdefault)
{
global.params.useArrayBounds = global.params.release
? CHECKENABLEsafeonly : CHECKENABLEon;
}
/* Assert code is generated if unittests are being compiled also, even if
release mode is turned on. */
if (global.params.useAssert == CHECKENABLEdefault)
{
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.params.useOut == CHECKENABLEdefault)
{
global.params.useOut = global.params.release
? CHECKENABLEoff : CHECKENABLEon;
}
if (global.params.betterC)
{
if (!global_options_set.x_flag_moduleinfo)
global.params.useModuleInfo = false;
if (!global_options_set.x_flag_rtti)
global.params.useTypeInfo = false;
if (!global_options_set.x_flag_exceptions)
global.params.useExceptions = false;
global.params.checkAction = CHECKACTION_C;
}
/* 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)
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.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;
global.params.obj = !flag_syntax_only;
/* Has no effect yet. */
global.params.pic = flag_pic != 0;
/* 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.debugids)
{
for (size_t i = 0; i < global.params.debugids->length; i++)
{
const char *s = (*global.params.debugids)[i];
DebugCondition::addGlobalIdent (s);
}
}
if (warn_return_type == -1)
warn_return_type = 0;
return false;
}
/* 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)
{
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. */
void
d_add_entrypoint_module (Module *entry, Module *root)
{
/* We are emitting this straight to object file. */
entrypoint_module = entry;
entrypoint_root_module = root;
}
/* Implements the lang_hooks.parse_file routine for language D. */
static void
d_parse_file (void)
{
if (global.params.verbose)
{
message ("binary %s", global.params.argv0.ptr);
message ("version %s", global.version.ptr);
if (global.versionids)
{
obstack buffer;
gcc_obstack_init (&buffer);
obstack_grow (&buffer, "predefs ", 9);
for (size_t i = 0; i < global.versionids->length; i++)
{
Identifier *id = (*global.versionids)[i];
const char *str = id->toChars ();
obstack_1grow (&buffer, ' ');
obstack_grow (&buffer, str, strlen (str));
}
message ("%s", (char *) obstack_finish (&buffer));
}
}
/* Start the main input file, if the debug writer wants it. */
if (debug_hooks->start_end_main_source_file)
debug_hooks->start_source_file (0, main_input_filename);
/* Create Module's for all sources we will load. */
Modules modules;
modules.reserve (num_in_fnames);
/* 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");
for (size_t i = 0; i < num_in_fnames; i++)
{
if (strcmp (in_fnames[i], "-") == 0)
{
/* 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);
modules.push (m);
/* 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;
}
else
{
/* Handling a D source file, strip off the path and extension. */
const char *basename = FileName::name (in_fnames[i]);
const char *name = FileName::removeExt (basename);
Module *m = Module::create (in_fnames[i], Identifier::idPool (name),
global.params.doDocComments,
global.params.doHdrGeneration);
modules.push (m);
FileName::free (name);
}
}
/* Read all D source files. */
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.length; i++)
{
Module *m = modules[i];
if (global.params.verbose)
message ("parse %s", m->toChars ());
if (!Module::rootModule)
Module::rootModule = m;
m->importedFrom = m;
m->parse ();
if (m->isDocFile)
{
gendocfile (m);
/* Remove M from list of modules. */
modules.remove (i);
i--;
}
}
/* Load the module containing D main. */
if (global.params.addMain)
{
unsigned errors = global.startGagging ();
Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
if (!global.endGagging (errors))
{
m->importedFrom = m;
modules.push (m);
}
}
if (global.errors)
goto had_errors;
if (global.params.doHdrGeneration)
{
/* 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.length; i++)
{
Module *m = modules[i];
if (d_option.fonly && m != Module::rootModule)
continue;
if (global.params.verbose)
message ("import %s", m->toChars ());
genhdrfile (m);
}
}
if (global.errors)
goto had_errors;
/* Load all unconditional imports for better symbol resolving. */
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
if (global.params.verbose)
message ("importall %s", m->toChars ());
m->importAll (NULL);
}
if (global.errors)
goto had_errors;
/* Do semantic analysis. */
doing_semantic_analysis_p = true;
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
if (global.params.verbose)
message ("semantic %s", m->toChars ());
dsymbolSemantic (m, NULL);
}
/* Do deferred semantic analysis. */
Module::dprogress = 1;
Module::runDeferredSemantic ();
if (Module::deferred.length)
{
for (size_t i = 0; i < Module::deferred.length; i++)
{
Dsymbol *sd = Module::deferred[i];
error_at (make_location_t (sd->loc),
"unable to resolve forward reference in definition");
}
}
/* Process all built-in modules or functions now for CTFE. */
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.length; i++)
{
Module *m = modules[i];
if (global.params.verbose)
message ("semantic2 %s", m->toChars ());
semantic2 (m, NULL);
}
Module::runDeferredSemantic2 ();
if (global.errors)
goto had_errors;
/* Do pass 3 semantic analysis. */
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
if (global.params.verbose)
message ("semantic3 %s", m->toChars ());
semantic3 (m, NULL);
}
Module::runDeferredSemantic3 ();
/* Check again, incase semantic3 pass loaded any more modules. */
while (builtin_modules.length != 0)
{
Module *m = builtin_modules.pop ();
d_maybe_set_builtin (m);
}
/* Do not attempt to generate output files if errors or warnings occurred. */
if (global.errors || global.warnings)
goto had_errors;
/* Generate output files. */
doing_semantic_analysis_p = false;
if (Module::rootModule)
{
/* 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.extractChars ();
}
/* Make dependencies. */
if (d_option.deps)
{
obstack buffer;
FILE *deps_stream;
gcc_obstack_init (&buffer);
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)
{
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);
}
}
/* Generate JSON files. */
if (global.params.doJsonGeneration)
{
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);
}
/* Generate Ddoc files. */
if (global.params.doDocComments && !global.errors && !errorcount)
{
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
gendocfile (m);
}
}
/* Handle -fdump-d-original. */
if (global.params.vcg_ast)
{
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
OutBuffer buf;
buf.doindent = 1;
moduleToBuffer (&buf, m);
message ("%s", buf.peekChars ());
}
}
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
if (d_option.fonly && m != Module::rootModule)
continue;
if (global.params.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);
}
}
/* And end the main input file, if the debug writer wants it. */
if (debug_hooks->start_end_main_source_file)
debug_hooks->end_source_file (0);
had_errors:
/* Add the D frontend error count to the GCC error count to correctly
exit with an error status. */
errorcount += (global.errors + global.warnings);
/* Write out globals. */
d_finish_compilation (vec_safe_address (global_declarations),
vec_safe_length (global_declarations));
}
/* Implements the lang_hooks.types.type_for_mode routine for language D. */
static tree
d_type_for_mode (machine_mode mode, int unsignedp)
{
if (mode == QImode)
return unsignedp ? d_ubyte_type : d_byte_type;
if (mode == HImode)
return unsignedp ? d_ushort_type : d_short_type;
if (mode == SImode)
return unsignedp ? d_uint_type : d_int_type;
if (mode == DImode)
return unsignedp ? d_ulong_type : d_long_type;
if (mode == TYPE_MODE (d_cent_type))
return unsignedp ? d_ucent_type : d_cent_type;
if (mode == TYPE_MODE (float_type_node))
return float_type_node;
if (mode == TYPE_MODE (double_type_node))
return double_type_node;
if (mode == TYPE_MODE (long_double_type_node))
return long_double_type_node;
if (mode == TYPE_MODE (build_pointer_type (char8_type_node)))
return build_pointer_type (char8_type_node);
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;
tree inner_type;
if (mode == TYPE_MODE (complex_float_type_node))
return complex_float_type_node;
if (mode == TYPE_MODE (complex_double_type_node))
return complex_double_type_node;
if (mode == TYPE_MODE (complex_long_double_type_node))
return complex_long_double_type_node;
inner_mode = (machine_mode) GET_MODE_INNER (mode);
inner_type = d_type_for_mode (inner_mode, unsignedp);
if (inner_type != NULL_TREE)
return build_complex_type (inner_type);
}
else if (VECTOR_MODE_P (mode))
{
machine_mode inner_mode = (machine_mode) GET_MODE_INNER (mode);
tree inner_type = d_type_for_mode (inner_mode, unsignedp);
if (inner_type != NULL_TREE)
return build_vector_type_for_mode (inner_type, mode);
}
return 0;
}
/* Implements the lang_hooks.types.type_for_size routine for language D. */
static tree
d_type_for_size (unsigned bits, int unsignedp)
{
if (bits <= TYPE_PRECISION (d_byte_type))
return unsignedp ? d_ubyte_type : d_byte_type;
if (bits <= TYPE_PRECISION (d_short_type))
return unsignedp ? d_ushort_type : d_short_type;
if (bits <= TYPE_PRECISION (d_int_type))
return unsignedp ? d_uint_type : d_int_type;
if (bits <= TYPE_PRECISION (d_long_type))
return unsignedp ? d_ulong_type : d_long_type;
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;
}
/* Implements the lang_hooks.types.type_promotes_to routine for language D. */
static tree
d_type_promotes_to (tree type)
{
/* Promotions are only applied on unnamed function arguments for declarations
with `extern(C)' or `extern(C++)' linkage. */
if (cfun && DECL_LANG_FRONTEND (cfun->decl)
&& DECL_LANG_FRONTEND (cfun->decl)->linkage != LINKd)
{
/* 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;
if (type == char32_type_node)
return d_uint_type;
if (TYPE_PRECISION (type) < TYPE_PRECISION (d_int_type))
return d_int_type;
}
/* Float arguments are converted to doubles. */
if (type == float_type_node)
return double_type_node;
if (type == ifloat_type_node)
return idouble_type_node;
}
return type;
}
/* Implements the lang_hooks.decls.global_bindings_p routine for language D.
Return true if we are in the global binding level. */
static bool
d_global_bindings_p (void)
{
return (current_binding_level == global_binding_level);
}
/* Return global_context, but create it first if need be. */
static tree
get_global_context (void)
{
if (!global_context)
{
global_context = build_translation_unit_decl (NULL_TREE);
debug_hooks->register_main_translation_unit (global_context);
}
return global_context;
}
/* Implements the lang_hooks.decls.pushdecl routine for language D.
Record DECL as belonging to the current lexical scope. */
tree
d_pushdecl (tree decl)
{
/* Set the context of the decl. If current_function_decl did not help in
determining the context, use global scope. */
if (!DECL_CONTEXT (decl))
{
if (current_function_decl)
DECL_CONTEXT (decl) = current_function_decl;
else
DECL_CONTEXT (decl) = get_global_context ();
}
/* Put decls on list in reverse order. */
if (TREE_STATIC (decl) || d_global_bindings_p ())
vec_safe_push (global_declarations, decl);
else
{
TREE_CHAIN (decl) = current_binding_level->names;
current_binding_level->names = decl;
}
return decl;
}
/* Implements the lang_hooks.decls.getdecls routine for language D.
Return the list of declarations of the current level. */
static tree
d_getdecls (void)
{
if (current_binding_level)
return current_binding_level->names;
return NULL_TREE;
}
/* Implements the lang_hooks.get_alias_set routine for language D.
Get the alias set corresponding to type or expression T.
Return -1 if we don't do anything special. */
static alias_set_type
d_get_alias_set (tree)
{
/* For now in D, assume everything aliases everything else, until we define
some solid rules backed by a specification. There are also some parts
of code generation routines that don't adhere to C alias rules, such as
build_vconvert. In any case, a lot of user code already assumes there
is no strict aliasing and will break if we were to change that. */
return 0;
}
/* Implements the lang_hooks.types_compatible_p routine for language D.
Compares two types for equivalence in the D programming language.
This routine should only return 1 if it is sure, even though the frontend
should have already ensured that all types are compatible before handing
over the parsed ASTs to the code generator. */
static int
d_types_compatible_p (tree x, tree y)
{
Type *tx = TYPE_LANG_FRONTEND (x);
Type *ty = TYPE_LANG_FRONTEND (y);
/* Try validating the types in the frontend. */
if (tx != NULL && ty != NULL)
{
/* Types are equivalent. */
if (same_type_p (tx, ty))
return true;
/* Type system allows implicit conversion between. */
if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
return true;
}
/* Fallback on using type flags for comparison. E.g: all dynamic arrays
are distinct types in D, but are VIEW_CONVERT compatible. */
if (TREE_CODE (x) == RECORD_TYPE && TREE_CODE (y) == RECORD_TYPE)
{
if (TYPE_DYNAMIC_ARRAY (x) && TYPE_DYNAMIC_ARRAY (y))
return true;
if (TYPE_DELEGATE (x) && TYPE_DELEGATE (y))
return true;
if (TYPE_ASSOCIATIVE_ARRAY (x) && TYPE_ASSOCIATIVE_ARRAY (y))
return true;
}
return false;
}
/* Implements the lang_hooks.finish_incomplete_decl routine for language D. */
static void
d_finish_incomplete_decl (tree decl)
{
if (VAR_P (decl))
{
/* D allows zero-length declarations. Such a declaration ends up with
DECL_SIZE (t) == NULL_TREE which is what the back-end function
assembler_variable checks. This could change in later versions, or
maybe all of these variables should be aliased to one symbol. */
if (DECL_SIZE (decl) == 0)
{
DECL_SIZE (decl) = bitsize_zero_node;
DECL_SIZE_UNIT (decl) = size_zero_node;
}
}
}
/* Implements the lang_hooks.types.classify_record routine for language D.
Return the true debug type for TYPE. */
static classify_record
d_classify_record (tree type)
{
Type *t = TYPE_LANG_FRONTEND (type);
TypeClass *tc = t ? t->isTypeClass () : NULL;
if (tc != NULL)
{
/* extern(C++) interfaces get emitted as classes. */
if (tc->sym->isInterfaceDeclaration ()
&& !tc->sym->isCPPinterface ())
return RECORD_IS_INTERFACE;
return RECORD_IS_CLASS;
}
return RECORD_IS_STRUCT;
}
/* Implements the lang_hooks.tree_size routine for language D.
Determine the size of our tcc_constant or tcc_exceptional nodes. */
static size_t
d_tree_size (tree_code code)
{
switch (code)
{
case FUNCFRAME_INFO:
return sizeof (tree_frame_info);
default:
gcc_unreachable ();
}
}
/* Implements the lang_hooks.print_xnode routine for language D. */
static void
d_print_xnode (FILE *file, tree node, int indent)
{
switch (TREE_CODE (node))
{
case FUNCFRAME_INFO:
print_node (file, "frame_type", FRAMEINFO_TYPE (node), indent + 4);
break;
default:
break;
}
}
/* Return which tree structure is used by NODE, or TS_D_GENERIC if NODE
is one of the language-independent trees. */
d_tree_node_structure_enum
d_tree_node_structure (lang_tree_node *t)
{
switch (TREE_CODE (&t->generic))
{
case IDENTIFIER_NODE:
return TS_D_IDENTIFIER;
case FUNCFRAME_INFO:
return TS_D_FRAMEINFO;
default:
return TS_D_GENERIC;
}
}
/* Allocate and return a lang specific structure for the frontend type. */
struct lang_type *
build_lang_type (Type *t)
{
struct lang_type *lt = ggc_cleared_alloc <struct lang_type> ();
lt->type = t;
return lt;
}
/* Allocate and return a lang specific structure for the frontend decl. */
struct lang_decl *
build_lang_decl (Declaration *d)
{
/* For compiler generated run-time typeinfo, a lang_decl is allocated even if
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> ();
struct lang_decl *ld = (d->csym) ? DECL_LANG_SPECIFIC (d->csym) : NULL;
if (ld == NULL)
ld = ggc_cleared_alloc <struct lang_decl> ();
if (ld->decl == NULL)
ld->decl = d;
return ld;
}
/* Implements the lang_hooks.dup_lang_specific_decl routine for language D.
Replace the DECL_LANG_SPECIFIC field of NODE with a copy. */
static void
d_dup_lang_specific_decl (tree node)
{
if (!DECL_LANG_SPECIFIC (node))
return;
struct lang_decl *ld = ggc_alloc <struct lang_decl> ();
memcpy (ld, DECL_LANG_SPECIFIC (node), sizeof (struct lang_decl));
DECL_LANG_SPECIFIC (node) = ld;
}
/* This preserves trees we create from the garbage collector. */
static GTY(()) tree d_keep_list = NULL_TREE;
void
d_keep (tree t)
{
d_keep_list = tree_cons (NULL_TREE, t, d_keep_list);
}
/* Implements the lang_hooks.eh_personality routine for language D.
Return the GDC personality function decl. */
static GTY(()) tree d_eh_personality_decl;
static tree
d_eh_personality (void)
{
if (!d_eh_personality_decl)
d_eh_personality_decl = build_personality_function ("gdc");
return d_eh_personality_decl;
}
/* Implements the lang_hooks.eh_runtime_type routine for language D. */
static tree
d_build_eh_runtime_type (tree type)
{
Type *t = TYPE_LANG_FRONTEND (type);
gcc_assert (t != NULL);
t = t->toBasetype ();
ClassDeclaration *cd = t->isTypeClass ()->sym;
tree decl;
if (cd->isCPPclass ())
decl = get_cpp_typeinfo_decl (cd);
else
decl = get_classinfo_decl (cd);
return convert (ptr_type_node, build_address (decl));
}
/* Definitions for our language-specific hooks. */
#undef LANG_HOOKS_NAME
#undef LANG_HOOKS_INIT
#undef LANG_HOOKS_INIT_TS
#undef LANG_HOOKS_INIT_OPTIONS
#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
#undef LANG_HOOKS_OPTION_LANG_MASK
#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_REGISTER_BUILTIN_TYPE
#undef LANG_HOOKS_FINISH_INCOMPLETE_DECL
#undef LANG_HOOKS_GIMPLIFY_EXPR
#undef LANG_HOOKS_CLASSIFY_RECORD
#undef LANG_HOOKS_TREE_SIZE
#undef LANG_HOOKS_PRINT_XNODE
#undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
#undef LANG_HOOKS_EH_PERSONALITY
#undef LANG_HOOKS_EH_RUNTIME_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
#define LANG_HOOKS_NAME "GNU D"
#define LANG_HOOKS_INIT d_init
#define LANG_HOOKS_INIT_TS d_init_ts
#define LANG_HOOKS_INIT_OPTIONS d_init_options
#define LANG_HOOKS_INIT_OPTIONS_STRUCT d_init_options_struct
#define LANG_HOOKS_OPTION_LANG_MASK d_option_lang_mask
#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_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_CLASSIFY_RECORD d_classify_record
#define LANG_HOOKS_TREE_SIZE d_tree_size
#define LANG_HOOKS_PRINT_XNODE d_print_xnode
#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_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
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
#include "gt-d-d-lang.h"
#include "gtype-d.h"